2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2018 Red Hat, Inc. All Rights Reserved.
7 # Test the XFS filestreams allocator for use-after-free inode access. The
8 # filestreams allocator uses the MRU and historically kept around unreferenced
9 # inode pointers in each element. These pointers could outlive the inodes they
10 # referred to and thus lead to access of freed or reused memory when the MRU
11 # element was reaped. Test for this problem by performing filestream allocations
12 # against short-lived parent directory inodes.
14 # Note that some form of kernel debug mechanism for use-after-free detection
15 # (i.e., KASAN) is required for this test to reproduce the original problem.
16 # This is because XFS uses a kmem cache for xfs_inode objects which means that
17 # the backing pages for freed inodes may still reside in the cache with the
18 # freed inodes in a partially initialized state.
21 seqres=$RESULT_DIR/$seq
22 echo "QA output created by $seq"
26 status=1 # failure is the default!
27 trap "_cleanup; exit \$status" 0 1 2 3 15
35 # get standard environment, filters and checks
38 . ./common/filestreams
40 # remove previous $seqres.full before test
43 # real QA test starts here
47 echo 2 > /proc/sys/vm/drop_caches
52 # Modify as appropriate.
55 _require_scratch_size $((2*1024*1024)) # kb
57 # check for filestreams
58 _check_filestreams_support || _notrun "filestreams not available"
60 # use small AGs for frequent stream switching
61 _scratch_mkfs_xfs -d agsize=20m,size=2g >> $seqres.full 2>&1 ||
63 _scratch_mount "-o filestreams"
65 # start background inode reclaim
69 # Stress the filestreams allocator via continuous allocation to a file under
70 # different parent dirs. Remove the old dirs as the file is moved so the MRU
71 # references point to an unlinked inode by the time they are removed. If the
72 # old dir inodes are reclaimed and associated memory reused, MRU cleanup can
73 # access the inode after it's been freed.
75 for i in $(seq 0 90); do
77 $XFS_IO_PROG -fc "falloc $(($i * 20))m 20m" $dir/$i/file
79 mkdir -p $dir/$((i + 1))
80 mv $dir/$i/file $dir/$((i + 1))/file
83 # throttle to ensure this loop sees several cache reclaims
87 kill $pid 2> /dev/null
88 wait $pid 2> /dev/null
90 echo Silence is golden