Per C99 standard [0], Section 6.7.8, Paragraph 10: If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. And in the same document, in appendix "J.2 Undefined behavior": The behavior is undefined in the following circumstances: [...] The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.8, 6.8). This means that use of an uninitialized stack variable is undefined behavior, and therefore that clang can choose to do a variety of scary things, such as not generating bytecode for "bunch of useful code" in the below example: void some_func() { int i; if (!i) return; // bunch of useful code } To add insult to injury, if some_func above is a helper function for some BPF program, clang can choose to not generate an "exit" insn, causing verifier to fail with "last insn is not an exit or jmp". Going from that verification failure to the root cause of uninitialized use is certain to be frustrating. This patch adds -Wuninitialized to the cflags for selftest BPF progs and fixes up existing instances of uninitialized use. [0]: https://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com> Cc: David Vernet <void@manifault.com> Cc: Tejun Heo <tj@kernel.org> Acked-by: David Vernet <void@manifault.com> Link: https://lore.kernel.org/r/20230303005500.1614874-1-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
86 lines
2 KiB
C
86 lines
2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
* Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
|
|
*
|
|
* Author: Roberto Sassu <roberto.sassu@huawei.com>
|
|
*/
|
|
|
|
#include "vmlinux.h"
|
|
#include <errno.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
#include <bpf/bpf_tracing.h>
|
|
#include "bpf_misc.h"
|
|
|
|
extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym;
|
|
extern void bpf_key_put(struct bpf_key *key) __ksym;
|
|
extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr,
|
|
struct bpf_dynptr *sig_ptr,
|
|
struct bpf_key *trusted_keyring) __ksym;
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
|
__uint(max_entries, 4096);
|
|
} ringbuf SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
|
__uint(max_entries, 1);
|
|
__type(key, __u32);
|
|
__type(value, __u32);
|
|
} array_map SEC(".maps");
|
|
|
|
int err, pid;
|
|
|
|
char _license[] SEC("license") = "GPL";
|
|
|
|
SEC("?lsm.s/bpf")
|
|
__failure __msg("cannot pass in dynptr at an offset=-8")
|
|
int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size)
|
|
{
|
|
unsigned long val;
|
|
|
|
return bpf_verify_pkcs7_signature((struct bpf_dynptr *)&val,
|
|
(struct bpf_dynptr *)&val, NULL);
|
|
}
|
|
|
|
SEC("?lsm.s/bpf")
|
|
__failure __msg("arg#0 expected pointer to stack or dynptr_ptr")
|
|
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size)
|
|
{
|
|
unsigned long val = 0;
|
|
|
|
return bpf_verify_pkcs7_signature((struct bpf_dynptr *)val,
|
|
(struct bpf_dynptr *)val, NULL);
|
|
}
|
|
|
|
SEC("lsm.s/bpf")
|
|
int BPF_PROG(dynptr_data_null, int cmd, union bpf_attr *attr, unsigned int size)
|
|
{
|
|
struct bpf_key *trusted_keyring;
|
|
struct bpf_dynptr ptr;
|
|
__u32 *value;
|
|
int ret, zero = 0;
|
|
|
|
if (bpf_get_current_pid_tgid() >> 32 != pid)
|
|
return 0;
|
|
|
|
value = bpf_map_lookup_elem(&array_map, &zero);
|
|
if (!value)
|
|
return 0;
|
|
|
|
/* Pass invalid flags. */
|
|
ret = bpf_dynptr_from_mem(value, sizeof(*value), ((__u64)~0ULL), &ptr);
|
|
if (ret != -EINVAL)
|
|
return 0;
|
|
|
|
trusted_keyring = bpf_lookup_system_key(0);
|
|
if (!trusted_keyring)
|
|
return 0;
|
|
|
|
err = bpf_verify_pkcs7_signature(&ptr, &ptr, trusted_keyring);
|
|
|
|
bpf_key_put(trusted_keyring);
|
|
|
|
return 0;
|
|
}
|