1#!/usr/bin/env bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Test the "inc" interpreter. 5# 6# See include/uapi/linux/securebits.h, include/uapi/linux/fcntl.h and 7# samples/check-exec/inc.c 8# 9# Copyright © 2024 Microsoft Corporation 10 11set -u -e -o pipefail 12 13EXPECTED_OUTPUT="1" 14exec 2>/dev/null 15 16DIR="$(dirname $(readlink -f "$0"))" 17source "${DIR}"/../kselftest/ktap_helpers.sh 18 19exec_direct() { 20 local expect="$1" 21 local script="$2" 22 shift 2 23 local ret=0 24 local out 25 26 # Updates PATH for `env` to execute the `inc` interpreter. 27 out="$(PATH="." "$@" "${script}")" || ret=$? 28 29 if [[ ${ret} -ne ${expect} ]]; then 30 echo "ERROR: Wrong expectation for direct file execution: ${ret}" 31 return 1 32 fi 33 if [[ ${ret} -eq 0 && "${out}" != "${EXPECTED_OUTPUT}" ]]; then 34 echo "ERROR: Wrong output for direct file execution: ${out}" 35 return 1 36 fi 37} 38 39exec_indirect() { 40 local expect="$1" 41 local script="$2" 42 shift 2 43 local ret=0 44 local out 45 46 # Script passed as argument. 47 out="$("$@" ./inc "${script}")" || ret=$? 48 49 if [[ ${ret} -ne ${expect} ]]; then 50 echo "ERROR: Wrong expectation for indirect file execution: ${ret}" 51 return 1 52 fi 53 if [[ ${ret} -eq 0 && "${out}" != "${EXPECTED_OUTPUT}" ]]; then 54 echo "ERROR: Wrong output for indirect file execution: ${out}" 55 return 1 56 fi 57} 58 59exec_stdin_reg() { 60 local expect="$1" 61 local script="$2" 62 shift 2 63 local ret=0 64 local out 65 66 # Executing stdin must be allowed if the related file is executable. 67 out="$("$@" ./inc -i < "${script}")" || ret=$? 68 69 if [[ ${ret} -ne ${expect} ]]; then 70 echo "ERROR: Wrong expectation for stdin regular file execution: ${ret}" 71 return 1 72 fi 73 if [[ ${ret} -eq 0 && "${out}" != "${EXPECTED_OUTPUT}" ]]; then 74 echo "ERROR: Wrong output for stdin regular file execution: ${out}" 75 return 1 76 fi 77} 78 79exec_stdin_pipe() { 80 local expect="$1" 81 shift 82 local ret=0 83 local out 84 85 # A pipe is not executable. 86 out="$(cat script-exec.inc | "$@" ./inc -i)" || ret=$? 87 88 if [[ ${ret} -ne ${expect} ]]; then 89 echo "ERROR: Wrong expectation for stdin pipe execution: ${ret}" 90 return 1 91 fi 92} 93 94exec_argument() { 95 local expect="$1" 96 local ret=0 97 shift 98 local out 99 100 # Script not coming from a file must not be executed. 101 out="$("$@" ./inc -c "$(< script-exec.inc)")" || ret=$? 102 103 if [[ ${ret} -ne ${expect} ]]; then 104 echo "ERROR: Wrong expectation for arbitrary argument execution: ${ret}" 105 return 1 106 fi 107 if [[ ${ret} -eq 0 && "${out}" != "${EXPECTED_OUTPUT}" ]]; then 108 echo "ERROR: Wrong output for arbitrary argument execution: ${out}" 109 return 1 110 fi 111} 112 113exec_interactive() { 114 exec_stdin_pipe "$@" 115 exec_argument "$@" 116} 117 118ktap_test() { 119 ktap_test_result "$*" "$@" 120} 121 122ktap_print_header 123ktap_set_plan 28 124 125# Without secbit configuration, nothing is changed. 126 127ktap_print_msg "By default, executable scripts are allowed to be interpreted and executed." 128ktap_test exec_direct 0 script-exec.inc 129ktap_test exec_indirect 0 script-exec.inc 130 131ktap_print_msg "By default, executable stdin is allowed to be interpreted." 132ktap_test exec_stdin_reg 0 script-exec.inc 133 134ktap_print_msg "By default, non-executable scripts are allowed to be interpreted, but not directly executed." 135# We get 126 because of direct execution by Bash. 136ktap_test exec_direct 126 script-noexec.inc 137ktap_test exec_indirect 0 script-noexec.inc 138 139ktap_print_msg "By default, non-executable stdin is allowed to be interpreted." 140ktap_test exec_stdin_reg 0 script-noexec.inc 141 142ktap_print_msg "By default, interactive commands are allowed to be interpreted." 143ktap_test exec_interactive 0 144 145# With only file restriction: protect non-malicious users from inadvertent errors (e.g. python ~/Downloads/*.py). 146 147ktap_print_msg "With -f, executable scripts are allowed to be interpreted and executed." 148ktap_test exec_direct 0 script-exec.inc ./set-exec -f -- 149ktap_test exec_indirect 0 script-exec.inc ./set-exec -f -- 150 151ktap_print_msg "With -f, executable stdin is allowed to be interpreted." 152ktap_test exec_stdin_reg 0 script-exec.inc ./set-exec -f -- 153 154ktap_print_msg "With -f, non-executable scripts are not allowed to be executed nor interpreted." 155# Direct execution of non-executable script is alwayse denied by the kernel. 156ktap_test exec_direct 1 script-noexec.inc ./set-exec -f -- 157ktap_test exec_indirect 1 script-noexec.inc ./set-exec -f -- 158 159ktap_print_msg "With -f, non-executable stdin is allowed to be interpreted." 160ktap_test exec_stdin_reg 0 script-noexec.inc ./set-exec -f -- 161 162ktap_print_msg "With -f, interactive commands are allowed to be interpreted." 163ktap_test exec_interactive 0 ./set-exec -f -- 164 165# With only denied interactive commands: check or monitor script content (e.g. with LSM). 166 167ktap_print_msg "With -i, executable scripts are allowed to be interpreted and executed." 168ktap_test exec_direct 0 script-exec.inc ./set-exec -i -- 169ktap_test exec_indirect 0 script-exec.inc ./set-exec -i -- 170 171ktap_print_msg "With -i, executable stdin is allowed to be interpreted." 172ktap_test exec_stdin_reg 0 script-exec.inc ./set-exec -i -- 173 174ktap_print_msg "With -i, non-executable scripts are allowed to be interpreted, but not directly executed." 175# Direct execution of non-executable script is alwayse denied by the kernel. 176ktap_test exec_direct 1 script-noexec.inc ./set-exec -i -- 177ktap_test exec_indirect 0 script-noexec.inc ./set-exec -i -- 178 179ktap_print_msg "With -i, non-executable stdin is not allowed to be interpreted." 180ktap_test exec_stdin_reg 1 script-noexec.inc ./set-exec -i -- 181 182ktap_print_msg "With -i, interactive commands are not allowed to be interpreted." 183ktap_test exec_interactive 1 ./set-exec -i -- 184 185# With both file restriction and denied interactive commands: only allow executable scripts. 186 187ktap_print_msg "With -fi, executable scripts are allowed to be interpreted and executed." 188ktap_test exec_direct 0 script-exec.inc ./set-exec -fi -- 189ktap_test exec_indirect 0 script-exec.inc ./set-exec -fi -- 190 191ktap_print_msg "With -fi, executable stdin is allowed to be interpreted." 192ktap_test exec_stdin_reg 0 script-exec.inc ./set-exec -fi -- 193 194ktap_print_msg "With -fi, non-executable scripts are not allowed to be interpreted nor executed." 195# Direct execution of non-executable script is alwayse denied by the kernel. 196ktap_test exec_direct 1 script-noexec.inc ./set-exec -fi -- 197ktap_test exec_indirect 1 script-noexec.inc ./set-exec -fi -- 198 199ktap_print_msg "With -fi, non-executable stdin is not allowed to be interpreted." 200ktap_test exec_stdin_reg 1 script-noexec.inc ./set-exec -fi -- 201 202ktap_print_msg "With -fi, interactive commands are not allowed to be interpreted." 203ktap_test exec_interactive 1 ./set-exec -fi -- 204 205ktap_finished 206