* [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks @ 2015-02-23 20:07 Brian Foster 2015-02-23 20:32 ` Eric Sandeen 2015-02-23 21:53 ` Dave Chinner 0 siblings, 2 replies; 5+ messages in thread From: Brian Foster @ 2015-02-23 20:07 UTC (permalink / raw) To: xfs The attr3 leaf header has a 16-bit firstused field that tracks the first used entry offset. This field is initialized to the block size in xfs_attr3_leaf_create() and updated accordingly in xfs_attr3_leaf_add_work() when new attributes are added. The initialization of firstused overflows if the block size exceeds 16-bits. E.g., xfstests test generic/117 causes assert failures on a -bsize=64k fs on ppc64 because ichdr.firstused evaluates to 0. Update the firstused initialization to not exceed the maximum value of an unsigned short. This avoids the overflow to 0 and allows firstused to be updated appropriately on subsequent xattr addition. Also update the freemap size calculation to use the actual block size rather than the potentially minimized version stored in firstused. Signed-off-by: Brian Foster <bfoster@redhat.com> --- fs/xfs/libxfs/xfs_attr_leaf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 15105db..dc7bda3 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -970,7 +970,8 @@ xfs_attr3_leaf_create( memset(leaf, 0, args->geo->blksize); memset(&ichdr, 0, sizeof(ichdr)); - ichdr.firstused = args->geo->blksize; + /* firstused is 16-bit */ + ichdr.firstused = min_t(int, USHRT_MAX, args->geo->blksize); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_blkinfo *hdr3 = bp->b_addr; @@ -986,7 +987,7 @@ xfs_attr3_leaf_create( ichdr.magic = XFS_ATTR_LEAF_MAGIC; ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); } - ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; + ichdr.freemap[0].size = args->geo->blksize - ichdr.freemap[0].base; xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1); -- 1.9.3 _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks 2015-02-23 20:07 [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks Brian Foster @ 2015-02-23 20:32 ` Eric Sandeen 2015-02-23 21:58 ` Dave Chinner 2015-02-24 13:28 ` Brian Foster 2015-02-23 21:53 ` Dave Chinner 1 sibling, 2 replies; 5+ messages in thread From: Eric Sandeen @ 2015-02-23 20:32 UTC (permalink / raw) To: Brian Foster, xfs On 2/23/15 2:07 PM, Brian Foster wrote: > The attr3 leaf header has a 16-bit firstused field that tracks the first > used entry offset. This field is initialized to the block size in > xfs_attr3_leaf_create() and updated accordingly in > xfs_attr3_leaf_add_work() when new attributes are added. > > The initialization of firstused overflows if the block size exceeds > 16-bits. E.g., xfstests test generic/117 causes assert failures on a > -bsize=64k fs on ppc64 because ichdr.firstused evaluates to 0. cool :) > Update the firstused initialization to not exceed the maximum value of > an unsigned short. This avoids the overflow to 0 and allows firstused to > be updated appropriately on subsequent xattr addition. Also update the > freemap size calculation to use the actual block size rather than the > potentially minimized version stored in firstused. I'm a little scared by this; does this truncated value risk going to disk? (Yes, I think so.) Is that ok? Does that ... mean we lose a byte of space we'd otherwise have? Maybe that's ok ... FWIW, I think the same problem exists in xfs_attr3_leaf_compact(): /* Initialise the incore headers */ ichdr_src = *ichdr_dst; /* struct copy */ ichdr_dst->firstused = args->geo->blksize; and xfs_attr3_leaf_unbalance(): tmphdr.firstused = state->args->geo->blksize; > Signed-off-by: Brian Foster <bfoster@redhat.com> > --- > fs/xfs/libxfs/xfs_attr_leaf.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c > index 15105db..dc7bda3 100644 > --- a/fs/xfs/libxfs/xfs_attr_leaf.c > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c > @@ -970,7 +970,8 @@ xfs_attr3_leaf_create( > memset(leaf, 0, args->geo->blksize); > > memset(&ichdr, 0, sizeof(ichdr)); > - ichdr.firstused = args->geo->blksize; > + /* firstused is 16-bit */ > + ichdr.firstused = min_t(int, USHRT_MAX, args->geo->blksize); > > if (xfs_sb_version_hascrc(&mp->m_sb)) { > struct xfs_da3_blkinfo *hdr3 = bp->b_addr; > @@ -986,7 +987,7 @@ xfs_attr3_leaf_create( > ichdr.magic = XFS_ATTR_LEAF_MAGIC; > ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); > } > - ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; > + ichdr.freemap[0].size = args->geo->blksize - ichdr.freemap[0].base; But now freemap.size is out of sync with firstused; is that ok? -Eric > xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr); > xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1); > _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks 2015-02-23 20:32 ` Eric Sandeen @ 2015-02-23 21:58 ` Dave Chinner 2015-02-24 13:28 ` Brian Foster 1 sibling, 0 replies; 5+ messages in thread From: Dave Chinner @ 2015-02-23 21:58 UTC (permalink / raw) To: Eric Sandeen; +Cc: Brian Foster, xfs On Mon, Feb 23, 2015 at 02:32:29PM -0600, Eric Sandeen wrote: > On 2/23/15 2:07 PM, Brian Foster wrote: > > The attr3 leaf header has a 16-bit firstused field that tracks the first > > used entry offset. This field is initialized to the block size in > > xfs_attr3_leaf_create() and updated accordingly in > > xfs_attr3_leaf_add_work() when new attributes are added. > > > > The initialization of firstused overflows if the block size exceeds > > 16-bits. E.g., xfstests test generic/117 causes assert failures on a > > -bsize=64k fs on ppc64 because ichdr.firstused evaluates to 0. > > cool :) > > > Update the firstused initialization to not exceed the maximum value of > > an unsigned short. This avoids the overflow to 0 and allows firstused to > > be updated appropriately on subsequent xattr addition. Also update the > > freemap size calculation to use the actual block size rather than the > > potentially minimized version stored in firstused. > > I'm a little scared by this; does this truncated value risk going to disk? > (Yes, I think so.) Is that ok? Does that ... mean we lose a byte of space > we'd otherwise have? Maybe that's ok ... > > FWIW, I think the same problem exists in xfs_attr3_leaf_compact(): > > /* Initialise the incore headers */ > ichdr_src = *ichdr_dst; /* struct copy */ > ichdr_dst->firstused = args->geo->blksize; > > and xfs_attr3_leaf_unbalance(): > > tmphdr.firstused = state->args->geo->blksize; And a loop in xfs_attr3_leaf_remove() that does: tmp = args->geo->blksize; ..... ichdr.firstused = tmp; so if the the loop in between does not modify tmp... 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] 5+ messages in thread
* Re: [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks 2015-02-23 20:32 ` Eric Sandeen 2015-02-23 21:58 ` Dave Chinner @ 2015-02-24 13:28 ` Brian Foster 1 sibling, 0 replies; 5+ messages in thread From: Brian Foster @ 2015-02-24 13:28 UTC (permalink / raw) To: Eric Sandeen; +Cc: xfs On Mon, Feb 23, 2015 at 02:32:29PM -0600, Eric Sandeen wrote: > On 2/23/15 2:07 PM, Brian Foster wrote: > > The attr3 leaf header has a 16-bit firstused field that tracks the first > > used entry offset. This field is initialized to the block size in > > xfs_attr3_leaf_create() and updated accordingly in > > xfs_attr3_leaf_add_work() when new attributes are added. > > > > The initialization of firstused overflows if the block size exceeds > > 16-bits. E.g., xfstests test generic/117 causes assert failures on a > > -bsize=64k fs on ppc64 because ichdr.firstused evaluates to 0. > > cool :) > > > Update the firstused initialization to not exceed the maximum value of > > an unsigned short. This avoids the overflow to 0 and allows firstused to > > be updated appropriately on subsequent xattr addition. Also update the > > freemap size calculation to use the actual block size rather than the > > potentially minimized version stored in firstused. > > I'm a little scared by this; does this truncated value risk going to disk? > (Yes, I think so.) Is that ok? Does that ... mean we lose a byte of space > we'd otherwise have? Maybe that's ok ... > I don't think it goes to disk in this situation, but even if it does I'm not sure it matters. Either it's a sane value for the field or it isn't. :) We've lost a byte according to the technical meaning of the field but I don't think that is the practical result. If you follow xfs_attr_shortform_to_leaf() down to xfs_attr3_leaf_add(), we use the freemap size and compare firstused against the base, so this is insignificant there. Continue further to xfs_attr3_leaf_add_work() where we do this: ichdr->freemap[mapindex].size -= xfs_attr_leaf_newentsize(args, &tmp); entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base + ichdr->freemap[mapindex].size); ... if (be16_to_cpu(entry->nameidx) < ichdr->firstused) ichdr->firstused = be16_to_cpu(entry->nameidx); ... ... and it looks to me that firstused will be updated appropriately on first insertion just the same since the data structure to track the entry itself is larger than a single byte (I think there's also 4-byte alignment rules in play here). All that said, that's just the insert after sf->leaf conversion case and I'm still working on grokking this code. I haven't considered the other compaction cases and whatnot yet. TBH, even if we do lose a byte in some circumstances, I think that's just a limitation of the on-disk format. We just have to make sure it's documented and handled correctly. Another question is what happens if one one of these blocks is emptied some time later (e.g., is conversion/removal guaranteed? maybe it's more appropriate to reduce the size as well, pretend the blocks are a few bytes shorter and avoid a landmine altogether). > FWIW, I think the same problem exists in xfs_attr3_leaf_compact(): > > /* Initialise the incore headers */ > ichdr_src = *ichdr_dst; /* struct copy */ > ichdr_dst->firstused = args->geo->blksize; > > and xfs_attr3_leaf_unbalance(): > > tmphdr.firstused = state->args->geo->blksize; > Indeed, thanks for catching these. I'll look through them and the one Dave pointed out. > > Signed-off-by: Brian Foster <bfoster@redhat.com> > > --- > > fs/xfs/libxfs/xfs_attr_leaf.c | 5 +++-- > > 1 file changed, 3 insertions(+), 2 deletions(-) > > > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c > > index 15105db..dc7bda3 100644 > > --- a/fs/xfs/libxfs/xfs_attr_leaf.c > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c > > @@ -970,7 +970,8 @@ xfs_attr3_leaf_create( > > memset(leaf, 0, args->geo->blksize); > > > > memset(&ichdr, 0, sizeof(ichdr)); > > - ichdr.firstused = args->geo->blksize; > > + /* firstused is 16-bit */ > > + ichdr.firstused = min_t(int, USHRT_MAX, args->geo->blksize); > > > > if (xfs_sb_version_hascrc(&mp->m_sb)) { > > struct xfs_da3_blkinfo *hdr3 = bp->b_addr; > > @@ -986,7 +987,7 @@ xfs_attr3_leaf_create( > > ichdr.magic = XFS_ATTR_LEAF_MAGIC; > > ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); > > } > > - ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; > > + ichdr.freemap[0].size = args->geo->blksize - ichdr.freemap[0].base; > > But now freemap.size is out of sync with firstused; is that ok? > I think so, according to the above logic. I'll have to see about those other cases... Brian > -Eric > > > xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr); > > xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1); > > > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs _______________________________________________ xfs mailing list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks 2015-02-23 20:07 [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks Brian Foster 2015-02-23 20:32 ` Eric Sandeen @ 2015-02-23 21:53 ` Dave Chinner 1 sibling, 0 replies; 5+ messages in thread From: Dave Chinner @ 2015-02-23 21:53 UTC (permalink / raw) To: Brian Foster; +Cc: xfs On Mon, Feb 23, 2015 at 03:07:30PM -0500, Brian Foster wrote: > The attr3 leaf header has a 16-bit firstused field that tracks the first > used entry offset. This field is initialized to the block size in > xfs_attr3_leaf_create() and updated accordingly in > xfs_attr3_leaf_add_work() when new attributes are added. > > The initialization of firstused overflows if the block size exceeds > 16-bits. E.g., xfstests test generic/117 causes assert failures on a > -bsize=64k fs on ppc64 because ichdr.firstused evaluates to 0. > > Update the firstused initialization to not exceed the maximum value of > an unsigned short. This avoids the overflow to 0 and allows firstused to > be updated appropriately on subsequent xattr addition. Also update the > freemap size calculation to use the actual block size rather than the > potentially minimized version stored in firstused. > > Signed-off-by: Brian Foster <bfoster@redhat.com> > --- > fs/xfs/libxfs/xfs_attr_leaf.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c > index 15105db..dc7bda3 100644 > --- a/fs/xfs/libxfs/xfs_attr_leaf.c > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c > @@ -970,7 +970,8 @@ xfs_attr3_leaf_create( > memset(leaf, 0, args->geo->blksize); > > memset(&ichdr, 0, sizeof(ichdr)); > - ichdr.firstused = args->geo->blksize; > + /* firstused is 16-bit */ > + ichdr.firstused = min_t(int, USHRT_MAX, args->geo->blksize); Needs a better comment. > > if (xfs_sb_version_hascrc(&mp->m_sb)) { > struct xfs_da3_blkinfo *hdr3 = bp->b_addr; > @@ -986,7 +987,7 @@ xfs_attr3_leaf_create( > ichdr.magic = XFS_ATTR_LEAF_MAGIC; > ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); > } > - ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; > + ichdr.freemap[0].size = args->geo->blksize - ichdr.freemap[0].base; And that also needs an explanation, too. 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] 5+ messages in thread
end of thread, other threads:[~2015-02-24 13:28 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-02-23 20:07 [PATCH] xfs: avoid firstused overflow in attr3 leaf header with 64k blocks Brian Foster 2015-02-23 20:32 ` Eric Sandeen 2015-02-23 21:58 ` Dave Chinner 2015-02-24 13:28 ` Brian Foster 2015-02-23 21:53 ` Dave Chinner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox