From: "Thiébaud Weksteen" <tweek@google.com>
To: Paul Moore <paul@paul-moore.com>,
Stephen Smalley <stephen.smalley.work@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Jeffrey Vander Stoep <jeffv@google.com>
Cc: "Thiébaud Weksteen" <tweek@google.com>,
"Ondrej Mosnacek" <omosnace@redhat.com>,
"Eric Suen" <ericsu@linux.microsoft.com>,
"Blaise Boscaccy" <bboscaccy@linux.microsoft.com>,
"Sid Nayyar" <sidnayyar@google.com>,
"Neill Kapron" <nkapron@google.com>,
"Eric Biggers" <ebiggers@google.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"KP Singh" <kpsingh@kernel.org>,
bpf@vger.kernel.org, selinux@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH bpf-next 5/5] selftests/bpf: add loader_load_fd tests
Date: Thu, 13 Aug 2026 10:26:18 +1000 [thread overview]
Message-ID: <20260813002618.3755631-6-tweek@google.com> (raw)
In-Reply-To: <20260813002618.3755631-1-tweek@google.com>
Add user-space selftests for BPF_LOADER_LOAD_FD command. The test ELF is
generated based on the existing light skeleton generator. An awk script
extracts the loader program and map. In the future, it is possible to
add an extra option to `bpftool gen skeleton` to output the ELF file
directly.
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
---
tools/testing/selftests/bpf/Makefile | 8 +-
tools/testing/selftests/bpf/loader_setup.sh | 68 ++++
.../selftests/bpf/prog_tests/loader_load_fd.c | 361 ++++++++++++++++++
.../testing/selftests/bpf/progs/test_loader.c | 21 +
4 files changed, 456 insertions(+), 2 deletions(-)
create mode 100755 tools/testing/selftests/bpf/loader_setup.sh
create mode 100644 tools/testing/selftests/bpf/prog_tests/loader_load_fd.c
create mode 100644 tools/testing/selftests/bpf/progs/test_loader.c
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index d3655a706482..6d881584abbc 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -525,7 +525,7 @@ LINKED_SKELS := test_static_linked.skel.h linked_funcs.skel.h \
LSKELS := fexit_sleep.c trace_printk.c trace_vprintk.c map_ptr_kern.c \
core_kern.c core_kern_overflow.c test_ringbuf.c \
test_ringbuf_n.c test_ringbuf_map_key.c test_ringbuf_write.c \
- test_ringbuf_overwrite.c
+ test_ringbuf_overwrite.c test_loader.c
LSKELS_SIGNED := fentry_test.c fexit_test.c atomics.c
@@ -577,7 +577,8 @@ TRUNNER_EXTRA_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \
$$(filter %.c,$(TRUNNER_EXTRA_SOURCES)))
TRUNNER_LIB_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, \
$$(filter %.c,$(TRUNNER_LIB_SOURCES)))
-TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES))
+TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES)) $$(TRUNNER_OUTPUT)/test_loader_processed.lskel.h
+
TRUNNER_TESTS_HDR := $(TRUNNER_TESTS_DIR)/tests.h
TRUNNER_BPF_SRCS := $$(notdir $$(wildcard $(TRUNNER_BPF_PROGS_DIR)/*.c))
TRUNNER_BPF_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.bpf.o, $$(TRUNNER_BPF_SRCS))
@@ -663,6 +664,9 @@ $(TRUNNER_BPF_LSKELS): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
}) && \
rm -f $$(<:.o=.llinked1.o) $$(<:.o=.llinked2.o) $$(<:.o=.llinked3.o)
+$$(TRUNNER_OUTPUT)/test_loader_processed.lskel.h: $$(TRUNNER_OUTPUT)/test_loader.lskel.h loader_setup.sh
+ $$(Q)./loader_setup.sh $$< $$@
+
$(TRUNNER_BPF_LSKELS_SIGNED): %.lskel.h: %.bpf.o $(BPFTOOL) | $(TRUNNER_OUTPUT)
$(Q)$(if $(PERMISSIVE),if [ ! -f $$< ]; then \
$$(RM) $$@; \
diff --git a/tools/testing/selftests/bpf/loader_setup.sh b/tools/testing/selftests/bpf/loader_setup.sh
new file mode 100755
index 000000000000..f86651b0718f
--- /dev/null
+++ b/tools/testing/selftests/bpf/loader_setup.sh
@@ -0,0 +1,68 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2026 Google LLC
+#
+# loader_setup.sh - Light skeleton data extraction helper for selftests/bpf
+#
+# This script parses an autogenerated light skeleton header (.lskel.h) produced
+# by bpftool ('bpftool gen skeleton -L'). It extracts the embedded loader data
+# ('opts_data') and loader BPF instructions ('opts_insn') string literals and
+# generates a C header file containing:
+# - loader_test_opts_data[]: Data for the '__loader.map' section.
+# - loader_test_opts_data_sz: Size of opts_data.
+# - loader_test_opts_insn[]: Instructions for the '__loader.prog' section.
+# - loader_test_opts_insn_sz: Size of opts_insn.
+#
+# These extracted sections are used by the 'loader_load_fd' selftest to populate
+# an in-memory ELF object file for kernel 'BPF_LOADER_LOAD_FD' testing.
+#
+# Usage:
+# loader_setup.sh <input_lskel.h> <output_data.h>
+
+INPUT="$1"
+OUTPUT="$2"
+
+if [ -z "$INPUT" ] || [ -z "$OUTPUT" ]; then
+ echo "Usage: $0 <input_lskel.h> <output_data.h>" >&2
+ exit 1
+fi
+
+awk -v input="$INPUT" '
+BEGIN {
+ print "/* Generated from " input " */"
+ in_data = 0
+ in_insn = 0
+}
+/opts_data\[\]/ {
+ in_data = 1
+ sub(/^.*opts_data\[\][^="]*=\s*"/, "")
+ printf "static const char test_loader_opts_data[] __attribute__((__aligned__(8))) = \""
+}
+in_data {
+ if (index($0, "\";") > 0) {
+ sub(/";.*/, "")
+ print $0 "\";"
+ print "static const size_t test_loader_opts_data_sz = " \
+ "sizeof(test_loader_opts_data) - 1;\n"
+ in_data = 0
+ } else {
+ print $0
+ }
+}
+/opts_insn\[\]/ {
+ in_insn = 1
+ sub(/^.*opts_insn\[\][^="]*=\s*"/, "")
+ printf "static const char test_loader_opts_insn[] __attribute__((__aligned__(8))) = \""
+}
+in_insn {
+ if (index($0, "\";") > 0) {
+ sub(/";.*/, "")
+ print $0 "\";"
+ print "static const size_t test_loader_opts_insn_sz = " \
+ "sizeof(test_loader_opts_insn) - 1;"
+ in_insn = 0
+ } else {
+ print $0
+ }
+}
+' "$INPUT" > "$OUTPUT"
diff --git a/tools/testing/selftests/bpf/prog_tests/loader_load_fd.c b/tools/testing/selftests/bpf/prog_tests/loader_load_fd.c
new file mode 100644
index 000000000000..ab971662dd04
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/loader_load_fd.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Google LLC */
+
+#define _GNU_SOURCE
+#include <test_progs.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <linux/bpf.h>
+
+#include "bpf/skel_internal.h"
+#include "test_loader_processed.lskel.h"
+
+/* Test helper to create an in-memory ELF */
+static int create_loader_elf(const void *insns, size_t insns_sz,
+ const void *map_data, size_t map_data_sz,
+ const char *license, size_t license_sz,
+ bool omit_prog, bool omit_map, bool omit_license)
+{
+ char shstrtab[] = "\0__loader.prog\0__loader.map\0license\0.shstrtab";
+ size_t prog_off = 1;
+ size_t map_off = prog_off + strlen("__loader.prog") + 1;
+ size_t lic_off = map_off + strlen("__loader.map") + 1;
+ size_t shstr_off = lic_off + strlen("license") + 1;
+ size_t shstrtab_sz = sizeof(shstrtab);
+ Elf_Data *shstr_data, *data;
+ Elf64_Shdr *shstr_shdr, *shdr;
+ Elf_Scn *shstr_scn, *scn;
+ Elf64_Ehdr *ehdr;
+ Elf *elf;
+ int fd;
+
+ fd = memfd_create("loader_elf", 0);
+ if (!ASSERT_GE(fd, 0, "memfd_create"))
+ return -1;
+
+ elf_version(EV_CURRENT);
+ elf = elf_begin(fd, ELF_C_WRITE, NULL);
+ if (!ASSERT_OK_PTR(elf, "elf_begin")) {
+ close(fd);
+ return -1;
+ }
+
+ ehdr = elf64_newehdr(elf);
+ if (!ASSERT_OK_PTR(ehdr, "elf64_newehdr"))
+ goto err;
+
+ ehdr->e_ident[EI_MAG0] = ELFMAG0;
+ ehdr->e_ident[EI_MAG1] = ELFMAG1;
+ ehdr->e_ident[EI_MAG2] = ELFMAG2;
+ ehdr->e_ident[EI_MAG3] = ELFMAG3;
+ ehdr->e_ident[EI_CLASS] = ELFCLASS64;
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr->e_machine = EM_BPF;
+ ehdr->e_type = ET_REL;
+ ehdr->e_version = EV_CURRENT;
+
+ shstr_scn = elf_newscn(elf);
+ shstr_shdr = elf64_getshdr(shstr_scn);
+ shstr_shdr->sh_name = shstr_off;
+ shstr_shdr->sh_type = SHT_STRTAB;
+ shstr_shdr->sh_flags = 0;
+
+ shstr_data = elf_newdata(shstr_scn);
+ shstr_data->d_buf = shstrtab;
+ shstr_data->d_size = shstrtab_sz;
+ shstr_data->d_type = ELF_T_BYTE;
+ shstr_data->d_align = 1;
+
+ ehdr->e_shstrndx = elf_ndxscn(shstr_scn);
+
+ if (!omit_prog && insns && insns_sz > 0) {
+ scn = elf_newscn(elf);
+ shdr = elf64_getshdr(scn);
+ shdr->sh_name = prog_off;
+ shdr->sh_type = SHT_PROGBITS;
+ shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
+
+ data = elf_newdata(scn);
+ data->d_buf = (void *)insns;
+ data->d_size = insns_sz;
+ data->d_type = ELF_T_BYTE;
+ data->d_align = 8;
+ }
+
+ if (!omit_map && map_data && map_data_sz > 0) {
+ scn = elf_newscn(elf);
+ shdr = elf64_getshdr(scn);
+ shdr->sh_name = map_off;
+ shdr->sh_type = SHT_PROGBITS;
+ shdr->sh_flags = SHF_ALLOC;
+
+ data = elf_newdata(scn);
+ data->d_buf = (void *)map_data;
+ data->d_size = map_data_sz;
+ data->d_type = ELF_T_BYTE;
+ data->d_align = 8;
+ }
+
+ if (!omit_license && license && license_sz > 0) {
+ scn = elf_newscn(elf);
+ shdr = elf64_getshdr(scn);
+ shdr->sh_name = lic_off;
+ shdr->sh_type = SHT_PROGBITS;
+ shdr->sh_flags = 0;
+
+ data = elf_newdata(scn);
+ data->d_buf = (void *)license;
+ data->d_size = license_sz;
+ data->d_type = ELF_T_BYTE;
+ data->d_align = 1;
+ }
+
+ if (elf_update(elf, ELF_C_WRITE) < 0)
+ goto err;
+
+ elf_end(elf);
+ lseek(fd, 0, SEEK_SET);
+ return fd;
+
+err:
+ elf_end(elf);
+ close(fd);
+ return -1;
+}
+
+static int sys_bpf_loader_load_fd(int loader_fd, void *ctx, __u32 ctx_size)
+{
+ union bpf_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.load_fd.loader_fd = loader_fd;
+ attr.load_fd.ctx = ptr_to_u64(ctx);
+ attr.load_fd.ctx_size = ctx_size;
+
+ return syscall(__NR_bpf, BPF_LOADER_LOAD_FD, &attr, sizeof(attr));
+}
+
+static void test_loader_load_fd_invalid_fd(void)
+{
+ struct bpf_loader_ctx ctx = {};
+ int err;
+
+ err = sys_bpf_loader_load_fd(-1, &ctx, sizeof(ctx));
+ ASSERT_EQ(err, -1, "invalid fd sys_bpf return");
+ ASSERT_EQ(errno, EINVAL, "invalid fd errno");
+}
+
+static void test_loader_load_fd_oversized_ctx(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char map_data[] = "data";
+ char license[] = "GPL";
+ struct bpf_loader_ctx ctx = {};
+ int elf_fd, err;
+
+ elf_fd = create_loader_elf(insns, sizeof(insns),
+ map_data, sizeof(map_data),
+ license, sizeof(license),
+ false, false, false);
+
+ if (!ASSERT_GE(elf_fd, 0, "create_loader_elf"))
+ return;
+
+ err = sys_bpf_loader_load_fd(elf_fd, &ctx, 65536U);
+ ASSERT_EQ(err, -1, "oversized ctx sys_bpf return");
+ ASSERT_EQ(errno, EINVAL, "oversized ctx errno");
+
+ close(elf_fd);
+}
+
+static void test_loader_load_fd_invalid_elf(void)
+{
+ char garbage[] = "not_an_elf_file_content";
+ struct bpf_loader_ctx ctx = {};
+ int fd, err;
+
+ fd = memfd_create("garbage_file", 0);
+ if (!ASSERT_GE(fd, 0, "memfd_create"))
+ return;
+
+ if (!ASSERT_EQ(write(fd, garbage, sizeof(garbage)), sizeof(garbage), "write garbage")) {
+ close(fd);
+ return;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ err = sys_bpf_loader_load_fd(fd, &ctx, sizeof(ctx));
+ ASSERT_EQ(err, -1, "invalid elf sys_bpf return");
+ ASSERT_EQ(errno, ENOEXEC, "invalid elf errno");
+
+ close(fd);
+}
+
+static void test_loader_load_fd_missing_prog_sec(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char map_data[] = "data";
+ char license[] = "GPL";
+ struct bpf_loader_ctx ctx = {};
+ int elf_fd, err;
+
+ elf_fd = create_loader_elf(insns, sizeof(insns),
+ map_data, sizeof(map_data),
+ license, sizeof(license),
+ true, false, false);
+ if (!ASSERT_GE(elf_fd, 0, "create_loader_elf"))
+ return;
+
+ err = sys_bpf_loader_load_fd(elf_fd, &ctx, sizeof(ctx));
+ ASSERT_EQ(err, -1, "missing prog sec sys_bpf return");
+ ASSERT_EQ(errno, EINVAL, "missing prog sec errno");
+
+ close(elf_fd);
+}
+
+static void test_loader_load_fd_missing_map_sec(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char map_data[] = "data";
+ char license[] = "GPL";
+ struct bpf_loader_ctx ctx = {};
+ int elf_fd, err;
+
+ elf_fd = create_loader_elf(insns, sizeof(insns),
+ map_data, sizeof(map_data),
+ license, sizeof(license),
+ false, true, false);
+ if (!ASSERT_GE(elf_fd, 0, "create_loader_elf"))
+ return;
+
+ err = sys_bpf_loader_load_fd(elf_fd, &ctx, sizeof(ctx));
+ ASSERT_EQ(err, -1, "missing map sec sys_bpf return");
+ ASSERT_EQ(errno, EINVAL, "missing map sec errno");
+
+ close(elf_fd);
+}
+
+static void test_loader_load_fd_missing_license_sec(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ char map_data[] = "data";
+ char license[] = "GPL";
+ struct bpf_loader_ctx ctx = {};
+ int elf_fd, err;
+
+ elf_fd = create_loader_elf(insns, sizeof(insns),
+ map_data, sizeof(map_data),
+ license, sizeof(license),
+ false, false, true);
+ if (!ASSERT_GE(elf_fd, 0, "create_loader_elf"))
+ return;
+
+ err = sys_bpf_loader_load_fd(elf_fd, &ctx, sizeof(ctx));
+ ASSERT_EQ(err, -1, "missing license sec sys_bpf return");
+ ASSERT_EQ(errno, EINVAL, "missing license sec errno");
+
+ close(elf_fd);
+}
+
+static void test_loader_load_fd_loader_failure(void)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, -EPERM),
+ BPF_EXIT_INSN(),
+ };
+ char map_data[] = "data";
+ char license[] = "GPL";
+ struct bpf_loader_ctx ctx = {};
+ int elf_fd, err;
+
+ elf_fd = create_loader_elf(insns, sizeof(insns),
+ map_data, sizeof(map_data),
+ license, sizeof(license),
+ false, false, false);
+ if (!ASSERT_GE(elf_fd, 0, "create_loader_elf"))
+ return;
+
+ err = sys_bpf_loader_load_fd(elf_fd, &ctx, sizeof(ctx));
+ ASSERT_EQ(err, -1, "loader failure sys_bpf return");
+ ASSERT_EQ(errno, EPERM, "loader failure errno");
+
+ close(elf_fd);
+}
+
+struct test_loader_lskel {
+ struct bpf_loader_ctx ctx;
+ struct {
+ struct bpf_map_desc test_map;
+ } maps;
+ struct {
+ struct bpf_prog_desc probe;
+ } progs;
+ struct {
+ int probe_fd;
+ } links;
+};
+
+static void test_loader_load_fd_lskel(void)
+{
+ struct test_loader_lskel skel = {};
+ int elf_fd, err;
+
+ skel.ctx.sz = (char *)&skel.links - (char *)&skel;
+
+ /* Build fake ELF using extracted opts_insn (__loader.prog) and opts_data (__loader.map) */
+ elf_fd = create_loader_elf(test_loader_opts_insn, test_loader_opts_insn_sz,
+ test_loader_opts_data, test_loader_opts_data_sz,
+ "GPL", sizeof("GPL"),
+ false, false, false);
+ if (!ASSERT_GE(elf_fd, 0, "create_loader_elf_lskel"))
+ return;
+
+ err = sys_bpf_loader_load_fd(elf_fd, &skel.ctx, skel.ctx.sz);
+ ASSERT_OK(err, "sys_bpf_loader_load_fd lskel");
+
+ ASSERT_GT(skel.progs.probe.prog_fd, 0, "test_loader probe prog_fd > 0");
+ ASSERT_GT(skel.maps.test_map.map_fd, 0, "test_loader test_map map_fd > 0");
+
+ if (skel.progs.probe.prog_fd > 0)
+ close(skel.progs.probe.prog_fd);
+ if (skel.maps.test_map.map_fd > 0)
+ close(skel.maps.test_map.map_fd);
+ close(elf_fd);
+}
+
+void test_loader_load_fd(void)
+{
+ if (test__start_subtest("invalid_fd"))
+ test_loader_load_fd_invalid_fd();
+ if (test__start_subtest("oversized_ctx"))
+ test_loader_load_fd_oversized_ctx();
+ if (test__start_subtest("invalid_elf"))
+ test_loader_load_fd_invalid_elf();
+ if (test__start_subtest("missing_prog_sec"))
+ test_loader_load_fd_missing_prog_sec();
+ if (test__start_subtest("missing_map_sec"))
+ test_loader_load_fd_missing_map_sec();
+ if (test__start_subtest("missing_license_sec"))
+ test_loader_load_fd_missing_license_sec();
+ if (test__start_subtest("loader_failure"))
+ test_loader_load_fd_loader_failure();
+ if (test__start_subtest("lskel"))
+ test_loader_load_fd_lskel();
+}
diff --git a/tools/testing/selftests/bpf/progs/test_loader.c b/tools/testing/selftests/bpf/progs/test_loader.c
new file mode 100644
index 000000000000..515e15ca042e
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_loader.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 4);
+ __type(key, __u32);
+ __type(value, __u64);
+} test_map SEC(".maps");
+
+SEC("socket")
+int probe(void *ctx)
+{
+ __u32 key = 0;
+ __u64 *val = bpf_map_lookup_elem(&test_map, &key);
+
+ return val ? (int)*val : 0;
+}
+
+char _license[] SEC("license") = "GPL";
--
2.55.0.691.gc56d675ccc-goog
next prev parent reply other threads:[~2026-08-13 0:26 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-13 0:26 [PATCH bpf-next 0/5] bpf: Introduce LOADER_LOAD_FD Thiébaud Weksteen
2026-08-13 0:26 ` [PATCH bpf-next 1/5] fs/kernel_read_file,selinux: Add BPF_LOADER constant Thiébaud Weksteen
2026-08-13 0:36 ` sashiko-bot
2026-08-13 1:25 ` bot+bpf-ci
2026-08-13 0:26 ` [PATCH bpf-next 2/5] bpf: Introduce BPF_LOADER_LOAD_FD command Thiébaud Weksteen
2026-08-13 0:42 ` sashiko-bot
2026-08-13 1:40 ` bot+bpf-ci
2026-08-13 0:26 ` [PATCH bpf-next 3/5] selinux: use kernel sid in security_bpf_* Thiébaud Weksteen
2026-08-13 0:40 ` sashiko-bot
2026-08-13 1:25 ` bot+bpf-ci
2026-08-13 0:26 ` [PATCH bpf-next 4/5] selinux: Add BPF_LOADER_LOAD_FD syscall permission Thiébaud Weksteen
2026-08-13 0:41 ` sashiko-bot
2026-08-13 0:26 ` Thiébaud Weksteen [this message]
2026-08-13 0:36 ` [PATCH bpf-next 5/5] selftests/bpf: add loader_load_fd tests sashiko-bot
2026-08-13 1:25 ` bot+bpf-ci
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260813002618.3755631-6-tweek@google.com \
--to=tweek@google.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bboscaccy@linux.microsoft.com \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=ebiggers@google.com \
--cc=ericsu@linux.microsoft.com \
--cc=gregkh@linuxfoundation.org \
--cc=jeffv@google.com \
--cc=kpsingh@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nkapron@google.com \
--cc=omosnace@redhat.com \
--cc=paul@paul-moore.com \
--cc=selinux@vger.kernel.org \
--cc=sidnayyar@google.com \
--cc=stephen.smalley.work@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.