Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Fix a few tests for GCC related warnings.

This patch corrects a few warnings to allow selftests to compile for
GCC.

-- progs/cpumask_failure.c --

progs/bpf_misc.h:136:22: error: ‘cpumask’ is used uninitialized
[-Werror=uninitialized]
136 | #define __sink(expr) asm volatile("" : "+g"(expr))
| ^~~
progs/cpumask_failure.c:68:9: note: in expansion of macro ‘__sink’
68 | __sink(cpumask);

The macro __sink(cpumask) with the '+' contraint modifier forces the
the compiler to expect a read and write from cpumask. GCC detects
that cpumask is never initialized and reports an error.
This patch removes the spurious non required definitions of cpumask.

-- progs/dynptr_fail.c --

progs/dynptr_fail.c:1444:9: error: ‘ptr1’ may be used uninitialized
[-Werror=maybe-uninitialized]
1444 | bpf_dynptr_clone(&ptr1, &ptr2);

Many of the tests in the file are related to the detection of
uninitialized pointers by the verifier. GCC is able to detect possible
uninitialized values, and reports this as an error.
The patch initializes all of the previous uninitialized structs.

-- progs/test_tunnel_kern.c --

progs/test_tunnel_kern.c:590:9: error: array subscript 1 is outside
array bounds of ‘struct geneve_opt[1]’ [-Werror=array-bounds=]
590 | *(int *) &gopt.opt_data = bpf_htonl(0xdeadbeef);
| ^~~~~~~~~~~~~~~~~~~~~~~
progs/test_tunnel_kern.c:575:27: note: at offset 4 into object ‘gopt’ of
size 4
575 | struct geneve_opt gopt;

This tests accesses beyond the defined data for the struct geneve_opt
which contains as last field "u8 opt_data[0]" which clearly does not get
reserved space (in stack) in the function header. This pattern is
repeated in ip6geneve_set_tunnel and geneve_set_tunnel functions.
GCC is able to see this and emits a warning.
The patch introduces a local struct that allocates enough space to
safely allow the write to opt_data field.

-- progs/jeq_infer_not_null_fail.c --

progs/jeq_infer_not_null_fail.c:21:40: error: array subscript ‘struct
bpf_map[0]’ is partly outside array bounds of ‘struct <anonymous>[1]’
[-Werror=array-bounds=]
21 | struct bpf_map *inner_map = map->inner_map_meta;
| ^~
progs/jeq_infer_not_null_fail.c:14:3: note: object ‘m_hash’ of size 32
14 | } m_hash SEC(".maps");

This example defines m_hash in the context of the compilation unit and
casts it to struct bpf_map which is much smaller than the size of struct
bpf_map. It errors out in GCC when it attempts to access an element that
would be defined in struct bpf_map outsize of the defined limits for
m_hash.
This patch disables the warning through a GCC pragma.

This changes were tested in bpf-next master selftests without any
regressions.

Signed-off-by: Cupertino Miranda <cupertino.miranda@oracle.com>
Cc: jose.marchesi@oracle.com
Cc: david.faust@oracle.com
Cc: Yonghong Song <yonghong.song@linux.dev>
Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Link: https://lore.kernel.org/r/20240510183850.286661-2-cupertino.miranda@oracle.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Cupertino Miranda and committed by
Alexei Starovoitov
5ddafcc3 792a04be

+37 -29
-3
tools/testing/selftests/bpf/progs/cpumask_failure.c
··· 61 61 __failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask") 62 62 int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags) 63 63 { 64 - struct bpf_cpumask *cpumask; 65 - 66 64 /* Can't set the CPU of a non-struct bpf_cpumask. */ 67 65 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr); 68 - __sink(cpumask); 69 66 70 67 return 0; 71 68 }
+6 -6
tools/testing/selftests/bpf/progs/dynptr_fail.c
··· 80 80 __failure __msg("Unreleased reference id=2") 81 81 int ringbuf_missing_release1(void *ctx) 82 82 { 83 - struct bpf_dynptr ptr; 83 + struct bpf_dynptr ptr = {}; 84 84 85 85 bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); 86 86 ··· 1385 1385 __failure __msg("Expected an initialized dynptr as arg #1") 1386 1386 int dynptr_adjust_invalid(void *ctx) 1387 1387 { 1388 - struct bpf_dynptr ptr; 1388 + struct bpf_dynptr ptr = {}; 1389 1389 1390 1390 /* this should fail */ 1391 1391 bpf_dynptr_adjust(&ptr, 1, 2); ··· 1398 1398 __failure __msg("Expected an initialized dynptr as arg #1") 1399 1399 int dynptr_is_null_invalid(void *ctx) 1400 1400 { 1401 - struct bpf_dynptr ptr; 1401 + struct bpf_dynptr ptr = {}; 1402 1402 1403 1403 /* this should fail */ 1404 1404 bpf_dynptr_is_null(&ptr); ··· 1411 1411 __failure __msg("Expected an initialized dynptr as arg #1") 1412 1412 int dynptr_is_rdonly_invalid(void *ctx) 1413 1413 { 1414 - struct bpf_dynptr ptr; 1414 + struct bpf_dynptr ptr = {}; 1415 1415 1416 1416 /* this should fail */ 1417 1417 bpf_dynptr_is_rdonly(&ptr); ··· 1424 1424 __failure __msg("Expected an initialized dynptr as arg #1") 1425 1425 int dynptr_size_invalid(void *ctx) 1426 1426 { 1427 - struct bpf_dynptr ptr; 1427 + struct bpf_dynptr ptr = {}; 1428 1428 1429 1429 /* this should fail */ 1430 1430 bpf_dynptr_size(&ptr); ··· 1437 1437 __failure __msg("Expected an initialized dynptr as arg #1") 1438 1438 int clone_invalid1(void *ctx) 1439 1439 { 1440 - struct bpf_dynptr ptr1; 1440 + struct bpf_dynptr ptr1 = {}; 1441 1441 struct bpf_dynptr ptr2; 1442 1442 1443 1443 /* this should fail */
+4
tools/testing/selftests/bpf/progs/jeq_infer_not_null_fail.c
··· 4 4 #include <bpf/bpf_helpers.h> 5 5 #include "bpf_misc.h" 6 6 7 + #ifndef __clang__ 8 + #pragma GCC diagnostic ignored "-Warray-bounds" 9 + #endif 10 + 7 11 char _license[] SEC("license") = "GPL"; 8 12 9 13 struct {
+27 -20
tools/testing/selftests/bpf/progs/test_tunnel_kern.c
··· 567 567 return TC_ACT_OK; 568 568 } 569 569 570 + struct local_geneve_opt { 571 + struct geneve_opt gopt; 572 + int data; 573 + }; 574 + 570 575 SEC("tc") 571 576 int geneve_set_tunnel(struct __sk_buff *skb) 572 577 { 573 578 int ret; 574 579 struct bpf_tunnel_key key; 575 - struct geneve_opt gopt; 580 + struct local_geneve_opt local_gopt; 581 + struct geneve_opt *gopt = (struct geneve_opt *) &local_gopt; 576 582 577 583 __builtin_memset(&key, 0x0, sizeof(key)); 578 584 key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ ··· 586 580 key.tunnel_tos = 0; 587 581 key.tunnel_ttl = 64; 588 582 589 - __builtin_memset(&gopt, 0x0, sizeof(gopt)); 590 - gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ 591 - gopt.type = 0x08; 592 - gopt.r1 = 0; 593 - gopt.r2 = 0; 594 - gopt.r3 = 0; 595 - gopt.length = 2; /* 4-byte multiple */ 596 - *(int *) &gopt.opt_data = bpf_htonl(0xdeadbeef); 583 + __builtin_memset(gopt, 0x0, sizeof(local_gopt)); 584 + gopt->opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ 585 + gopt->type = 0x08; 586 + gopt->r1 = 0; 587 + gopt->r2 = 0; 588 + gopt->r3 = 0; 589 + gopt->length = 2; /* 4-byte multiple */ 590 + *(int *) &gopt->opt_data = bpf_htonl(0xdeadbeef); 597 591 598 592 ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 599 593 BPF_F_ZERO_CSUM_TX); ··· 602 596 return TC_ACT_SHOT; 603 597 } 604 598 605 - ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt)); 599 + ret = bpf_skb_set_tunnel_opt(skb, gopt, sizeof(local_gopt)); 606 600 if (ret < 0) { 607 601 log_err(ret); 608 602 return TC_ACT_SHOT; ··· 637 631 int ip6geneve_set_tunnel(struct __sk_buff *skb) 638 632 { 639 633 struct bpf_tunnel_key key; 640 - struct geneve_opt gopt; 634 + struct local_geneve_opt local_gopt; 635 + struct geneve_opt *gopt = (struct geneve_opt *) &local_gopt; 641 636 int ret; 642 637 643 638 __builtin_memset(&key, 0x0, sizeof(key)); ··· 654 647 return TC_ACT_SHOT; 655 648 } 656 649 657 - __builtin_memset(&gopt, 0x0, sizeof(gopt)); 658 - gopt.opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ 659 - gopt.type = 0x08; 660 - gopt.r1 = 0; 661 - gopt.r2 = 0; 662 - gopt.r3 = 0; 663 - gopt.length = 2; /* 4-byte multiple */ 664 - *(int *) &gopt.opt_data = bpf_htonl(0xfeedbeef); 650 + __builtin_memset(gopt, 0x0, sizeof(local_gopt)); 651 + gopt->opt_class = bpf_htons(0x102); /* Open Virtual Networking (OVN) */ 652 + gopt->type = 0x08; 653 + gopt->r1 = 0; 654 + gopt->r2 = 0; 655 + gopt->r3 = 0; 656 + gopt->length = 2; /* 4-byte multiple */ 657 + *(int *) &gopt->opt_data = bpf_htonl(0xfeedbeef); 665 658 666 - ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt)); 659 + ret = bpf_skb_set_tunnel_opt(skb, gopt, sizeof(gopt)); 667 660 if (ret < 0) { 668 661 log_err(ret); 669 662 return TC_ACT_SHOT;