xfs: filestream allocator inode use-after-free test
[xfstests-dev.git] / tests / xfs / 445
1 #! /bin/bash
2 # FS QA Test 445
3 #
4 # Test the XFS filestreams allocator for use-after-free inode access. The
5 # filestreams allocator uses the MRU and historically kept around unreferenced
6 # inode pointers in each element. These pointers could outlive the inodes they
7 # referred to and thus lead to access of freed or reused memory when the MRU
8 # element was reaped. Test for this problem by performing filestream allocations
9 # against short-lived parent directory inodes.
10 #
11 # Note that some form of kernel debug mechanism for use-after-free detection
12 # (i.e., KASAN) is required for this test to reproduce the original problem.
13 # This is because XFS uses a kmem cache for xfs_inode objects which means that
14 # the backing pages for freed inodes may still reside in the cache with the
15 # freed inodes in a partially initialized state.
16 #
17 #-----------------------------------------------------------------------
18 # Copyright (c) 2018 Red Hat, Inc.  All Rights Reserved.
19 #
20 # This program is free software; you can redistribute it and/or
21 # modify it under the terms of the GNU General Public License as
22 # published by the Free Software Foundation.
23 #
24 # This program is distributed in the hope that it would be useful,
25 # but WITHOUT ANY WARRANTY; without even the implied warranty of
26 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 # GNU General Public License for more details.
28 #
29 # You should have received a copy of the GNU General Public License
30 # along with this program; if not, write the Free Software Foundation,
31 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
32 #-----------------------------------------------------------------------
33 #
34
35 seq=`basename $0`
36 seqres=$RESULT_DIR/$seq
37 echo "QA output created by $seq"
38
39 here=`pwd`
40 tmp=/tmp/$$
41 status=1        # failure is the default!
42 trap "_cleanup; exit \$status" 0 1 2 3 15
43
44 _cleanup()
45 {
46         cd /
47         rm -f $tmp.*
48 }
49
50 # get standard environment, filters and checks
51 . ./common/rc
52 . ./common/filter
53 . ./common/filestreams
54
55 # remove previous $seqres.full before test
56 rm -f $seqres.full
57
58 # real QA test starts here
59 drop_caches()
60 {
61         while [ true ]; do
62                 echo 2 > /proc/sys/vm/drop_caches
63                 sleep 1
64         done
65 }
66
67 # Modify as appropriate.
68 _supported_fs generic
69 _supported_os Linux
70 _require_scratch_size $((2*1024*1024)) # kb
71
72 # check for filestreams
73 _check_filestreams_support || _notrun "filestreams not available"
74
75 # use small AGs for frequent stream switching
76 _scratch_mkfs_xfs -d agsize=20m,size=2g >> $seqres.full 2>&1 ||
77         _fail "mkfs failed"
78 _scratch_mount "-o filestreams"
79
80 # start background inode reclaim
81 drop_caches &
82 pid=$!
83
84 # Stress the filestreams allocator via continuous allocation to a file under
85 # different parent dirs. Remove the old dirs as the file is moved so the MRU
86 # references point to an unlinked inode by the time they are removed. If the
87 # old dir inodes are reclaimed and associated memory reused, MRU cleanup can
88 # access the inode after it's been freed.
89 dir=$SCRATCH_MNT
90 for i in $(seq 0 90); do
91         mkdir -p $dir/$i
92         $XFS_IO_PROG -fc "falloc $(($i * 20))m 20m" $dir/$i/file
93
94         mkdir -p $dir/$((i + 1))
95         mv $dir/$i/file $dir/$((i + 1))/file
96         rmdir $dir/$i
97
98         # throttle to ensure this loop sees several cache reclaims
99         sleep 0.1
100 done
101
102 kill $pid 2> /dev/null
103 wait $pid 2> /dev/null
104
105 echo Silence is golden
106
107 # success, all done
108 status=0
109 exit