aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCheng-Min Chiang <chmnchiang@google.com>2020-07-24 18:05:18 -0700
committerDmitry Vyukov <dvyukov@google.com>2020-08-07 09:28:26 +0200
commit20a3465b973bec140ff12740acffa6c357b27edc (patch)
tree055bd8837d2f68319165366dfc273ea8b891a92c
parentcb436c69d9bcb0330518a48559649c9436ed5e7a (diff)
sys/linux: add descriptions for BPF LSM
This commit includes the following changes: * executor: add a new syz_btf_id_by_name psuedo-syscall * sys/linux: add descriptions for BPF LSM subsystem * sys/linux: add instructions on how to dump vmlinux and install bpftool * sys/linux/test: add tests for the new psuedo-syscall * pkg/host: add support detection for the new psuedo-syscall * pkg/runtest: skip the coverage test when invoking the new psuedo-syscall Update #533.
-rw-r--r--executor/common_linux.h188
-rw-r--r--pkg/csource/generated.go165
-rw-r--r--pkg/host/syscalls_linux.go10
-rw-r--r--pkg/runtest/run.go4
-rw-r--r--sys/linux/bpf.txt14
-rw-r--r--sys/linux/bpf_lsm.txt28
-rw-r--r--sys/linux/bpf_lsm_386.const5
-rw-r--r--sys/linux/bpf_lsm_amd64.const5
-rw-r--r--sys/linux/bpf_lsm_arm.const5
-rw-r--r--sys/linux/bpf_lsm_arm64.const5
-rw-r--r--sys/linux/bpf_lsm_mips64le.const5
-rw-r--r--sys/linux/bpf_lsm_ppc64le.const5
-rw-r--r--sys/linux/bpf_lsm_riscv64.const5
-rw-r--r--sys/linux/bpf_lsm_s390x.const5
-rw-r--r--sys/linux/test/btf_id19
15 files changed, 460 insertions, 8 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index b49e67542..329d865d0 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -1563,6 +1563,194 @@ static long syz_io_uring_submit(volatile long a0, volatile long a1, volatile lon
#endif
+#if SYZ_EXECUTOR || __NR_syz_btf_id_by_name
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// Some items in linux/btf.h are relatively new, so we copy them here for
+// backward compatibility.
+#define BTF_MAGIC 0xeB9F
+
+struct btf_header {
+ __u16 magic;
+ __u8 version;
+ __u8 flags;
+ __u32 hdr_len;
+ __u32 type_off;
+ __u32 type_len;
+ __u32 str_off;
+ __u32 str_len;
+};
+
+#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
+#define BTF_INFO_VLEN(info) ((info)&0xffff)
+
+#define BTF_KIND_INT 1
+#define BTF_KIND_ARRAY 3
+#define BTF_KIND_STRUCT 4
+#define BTF_KIND_UNION 5
+#define BTF_KIND_ENUM 6
+#define BTF_KIND_FUNC_PROTO 13
+#define BTF_KIND_VAR 14
+#define BTF_KIND_DATASEC 15
+
+struct btf_type {
+ __u32 name_off;
+ __u32 info;
+ union {
+ __u32 size;
+ __u32 type;
+ };
+};
+
+struct btf_enum {
+ __u32 name_off;
+ __s32 val;
+};
+
+struct btf_array {
+ __u32 type;
+ __u32 index_type;
+ __u32 nelems;
+};
+
+struct btf_member {
+ __u32 name_off;
+ __u32 type;
+ __u32 offset;
+};
+
+struct btf_param {
+ __u32 name_off;
+ __u32 type;
+};
+
+struct btf_var {
+ __u32 linkage;
+};
+
+struct btf_var_secinfo {
+ __u32 type;
+ __u32 offset;
+ __u32 size;
+};
+
+// Set the limit on the maximum size of btf/vmlinux to be 10 MiB.
+#define VMLINUX_MAX_SUPPORT_SIZE (10 * 1024 * 1024)
+
+// Read out all the content of /sys/kernel/btf/vmlinux to the fixed address
+// buffer and return it. Return NULL if failed.
+static char* read_btf_vmlinux()
+{
+ static bool is_read = false;
+ static char buf[VMLINUX_MAX_SUPPORT_SIZE];
+
+ // There could be a race condition here, but it should not be harmful.
+ if (is_read)
+ return buf;
+
+ int fd = open("/sys/kernel/btf/vmlinux", O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ unsigned long bytes_read = 0;
+ for (;;) {
+ ssize_t ret = read(fd, buf + bytes_read,
+ VMLINUX_MAX_SUPPORT_SIZE - bytes_read);
+
+ if (ret < 0 || bytes_read + ret == VMLINUX_MAX_SUPPORT_SIZE)
+ return NULL;
+
+ if (ret == 0)
+ break;
+
+ bytes_read += ret;
+ }
+
+ is_read = true;
+ return buf;
+}
+
+// Given a pointer to a C-string as the only argument a0, return the
+// corresponding btf ID for this name. Return -1 if there is an error when
+// opening the vmlinux file or the name is not found in vmlinux.
+static long syz_btf_id_by_name(volatile long a0)
+{
+ // syzlang: syz_btf_id_by_name(name ptr[in, string]) btf_id
+ // C: syz_btf_id_by_name(char* name)
+ char* target = (char*)a0;
+
+ char* vmlinux = read_btf_vmlinux();
+ if (vmlinux == NULL)
+ return -1;
+
+ struct btf_header* btf_header = (struct btf_header*)vmlinux;
+ if (btf_header->magic != BTF_MAGIC)
+ return -1;
+ // These offsets are bytes relative to the end of the header.
+ char* btf_type_sec = vmlinux + btf_header->hdr_len + btf_header->type_off;
+ char* btf_str_sec = vmlinux + btf_header->hdr_len + btf_header->str_off;
+ // Scan through the btf type section, and find a type description that
+ // matches the provided name.
+ unsigned int bytes_parsed = 0;
+ // BTF index starts at 1.
+ long idx = 1;
+ while (bytes_parsed < btf_header->type_len) {
+ struct btf_type* btf_type = (struct btf_type*)(btf_type_sec + bytes_parsed);
+ uint32 kind = BTF_INFO_KIND(btf_type->info);
+ uint32 vlen = BTF_INFO_VLEN(btf_type->info);
+ char* name = btf_str_sec + btf_type->name_off;
+
+ if (strcmp(name, target) == 0)
+ return idx;
+
+ // From /include/uapi/linux/btf.h, some kinds of types are
+ // followed by extra data.
+ size_t skip;
+ switch (kind) {
+ case BTF_KIND_INT:
+ skip = sizeof(uint32);
+ break;
+ case BTF_KIND_ENUM:
+ skip = sizeof(struct btf_enum) * vlen;
+ break;
+ case BTF_KIND_ARRAY:
+ skip = sizeof(struct btf_array);
+ break;
+ case BTF_KIND_STRUCT:
+ case BTF_KIND_UNION:
+ skip = sizeof(struct btf_member) * vlen;
+ break;
+ case BTF_KIND_FUNC_PROTO:
+ skip = sizeof(struct btf_param) * vlen;
+ break;
+ case BTF_KIND_VAR:
+ skip = sizeof(struct btf_var);
+ break;
+ case BTF_KIND_DATASEC:
+ skip = sizeof(struct btf_var_secinfo) * vlen;
+ break;
+ default:
+ skip = 0;
+ }
+
+ bytes_parsed += sizeof(struct btf_type) + skip;
+ idx++;
+ }
+
+ return -1;
+}
+
+#endif // SYZ_EXECUTOR || __NR_syz_btf_id_by_name
+
// Same as memcpy except that it accepts offset to dest and src.
#if SYZ_EXECUTOR || __NR_syz_memcpy_off
static long syz_memcpy_off(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4)
diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go
index dda5a5525..2643c8767 100644
--- a/pkg/csource/generated.go
+++ b/pkg/csource/generated.go
@@ -3660,6 +3660,171 @@ static long syz_io_uring_submit(volatile long a0, volatile long a1, volatile lon
#endif
#endif
+
+#if SYZ_EXECUTOR || __NR_syz_btf_id_by_name
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#define BTF_MAGIC 0xeB9F
+
+struct btf_header {
+ __u16 magic;
+ __u8 version;
+ __u8 flags;
+ __u32 hdr_len;
+ __u32 type_off;
+ __u32 type_len;
+ __u32 str_off;
+ __u32 str_len;
+};
+
+#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
+#define BTF_INFO_VLEN(info) ((info)&0xffff)
+
+#define BTF_KIND_INT 1
+#define BTF_KIND_ARRAY 3
+#define BTF_KIND_STRUCT 4
+#define BTF_KIND_UNION 5
+#define BTF_KIND_ENUM 6
+#define BTF_KIND_FUNC_PROTO 13
+#define BTF_KIND_VAR 14
+#define BTF_KIND_DATASEC 15
+
+struct btf_type {
+ __u32 name_off;
+ __u32 info;
+ union {
+ __u32 size;
+ __u32 type;
+ };
+};
+
+struct btf_enum {
+ __u32 name_off;
+ __s32 val;
+};
+
+struct btf_array {
+ __u32 type;
+ __u32 index_type;
+ __u32 nelems;
+};
+
+struct btf_member {
+ __u32 name_off;
+ __u32 type;
+ __u32 offset;
+};
+
+struct btf_param {
+ __u32 name_off;
+ __u32 type;
+};
+
+struct btf_var {
+ __u32 linkage;
+};
+
+struct btf_var_secinfo {
+ __u32 type;
+ __u32 offset;
+ __u32 size;
+};
+#define VMLINUX_MAX_SUPPORT_SIZE (10 * 1024 * 1024)
+static char* read_btf_vmlinux()
+{
+ static bool is_read = false;
+ static char buf[VMLINUX_MAX_SUPPORT_SIZE];
+ if (is_read)
+ return buf;
+
+ int fd = open("/sys/kernel/btf/vmlinux", O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ unsigned long bytes_read = 0;
+ for (;;) {
+ ssize_t ret = read(fd, buf + bytes_read,
+ VMLINUX_MAX_SUPPORT_SIZE - bytes_read);
+
+ if (ret < 0 || bytes_read + ret == VMLINUX_MAX_SUPPORT_SIZE)
+ return NULL;
+
+ if (ret == 0)
+ break;
+
+ bytes_read += ret;
+ }
+
+ is_read = true;
+ return buf;
+}
+static long syz_btf_id_by_name(volatile long a0)
+{
+ char* target = (char*)a0;
+
+ char* vmlinux = read_btf_vmlinux();
+ if (vmlinux == NULL)
+ return -1;
+
+ struct btf_header* btf_header = (struct btf_header*)vmlinux;
+ if (btf_header->magic != BTF_MAGIC)
+ return -1;
+ char* btf_type_sec = vmlinux + btf_header->hdr_len + btf_header->type_off;
+ char* btf_str_sec = vmlinux + btf_header->hdr_len + btf_header->str_off;
+ unsigned int bytes_parsed = 0;
+ long idx = 1;
+ while (bytes_parsed < btf_header->type_len) {
+ struct btf_type* btf_type = (struct btf_type*)(btf_type_sec + bytes_parsed);
+ uint32 kind = BTF_INFO_KIND(btf_type->info);
+ uint32 vlen = BTF_INFO_VLEN(btf_type->info);
+ char* name = btf_str_sec + btf_type->name_off;
+
+ if (strcmp(name, target) == 0)
+ return idx;
+ size_t skip;
+ switch (kind) {
+ case BTF_KIND_INT:
+ skip = sizeof(uint32);
+ break;
+ case BTF_KIND_ENUM:
+ skip = sizeof(struct btf_enum) * vlen;
+ break;
+ case BTF_KIND_ARRAY:
+ skip = sizeof(struct btf_array);
+ break;
+ case BTF_KIND_STRUCT:
+ case BTF_KIND_UNION:
+ skip = sizeof(struct btf_member) * vlen;
+ break;
+ case BTF_KIND_FUNC_PROTO:
+ skip = sizeof(struct btf_param) * vlen;
+ break;
+ case BTF_KIND_VAR:
+ skip = sizeof(struct btf_var);
+ break;
+ case BTF_KIND_DATASEC:
+ skip = sizeof(struct btf_var_secinfo) * vlen;
+ break;
+ default:
+ skip = 0;
+ }
+
+ bytes_parsed += sizeof(struct btf_type) + skip;
+ idx++;
+ }
+
+ return -1;
+}
+
+#endif
#if SYZ_EXECUTOR || __NR_syz_memcpy_off
static long syz_memcpy_off(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4)
{
diff --git a/pkg/host/syscalls_linux.go b/pkg/host/syscalls_linux.go
index f1c8f03c8..06e9a261f 100644
--- a/pkg/host/syscalls_linux.go
+++ b/pkg/host/syscalls_linux.go
@@ -243,6 +243,13 @@ func isSyzIoUringSupported(c *prog.Syscall, target *prog.Target, sandbox string)
return isSupportedSyscall(ioUringSyscall, target)
}
+func isBtfVmlinuxSupported(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
+ if err := osutil.IsAccessible("/sys/kernel/btf/vmlinux"); err != nil {
+ return false, err.Error()
+ }
+ return onlySandboxNone(sandbox)
+}
+
var syzkallSupport = map[string]func(*prog.Syscall, *prog.Target, string) (bool, string){
"syz_open_dev": isSyzOpenDevSupported,
"syz_open_procfs": alwaysSupported,
@@ -267,7 +274,8 @@ var syzkallSupport = map[string]func(*prog.Syscall, *prog.Target, string) (bool,
"syz_io_uring_setup": isSyzIoUringSupported,
// syz_memcpy_off is only used for io_uring descriptions, thus, enable it
// only if io_uring syscalls are enabled.
- "syz_memcpy_off": isSyzIoUringSupported,
+ "syz_memcpy_off": isSyzIoUringSupported,
+ "syz_btf_id_by_name": isBtfVmlinuxSupported,
}
func isSupportedSyzkall(c *prog.Syscall, target *prog.Target, sandbox string) (bool, string) {
diff --git a/pkg/runtest/run.go b/pkg/runtest/run.go
index af57e7629..119e69b98 100644
--- a/pkg/runtest/run.go
+++ b/pkg/runtest/run.go
@@ -503,7 +503,9 @@ func checkResult(req *RunRequest) error {
if len(inf.Signal) < 2 && !calls[callName] && len(info.Extra.Signal) == 0 {
return fmt.Errorf("run %v: call %v: no signal", run, i)
}
- if len(inf.Cover) == 0 {
+ // syz_btf_id_by_name is a pseudo-syscall that might not provide
+ // any coverage when invoked.
+ if len(inf.Cover) == 0 && callName != "syz_btf_id_by_name" {
return fmt.Errorf("run %v: call %v: no cover", run, i)
}
calls[callName] = true
diff --git a/sys/linux/bpf.txt b/sys/linux/bpf.txt
index ec9fe0926..b45df8001 100644
--- a/sys/linux/bpf.txt
+++ b/sys/linux/bpf.txt
@@ -48,7 +48,7 @@ bpf$BPF_GET_PROG_INFO(cmd const[BPF_OBJ_GET_INFO_BY_FD], arg ptr[in, bpf_get_pro
bpf$BPF_GET_MAP_INFO(cmd const[BPF_OBJ_GET_INFO_BY_FD], arg ptr[in, bpf_get_map_info_arg], size len[arg])
bpf$BPF_GET_BTF_INFO(cmd const[BPF_OBJ_GET_INFO_BY_FD], arg ptr[in, bpf_get_btf_info_arg], size len[arg])
bpf$BPF_PROG_QUERY(cmd const[BPF_PROG_QUERY], arg ptr[in, bpf_prog_query], size len[arg])
-bpf$BPF_RAW_TRACEPOINT_OPEN(cmd const[BPF_RAW_TRACEPOINT_OPEN], arg ptr[in, bpf_raw_tracepoint], size len[arg]) fd_perf_base
+bpf$BPF_RAW_TRACEPOINT_OPEN(cmd const[BPF_RAW_TRACEPOINT_OPEN], arg ptr[in, bpf_raw_tracepoint], size len[arg]) fd_perf_base (timeout[500])
bpf$BPF_BTF_LOAD(cmd const[BPF_BTF_LOAD], arg ptr[in, bpf_btf_load], size len[arg]) fd_btf
bpf$BPF_BTF_GET_FD_BY_ID(cmd const[BPF_BTF_GET_FD_BY_ID], arg ptr[in, bpf_btf_id], size len[arg]) fd_btf
bpf$BPF_TASK_FD_QUERY(cmd const[BPF_TASK_FD_QUERY], arg ptr[inout, bpf_task_fd_query], size len[arg])
@@ -162,8 +162,8 @@ bpf_batch_flags = BPF_F_LOCK
define BPF_LINE_INFO_SIZE sizeof(struct bpf_line_info)
define BPF_FUNC_INFO_SIZE sizeof(struct bpf_func_info)
-bpf_prog {
- type flags[bpf_prog_type, int32]
+type bpf_prog_t[TYPE, ATTACH_TYPE, BTF_ID, PROG_FD] {
+ type TYPE
ninsn bytesize8[insns, int32]
insns ptr64[in, bpf_instructions]
license ptr64[in, string[bpf_licenses]]
@@ -174,7 +174,7 @@ bpf_prog {
flags flags[bpf_prog_load_flags, int32]
prog_name array[const[0, int8], BPF_OBJ_NAME_LEN]
prog_ifindex ifindex[opt]
- expected_attach_type flags[bpf_attach_type, int32]
+ expected_attach_type ATTACH_TYPE
btf_fd fd_btf[opt]
func_info_rec_size const[BPF_FUNC_INFO_SIZE, int32]
func_info ptr64[in, bpf_func_info]
@@ -182,10 +182,12 @@ bpf_prog {
line_info_rec_size const[BPF_LINE_INFO_SIZE, int32]
line_info ptr64[in, bpf_line_info]
line_info_cnt len[line_info, int32]
- attach_btf_id bpf_btf_id[opt]
- attach_prog_fd fd_bpf_prog[opt]
+ attach_btf_id BTF_ID
+ attach_prog_fd PROG_FD
}
+type bpf_prog bpf_prog_t[flags[bpf_prog_type, int32], flags[bpf_attach_type, int32], bpf_btf_id[opt], fd_bpf_prog[opt]]
+
bpf_licenses = "GPL", "syzkaller"
bpf_kern_version = 0x40f00, 0x41000, 0x41100
diff --git a/sys/linux/bpf_lsm.txt b/sys/linux/bpf_lsm.txt
new file mode 100644
index 000000000..7f5d88d9c
--- /dev/null
+++ b/sys/linux/bpf_lsm.txt
@@ -0,0 +1,28 @@
+# Copyright 2020 syzkaller project authors. All rights reserved.
+# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+include <uapi/linux/bpf.h>
+
+resource bpf_lsm_btf_id[bpf_btf_id]
+
+syz_btf_id_by_name$bpf_lsm(name ptr[in, string[bpf_lsm_func_names]]) bpf_lsm_btf_id (timeout[500])
+
+bpf$BPF_LSM_PROG_LOAD(cmd const[BPF_PROG_LOAD], arg ptr[in, bpf_lsm_prog], size len[arg]) fd_bpf_prog (timeout[500])
+
+type bpf_lsm_prog bpf_prog_t[const[BPF_PROG_TYPE_LSM, int32], const[BPF_LSM_MAC, int32], bpf_lsm_btf_id, const[0, int32]]
+
+# The list is generated by the following commands:
+# $ VMLINUX=[path to Linux kernel source directory]/vmlinux
+# $ bpftool btf dump file $VMLINUX | sed -n "s/.*FUNC '\(bpf_lsm\w*\).*/\"\1\"/p" | tr '\n' ',' | sed 's/,$/\n/'
+# where `$VMLINUX` should exist after compiling the Linux kernel.
+# You can also do `VMLINUX=/sys/kernel/btf/vmlinux` and run the command inside the target machine.
+#
+# How to install bpftool:
+# 1. Download the source code of the Linux kernel after version 5.4.
+# 2. Run the following commands (might need to run `make install` with root permission):
+# $ KERNEL=[path to Linux kernel source directory]
+# cd $KERNEL/tools/bpf/bpftool
+# make
+# make install
+
+bpf_lsm_func_names = "bpf_lsm_verify_prog", "bpf_lsm_perf_event_write", "bpf_lsm_perf_event_read", "bpf_lsm_perf_event_free", "bpf_lsm_perf_event_alloc", "bpf_lsm_perf_event_open", "bpf_lsm_locked_down", "bpf_lsm_bpf_prog_free_security", "bpf_lsm_bpf_prog_alloc_security", "bpf_lsm_bpf_map_free_security", "bpf_lsm_bpf_map_alloc_security", "bpf_lsm_bpf_prog", "bpf_lsm_bpf_map", "bpf_lsm_bpf", "bpf_lsm_audit_rule_free", "bpf_lsm_audit_rule_match", "bpf_lsm_audit_rule_known", "bpf_lsm_audit_rule_init", "bpf_lsm_key_getsecurity", "bpf_lsm_key_permission", "bpf_lsm_key_free", "bpf_lsm_key_alloc", "bpf_lsm_xfrm_decode_session", "bpf_lsm_xfrm_state_pol_flow_match", "bpf_lsm_xfrm_policy_lookup", "bpf_lsm_xfrm_state_delete_security", "bpf_lsm_xfrm_state_free_security", "bpf_lsm_xfrm_state_alloc_acquire", "bpf_lsm_xfrm_state_alloc", "bpf_lsm_xfrm_policy_delete_security", "bpf_lsm_xfrm_policy_free_security", "bpf_lsm_xfrm_policy_clone_security", "bpf_lsm_xfrm_policy_alloc_security", "bpf_lsm_ib_free_security", "bpf_lsm_ib_alloc_security", "bpf_lsm_ib_endport_manage_subnet", "bpf_lsm_ib_pkey_access", "bpf_lsm_sctp_sk_clone", "bpf_lsm_sctp_bind_connect", "bpf_lsm_sctp_assoc_request", "bpf_lsm_tun_dev_open", "bpf_lsm_tun_dev_attach", "bpf_lsm_tun_dev_attach_queue", "bpf_lsm_tun_dev_create", "bpf_lsm_tun_dev_free_security", "bpf_lsm_tun_dev_alloc_security", "bpf_lsm_req_classify_flow", "bpf_lsm_secmark_refcount_dec", "bpf_lsm_secmark_refcount_inc", "bpf_lsm_secmark_relabel_packet", "bpf_lsm_inet_conn_established", "bpf_lsm_inet_csk_clone", "bpf_lsm_inet_conn_request", "bpf_lsm_sock_graft", "bpf_lsm_sk_getsecid", "bpf_lsm_sk_clone_security", "bpf_lsm_sk_free_security", "bpf_lsm_sk_alloc_security", "bpf_lsm_socket_getpeersec_dgram", "bpf_lsm_socket_getpeersec_stream", "bpf_lsm_socket_sock_rcv_skb", "bpf_lsm_socket_shutdown", "bpf_lsm_socket_setsockopt", "bpf_lsm_socket_getsockopt", "bpf_lsm_socket_getpeername", "bpf_lsm_socket_getsockname", "bpf_lsm_socket_recvmsg", "bpf_lsm_socket_sendmsg", "bpf_lsm_socket_accept", "bpf_lsm_socket_listen", "bpf_lsm_socket_connect", "bpf_lsm_socket_bind", "bpf_lsm_socket_socketpair", "bpf_lsm_socket_post_create", "bpf_lsm_socket_create", "bpf_lsm_unix_may_send", "bpf_lsm_unix_stream_connect", "bpf_lsm_post_notification", "bpf_lsm_inode_getsecctx", "bpf_lsm_inode_setsecctx", "bpf_lsm_inode_notifysecctx", "bpf_lsm_inode_invalidate_secctx", "bpf_lsm_release_secctx", "bpf_lsm_secctx_to_secid", "bpf_lsm_secid_to_secctx", "bpf_lsm_ismaclabel", "bpf_lsm_setprocattr", "bpf_lsm_getprocattr", "bpf_lsm_d_instantiate", "bpf_lsm_netlink_send", "bpf_lsm_sem_semop", "bpf_lsm_sem_semctl", "bpf_lsm_sem_associate", "bpf_lsm_sem_free_security", "bpf_lsm_sem_alloc_security", "bpf_lsm_shm_shmat", "bpf_lsm_shm_shmctl", "bpf_lsm_shm_associate", "bpf_lsm_shm_free_security", "bpf_lsm_shm_alloc_security", "bpf_lsm_msg_queue_msgrcv", "bpf_lsm_msg_queue_msgsnd", "bpf_lsm_msg_queue_msgctl", "bpf_lsm_msg_queue_associate", "bpf_lsm_msg_queue_free_security", "bpf_lsm_msg_queue_alloc_security", "bpf_lsm_msg_msg_free_security", "bpf_lsm_msg_msg_alloc_security", "bpf_lsm_ipc_getsecid", "bpf_lsm_ipc_permission", "bpf_lsm_task_to_inode", "bpf_lsm_task_prctl", "bpf_lsm_task_kill", "bpf_lsm_task_movememory", "bpf_lsm_task_getscheduler", "bpf_lsm_task_setscheduler", "bpf_lsm_task_setrlimit", "bpf_lsm_task_prlimit", "bpf_lsm_task_getioprio", "bpf_lsm_task_setioprio", "bpf_lsm_task_setnice", "bpf_lsm_task_getsecid", "bpf_lsm_task_getsid", "bpf_lsm_task_getpgid", "bpf_lsm_task_setpgid", "bpf_lsm_task_fix_setgid", "bpf_lsm_task_fix_setuid", "bpf_lsm_kernel_post_read_file", "bpf_lsm_kernel_read_file", "bpf_lsm_kernel_load_data", "bpf_lsm_kernel_module_request", "bpf_lsm_kernel_create_files_as", "bpf_lsm_kernel_act_as", "bpf_lsm_cred_getsecid", "bpf_lsm_cred_transfer", "bpf_lsm_cred_prepare", "bpf_lsm_cred_free", "bpf_lsm_cred_alloc_blank", "bpf_lsm_task_free", "bpf_lsm_task_alloc", "bpf_lsm_file_open", "bpf_lsm_file_receive", "bpf_lsm_file_send_sigiotask", "bpf_lsm_file_set_fowner", "bpf_lsm_file_fcntl", "bpf_lsm_file_lock", "bpf_lsm_file_mprotect", "bpf_lsm_mmap_file", "bpf_lsm_mmap_addr", "bpf_lsm_file_ioctl", "bpf_lsm_file_free_security", "bpf_lsm_file_alloc_security", "bpf_lsm_file_permission", "bpf_lsm_kernfs_init_security", "bpf_lsm_inode_copy_up_xattr", "bpf_lsm_inode_copy_up", "bpf_lsm_inode_getsecid", "bpf_lsm_inode_listsecurity", "bpf_lsm_inode_setsecurity", "bpf_lsm_inode_getsecurity", "bpf_lsm_inode_killpriv", "bpf_lsm_inode_need_killpriv", "bpf_lsm_inode_removexattr", "bpf_lsm_inode_listxattr", "bpf_lsm_inode_getxattr", "bpf_lsm_inode_post_setxattr", "bpf_lsm_inode_setxattr", "bpf_lsm_inode_getattr", "bpf_lsm_inode_setattr", "bpf_lsm_inode_permission", "bpf_lsm_inode_follow_link", "bpf_lsm_inode_readlink", "bpf_lsm_inode_rename", "bpf_lsm_inode_mknod", "bpf_lsm_inode_rmdir", "bpf_lsm_inode_mkdir", "bpf_lsm_inode_symlink", "bpf_lsm_inode_unlink", "bpf_lsm_inode_link", "bpf_lsm_inode_create", "bpf_lsm_inode_init_security", "bpf_lsm_inode_free_security", "bpf_lsm_inode_alloc_security", "bpf_lsm_path_notify", "bpf_lsm_path_chroot", "bpf_lsm_path_chown", "bpf_lsm_path_chmod", "bpf_lsm_path_rename", "bpf_lsm_path_link", "bpf_lsm_path_symlink", "bpf_lsm_path_truncate", "bpf_lsm_path_mknod", "bpf_lsm_path_rmdir", "bpf_lsm_path_mkdir", "bpf_lsm_path_unlink", "bpf_lsm_dentry_create_files_as", "bpf_lsm_dentry_init_security", "bpf_lsm_move_mount", "bpf_lsm_sb_add_mnt_opt", "bpf_lsm_sb_clone_mnt_opts", "bpf_lsm_sb_set_mnt_opts", "bpf_lsm_sb_pivotroot", "bpf_lsm_sb_umount", "bpf_lsm_sb_mount", "bpf_lsm_sb_statfs", "bpf_lsm_sb_show_options", "bpf_lsm_sb_kern_mount", "bpf_lsm_sb_remount", "bpf_lsm_sb_eat_lsm_opts", "bpf_lsm_sb_free_mnt_opts", "bpf_lsm_sb_free_security", "bpf_lsm_sb_alloc_security", "bpf_lsm_fs_context_parse_param", "bpf_lsm_fs_context_dup", "bpf_lsm_bprm_committed_creds", "bpf_lsm_bprm_committing_creds", "bpf_lsm_bprm_check_security", "bpf_lsm_bprm_creds_from_file", "bpf_lsm_bprm_creds_for_exec", "bpf_lsm_vm_enough_memory", "bpf_lsm_settime", "bpf_lsm_syslog", "bpf_lsm_quota_on", "bpf_lsm_quotactl", "bpf_lsm_capable", "bpf_lsm_capset", "bpf_lsm_capget", "bpf_lsm_ptrace_traceme", "bpf_lsm_ptrace_access_check", "bpf_lsm_binder_transfer_file", "bpf_lsm_binder_transfer_binder", "bpf_lsm_binder_transaction", "bpf_lsm_binder_set_context_mgr"
diff --git a/sys/linux/bpf_lsm_386.const b/sys/linux/bpf_lsm_386.const
new file mode 100644
index 000000000..1f4dba5ad
--- /dev/null
+++ b/sys/linux/bpf_lsm_386.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 357
diff --git a/sys/linux/bpf_lsm_amd64.const b/sys/linux/bpf_lsm_amd64.const
new file mode 100644
index 000000000..621ccfbcc
--- /dev/null
+++ b/sys/linux/bpf_lsm_amd64.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 321
diff --git a/sys/linux/bpf_lsm_arm.const b/sys/linux/bpf_lsm_arm.const
new file mode 100644
index 000000000..5abce537d
--- /dev/null
+++ b/sys/linux/bpf_lsm_arm.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 386
diff --git a/sys/linux/bpf_lsm_arm64.const b/sys/linux/bpf_lsm_arm64.const
new file mode 100644
index 000000000..421653322
--- /dev/null
+++ b/sys/linux/bpf_lsm_arm64.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 280
diff --git a/sys/linux/bpf_lsm_mips64le.const b/sys/linux/bpf_lsm_mips64le.const
new file mode 100644
index 000000000..24cb5a200
--- /dev/null
+++ b/sys/linux/bpf_lsm_mips64le.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 5315
diff --git a/sys/linux/bpf_lsm_ppc64le.const b/sys/linux/bpf_lsm_ppc64le.const
new file mode 100644
index 000000000..d8c53f7c0
--- /dev/null
+++ b/sys/linux/bpf_lsm_ppc64le.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 361
diff --git a/sys/linux/bpf_lsm_riscv64.const b/sys/linux/bpf_lsm_riscv64.const
new file mode 100644
index 000000000..421653322
--- /dev/null
+++ b/sys/linux/bpf_lsm_riscv64.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 280
diff --git a/sys/linux/bpf_lsm_s390x.const b/sys/linux/bpf_lsm_s390x.const
new file mode 100644
index 000000000..4791cb7ce
--- /dev/null
+++ b/sys/linux/bpf_lsm_s390x.const
@@ -0,0 +1,5 @@
+# AUTOGENERATED FILE
+BPF_LSM_MAC = 27
+BPF_PROG_LOAD = 5
+BPF_PROG_TYPE_LSM = 29
+__NR_bpf = 351
diff --git a/sys/linux/test/btf_id b/sys/linux/test/btf_id
new file mode 100644
index 000000000..88c5a7cc9
--- /dev/null
+++ b/sys/linux/test/btf_id
@@ -0,0 +1,19 @@
+# Query the btf_id of the hook name.
+
+r0 = syz_btf_id_by_name$bpf_lsm(&AUTO='bpf_lsm_path_mkdir\x00')
+
+# Load the bpf program.
+
+r1 = bpf$BPF_LSM_PROG_LOAD(0x5, &AUTO={0x1d, AUTO, &AUTO=@framed={{AUTO, AUTO, AUTO, AUTO, 0x0, AUTO, AUTO, AUTO, 0x0}, [], {AUTO, AUTO, AUTO, AUTO}}, &AUTO='GPL\x00', 0x0, 0x0, 0x0, 0x0, 0x0, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], 0x0, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, r0, 0x0}, 0x78)
+
+# Attach the bpf program to the lsm hook.
+
+r2 = bpf$BPF_RAW_TRACEPOINT_OPEN(0x11, &AUTO={0x0, r1}, 0x10)
+
+# Run again to test that memorization works.
+
+r3 = syz_btf_id_by_name$bpf_lsm(&AUTO='bpf_lsm_path_mkdir\x00')
+
+r4 = bpf$BPF_LSM_PROG_LOAD(0x5, &AUTO={0x1d, AUTO, &AUTO=@framed={{AUTO, AUTO, AUTO, AUTO, 0x0, AUTO, AUTO, AUTO, 0x0}, [], {AUTO, AUTO, AUTO, AUTO}}, &AUTO='GPL\x00', 0x0, 0x0, 0x0, 0x0, 0x0, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], 0x0, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, r3, 0x0}, 0x78)
+
+r5 = bpf$BPF_RAW_TRACEPOINT_OPEN(0x11, &AUTO={0x0, r4}, 0x10)