aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Chinner <david@fromorbit.com>2008-10-30 02:36:40 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 02:36:40 -0400
commit99fa8cb3c580d4445fe8fc239454e8f37a3b6847 (patch)
tree88b539774448ce3958d264f4a50a821d0dcde6f4
parentbf904248a2adb3f3be4eb4fb1837ce3bb28cca76 (diff)
[XFS] Prevent use-after-free caused by synchronous inode reclaim
With the combined linux and XFS inode, we need to ensure that the combined structure is not freed before the generic code is finished with the inode. As it turns out, there is a case where the XFS inode is freed before the linux inode - when xfs_reclaim() is called from ->clear_inode() on a clean inode, the xfs inode is freed during that call. The generic code references the inode after the ->clear_inode() call, so this is a use after free situation. Fix the problem by moving the xfs_reclaim() call to ->destroy_inode() instead of in ->clear_inode(). This ensures the combined inode structure is not freed until after the generic code has finished with it. SGI-PV: 988141 SGI-Modid: xfs-linux-melb:xfs-kern:32324a Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c32
1 files changed, 14 insertions, 18 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index c6ef684bf2e3..bb535a7737b5 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -875,13 +875,18 @@ xfs_fs_alloc_inode(
875} 875}
876 876
877/* 877/*
878 * we need to provide an empty inode free function to prevent 878 * Now that the generic code is guaranteed not to be accessing
879 * the generic code from trying to free our combined inode. 879 * the linux inode, we can reclaim the inode.
880 */ 880 */
881STATIC void 881STATIC void
882xfs_fs_destroy_inode( 882xfs_fs_destroy_inode(
883 struct inode *inode) 883 struct inode *inode)
884{ 884{
885 xfs_inode_t *ip = XFS_I(inode);
886
887 XFS_STATS_INC(vn_reclaim);
888 if (xfs_reclaim(ip))
889 panic("%s: cannot reclaim 0x%p\n", __func__, inode);
885} 890}
886 891
887/* 892/*
@@ -958,22 +963,13 @@ xfs_fs_clear_inode(
958{ 963{
959 xfs_inode_t *ip = XFS_I(inode); 964 xfs_inode_t *ip = XFS_I(inode);
960 965
961 /* 966 xfs_itrace_entry(ip);
962 * ip can be null when xfs_iget_core calls xfs_idestroy if we 967 XFS_STATS_INC(vn_rele);
963 * find an inode with di_mode == 0 but without IGET_CREATE set. 968 XFS_STATS_INC(vn_remove);
964 */ 969 XFS_STATS_DEC(vn_active);
965 if (ip) { 970
966 xfs_itrace_entry(ip); 971 xfs_inactive(ip);
967 XFS_STATS_INC(vn_rele); 972 xfs_iflags_clear(ip, XFS_IMODIFIED);
968 XFS_STATS_INC(vn_remove);
969 XFS_STATS_INC(vn_reclaim);
970 XFS_STATS_DEC(vn_active);
971
972 xfs_inactive(ip);
973 xfs_iflags_clear(ip, XFS_IMODIFIED);
974 if (xfs_reclaim(ip))
975 panic("%s: cannot reclaim 0x%p\n", __func__, inode);
976 }
977} 973}
978 974
979STATIC void 975STATIC void