All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] xfs: add a few more verifier tests
@ 2014-08-19  3:14 Eric Sandeen
  2014-08-19 18:15 ` Christoph Hellwig
  2014-08-19 19:36 ` [PATCH V2] " Eric Sandeen
  0 siblings, 2 replies; 6+ messages in thread
From: Eric Sandeen @ 2014-08-19  3:14 UTC (permalink / raw)
  To: xfs-oss

These were exposed by fsfuzzer runs; without them we fail
in various exciting and sometimes convoluted ways when we
encounter disk corruption.

Without the MAXLEVELS tests we tend to walk off the end of
an array in a loop like this:

        for (i = 0; i < cur->bc_nlevels; i++) {
                if (cur->bc_bufs[i])

Without the dirblklog test we try to allocate more memory
than we could possibly hope for and loop forever:

xfs_dabuf_map()
	nfsb = mp->m_dir_geo->fsbcount;
	irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP...

As for the logbsize check, that's the convoluted one.

If logbsize is specified at mount time, it's sanitized
in xfs_parseargs; in particular it makes sure that it's
not > XLOG_MAX_RECORD_BSIZE.
    
If not specified at mount time, it comes from the superblock
via sb_logsunit; this is limited to 256k at mkfs time as well;
it's copied into m_logbsize in xfs_finish_flags().
    
However, if for some reason the on-disk value is corrupt and
too large, nothing catches it.  It's a circuitous path, but
that size eventually finds its way to places that make the kernel
very unhappy, leading to oopses in xlog_pack_data() because we
use the size as an index into iclog->ic_data, but the array
is not necessarily that big.

Anyway - bounds checking when we read from disk is a good thing!

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
--

(if this should be separate patches, I can resend if you like)

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 4bffffe..a4a9e0e 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -2209,6 +2209,10 @@ xfs_agf_verify(
 	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
 		return false;
 
+	if (!(be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) <= XFS_BTREE_MAXLEVELS &&
+	      be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) <= XFS_BTREE_MAXLEVELS))
+		return false;
+	
 	/*
 	 * during growfs operations, the perag is not fully initialised,
 	 * so we can't use it for any useful checking. growfs ensures we can't
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index b62771f..ae15060 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2051,6 +2051,8 @@ xfs_agi_verify(
 	if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
 		return false;
 
+	if (!(be32_to_cpu(agi->agi_level) <= XFS_BTREE_MAXLEVELS))
+		return false;
 	/*
 	 * during growfs operations, the perag is not fully initialised,
 	 * so we can't use it for any useful checking. growfs ensures we can't
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index ad525a5..8426e5e 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -279,11 +279,13 @@ xfs_mount_validate_sb(
 	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
 	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
 	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
+	    sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG			||
 	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
 	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
 	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
 	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
 	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
+	    sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE			||
 	    sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
 	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
 	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] xfs: add a few more verifier tests
  2014-08-19  3:14 [PATCH] xfs: add a few more verifier tests Eric Sandeen
@ 2014-08-19 18:15 ` Christoph Hellwig
  2014-08-19 19:07   ` Eric Sandeen
  2014-08-19 19:36 ` [PATCH V2] " Eric Sandeen
  1 sibling, 1 reply; 6+ messages in thread
From: Christoph Hellwig @ 2014-08-19 18:15 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: xfs-oss

> Anyway - bounds checking when we read from disk is a good thing!

Absolutelt!

Looks good modulo a few nitpicks below.

Reviewed-by: Christoph Hellwig <hch@lst.de>

> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 4bffffe..a4a9e0e 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -2209,6 +2209,10 @@ xfs_agf_verify(
>  	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
>  		return false;
>  
> +	if (!(be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) <= XFS_BTREE_MAXLEVELS &&
> +	      be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) <= XFS_BTREE_MAXLEVELS))
> +		return false;

Maybe it's just me, but negated numeric comparisms always confuse the
hell out of me, why not simply:

	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS)
		return false;
	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
		return false;

> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -2051,6 +2051,8 @@ xfs_agi_verify(
>  	if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
>  		return false;
>  
> +	if (!(be32_to_cpu(agi->agi_level) <= XFS_BTREE_MAXLEVELS))
> +		return false;

Same here.

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] xfs: add a few more verifier tests
  2014-08-19 18:15 ` Christoph Hellwig
@ 2014-08-19 19:07   ` Eric Sandeen
  2014-08-19 22:38     ` Dave Chinner
  0 siblings, 1 reply; 6+ messages in thread
From: Eric Sandeen @ 2014-08-19 19:07 UTC (permalink / raw)
  To: Christoph Hellwig, Eric Sandeen; +Cc: xfs-oss

On 8/19/14, 1:15 PM, Christoph Hellwig wrote:
>> Anyway - bounds checking when we read from disk is a good thing!
> 
> Absolutelt!
> 
> Looks good modulo a few nitpicks below.
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> 
>> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
>> index 4bffffe..a4a9e0e 100644
>> --- a/fs/xfs/libxfs/xfs_alloc.c
>> +++ b/fs/xfs/libxfs/xfs_alloc.c
>> @@ -2209,6 +2209,10 @@ xfs_agf_verify(
>>  	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
>>  		return false;
>>  
>> +	if (!(be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) <= XFS_BTREE_MAXLEVELS &&
>> +	      be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) <= XFS_BTREE_MAXLEVELS))
>> +		return false;
> 
> Maybe it's just me, but negated numeric comparisms always confuse the
> hell out of me, why not simply:
> 
> 	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS)
> 		return false;
> 	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
> 		return false;
> 
>> --- a/fs/xfs/libxfs/xfs_ialloc.c
>> +++ b/fs/xfs/libxfs/xfs_ialloc.c
>> @@ -2051,6 +2051,8 @@ xfs_agi_verify(
>>  	if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
>>  		return false;
>>  
>> +	if (!(be32_to_cpu(agi->agi_level) <= XFS_BTREE_MAXLEVELS))
>> +		return false;
> 
> Same here.

yeah; just following the style of the functions as they exist today...

        if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
              XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
              be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
...

dunno. Don't care too much either way, but consistency and all that...

Maybe the "AGF_GOOD_VERSION" required the negation, and it all got lumped
together?

Thanks,
-Eric

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH V2] xfs: add a few more verifier tests
  2014-08-19  3:14 [PATCH] xfs: add a few more verifier tests Eric Sandeen
  2014-08-19 18:15 ` Christoph Hellwig
@ 2014-08-19 19:36 ` Eric Sandeen
  2014-09-09  1:47   ` Dave Chinner
  1 sibling, 1 reply; 6+ messages in thread
From: Eric Sandeen @ 2014-08-19 19:36 UTC (permalink / raw)
  To: Eric Sandeen, xfs-oss

These were exposed by fsfuzzer runs; without them we fail
in various exciting and sometimes convoluted ways when we
encounter disk corruption.

Without the MAXLEVELS tests we tend to walk off the end of
an array in a loop like this:

        for (i = 0; i < cur->bc_nlevels; i++) {
                if (cur->bc_bufs[i])

Without the dirblklog test we try to allocate more memory
than we could possibly hope for and loop forever:

xfs_dabuf_map()
	nfsb = mp->m_dir_geo->fsbcount;
	irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP...

As for the logbsize check, that's the convoluted one.

If logbsize is specified at mount time, it's sanitized
in xfs_parseargs; in particular it makes sure that it's
not > XLOG_MAX_RECORD_BSIZE.
    
If not specified at mount time, it comes from the superblock
via sb_logsunit; this is limited to 256k at mkfs time as well;
it's copied into m_logbsize in xfs_finish_flags().
    
However, if for some reason the on-disk value is corrupt and
too large, nothing catches it.  It's a circuitous path, but
that size eventually finds its way to places that make the kernel
very unhappy, leading to oopses in xlog_pack_data() because we
use the size as an index into iclog->ic_data, but the array
is not necessarily that big.

Anyway - bounds checking when we read from disk is a good thing!

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
--


V2: un-obfuscate the btree level tests, removing negated comparisons, per
hch's suggestion.

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 4bffffe..eff3421 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -2209,6 +2209,10 @@ xfs_agf_verify(
 	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
 		return false;
 
+	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||
+	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
+		return false;
+
 	/*
 	 * during growfs operations, the perag is not fully initialised,
 	 * so we can't use it for any useful checking. growfs ensures we can't
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index b62771f..d213a2e 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2051,6 +2051,8 @@ xfs_agi_verify(
 	if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
 		return false;
 
+	if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS)
+		return false;
 	/*
 	 * during growfs operations, the perag is not fully initialised,
 	 * so we can't use it for any useful checking. growfs ensures we can't
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index ad525a5..8426e5e 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -279,11 +279,13 @@ xfs_mount_validate_sb(
 	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
 	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
 	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
+	    sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG			||
 	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
 	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
 	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
 	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
 	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
+	    sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE			||
 	    sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) ||
 	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
 	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] xfs: add a few more verifier tests
  2014-08-19 19:07   ` Eric Sandeen
@ 2014-08-19 22:38     ` Dave Chinner
  0 siblings, 0 replies; 6+ messages in thread
From: Dave Chinner @ 2014-08-19 22:38 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Christoph Hellwig, Eric Sandeen, xfs-oss

On Tue, Aug 19, 2014 at 02:07:39PM -0500, Eric Sandeen wrote:
> On 8/19/14, 1:15 PM, Christoph Hellwig wrote:
> >> Anyway - bounds checking when we read from disk is a good thing!
> > 
> > Absolutelt!
> > 
> > Looks good modulo a few nitpicks below.
> > 
> > Reviewed-by: Christoph Hellwig <hch@lst.de>
> > 
> >> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> >> index 4bffffe..a4a9e0e 100644
> >> --- a/fs/xfs/libxfs/xfs_alloc.c
> >> +++ b/fs/xfs/libxfs/xfs_alloc.c
> >> @@ -2209,6 +2209,10 @@ xfs_agf_verify(
> >>  	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)))
> >>  		return false;
> >>  
> >> +	if (!(be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) <= XFS_BTREE_MAXLEVELS &&
> >> +	      be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) <= XFS_BTREE_MAXLEVELS))
> >> +		return false;
> > 
> > Maybe it's just me, but negated numeric comparisms always confuse the
> > hell out of me, why not simply:
> > 
> > 	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS)
> > 		return false;
> > 	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS)
> > 		return false;
> > 
> >> --- a/fs/xfs/libxfs/xfs_ialloc.c
> >> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> >> @@ -2051,6 +2051,8 @@ xfs_agi_verify(
> >>  	if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum)))
> >>  		return false;
> >>  
> >> +	if (!(be32_to_cpu(agi->agi_level) <= XFS_BTREE_MAXLEVELS))
> >> +		return false;
> > 
> > Same here.
> 
> yeah; just following the style of the functions as they exist today...
> 
>         if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
>               XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
>               be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) &&
> ...
> 
> dunno. Don't care too much either way, but consistency and all that...

I prefer the metho Christoph suggested - most of the verifiers use
that "single check per if statement" pattern because it makes the
checks being performed so much easier to read.

> Maybe the "AGF_GOOD_VERSION" required the negation, and it all got lumped
> together?

Those should probably be cleaned up - they were done like that
originally as a direct transcript from pre-existing code checks
to simplify review, not because it was "nice" code.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH V2] xfs: add a few more verifier tests
  2014-08-19 19:36 ` [PATCH V2] " Eric Sandeen
@ 2014-09-09  1:47   ` Dave Chinner
  0 siblings, 0 replies; 6+ messages in thread
From: Dave Chinner @ 2014-09-09  1:47 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Eric Sandeen, xfs-oss

On Tue, Aug 19, 2014 at 02:36:06PM -0500, Eric Sandeen wrote:
> These were exposed by fsfuzzer runs; without them we fail
> in various exciting and sometimes convoluted ways when we
> encounter disk corruption.
> 
> Without the MAXLEVELS tests we tend to walk off the end of
> an array in a loop like this:
> 
>         for (i = 0; i < cur->bc_nlevels; i++) {
>                 if (cur->bc_bufs[i])
> 
> Without the dirblklog test we try to allocate more memory
> than we could possibly hope for and loop forever:
> 
> xfs_dabuf_map()
> 	nfsb = mp->m_dir_geo->fsbcount;
> 	irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP...
> 
> As for the logbsize check, that's the convoluted one.
> 
> If logbsize is specified at mount time, it's sanitized
> in xfs_parseargs; in particular it makes sure that it's
> not > XLOG_MAX_RECORD_BSIZE.
>     
> If not specified at mount time, it comes from the superblock
> via sb_logsunit; this is limited to 256k at mkfs time as well;
> it's copied into m_logbsize in xfs_finish_flags().
>     
> However, if for some reason the on-disk value is corrupt and
> too large, nothing catches it.  It's a circuitous path, but
> that size eventually finds its way to places that make the kernel
> very unhappy, leading to oopses in xlog_pack_data() because we
> use the size as an index into iclog->ic_data, but the array
> is not necessarily that big.
> 
> Anyway - bounds checking when we read from disk is a good thing!
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> --

Looks good.

Reviewed-by: Dave Chinner <dchinner@redhat.com>

-- 
Dave Chinner
david@fromorbit.com

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-09-09  1:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-19  3:14 [PATCH] xfs: add a few more verifier tests Eric Sandeen
2014-08-19 18:15 ` Christoph Hellwig
2014-08-19 19:07   ` Eric Sandeen
2014-08-19 22:38     ` Dave Chinner
2014-08-19 19:36 ` [PATCH V2] " Eric Sandeen
2014-09-09  1:47   ` Dave Chinner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.