~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/livepatch/functions.sh

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/bin/bash
  2 # SPDX-License-Identifier: GPL-2.0
  3 # Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>
  4 
  5 # Shell functions for the rest of the scripts.
  6 
  7 MAX_RETRIES=600
  8 RETRY_INTERVAL=".1"     # seconds
  9 KLP_SYSFS_DIR="/sys/kernel/livepatch"
 10 
 11 # Kselftest framework requirement - SKIP code is 4
 12 ksft_skip=4
 13 
 14 # log(msg) - write message to kernel log
 15 #       msg - insightful words
 16 function log() {
 17         echo "$1" > /dev/kmsg
 18 }
 19 
 20 # skip(msg) - testing can't proceed
 21 #       msg - explanation
 22 function skip() {
 23         log "SKIP: $1"
 24         echo "SKIP: $1" >&2
 25         exit $ksft_skip
 26 }
 27 
 28 # root test
 29 function is_root() {
 30         uid=$(id -u)
 31         if [ $uid -ne 0 ]; then
 32                 echo "skip all tests: must be run as root" >&2
 33                 exit $ksft_skip
 34         fi
 35 }
 36 
 37 # Check if we can compile the modules before loading them
 38 function has_kdir() {
 39         if [ -z "$KDIR" ]; then
 40                 KDIR="/lib/modules/$(uname -r)/build"
 41         fi
 42 
 43         if [ ! -d "$KDIR" ]; then
 44                 echo "skip all tests: KDIR ($KDIR) not available to compile modules."
 45                 exit $ksft_skip
 46         fi
 47 }
 48 
 49 # die(msg) - game over, man
 50 #       msg - dying words
 51 function die() {
 52         log "ERROR: $1"
 53         echo "ERROR: $1" >&2
 54         exit 1
 55 }
 56 
 57 function push_config() {
 58         DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \
 59                         awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}')
 60         FTRACE_ENABLED=$(sysctl --values kernel.ftrace_enabled)
 61 }
 62 
 63 function pop_config() {
 64         if [[ -n "$DYNAMIC_DEBUG" ]]; then
 65                 echo -n "$DYNAMIC_DEBUG" > /sys/kernel/debug/dynamic_debug/control
 66         fi
 67         if [[ -n "$FTRACE_ENABLED" ]]; then
 68                 sysctl kernel.ftrace_enabled="$FTRACE_ENABLED" &> /dev/null
 69         fi
 70 }
 71 
 72 function set_dynamic_debug() {
 73         cat <<-EOF > /sys/kernel/debug/dynamic_debug/control
 74                 file kernel/livepatch/* +p
 75                 func klp_try_switch_task -p
 76                 EOF
 77 }
 78 
 79 function set_ftrace_enabled() {
 80         local can_fail=0
 81         if [[ "$1" == "--fail" ]] ; then
 82                 can_fail=1
 83                 shift
 84         fi
 85 
 86         local err=$(sysctl -q kernel.ftrace_enabled="$1" 2>&1)
 87         local result=$(sysctl --values kernel.ftrace_enabled)
 88 
 89         if [[ "$result" != "$1" ]] ; then
 90                 if [[ $can_fail -eq 1 ]] ; then
 91                         echo "livepatch: $err" | sed 's#/proc/sys/kernel/#kernel.#' > /dev/kmsg
 92                         return
 93                 fi
 94 
 95                 skip "failed to set kernel.ftrace_enabled = $1"
 96         fi
 97 
 98         echo "livepatch: kernel.ftrace_enabled = $result" > /dev/kmsg
 99 }
100 
101 function cleanup() {
102         pop_config
103 }
104 
105 # setup_config - save the current config and set a script exit trap that
106 #                restores the original config.  Setup the dynamic debug
107 #                for verbose livepatching output and turn on
108 #                the ftrace_enabled sysctl.
109 function setup_config() {
110         is_root
111         has_kdir
112         push_config
113         set_dynamic_debug
114         set_ftrace_enabled 1
115         trap cleanup EXIT INT TERM HUP
116 }
117 
118 # loop_until(cmd) - loop a command until it is successful or $MAX_RETRIES,
119 #                   sleep $RETRY_INTERVAL between attempts
120 #       cmd - command and its arguments to run
121 function loop_until() {
122         local cmd="$*"
123         local i=0
124         while true; do
125                 eval "$cmd" && return 0
126                 [[ $((i++)) -eq $MAX_RETRIES ]] && return 1
127                 sleep $RETRY_INTERVAL
128         done
129 }
130 
131 function is_livepatch_mod() {
132         local mod="$1"
133 
134         if [[ ! -f "test_modules/$mod.ko" ]]; then
135                 die "Can't find \"test_modules/$mod.ko\", try \"make\""
136         fi
137 
138         if [[ $(modinfo "test_modules/$mod.ko" | awk '/^livepatch:/{print $NF}') == "Y" ]]; then
139                 return 0
140         fi
141 
142         return 1
143 }
144 
145 function __load_mod() {
146         local mod="$1"; shift
147 
148         local msg="% insmod test_modules/$mod.ko $*"
149         log "${msg%% }"
150         ret=$(insmod "test_modules/$mod.ko" "$@" 2>&1)
151         if [[ "$ret" != "" ]]; then
152                 die "$ret"
153         fi
154 
155         # Wait for module in sysfs ...
156         loop_until '[[ -e "/sys/module/$mod" ]]' ||
157                 die "failed to load module $mod"
158 }
159 
160 
161 # load_mod(modname, params) - load a kernel module
162 #       modname - module name to load
163 #       params  - module parameters to pass to insmod
164 function load_mod() {
165         local mod="$1"; shift
166 
167         is_livepatch_mod "$mod" &&
168                 die "use load_lp() to load the livepatch module $mod"
169 
170         __load_mod "$mod" "$@"
171 }
172 
173 # load_lp_nowait(modname, params) - load a kernel module with a livepatch
174 #                       but do not wait on until the transition finishes
175 #       modname - module name to load
176 #       params  - module parameters to pass to insmod
177 function load_lp_nowait() {
178         local mod="$1"; shift
179 
180         is_livepatch_mod "$mod" ||
181                 die "module $mod is not a livepatch"
182 
183         __load_mod "$mod" "$@"
184 
185         # Wait for livepatch in sysfs ...
186         loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' ||
187                 die "failed to load module $mod (sysfs)"
188 }
189 
190 # load_lp(modname, params) - load a kernel module with a livepatch
191 #       modname - module name to load
192 #       params  - module parameters to pass to insmod
193 function load_lp() {
194         local mod="$1"; shift
195 
196         load_lp_nowait "$mod" "$@"
197 
198         # Wait until the transition finishes ...
199         loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' ||
200                 die "failed to complete transition"
201 }
202 
203 # load_failing_mod(modname, params) - load a kernel module, expect to fail
204 #       modname - module name to load
205 #       params  - module parameters to pass to insmod
206 function load_failing_mod() {
207         local mod="$1"; shift
208 
209         local msg="% insmod test_modules/$mod.ko $*"
210         log "${msg%% }"
211         ret=$(insmod "test_modules/$mod.ko" "$@" 2>&1)
212         if [[ "$ret" == "" ]]; then
213                 die "$mod unexpectedly loaded"
214         fi
215         log "$ret"
216 }
217 
218 # unload_mod(modname) - unload a kernel module
219 #       modname - module name to unload
220 function unload_mod() {
221         local mod="$1"
222 
223         # Wait for module reference count to clear ...
224         loop_until '[[ $(cat "/sys/module/$mod/refcnt") == "0" ]]' ||
225                 die "failed to unload module $mod (refcnt)"
226 
227         log "% rmmod $mod"
228         ret=$(rmmod "$mod" 2>&1)
229         if [[ "$ret" != "" ]]; then
230                 die "$ret"
231         fi
232 
233         # Wait for module in sysfs ...
234         loop_until '[[ ! -e "/sys/module/$mod" ]]' ||
235                 die "failed to unload module $mod (/sys/module)"
236 }
237 
238 # unload_lp(modname) - unload a kernel module with a livepatch
239 #       modname - module name to unload
240 function unload_lp() {
241         unload_mod "$1"
242 }
243 
244 # disable_lp(modname) - disable a livepatch
245 #       modname - module name to unload
246 function disable_lp() {
247         local mod="$1"
248 
249         log "% echo 0 > /sys/kernel/livepatch/$mod/enabled"
250         echo 0 > /sys/kernel/livepatch/"$mod"/enabled
251 
252         # Wait until the transition finishes and the livepatch gets
253         # removed from sysfs...
254         loop_until '[[ ! -e "/sys/kernel/livepatch/$mod" ]]' ||
255                 die "failed to disable livepatch $mod"
256 }
257 
258 # set_pre_patch_ret(modname, pre_patch_ret)
259 #       modname - module name to set
260 #       pre_patch_ret - new pre_patch_ret value
261 function set_pre_patch_ret {
262         local mod="$1"; shift
263         local ret="$1"
264 
265         log "% echo $ret > /sys/module/$mod/parameters/pre_patch_ret"
266         echo "$ret" > /sys/module/"$mod"/parameters/pre_patch_ret
267 
268         # Wait for sysfs value to hold ...
269         loop_until '[[ $(cat "/sys/module/$mod/parameters/pre_patch_ret") == "$ret" ]]' ||
270                 die "failed to set pre_patch_ret parameter for $mod module"
271 }
272 
273 function start_test {
274         local test="$1"
275 
276         # Dump something unique into the dmesg log, then stash the entry
277         # in LAST_DMESG.  The check_result() function will use it to
278         # find new kernel messages since the test started.
279         local last_dmesg_msg="livepatch kselftest timestamp: $(date --rfc-3339=ns)"
280         log "$last_dmesg_msg"
281         loop_until 'dmesg | grep -q "$last_dmesg_msg"' ||
282                 die "buffer busy? can't find canary dmesg message: $last_dmesg_msg"
283         LAST_DMESG=$(dmesg | grep "$last_dmesg_msg")
284 
285         echo -n "TEST: $test ... "
286         log "===== TEST: $test ====="
287 }
288 
289 # check_result() - verify dmesg output
290 #       TODO - better filter, out of order msgs, etc?
291 function check_result {
292         local expect="$*"
293         local result
294 
295         # Test results include any new dmesg entry since LAST_DMESG, then:
296         # - include lines matching keywords
297         # - exclude lines matching keywords
298         # - filter out dmesg timestamp prefixes
299         result=$(dmesg | awk -v last_dmesg="$LAST_DMESG" 'p; $0 == last_dmesg { p=1 }' | \
300                  grep -e 'livepatch:' -e 'test_klp' | \
301                  grep -v '\(tainting\|taints\) kernel' | \
302                  sed 's/^\[[ 0-9.]*\] //')
303 
304         if [[ "$expect" == "$result" ]] ; then
305                 echo "ok"
306         elif [[ "$result" == "" ]] ; then
307                 echo -e "not ok\n\nbuffer overrun? can't find canary dmesg entry: $LAST_DMESG\n"
308                 die "livepatch kselftest(s) failed"
309         else
310                 echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n"
311                 die "livepatch kselftest(s) failed"
312         fi
313 }
314 
315 # check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs
316 # path permissions
317 #       modname - livepatch module creating the sysfs interface
318 #       rel_path - relative path of the sysfs interface
319 #       expected_rights - expected access rights
320 function check_sysfs_rights() {
321         local mod="$1"; shift
322         local rel_path="$1"; shift
323         local expected_rights="$1"; shift
324 
325         local path="$KLP_SYSFS_DIR/$mod/$rel_path"
326         local rights=$(/bin/stat --format '%A' "$path")
327         if test "$rights" != "$expected_rights" ; then
328                 die "Unexpected access rights of $path: $expected_rights vs. $rights"
329         fi
330 }
331 
332 # check_sysfs_value(modname, rel_path, expected_value) - check sysfs value
333 #       modname - livepatch module creating the sysfs interface
334 #       rel_path - relative path of the sysfs interface
335 #       expected_value - expected value read from the file
336 function check_sysfs_value() {
337         local mod="$1"; shift
338         local rel_path="$1"; shift
339         local expected_value="$1"; shift
340 
341         local path="$KLP_SYSFS_DIR/$mod/$rel_path"
342         local value=`cat $path`
343         if test "$value" != "$expected_value" ; then
344                 die "Unexpected value in $path: $expected_value vs. $value"
345         fi
346 }

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php