* [bpf-next 0/4] selftest related fixes
@ 2026-08-03 17:02 Vineet Gupta
2026-08-03 17:02 ` [bpf-next 1/4] selftests/bpf: map_kptr: force BPF_STX for the scalar store to kptr Vineet Gupta
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Vineet Gupta @ 2026-08-03 17:02 UTC (permalink / raw)
To: bpf, ast, Eduard Zingerman, Andrii Nakryiko, Ihor Solodrai
Cc: linux-kernel, Vineet Gupta
Hi,
This is a set of fixes accumulated during BPF_GCC testing and an in-works
verifier enhacement series for 32-bit tracking.
Thx,
-Vineet
Vineet Gupta (4):
selftests/bpf: map_kptr: force BPF_STX for the scalar store to kptr
selftests/bpf: add --no-error-summary to skip end-of-run error log
dump
selftests/bpf: report failed subtest count in test_progs summary
selftests/bpf: vmtest.sh: preserve command quoting when running in the
VM
.../selftests/bpf/progs/map_kptr_fail.c | 11 +++-
tools/testing/selftests/bpf/test_progs.c | 62 ++++++++++++-------
tools/testing/selftests/bpf/test_progs.h | 3 +-
tools/testing/selftests/bpf/vmtest.sh | 13 +++-
4 files changed, 64 insertions(+), 25 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [bpf-next 1/4] selftests/bpf: map_kptr: force BPF_STX for the scalar store to kptr 2026-08-03 17:02 [bpf-next 0/4] selftest related fixes Vineet Gupta @ 2026-08-03 17:02 ` Vineet Gupta 2026-08-03 17:02 ` [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump Vineet Gupta ` (2 subsequent siblings) 3 siblings, 0 replies; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 17:02 UTC (permalink / raw) To: bpf, ast, Eduard Zingerman, Andrii Nakryiko, Ihor Solodrai Cc: linux-kernel, Vineet Gupta reject_scalar_store_to_kptr stores a scalar constant to a kptr field: *(volatile u64 *)&v->unref_ptr = 0xBADC0DE; Compilers generate one of two encodings for that: 1. Materialize the constant into a register and emit BPF_STX: r1 = 0xbadc0de *(u64 *)(r0 + 0x8) = r1 2. Or fold it into a single BPF_ST (store immediate): *(u64 *)(r0 + 0x8) = 0xbadc0de check_map_kptr_access() rejects both, but through very different checks. BPF_STX goes through map_kptr_match_type(), whose first test is base_type(reg->type) != PTR_TO_BTF_ID - the scalar rejection this test is named for - and which prints "invalid kptr access, R...". BPF_ST only gets the trivial "BPF_ST imm must be 0 when storing to kptr" immediate check and never reaches map_kptr_match_type() at all. So on a compiler that folds the constant - bpf-gcc, and clang from -mcpu=v4, which enabled BPF_ST around v4 support due to historical verifier limitations - the test fails against its expected message. Widening the __msg to accept either message would make it pass again, but on those toolchains it would then only re-test the imm != 0 path, which verifier/map_kptr.c ("map_kptr: BPF_ST imm != 0") already covers, and the scalar-vs-PTR_TO_BTF_ID check would lose its only test in the tree. Route the value through barrier_var() instead, so the store stays a BPF_STX everywhere and the test keeps asserting what it was written to assert. clang -mcpu=v1..v4 and bpf-gcc 16.1 all emit the register form afterwards. bpf-gcc, before: #229/20 map_kptr/reject_scalar_store_to_kptr:FAIL bpf-gcc, after : #229/20 map_kptr/reject_scalar_store_to_kptr:OK Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev> --- tools/testing/selftests/bpf/progs/map_kptr_fail.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c index f11848dfa78f..cb84e23b83c0 100644 --- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c @@ -390,13 +390,22 @@ __failure __msg("invalid kptr access, R") int reject_scalar_store_to_kptr(struct __sk_buff *ctx) { struct map_value *v; + u64 val = 0xBADC0DE; int key = 0; v = bpf_map_lookup_elem(&array_map, &key); if (!v) return 0; - *(volatile u64 *)&v->unref_ptr = 0xBADC0DE; + /* + * Keep the value in a register so this stays a BPF_STX and keeps + * exercising map_kptr_match_type(). Compilers that fold the constant + * into a BPF_ST (store immediate) instead - bpf-gcc, and clang from + * -mcpu=v4 - would be rejected by the far weaker "BPF_ST imm must be + * 0" check, which verifier/map_kptr.c already covers. + */ + barrier_var(val); + *(volatile u64 *)&v->unref_ptr = val; return 0; } -- 2.55.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump 2026-08-03 17:02 [bpf-next 0/4] selftest related fixes Vineet Gupta 2026-08-03 17:02 ` [bpf-next 1/4] selftests/bpf: map_kptr: force BPF_STX for the scalar store to kptr Vineet Gupta @ 2026-08-03 17:02 ` Vineet Gupta 2026-08-03 18:15 ` bot+bpf-ci 2026-08-03 17:02 ` [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary Vineet Gupta 2026-08-03 17:02 ` [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM Vineet Gupta 3 siblings, 1 reply; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 17:02 UTC (permalink / raw) To: bpf, ast, Eduard Zingerman, Andrii Nakryiko, Ihor Solodrai Cc: linux-kernel, Vineet Gupta By default test_progs re-prints the aggregated error logs of all failed tests at the end of the run (when not in verbose mode), starting with "All error logs:". With bpf-gcc the current failures and a couple runaway 1M fails cause a huge print overhead/delay at the end. Add a subtractive --no-error-summary flag, gated on a new env.error_summary field which defaults to true, so the default behavior is unchanged. Passing --no-error-summary suppresses the final "All error logs:" dump. Only the human readable output is elided. dump_test_log() also emits the per-test and per-subtest entries of the --json-summary "results" array, so it keeps being called (via a new @quiet argument) and the JSON report is bit for bit what it was before. Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev> --- tools/testing/selftests/bpf/test_progs.c | 41 ++++++++++++++++-------- tools/testing/selftests/bpf/test_progs.h | 1 + 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index aa06bab30966..8ee46745e2e8 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -424,10 +424,12 @@ static void jsonw_write_log_message(json_writer_t *w, char *log_buf, size_t log_ } } +/* @quiet elides the human readable output, the JSON report is unaffected */ static void dump_test_log(const struct prog_test_def *test, const struct test_state *test_state, bool skip_ok_subtests, bool par_exec_result, + bool quiet, json_writer_t *w) { bool test_failed = test_state->error_cnt > 0; @@ -449,7 +451,7 @@ static void dump_test_log(const struct prog_test_def *test, if (verbose() && !par_exec_result) return; - if (test_state->log_cnt && print_test) + if (test_state->log_cnt && print_test && !quiet) print_test_log(test_state->log_buf, test_state->log_cnt); if (w && print_test) { @@ -471,15 +473,16 @@ static void dump_test_log(const struct prog_test_def *test, if ((skip_ok_subtests && !subtest_failed) || subtest_filtered) continue; - if (subtest_state->log_cnt && print_subtest) { + if (subtest_state->log_cnt && print_subtest && !quiet) { print_test_log(subtest_state->log_buf, subtest_state->log_cnt); } - print_subtest_name(test->test_num, i + 1, - test->test_name, subtest_state->name, - test_result(subtest_state->error_cnt, - subtest_state->skipped)); + if (!quiet) + print_subtest_name(test->test_num, i + 1, + test->test_name, subtest_state->name, + test_result(subtest_state->error_cnt, + subtest_state->skipped)); if (w && print_subtest) { jsonw_start_object(w); @@ -496,7 +499,8 @@ static void dump_test_log(const struct prog_test_def *test, jsonw_end_object(w); } - print_test_result(test, test_state); + if (!quiet) + print_test_result(test, test_state); } /* A bunch of tests set custom affinity per-thread and/or per-process. Reset @@ -899,6 +903,7 @@ enum ARG_KEYS { ARG_JSON_SUMMARY = 'J', ARG_TRAFFIC_MONITOR = 'm', ARG_WATCHDOG_TIMEOUT = 'w', + ARG_NO_ERROR_SUMMARY = -2, }; static const struct argp_option opts[] = { @@ -931,6 +936,8 @@ static const struct argp_option opts[] = { #endif { "watchdog-timeout", ARG_WATCHDOG_TIMEOUT, "SECONDS", 0, "Kill the process if tests are not making progress for specified number of seconds." }, + { "no-error-summary", ARG_NO_ERROR_SUMMARY, NULL, 0, + "Do not re-print the aggregated error logs of failed tests at the end of the run." }, {}, }; @@ -1132,6 +1139,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case ARG_DEBUG: env->debug = true; break; + case ARG_NO_ERROR_SUMMARY: + env->error_summary = false; + break; case ARG_JSON_SUMMARY: env->json = fopen(arg, "w"); if (env->json == NULL) { @@ -1304,7 +1314,7 @@ static void dump_crash_log(void) if (env.test) { env.test_state->error_cnt++; - dump_test_log(env.test, env.test_state, true, false, NULL); + dump_test_log(env.test, env.test_state, true, false, false, NULL); } } @@ -1462,7 +1472,7 @@ static void run_one_test(int test_num) free(stop_libbpf_log_capture()); - dump_test_log(test, state, false, false, NULL); + dump_test_log(test, state, false, false, false, NULL); } struct dispatch_data { @@ -1623,7 +1633,7 @@ static void *dispatch_thread(void *ctx) } while (false); pthread_mutex_lock(&stdout_output_lock); - dump_test_log(test, state, false, true, NULL); + dump_test_log(test, state, false, true, false, NULL); pthread_mutex_unlock(&stdout_output_lock); } /* while (true) */ error: @@ -1686,9 +1696,12 @@ static void calculate_summary_and_print_errors(struct test_env *env) * We only print error logs summary when there are failed tests and * verbose mode is not enabled. Otherwise, results may be inconsistent. * + * --no-error-summary only elides the human readable dump: the walk + * still happens so the JSON report keeps its per-test results. */ - if (!verbose() && fail_cnt) { - printf("\nAll error logs:\n"); + if (!verbose() && fail_cnt && (env->error_summary || w)) { + if (env->error_summary) + printf("\nAll error logs:\n"); /* print error logs again */ for (i = 0; i < prog_test_cnt; i++) { @@ -1698,7 +1711,8 @@ static void calculate_summary_and_print_errors(struct test_env *env) if (!state->tested || !state->error_cnt) continue; - dump_test_log(test, state, true, true, w); + dump_test_log(test, state, true, true, + !env->error_summary, w); } } @@ -2028,6 +2042,7 @@ int main(int argc, char **argv) env.secs_till_notify = 10; env.secs_till_kill = 120; + env.error_summary = true; err = argp_parse(&argp, argc, argv, 0, NULL, &env); if (err) return err; diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index 2cf950afcd85..e66d5c457901 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -105,6 +105,7 @@ struct test_env { struct test_selector tmon_selector; bool verifier_stats; bool debug; + bool error_summary; enum verbosity verbosity; bool jit_enabled; -- 2.55.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump 2026-08-03 17:02 ` [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump Vineet Gupta @ 2026-08-03 18:15 ` bot+bpf-ci 2026-08-03 19:48 ` Vineet Gupta 0 siblings, 1 reply; 11+ messages in thread From: bot+bpf-ci @ 2026-08-03 18:15 UTC (permalink / raw) To: vineet.gupta, bpf, ast, eddyz87, andrii, ihor.solodrai Cc: linux-kernel, vineet.gupta, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 1721 bytes --] > diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c > index aa06bab309665..8ee46745e2e85 100644 > --- a/tools/testing/selftests/bpf/test_progs.c > +++ b/tools/testing/selftests/bpf/test_progs.c [ ... ] > @@ -1686,9 +1696,12 @@ static void calculate_summary_and_print_errors(struct test_env *env) > * We only print error logs summary when there are failed tests and > * verbose mode is not enabled. Otherwise, results may be inconsistent. > * > + * --no-error-summary only elides the human readable dump: the walk > + * still happens so the JSON report keeps its per-test results. > */ > - if (!verbose() && fail_cnt) { > - printf("\nAll error logs:\n"); > + if (!verbose() && fail_cnt && (env->error_summary || w)) { > + if (env->error_summary) > + printf("\nAll error logs:\n"); Does the comment match what the code does? The comment says "the walk still happens", but the guard now requires either env->error_summary or w to be non-NULL. When --no-error-summary is passed without --json-summary, both env->error_summary and w are false/NULL, so the entire for loop at the bottom of this function gets skipped, not just the human readable output. The walk does happen with --no-error-summary --json-summary FILE (where w != NULL), but not in the no-JSON case. Could the comment be more specific, maybe "the walk still happens when a JSON report was requested, so the JSON report keeps its per-test results"? --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/30836252778 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump 2026-08-03 18:15 ` bot+bpf-ci @ 2026-08-03 19:48 ` Vineet Gupta 0 siblings, 0 replies; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 19:48 UTC (permalink / raw) To: bot+bpf-ci, bpf, ast, eddyz87, andrii, ihor.solodrai Cc: linux-kernel, daniel, martin.lau, yonghong.song, clm On 8/3/26 11:15 AM, bot+bpf-ci@kernel.org wrote: >> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c >> index aa06bab309665..8ee46745e2e85 100644 >> --- a/tools/testing/selftests/bpf/test_progs.c >> +++ b/tools/testing/selftests/bpf/test_progs.c > [ ... ] > >> @@ -1686,9 +1696,12 @@ static void calculate_summary_and_print_errors(struct test_env *env) >> * We only print error logs summary when there are failed tests and >> * verbose mode is not enabled. Otherwise, results may be inconsistent. >> * >> + * --no-error-summary only elides the human readable dump: the walk >> + * still happens so the JSON report keeps its per-test results. >> */ >> - if (!verbose() && fail_cnt) { >> - printf("\nAll error logs:\n"); >> + if (!verbose() && fail_cnt && (env->error_summary || w)) { >> + if (env->error_summary) >> + printf("\nAll error logs:\n"); > Does the comment match what the code does? The comment says "the walk > still happens", but the guard now requires either env->error_summary or w > to be non-NULL. > > When --no-error-summary is passed without --json-summary, both > env->error_summary and w are false/NULL, so the entire for loop at the > bottom of this function gets skipped, not just the human readable output. > > The walk does happen with --no-error-summary --json-summary FILE (where > w != NULL), but not in the no-JSON case. Could the comment be more > specific, maybe "the walk still happens when a JSON report was requested, > so the JSON report keeps its per-test results"? Good catch indeed the comment overstate it. Will reword in v2. Thx, -Vineet > --- > AI reviewed your patch. Please fix the bug or email reply why it's not a bug. > See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md > > CI run summary: https://github.com/kernel-patches/bpf/actions/runs/30836252778 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary 2026-08-03 17:02 [bpf-next 0/4] selftest related fixes Vineet Gupta 2026-08-03 17:02 ` [bpf-next 1/4] selftests/bpf: map_kptr: force BPF_STX for the scalar store to kptr Vineet Gupta 2026-08-03 17:02 ` [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump Vineet Gupta @ 2026-08-03 17:02 ` Vineet Gupta 2026-08-03 18:31 ` bot+bpf-ci 2026-08-03 17:02 ` [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM Vineet Gupta 3 siblings, 1 reply; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 17:02 UTC (permalink / raw) To: bpf, ast, Eduard Zingerman, Andrii Nakryiko, Ihor Solodrai Cc: linux-kernel, Vineet Gupta The final summary line is asymmetric: the PASSED field reports both the number of top-level tests and the number of subtests within them, while the FAILED field reports only top-level tests: Summary: 640/5750 PASSED, 7760 SKIPPED, 100 FAILED There is no way to tell whether those 100 failing tests amount to 100 broken subtests or 1000. So count subtests with a non-zero error_cnt into a new sub_fail_cnt and print it alongside fail_cnt: Summary: 640/5750 PASSED, 7760 SKIPPED, 100/342 FAILED ^^^^^ This is correct for -j runs, as subtest_states[] is populated both in sequential and parallel modes. A test that fails without declaring any subtests contributes 0 to sub_fail_cnt. That mirrors the existing behaviour of sub_succ_cnt for tests that pass without subtests, keeping the two numerators comparable. Also emit the new count as a "failed_subtest" field in the JSON output, for parity with the existing "success_subtest". Note that this changes the trailing field of the summary line from a bare integer to "A/B", so anything scraping "N FAILED" out of it needs updating. While here, fix the fail_cnt comment in struct test_env, which claims it counts "total failed tests + sub-tests". Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev> --- tools/testing/selftests/bpf/test_progs.c | 21 +++++++++++++-------- tools/testing/selftests/bpf/test_progs.h | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 8ee46745e2e8..5e2f6ec2e212 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -1656,8 +1656,8 @@ static void *dispatch_thread(void *ctx) static void calculate_summary_and_print_errors(struct test_env *env) { - int i; - int succ_cnt = 0, fail_cnt = 0, sub_succ_cnt = 0, skip_cnt = 0; + int i, j; + int succ_cnt = 0, fail_cnt = 0, sub_succ_cnt = 0, sub_fail_cnt = 0, skip_cnt = 0; json_writer_t *w = NULL; for (i = 0; i < prog_test_cnt; i++) { @@ -1670,10 +1670,14 @@ static void calculate_summary_and_print_errors(struct test_env *env) sub_succ_cnt += state->sub_succ_cnt; skip_cnt += state->skip_cnt; - if (state->error_cnt) + if (state->error_cnt) { fail_cnt++; - else if (!test->not_built) + for (j = 0; j < state->subtest_num; j++) + if (state->subtest_states[j].error_cnt) + sub_fail_cnt++; + } else if (!test->not_built) { succ_cnt++; + } } if (env->json) { @@ -1688,6 +1692,7 @@ static void calculate_summary_and_print_errors(struct test_env *env) jsonw_uint_field(w, "success_subtest", sub_succ_cnt); jsonw_uint_field(w, "skipped", skip_cnt); jsonw_uint_field(w, "failed", fail_cnt); + jsonw_uint_field(w, "failed_subtest", sub_fail_cnt); jsonw_name(w, "results"); jsonw_start_array(w); } @@ -1726,12 +1731,12 @@ static void calculate_summary_and_print_errors(struct test_env *env) fclose(env->json); if (env->not_built_cnt) - printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d FAILED\n", + printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d/%d FAILED\n", succ_cnt, sub_succ_cnt, skip_cnt, env->not_built_cnt, - fail_cnt); + fail_cnt, sub_fail_cnt); else - printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", - succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt); + printf("Summary: %d/%d PASSED, %d SKIPPED, %d/%d FAILED\n", + succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt, sub_fail_cnt); env->succ_cnt = succ_cnt; env->sub_succ_cnt = sub_succ_cnt; diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index e66d5c457901..ea493c477fbd 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -124,7 +124,7 @@ struct test_env { int succ_cnt; /* successful tests */ int sub_succ_cnt; /* successful sub-tests */ - int fail_cnt; /* total failed tests + sub-tests */ + int fail_cnt; /* failed tests */ int skip_cnt; /* skipped tests */ int not_built_cnt; /* tests not built */ -- 2.55.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary 2026-08-03 17:02 ` [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary Vineet Gupta @ 2026-08-03 18:31 ` bot+bpf-ci 2026-08-03 18:36 ` Vineet Gupta 0 siblings, 1 reply; 11+ messages in thread From: bot+bpf-ci @ 2026-08-03 18:31 UTC (permalink / raw) To: vineet.gupta, bpf, ast, eddyz87, andrii, ihor.solodrai Cc: linux-kernel, vineet.gupta, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 1997 bytes --] > diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c > --- a/tools/testing/selftests/bpf/test_progs.c > +++ b/tools/testing/selftests/bpf/test_progs.c [ ... ] > @@ -1726,12 +1731,12 @@ > fclose(env->json); > > if (env->not_built_cnt) > - printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d FAILED\n", > + printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d/%d FAILED\n", > succ_cnt, sub_succ_cnt, skip_cnt, env->not_built_cnt, > - fail_cnt); > + fail_cnt, sub_fail_cnt); > else > - printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", > - succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt); > + printf("Summary: %d/%d PASSED, %d SKIPPED, %d/%d FAILED\n", > + succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt, sub_fail_cnt); A subsystem pattern flags this as potentially concerning: the BPF selftests guide asks that test binaries emit TAP-compliant output via kselftest.h (ksft_set_plan()/ksft_finished()) rather than hand-formatting their own summary lines with printf(), so that kselftest runners and CI can parse the results uniformly. test_progs.c has always had its own reporting framework and does not use kselftest.h; this predates the patch by many years and converting it is far outside the scope of this change. The patch only widens one existing field on an already ad hoc line. The changelog acknowledges that the field-format change means "anything scraping 'N FAILED' out of it needs updating." A search over .github/workflows, .github/scripts, ci/, tools/testing/selftests/bpf/*.sh and Documentation/ turned up no in-tree parser of the test_progs summary line. Does this output format remain compatible with the consumers you're aware of? --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/30836252778 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary 2026-08-03 18:31 ` bot+bpf-ci @ 2026-08-03 18:36 ` Vineet Gupta 0 siblings, 0 replies; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 18:36 UTC (permalink / raw) To: bot+bpf-ci, bpf, ast, eddyz87, andrii, ihor.solodrai Cc: linux-kernel, daniel, martin.lau, yonghong.song, clm On 8/3/26 11:31 AM, bot+bpf-ci@kernel.org wrote: >> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c >> --- a/tools/testing/selftests/bpf/test_progs.c >> +++ b/tools/testing/selftests/bpf/test_progs.c > [ ... ] > >> @@ -1726,12 +1731,12 @@ >> fclose(env->json); >> >> if (env->not_built_cnt) >> - printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d FAILED\n", >> + printf("Summary: %d/%d PASSED, %d SKIPPED (%d not built), %d/%d FAILED\n", >> succ_cnt, sub_succ_cnt, skip_cnt, env->not_built_cnt, >> - fail_cnt); >> + fail_cnt, sub_fail_cnt); >> else >> - printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", >> - succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt); >> + printf("Summary: %d/%d PASSED, %d SKIPPED, %d/%d FAILED\n", >> + succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt, sub_fail_cnt); > A subsystem pattern flags this as potentially concerning: the BPF selftests > guide asks that test binaries emit TAP-compliant output via kselftest.h > (ksft_set_plan()/ksft_finished()) rather than hand-formatting their own > summary lines with printf(), so that kselftest runners and CI can parse the > results uniformly. > > test_progs.c has always had its own reporting framework and does not use > kselftest.h; this predates the patch by many years and converting it is far > outside the scope of this change. The patch only widens one existing field on > an already ad hoc line. > > The changelog acknowledges that the field-format change means "anything > scraping 'N FAILED' out of it needs updating." A search over .github/workflows, > .github/scripts, ci/, tools/testing/selftests/bpf/*.sh and Documentation/ > turned up no in-tree parser of the test_progs summary line. > > Does this output format remain compatible with the consumers you're aware of? As the Changelog mentions, I don't know of any existing in-tree consumers/parser of the existing info. Thx, -Vineet > > > --- > AI reviewed your patch. Please fix the bug or email reply why it's not a bug. > See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md > > CI run summary: https://github.com/kernel-patches/bpf/actions/runs/30836252778 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM 2026-08-03 17:02 [bpf-next 0/4] selftest related fixes Vineet Gupta ` (2 preceding siblings ...) 2026-08-03 17:02 ` [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary Vineet Gupta @ 2026-08-03 17:02 ` Vineet Gupta 2026-08-03 18:31 ` bot+bpf-ci 3 siblings, 1 reply; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 17:02 UTC (permalink / raw) To: bpf, ast, Eduard Zingerman, Andrii Nakryiko, Ihor Solodrai Cc: linux-kernel, Vineet Gupta vmtest.sh captures the trailing command with command="$@", which flattens the arguments into a single space-separated string, and then pastes it into the generated guest init script: cd /root/bpf echo ${command} stdbuf -oL -eL ${command} That here-doc is unquoted, so the host expands ${command} and the flattened text lands in the script verbatim. The guest bash then parses those lines as shell source, re-splitting the text on whitespace and glob-expanding it against /root/bpf. As a result any command with a glob or an argument containing spaces is corrupted before it reaches the test binary. For example: vmtest.sh -- ./test_progs -a 'verifier_*' has 'verifier_*' expanded in the guest into the matching object/skeleton files (verifier_align.bpf.o verifier_align.skel.h ...), so test_progs is handed a list of filenames instead of the intended name filter and runs no matching tests. Quote each argument with printf '%q ' so the command is reproduced verbatim inside the VM: the escaped text goes through exactly one round of quote removal when the guest parses the init script, yielding the original argv with globs and special characters intact. The common case (e.g. -t <name>) is unaffected. Only do this when there is a command to quote. printf '%q ' with no arguments still applies the format once and emits '', which the -s (debug shell) path would take for a real command and try to run. Note this makes the trailing command strictly an argv rather than a shell snippet: passing it pre-quoted as one word, e.g. vmtest.sh -- "./test_progs -t foo" no longer works, and neither does embedding guest-side shell syntax such as ';' or a redirection. Neither form is documented - usage() and README.rst both show the command unquoted - and 'sh -c ...' still works. Fixes: c9709f52386d ("bpf: Helper script for running BPF presubmit tests") Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev> --- tools/testing/selftests/bpf/vmtest.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/vmtest.sh b/tools/testing/selftests/bpf/vmtest.sh index 9ca802285393..6a3d026d76bd 100755 --- a/tools/testing/selftests/bpf/vmtest.sh +++ b/tools/testing/selftests/bpf/vmtest.sh @@ -428,8 +428,17 @@ main() if [[ $# -eq 0 && "${debug_shell}" == "no" ]]; then echo "No command specified, will run ${DEFAULT_COMMAND} in the vm" - else - command="$@" + elif [[ $# -gt 0 ]]; then + # Quote each argument so the command survives into the guest: the + # host expands ${command} into the generated init script, which + # the guest bash then parses as shell source. Without the %q + # escapes an argument with a space or a glob (e.g. -a 'verifier_*') + # is re-split and expanded against /root/bpf there. + # + # Skip this when there is no command: printf '%q ' would still + # apply the format once and emit '', which is not the empty + # command that -s (debug shell) expects. + command=$(printf '%q ' "$@") fi local kconfig_file="${OUTPUT_DIR}/latest.config" -- 2.55.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM 2026-08-03 17:02 ` [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM Vineet Gupta @ 2026-08-03 18:31 ` bot+bpf-ci 2026-08-03 19:52 ` Vineet Gupta 0 siblings, 1 reply; 11+ messages in thread From: bot+bpf-ci @ 2026-08-03 18:31 UTC (permalink / raw) To: vineet.gupta, bpf, ast, eddyz87, andrii, ihor.solodrai Cc: linux-kernel, vineet.gupta, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 4162 bytes --] > diff --git a/tools/testing/selftests/bpf/vmtest.sh b/tools/testing/selftests/bpf/vmtest.sh > index 9ca8022853933..6a3d026d76bd6 100755 > --- a/tools/testing/selftests/bpf/vmtest.sh > +++ b/tools/testing/selftests/bpf/vmtest.sh > @@ -428,8 +428,17 @@ main() > > if [[ $# -eq 0 && "${debug_shell}" == "no" ]]; then > echo "No command specified, will run ${DEFAULT_COMMAND} in the vm" > - else > - command="$@" > + elif [[ $# -gt 0 ]]; then > + # Quote each argument so the command survives into the guest: the > + # host expands ${command} into the generated init script, which > + # the guest bash then parses as shell source. Without the %q > + # escapes an argument with a space or a glob (e.g. -a 'verifier_*') > + # is re-split and expanded against /root/bpf there. > + # > + # Skip this when there is no command: printf '%q ' would still > + # apply the format once and emit '', which is not the empty > + # command that -s (debug shell) expects. > + command=$(printf '%q ' "$@") > fi > > local kconfig_file="${OUTPUT_DIR}/latest.config" The commit message states: > Note this makes the trailing command strictly an argv rather than a shell > snippet: passing it pre-quoted as one word, e.g. > > vmtest.sh -- "./test_progs -t foo" > > no longer works, and neither does embedding guest-side shell syntax such > as ';' or a redirection. Neither form is documented - usage() and > README.rst both show the command unquoted - and 'sh -c ...' still works. Is the claim about README.rst accurate? Looking at tools/testing/selftests/bpf/README.rst lines 106-115, there is a documented vmtest.sh invocation whose trailing command is explicitly quoted: $ PLATFORM=riscv64 CROSS_COMPILE=riscv64-linux-gnu- \ tools/testing/selftests/bpf/vmtest.sh \ -l <path of local rootfs image> -- \ ./test_progs -d \ \"$(cat tools/testing/selftests/bpf/DENYLIST.riscv64 | ... | tr -s '\n' ',' )\" The `\"` are escaped in the user's host shell, so vmtest.sh's main() receives argv[3] as the literal 10-character string `",exceptions,"` including the double quotes. Under the old `command="$@"`, the guest bash's second parse of the init script performed quote removal on those literal quotes, so test_progs received `-d ,exceptions,`. That is exactly what the `\"` in the recipe are for: they survive the host and are consumed by the guest. With `command=$(printf '%q ' "$@")` the quotes are escaped (`\",exceptions,\"`) and reach the binary verbatim, so test_progs now receives `-d ",exceptions,"`. Downstream that argument goes to parse_arg() ARG_TEST_NAME_GLOB_DENYLIST -> parse_test_list() (tools/testing/selftests/bpf/testing_helpers.c), which strtok_r()s on ',' and hands each field to insert_test() with is_glob_pattern=true. So the filter list becomes three globs instead of one: ["] [exceptions] ["], two of which can never match a test name in glob_match() (test_progs.c). For DENYLIST.riscv64 as it stands today the damage is confined to those two junk filters, because the file's first line is a comment and therefore reduces to an empty leading field. The same recipe applied to a denylist file whose first line is a real entry silently drops that entry. With DENYLIST.asan-shaped input: OLD guest -> test_progs -d [*arena*,task_local_data,uprobe_multi_test,] filters: [*arena*] [task_local_data] [uprobe_multi_test] NEW guest -> test_progs -d ["*arena*,task_local_data,uprobe_multi_test,"] filters: ["*arena*] [task_local_data] [uprobe_multi_test] ["] `"*arena*` matches nothing, so the *arena* tests are no longer denied and run anyway, a silent loss of denylist coverage rather than an error. Should the commit message be corrected to acknowledge that README.rst does document a quoted invocation that breaks with this change, and should README.rst lines 109-115 be updated in the same patch to remove the now-harmful `\"`? --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/30836252778 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM 2026-08-03 18:31 ` bot+bpf-ci @ 2026-08-03 19:52 ` Vineet Gupta 0 siblings, 0 replies; 11+ messages in thread From: Vineet Gupta @ 2026-08-03 19:52 UTC (permalink / raw) To: bot+bpf-ci, bpf, ast, eddyz87, andrii, ihor.solodrai Cc: linux-kernel, daniel, martin.lau, yonghong.song, clm On 8/3/26 11:31 AM, bot+bpf-ci@kernel.org wrote: >> Note this makes the trailing command strictly an argv rather than a shell >> snippet: passing it pre-quoted as one word, e.g. >> >> vmtest.sh -- "./test_progs -t foo" >> >> no longer works, and neither does embedding guest-side shell syntax such >> as ';' or a redirection. Neither form is documented - usage() and >> README.rst both show the command unquoted - and 'sh -c ...' still works. > Is the claim about README.rst accurate? You are right, it is not. > Looking at > tools/testing/selftests/bpf/README.rst lines 106-115, there is a > documented vmtest.sh invocation whose trailing command is explicitly > quoted: > > $ PLATFORM=riscv64 CROSS_COMPILE=riscv64-linux-gnu- \ > tools/testing/selftests/bpf/vmtest.sh \ > -l <path of local rootfs image> -- \ > ./test_progs -d \ > \"$(cat tools/testing/selftests/bpf/DENYLIST.riscv64 | ... | tr -s '\n' ',' )\" > > The `\"` are escaped in the user's host shell, so vmtest.sh's main() > receives argv[3] as the literal 10-character string `",exceptions,"` > including the double quotes. > > Under the old `command="$@"`, the guest bash's second parse of the init > script performed quote removal on those literal quotes, so test_progs > received `-d ,exceptions,`. That is exactly what the `\"` in the recipe > are for: they survive the host and are consumed by the guest. > > With `command=$(printf '%q ' "$@")` the quotes are escaped > (`\",exceptions,\"`) and reach the binary verbatim, so test_progs now > receives `-d ",exceptions,"`. > > Downstream that argument goes to parse_arg() ARG_TEST_NAME_GLOB_DENYLIST > -> parse_test_list() (tools/testing/selftests/bpf/testing_helpers.c), > which strtok_r()s on ',' and hands each field to insert_test() with > is_glob_pattern=true. So the filter list becomes three globs instead of > one: ["] [exceptions] ["], two of which can never match a test name in > glob_match() (test_progs.c). > > For DENYLIST.riscv64 as it stands today the damage is confined to those > two junk filters, because the file's first line is a comment and > therefore reduces to an empty leading field. > > The same recipe applied to a denylist file whose first line is a real > entry silently drops that entry. With DENYLIST.asan-shaped input: > > OLD guest -> test_progs -d [*arena*,task_local_data,uprobe_multi_test,] > filters: [*arena*] [task_local_data] [uprobe_multi_test] > NEW guest -> test_progs -d ["*arena*,task_local_data,uprobe_multi_test,"] > filters: ["*arena*] [task_local_data] [uprobe_multi_test] ["] > > `"*arena*` matches nothing, so the *arena* tests are no longer denied > and run anyway, a silent loss of denylist coverage rather than an error. This is a really good catch. Indeed arena never matches. > Should the commit message be corrected to acknowledge that README.rst > does document a quoted invocation that breaks with this change, and > should README.rst lines 109-115 be updated in the same patch to remove > the now-harmful `\"`? v2 drops the backslash, fixes README.rst and also updates the changelog accordingly. Thx, -Vineet > --- > AI reviewed your patch. Please fix the bug or email reply why it's not a bug. > See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md > > CI run summary: https://github.com/kernel-patches/bpf/actions/runs/30836252778 ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-08-04 4:19 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-03 17:02 [bpf-next 0/4] selftest related fixes Vineet Gupta 2026-08-03 17:02 ` [bpf-next 1/4] selftests/bpf: map_kptr: force BPF_STX for the scalar store to kptr Vineet Gupta 2026-08-03 17:02 ` [bpf-next 2/4] selftests/bpf: add --no-error-summary to skip end-of-run error log dump Vineet Gupta 2026-08-03 18:15 ` bot+bpf-ci 2026-08-03 19:48 ` Vineet Gupta 2026-08-03 17:02 ` [bpf-next 3/4] selftests/bpf: report failed subtest count in test_progs summary Vineet Gupta 2026-08-03 18:31 ` bot+bpf-ci 2026-08-03 18:36 ` Vineet Gupta 2026-08-03 17:02 ` [bpf-next 4/4] selftests/bpf: vmtest.sh: preserve command quoting when running in the VM Vineet Gupta 2026-08-03 18:31 ` bot+bpf-ci 2026-08-03 19:52 ` Vineet Gupta
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).