xfsprogs: fix use after free in inode_item_done()
PATCH 1/1 xfsprogs: fix use after free in inode_item_done()
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
libxfs_iput() already does the check for ip->i_itemp, and a kmem_zone_free() if it's present, and then frees the ip pointer. Re-checking ip->i_itemp after the libxfs_iput call will access the freed ip pointer, as will setting ip_>i_itemp to NULL.
Simply remove the offending code to fix this up.
---
libxfs/trans.c +0 -7
@@ -694,7 +694,6 @@ inode_item_done(xfs_mount_t *mp;xfs_buf_t *bp;int error; -extern kmem_zone_t *xfs_ili_zone; ip = iip->ili_inode; mp = iip->ili_item.li_mountp;
@@ -739,12 +738,6 @@ ili_done: }else {libxfs_iput (ip,0 ); } - -if (ip->i_itemp) -kmem_zone_free (xfs_ili_zone, ip->i_itemp); -else -ASSERT (0 ); - ip->i_itemp =NULL ; } static void
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 9 lines · Eric Sandeen
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
libxfs_iput()already does the check forip->i_itemp, and akmem_zone_free()if it's present, and then frees the ip pointer. Re-checkingip->i_itempafter thelibxfs_iputcall will access the freed ip pointer, as will setting ip_>i_itemp to NULL.Simply remove the offending code to fix this up.
which leaves the rest of the ili_done: code looking a little strange.
can you convert that now to be:
ili_done:
if (iip->ili_lock_flags) {
iip->ili_lock_flags = 0;
return;
}
/* free the inode */
libxfs_iput(ip, 0);
}Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Quoted 16 lines · Dave Chinner
Quoted 9 lines · Eric Sandeen
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
libxfs_iput()already does the check forip->i_itemp, and akmem_zone_free()if it's present, and then frees the ip pointer. Re-checkingip->i_itempafter thelibxfs_iputcall will access the freed ip pointer, as will setting ip_>i_itemp to NULL.Simply remove the offending code to fix this up.
which leaves the rest of the
ili_done: code looking a little strange.can you convert that now to be:
Quoted 8 lines
ili_done:if (iip->ili_lock_flags) { iip->ili_lock_flags = 0; return; } /* free the inode */ libxfs_iput(ip, 0); }
yeah, I actually had that first. Not sure why I didn't go with it ;)
(Still looks strange to my untrained eye; "if lock flags are set, unset them and don't free the inode, otherwise free it")
Anyway, I'll resend. No need to educate me on these details, for now. ;)
-Eric
Quoted 4 lines
Cheers,
Dave.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 26 lines · Eric Sandeen
Quoted 16 lines · Dave Chinner
Quoted 9 lines · Eric Sandeen
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
libxfs_iput()already does the check forip->i_itemp, and akmem_zone_free()if it's present, and then frees the ip pointer. Re-checkingip->i_itempafter thelibxfs_iputcall will access the freed ip pointer, as will setting ip_>i_itemp to NULL.Simply remove the offending code to fix this up.
which leaves the rest of the
ili_done: code looking a little strange.can you convert that now to be:
Quoted 8 lines
ili_done:if (iip->ili_lock_flags) { iip->ili_lock_flags = 0; return; } /* free the inode */ libxfs_iput(ip, 0); }
Quoted 3 lines
yeah, I actually had that first. Not sure why I didn't go with it ;)
(Still looks strange to my untrained eye; "if lock flags are set, unset them and don't free the inode, otherwise free it")
If the lock falgs are set, it means the caller expects the transaction commit to return the inode to it in a locked state. Exactly the same semantics as the kernel code - the lock flags track how the transaction releases the inode...
Cheers,
Dave.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Quoted 1 line · Eric Sandeen
On 3/3/14, 4:36 PM, Dave Chinner wrote:
...
Quoted 14 lines
Quoted 5 lines
which leaves the rest of the
ili_done: code looking a little strange.can you convert that now to be:
Quoted 8 lines
ili_done:if (iip->ili_lock_flags) { iip->ili_lock_flags = 0; return; } /* free the inode */ libxfs_iput(ip, 0); }
Quoted 4 lines
yeah, I actually had that first. Not sure why I didn't go with it ;)
(Still looks strange to my untrained eye; "if lock flags are set, unset them and don't free the inode, otherwise free it")
I'd be tempted to write:
ili_done:
if (iip->ili_lock_flags == 0) /* don't return locked inode */ libxfs_iput(ip, 0); iip->ili_lock_flags = 0;
Signature · 6 lines
Roger Willcocks <[email protected]> _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
PATCH v2 1/1 xfsprogs: fix use after free in inode_item_done()
In reply to Eric SandeenCommit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
libxfs_iput() already does the check for ip->i_itemp, and a kmem_zone_free() if it's present, and then frees the ip pointer. Re-checking ip->i_itemp after the libxfs_iput call will access the freed ip pointer, as will setting ip_>i_itemp to NULL.
Simply remove the offending code to fix this up.
---
V2: Make it prettier based on Dave's comments.
libxfs/trans.c +2 -9
@@ -694,7 +694,6 @@ inode_item_done(xfs_mount_t *mp;xfs_buf_t *bp;int error; -extern kmem_zone_t *xfs_ili_zone; ip = iip->ili_inode; mp = iip->ili_item.li_mountp;
@@ -736,15 +735,9 @@ ili_done:if (iip->ili_lock_flags) { iip->ili_lock_flags =0 ;return ; - }else { -libxfs_iput (ip,0 ); } - -if (ip->i_itemp) -kmem_zone_free (xfs_ili_zone, ip->i_itemp); -else -ASSERT (0 ); - ip->i_itemp =NULL ; +/* free the inode */ +libxfs_iput (ip,0 ); } static void
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 8 lines · Eric Sandeen
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
libxfs_iput()already does the check forip->i_itemp, and akmem_zone_free()if it's present, and then frees the ip pointer. Re-checkingip->i_itempafter thelibxfs_iputcall will access the freed ip pointer, as will setting ip_>i_itemp to NULL.
Quoted 6 lines
Simply remove the offending code to fix this up.
Signed-off-by Eric Sandeen <[email protected]>---
V2: Make it prettier based on Dave's comments.
looks good.
Signature · 7 lines
Dave Chinner [email protected] _______________________________________________ xfs mailing list [email protected] http://oss.sgi.com/mailman/listinfo/xfs
Quoted 2 lines · Eric Sandeen
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
I see the use after free, but I don't see how I would have introduced it in that commit. Before that libxfs_iput already was freeing the inode through the cache code, now we do it directly.
libxfs/trans.c ili_done: · line 741
Quoted 11 lines
libxfs/trans.c +0
-6@@ -739,12 +738,6 @@ ili_done: }else {libxfs_iput (ip,0 ); } - -if (ip->i_itemp) -kmem_zone_free (xfs_ili_zone, ip->i_itemp); -else -ASSERT (0 ); - ip->i_itemp =NULL ; }
Seems like inode_item_done should call into inode_item_unlock, which factors the exact sequence we want into a nice helper.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
Quoted 7 lines · Christoph Hellwig
Quoted 2 lines · Eric Sandeen
Commit "3a19fb7 libxfs: stop caching inode structures" introduced a use after free.
I see the use after free, but I don't see how I would have introduced it in that commit. Before that
libxfs_iputalready was freeing the inode through the cache code, now we do it directly.
Ok, sorry if I wrongly implicated that commit.
Quoted 6 lines
Quoted 6 lines
libxfs/trans.c +0
-2@@ -739,12 +738,6 @@ ili_done: }else {libxfs_iput (ip,0 ); } - -if (ip->i_itemp)
Quoted 8 lines
libxfs/trans.c ili_done: · line 741
Quoted 5 lines
libxfs/trans.c +0
-4-kmem_zone_free (xfs_ili_zone, ip->i_itemp); - else - ASSERT(0); - ip->i_itemp =NULL ; }Seems like
inode_item_doneshould call intoinode_item_unlock, which factors the exact sequence we want into a nice helper.
Yeah, that does seem better! Thanks for spotting that.
The difference when calling inode_item_unlock is a bit more zeroing-out:
ip->i_transp = NULL;
iip->ili_flags = 0;I'm not sure of the implications of that offhand, TBH.
Dave, hold off on my commit I guess ;)
-Eric
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 7 lines · Christoph Hellwig
Quoted 6 lines · Eric Sandeen
Yeah, that does seem better! Thanks for spotting that.
The difference when calling
inode_item_unlockis a bit more zeroing-out:ip->i_transp = NULL;
Quoted 8 lines
Quoted 5 lines
iip->ili_flags = 0;I'm not sure of the implications of that offhand, TBH.
Dave, hold off on my commit I guess ;)
i_itranspnulling is obviously harmless as we are freeing the inode right after.
Not in all cases, right?
static void
inode_item_unlock(
xfs_inode_log_item_t *iip)
{
xfs_inode_t *ip = iip->ili_inode;
/* Clear the transaction pointer in the inode. */
ip->i_transp = NULL;
iip->ili_flags = 0;
if (!iip->ili_lock_flags)
libxfs_iput(ip, 0);
else
iip->ili_lock_flags = 0; // <-- not here.
}Quoted 2 lines
ili_flagsis always 0 in libxfs and we might as well just remove it.
_______________________________________________
xfs mailing list
[email protected]
http://oss.sgi.com/mailman/listinfo/xfs