--- /dev/null
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Red Hat, Inc. All Rights Reserved.
+#
+# FS QA Test No. 597
+#
+# Test protected_symlink and protected_hardlink sysctls
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ rm -rf $TEST_DIR/$seq
+ [ ! -z "$SYMLINK_PROTECTION" ] \
+ && sysctl -qw fs.protected_symlinks=$SYMLINK_PROTECTION
+ [ ! -z "$HARDLINK_PROTECTION" ] \
+ && sysctl -qw fs.protected_hardlinks=$HARDLINK_PROTECTION
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs generic
+_supported_os Linux
+_require_test
+_require_sysctl_variable fs.protected_symlinks
+_require_sysctl_variable fs.protected_hardlinks
+# su in _require_user prints warnings about user name starts with a digit,
+# discard the warning
+_require_user 123456-fsgqa >/dev/null 2>&1
+# Do this SECOND so that qa_user is fsgqa, and _user_do uses that account
+_require_user fsgqa
+
+OWNER=123456-fsgqa
+OTHER=fsgqa
+
+# Save current system state to reset when done
+SYMLINK_PROTECTION=`sysctl -n fs.protected_symlinks`
+HARDLINK_PROTECTION=`sysctl -n fs.protected_hardlinks`
+
+test_symlink()
+{
+ ln -s $TEST_DIR/$seq/target $TEST_DIR/$seq/sticky_dir/symlink
+ chown $OTHER.$OTHER $TEST_DIR/$seq/sticky_dir
+ chown $OWNER.$OWNER $TEST_DIR/$seq/sticky_dir/symlink
+ # If we can read the target, we followed the link
+ _user_do "cat $TEST_DIR/$seq/sticky_dir/symlink" | _filter_test_dir
+ rm -f $TEST_DIR/$seq/sticky_dir/symlink
+}
+
+test_hardlink()
+{
+ chown $OWNER.$OWNER $TEST_DIR/$seq/target
+ chmod go-rw $TEST_DIR/$seq/target
+ _user_do "ln $TEST_DIR/$seq/target $TEST_DIR/$seq/sticky_dir/hardlink" \
+ | _filter_test_dir
+ test -f $TEST_DIR/$seq/sticky_dir/hardlink \
+ && echo "successfully created hardlink"
+ rm -f $TEST_DIR/$seq/sticky_dir/hardlink
+}
+
+setup_tree()
+{
+ # Create world-writable sticky dir
+ mkdir -p $TEST_DIR/$seq/sticky_dir
+ chmod 1777 $TEST_DIR/$seq/sticky_dir
+ # And a file elsewhere that will be linked to from that sticky dir
+ mkdir -p $TEST_DIR/$seq
+ # If we can read it, we followed the link.
+ echo "successfully followed symlink" > $TEST_DIR/$seq/target
+}
+
+setup_tree
+
+# First test fs.protected_symlinks
+# With protection on, symlink follows should fail if the
+# link owner != the sticky directory owner, and the process
+# is not the link owner.
+echo "== Test symlink follow protection when"
+echo "== process != link owner and dir owner != link owner"
+sysctl -w fs.protected_symlinks=0
+test_symlink
+sysctl -w fs.protected_symlinks=1
+test_symlink
+
+echo
+
+# Now test fs.protected_hardlinks
+# With protection on, hardlink creation should fail if the
+# process does not own the target file, and the process does not have
+# read-write access to the target
+echo "== Test hardlink create protection when"
+echo "== process != target owner and process cannot read target"
+sysctl -w fs.protected_hardlinks=0
+test_hardlink
+sysctl -w fs.protected_hardlinks=1
+test_hardlink
+
+# success, all done
+status=0
+exit
--- /dev/null
+QA output created by 597
+== Test symlink follow protection when
+== process != link owner and dir owner != link owner
+fs.protected_symlinks = 0
+successfully followed symlink
+fs.protected_symlinks = 1
+Permission denied
+
+== Test hardlink create protection when
+== process != target owner and process cannot read target
+fs.protected_hardlinks = 0
+successfully created hardlink
+fs.protected_hardlinks = 1
+ln: failed to create hard link 'TEST_DIR/597/sticky_dir/hardlink' => 'TEST_DIR/597/target': Operation not permitted