mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 16:21:45 -04:00
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:
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user