[PATCH 14/14] bpf: Augment BPF_PROG_LOAD to use in-kernel relocations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The basic algorithm here is to allow the user to supply a sysfs entry
corresponding to a previously in-kernel relocated elf object, and a
symbol name that they wish to load. From there the loader ignores any
supplied bpf instruction buffers and relies on the in-kernel
representation. However, maps and other associated file descriptors
passed in from userspace are handled as normal.

Signed-off-by: Blaise Boscaccy <bboscaccy@xxxxxxxxxxxxxxxxxxx>
---
 kernel/bpf/syscall.c | 56 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 7 deletions(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index ea0401634e752..8159fe75cd359 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2740,9 +2740,13 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 	struct bpf_prog *prog, *dst_prog = NULL;
 	struct btf *attach_btf = NULL;
 	struct bpf_token *token = NULL;
+	struct bpf_obj *obj = NULL;
+	struct bpf_prog_obj *prog_obj = NULL;
 	bool bpf_cap;
-	int err;
+	int err, i;
 	char license[128];
+	char symbol_name[32];
+	struct fd loader_fd;
 
 	if (CHECK_ATTR(BPF_PROG_LOAD))
 		return -EINVAL;
@@ -2855,8 +2859,40 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 		goto put_token;
 	}
 
+	if (attr->prog_loader_fd) {
+		loader_fd = fdget(attr->prog_loader_fd);
+		if (!fd_file(loader_fd)) {
+			err = -EBADF;
+			goto put_token;
+		}
+
+		obj = fd_file(loader_fd)->private_data;
+
+		/* copy eBPF program symbol name from user space */
+		if (strncpy_from_bpfptr(symbol_name,
+					make_bpfptr(attr->symbol_loader_name, uattr.is_kernel),
+					sizeof(symbol_name) - 1) < 0)
+			goto put_token;
+
+		symbol_name[sizeof(symbol_name) - 1] = 0;
+
+		for (i = 0; i < obj->nr_programs; i++) {
+			if (strcmp(symbol_name, obj->progs[i].name) == 0) {
+				prog_obj = &obj->progs[i];
+				break;
+			}
+		}
+
+		if (!prog_obj)
+			goto put_token;
+	}
+
 	/* plain bpf_prog allocation */
-	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
+	if (prog_obj)
+		prog = bpf_prog_alloc(bpf_prog_size(prog_obj->insn_cnt), GFP_USER);
+	else
+		prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
+
 	if (!prog) {
 		if (dst_prog)
 			bpf_prog_put(dst_prog);
@@ -2879,13 +2915,19 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
 	token = NULL;
 
 	prog->aux->user = get_current_user();
-	prog->len = attr->insn_cnt;
 
 	err = -EFAULT;
-	if (copy_from_bpfptr(prog->insns,
-			     make_bpfptr(attr->insns, uattr.is_kernel),
-			     bpf_prog_insn_size(prog)) != 0)
-		goto free_prog;
+	if (prog_obj) {
+		prog->len = prog_obj->insn_cnt;
+		memcpy(prog->insnsi, prog_obj->insn, prog_obj->insn_cnt * sizeof(struct bpf_insn));
+	} else {
+		prog->len = attr->insn_cnt;
+		if (copy_from_bpfptr(prog->insns,
+				     make_bpfptr(attr->insns, uattr.is_kernel),
+				     bpf_prog_insn_size(prog)) != 0)
+			goto free_prog;
+	}
+
 	/* copy eBPF program license from user space */
 	if (strncpy_from_bpfptr(license,
 				make_bpfptr(attr->license, uattr.is_kernel),
-- 
2.47.1





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux