mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
linux_kselftest-fixes-6.8-rc3
This kselftest fixes update for Linux 6.8-rc3 consists of three fixes to livepatch, rseq, and seccomp tests. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmW5bRQACgkQCwJExA0N QxyMNxAAj/VwvGuZMHtFv7PNS2GAe0ifCKQvuOGJXx53K+SZQZ9VftJ9wIc9TqwT GtQCyXznpxBc1jELjE/7mx9xybCBIwwzIqPsDPmVmWopUVJeboh6W4nSeg0EALcZ md6w6ps0n7x2kuXvVR/Ie4LFG8WMMXyttLkS/Typd4TNERjr8bDmx1bABuA21uxg qG7FfME9AldaDUdj3AVsEKlqWXDnbMrou2mIzOSNLXk3UFcjx9dDsbeYC3WYvi/9 /3wmNElPssco9JgWjn+14CV690qXDXR7FhsK/osHpojWXMweW1i3msAyrwYR3gCL HtrLJwh94LRiS6EvddqaoL+A5/N5irbS6xzXlsxW9axsmbFlHKnzu56C4uVfp+hE eZp8U69CygTUXLhJOs3wM+Ahkss2HHZDL6caA6Mb25Ui7iAZi1oTNToyADYVauMo jFKYW/FNTZBGMUaJCY3nIU5QGBVpG6bDzJZDyRQVrhrQMs2YEkILzSnK8ru+28kj KNMxbRnvrOCu6NxG7mPPIT1nCJwSx0+z2oCGnGuN9G4p6tidMQXIVyVPcgsHktjG Z2KkcUTVdk6Qkdgmdmfvtak1jswoQvDu6QK+Ub+In6L8QJVj2Mc7UvpGUwinwhEM aGxp/ref/Go+WL0W82p1vThEes2sdYb/PrJAbuGjONBAoXgLpvI= =0a0Q -----END PGP SIGNATURE----- Merge tag 'linux_kselftest-fixes-6.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull kselftest fixes from Shuah Khan: "Three fixes to livepatch, rseq, and seccomp tests" * tag 'linux_kselftest-fixes-6.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kselftest/seccomp: Report each expectation we assert as a KTAP test kselftest/seccomp: Use kselftest output functions for benchmark selftests/livepatch: fix and refactor new dmesg message code selftests/rseq: Do not skip !allowed_cpus for mm_cid
This commit is contained in:
commit
d1d873a9bf
@ -42,17 +42,6 @@ function die() {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# save existing dmesg so we can detect new content
|
||||
function save_dmesg() {
|
||||
SAVED_DMESG=$(mktemp --tmpdir -t klp-dmesg-XXXXXX)
|
||||
dmesg > "$SAVED_DMESG"
|
||||
}
|
||||
|
||||
# cleanup temporary dmesg file from save_dmesg()
|
||||
function cleanup_dmesg_file() {
|
||||
rm -f "$SAVED_DMESG"
|
||||
}
|
||||
|
||||
function push_config() {
|
||||
DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \
|
||||
awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}')
|
||||
@ -99,7 +88,6 @@ function set_ftrace_enabled() {
|
||||
|
||||
function cleanup() {
|
||||
pop_config
|
||||
cleanup_dmesg_file
|
||||
}
|
||||
|
||||
# setup_config - save the current config and set a script exit trap that
|
||||
@ -280,7 +268,15 @@ function set_pre_patch_ret {
|
||||
function start_test {
|
||||
local test="$1"
|
||||
|
||||
save_dmesg
|
||||
# Dump something unique into the dmesg log, then stash the entry
|
||||
# in LAST_DMESG. The check_result() function will use it to
|
||||
# find new kernel messages since the test started.
|
||||
local last_dmesg_msg="livepatch kselftest timestamp: $(date --rfc-3339=ns)"
|
||||
log "$last_dmesg_msg"
|
||||
loop_until 'dmesg | grep -q "$last_dmesg_msg"' ||
|
||||
die "buffer busy? can't find canary dmesg message: $last_dmesg_msg"
|
||||
LAST_DMESG=$(dmesg | grep "$last_dmesg_msg")
|
||||
|
||||
echo -n "TEST: $test ... "
|
||||
log "===== TEST: $test ====="
|
||||
}
|
||||
@ -291,23 +287,24 @@ function check_result {
|
||||
local expect="$*"
|
||||
local result
|
||||
|
||||
# Note: when comparing dmesg output, the kernel log timestamps
|
||||
# help differentiate repeated testing runs. Remove them with a
|
||||
# post-comparison sed filter.
|
||||
|
||||
result=$(dmesg | comm --nocheck-order -13 "$SAVED_DMESG" - | \
|
||||
# Test results include any new dmesg entry since LAST_DMESG, then:
|
||||
# - include lines matching keywords
|
||||
# - exclude lines matching keywords
|
||||
# - filter out dmesg timestamp prefixes
|
||||
result=$(dmesg | awk -v last_dmesg="$LAST_DMESG" 'p; $0 == last_dmesg { p=1 }' | \
|
||||
grep -e 'livepatch:' -e 'test_klp' | \
|
||||
grep -v '\(tainting\|taints\) kernel' | \
|
||||
sed 's/^\[[ 0-9.]*\] //')
|
||||
|
||||
if [[ "$expect" == "$result" ]] ; then
|
||||
echo "ok"
|
||||
elif [[ "$result" == "" ]] ; then
|
||||
echo -e "not ok\n\nbuffer overrun? can't find canary dmesg entry: $LAST_DMESG\n"
|
||||
die "livepatch kselftest(s) failed"
|
||||
else
|
||||
echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n"
|
||||
die "livepatch kselftest(s) failed"
|
||||
fi
|
||||
|
||||
cleanup_dmesg_file
|
||||
}
|
||||
|
||||
# check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs
|
||||
|
@ -24,6 +24,11 @@ bool rseq_validate_cpu_id(void)
|
||||
{
|
||||
return rseq_mm_cid_available();
|
||||
}
|
||||
static
|
||||
bool rseq_use_cpu_index(void)
|
||||
{
|
||||
return false; /* Use mm_cid */
|
||||
}
|
||||
#else
|
||||
# define RSEQ_PERCPU RSEQ_PERCPU_CPU_ID
|
||||
static
|
||||
@ -36,6 +41,11 @@ bool rseq_validate_cpu_id(void)
|
||||
{
|
||||
return rseq_current_cpu_raw() >= 0;
|
||||
}
|
||||
static
|
||||
bool rseq_use_cpu_index(void)
|
||||
{
|
||||
return true; /* Use cpu_id as index. */
|
||||
}
|
||||
#endif
|
||||
|
||||
struct percpu_lock_entry {
|
||||
@ -274,7 +284,7 @@ void test_percpu_list(void)
|
||||
/* Generate list entries for every usable cpu. */
|
||||
sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
for (j = 1; j <= 100; j++) {
|
||||
struct percpu_list_node *node;
|
||||
@ -299,7 +309,7 @@ void test_percpu_list(void)
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
struct percpu_list_node *node;
|
||||
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
|
||||
while ((node = __percpu_list_pop(&list, i))) {
|
||||
|
@ -288,6 +288,11 @@ bool rseq_validate_cpu_id(void)
|
||||
{
|
||||
return rseq_mm_cid_available();
|
||||
}
|
||||
static
|
||||
bool rseq_use_cpu_index(void)
|
||||
{
|
||||
return false; /* Use mm_cid */
|
||||
}
|
||||
# ifdef TEST_MEMBARRIER
|
||||
/*
|
||||
* Membarrier does not currently support targeting a mm_cid, so
|
||||
@ -312,6 +317,11 @@ bool rseq_validate_cpu_id(void)
|
||||
{
|
||||
return rseq_current_cpu_raw() >= 0;
|
||||
}
|
||||
static
|
||||
bool rseq_use_cpu_index(void)
|
||||
{
|
||||
return true; /* Use cpu_id as index. */
|
||||
}
|
||||
# ifdef TEST_MEMBARRIER
|
||||
static
|
||||
int rseq_membarrier_expedited(int cpu)
|
||||
@ -715,7 +725,7 @@ void test_percpu_list(void)
|
||||
/* Generate list entries for every usable cpu. */
|
||||
sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
for (j = 1; j <= 100; j++) {
|
||||
struct percpu_list_node *node;
|
||||
@ -752,7 +762,7 @@ void test_percpu_list(void)
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
struct percpu_list_node *node;
|
||||
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
|
||||
while ((node = __percpu_list_pop(&list, i))) {
|
||||
@ -902,7 +912,7 @@ void test_percpu_buffer(void)
|
||||
/* Generate list entries for every usable cpu. */
|
||||
sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
/* Worse-case is every item in same CPU. */
|
||||
buffer.c[i].array =
|
||||
@ -952,7 +962,7 @@ void test_percpu_buffer(void)
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
struct percpu_buffer_node *node;
|
||||
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
|
||||
while ((node = __percpu_buffer_pop(&buffer, i))) {
|
||||
@ -1113,7 +1123,7 @@ void test_percpu_memcpy_buffer(void)
|
||||
/* Generate list entries for every usable cpu. */
|
||||
sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus);
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
/* Worse-case is every item in same CPU. */
|
||||
buffer.c[i].array =
|
||||
@ -1160,7 +1170,7 @@ void test_percpu_memcpy_buffer(void)
|
||||
for (i = 0; i < CPU_SETSIZE; i++) {
|
||||
struct percpu_memcpy_buffer_node item;
|
||||
|
||||
if (!CPU_ISSET(i, &allowed_cpus))
|
||||
if (rseq_use_cpu_index() && !CPU_ISSET(i, &allowed_cpus))
|
||||
continue;
|
||||
|
||||
while (__percpu_memcpy_buffer_pop(&buffer, &item, i)) {
|
||||
|
@ -38,10 +38,10 @@ unsigned long long timing(clockid_t clk_id, unsigned long long samples)
|
||||
i *= 1000000000ULL;
|
||||
i += finish.tv_nsec - start.tv_nsec;
|
||||
|
||||
printf("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n",
|
||||
finish.tv_sec, finish.tv_nsec,
|
||||
start.tv_sec, start.tv_nsec,
|
||||
i, (double)i / 1000000000.0);
|
||||
ksft_print_msg("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n",
|
||||
finish.tv_sec, finish.tv_nsec,
|
||||
start.tv_sec, start.tv_nsec,
|
||||
i, (double)i / 1000000000.0);
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -53,7 +53,7 @@ unsigned long long calibrate(void)
|
||||
pid_t pid, ret;
|
||||
int seconds = 15;
|
||||
|
||||
printf("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds);
|
||||
ksft_print_msg("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds);
|
||||
|
||||
samples = 0;
|
||||
pid = getpid();
|
||||
@ -98,24 +98,36 @@ bool le(int i_one, int i_two)
|
||||
}
|
||||
|
||||
long compare(const char *name_one, const char *name_eval, const char *name_two,
|
||||
unsigned long long one, bool (*eval)(int, int), unsigned long long two)
|
||||
unsigned long long one, bool (*eval)(int, int), unsigned long long two,
|
||||
bool skip)
|
||||
{
|
||||
bool good;
|
||||
|
||||
printf("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two,
|
||||
(long long)one, name_eval, (long long)two);
|
||||
if (skip) {
|
||||
ksft_test_result_skip("%s %s %s\n", name_one, name_eval,
|
||||
name_two);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ksft_print_msg("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two,
|
||||
(long long)one, name_eval, (long long)two);
|
||||
if (one > INT_MAX) {
|
||||
printf("Miscalculation! Measurement went negative: %lld\n", (long long)one);
|
||||
return 1;
|
||||
ksft_print_msg("Miscalculation! Measurement went negative: %lld\n", (long long)one);
|
||||
good = false;
|
||||
goto out;
|
||||
}
|
||||
if (two > INT_MAX) {
|
||||
printf("Miscalculation! Measurement went negative: %lld\n", (long long)two);
|
||||
return 1;
|
||||
ksft_print_msg("Miscalculation! Measurement went negative: %lld\n", (long long)two);
|
||||
good = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
good = eval(one, two);
|
||||
printf("%s\n", good ? "✔️" : "❌");
|
||||
|
||||
out:
|
||||
ksft_test_result(good, "%s %s %s\n", name_one, name_eval, name_two);
|
||||
|
||||
return good ? 0 : 1;
|
||||
}
|
||||
|
||||
@ -142,15 +154,22 @@ int main(int argc, char *argv[])
|
||||
unsigned long long samples, calc;
|
||||
unsigned long long native, filter1, filter2, bitmap1, bitmap2;
|
||||
unsigned long long entry, per_filter1, per_filter2;
|
||||
bool skip = false;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
printf("Running on:\n");
|
||||
ksft_print_header();
|
||||
ksft_set_plan(7);
|
||||
|
||||
ksft_print_msg("Running on:\n");
|
||||
ksft_print_msg("");
|
||||
system("uname -a");
|
||||
|
||||
printf("Current BPF sysctl settings:\n");
|
||||
ksft_print_msg("Current BPF sysctl settings:\n");
|
||||
/* Avoid using "sysctl" which may not be installed. */
|
||||
ksft_print_msg("");
|
||||
system("grep -H . /proc/sys/net/core/bpf_jit_enable");
|
||||
ksft_print_msg("");
|
||||
system("grep -H . /proc/sys/net/core/bpf_jit_harden");
|
||||
|
||||
if (argc > 1)
|
||||
@ -158,11 +177,11 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
samples = calibrate();
|
||||
|
||||
printf("Benchmarking %llu syscalls...\n", samples);
|
||||
ksft_print_msg("Benchmarking %llu syscalls...\n", samples);
|
||||
|
||||
/* Native call */
|
||||
native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
|
||||
printf("getpid native: %llu ns\n", native);
|
||||
ksft_print_msg("getpid native: %llu ns\n", native);
|
||||
|
||||
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
|
||||
assert(ret == 0);
|
||||
@ -172,35 +191,37 @@ int main(int argc, char *argv[])
|
||||
assert(ret == 0);
|
||||
|
||||
bitmap1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
|
||||
printf("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1);
|
||||
ksft_print_msg("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1);
|
||||
|
||||
/* Second filter resulting in a bitmap */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog);
|
||||
assert(ret == 0);
|
||||
|
||||
bitmap2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
|
||||
printf("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2);
|
||||
ksft_print_msg("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2);
|
||||
|
||||
/* Third filter, can no longer be converted to bitmap */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
|
||||
assert(ret == 0);
|
||||
|
||||
filter1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
|
||||
printf("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1);
|
||||
ksft_print_msg("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1);
|
||||
|
||||
/* Fourth filter, can not be converted to bitmap because of filter 3 */
|
||||
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog);
|
||||
assert(ret == 0);
|
||||
|
||||
filter2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples;
|
||||
printf("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2);
|
||||
ksft_print_msg("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2);
|
||||
|
||||
/* Estimations */
|
||||
#define ESTIMATE(fmt, var, what) do { \
|
||||
var = (what); \
|
||||
printf("Estimated " fmt ": %llu ns\n", var); \
|
||||
if (var > INT_MAX) \
|
||||
goto more_samples; \
|
||||
ksft_print_msg("Estimated " fmt ": %llu ns\n", var); \
|
||||
if (var > INT_MAX) { \
|
||||
skip = true; \
|
||||
ret |= 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
ESTIMATE("total seccomp overhead for 1 bitmapped filter", calc,
|
||||
@ -218,31 +239,34 @@ int main(int argc, char *argv[])
|
||||
ESTIMATE("seccomp per-filter overhead (filters / 4)", per_filter2,
|
||||
(filter2 - native - entry) / 4);
|
||||
|
||||
printf("Expectations:\n");
|
||||
ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1);
|
||||
bits = compare("native", "≤", "1 filter", native, le, filter1);
|
||||
ksft_print_msg("Expectations:\n");
|
||||
ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1,
|
||||
skip);
|
||||
bits = compare("native", "≤", "1 filter", native, le, filter1,
|
||||
skip);
|
||||
if (bits)
|
||||
goto more_samples;
|
||||
skip = true;
|
||||
|
||||
ret |= compare("per-filter (last 2 diff)", "≈", "per-filter (filters / 4)",
|
||||
per_filter1, approx, per_filter2);
|
||||
per_filter1, approx, per_filter2, skip);
|
||||
|
||||
bits = compare("1 bitmapped", "≈", "2 bitmapped",
|
||||
bitmap1 - native, approx, bitmap2 - native);
|
||||
bitmap1 - native, approx, bitmap2 - native, skip);
|
||||
if (bits) {
|
||||
printf("Skipping constant action bitmap expectations: they appear unsupported.\n");
|
||||
goto out;
|
||||
ksft_print_msg("Skipping constant action bitmap expectations: they appear unsupported.\n");
|
||||
skip = true;
|
||||
}
|
||||
|
||||
ret |= compare("entry", "≈", "1 bitmapped", entry, approx, bitmap1 - native);
|
||||
ret |= compare("entry", "≈", "2 bitmapped", entry, approx, bitmap2 - native);
|
||||
ret |= compare("entry", "≈", "1 bitmapped", entry, approx,
|
||||
bitmap1 - native, skip);
|
||||
ret |= compare("entry", "≈", "2 bitmapped", entry, approx,
|
||||
bitmap2 - native, skip);
|
||||
ret |= compare("native + entry + (per filter * 4)", "≈", "4 filters total",
|
||||
entry + (per_filter1 * 4) + native, approx, filter2);
|
||||
if (ret == 0)
|
||||
goto out;
|
||||
entry + (per_filter1 * 4) + native, approx, filter2,
|
||||
skip);
|
||||
|
||||
more_samples:
|
||||
printf("Saw unexpected benchmark result. Try running again with more samples?\n");
|
||||
out:
|
||||
return 0;
|
||||
if (ret)
|
||||
ksft_print_msg("Saw unexpected benchmark result. Try running again with more samples?\n");
|
||||
|
||||
ksft_finished();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user