Commit b02f072a authored by Andrii Nakryiko's avatar Andrii Nakryiko
Browse files

Merge branch 'support-freplace-prog-from-user-namespace'

Mykyta Yatsenko says:

====================
Support freplace prog from user namespace

From: Mykyta Yatsenko <yatsenko@meta.com>

Freplace programs can't be loaded from user namespace, as
bpf_program__set_attach_target() requires searching for target prog BTF,
which is locked under CAP_SYS_ADMIN.
This patch set enables this use case by:
1. Relaxing capable check in bpf's BPF_BTF_GET_FD_BY_ID, check for CAP_BPF
instead of CAP_SYS_ADMIN, support BPF token in attr argument.
2. Pass BPF token around libbpf from bpf_program__set_attach_target() to
bpf syscall where capable check is.
3. Validate positive/negative scenarios in selftests

This patch set is enabled by the recent libbpf change[1], that
introduced bpf_object__prepare() API. Calling bpf_object__prepare() for
freplace program before bpf_program__set_attach_target() initializes BPF
token, which is then passed to bpf syscall by libbpf.

[1] https://lore.kernel.org/all/20250303135752.158343-1-mykyta.yatsenko5@gmail.com/
====================

Link: https://patch.msgid.link/20250317174039.161275-1-mykyta.yatsenko5@gmail.com


Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
parents 812f7702 a024843d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1652,6 +1652,7 @@ union bpf_attr {
		};
		__u32		next_id;
		__u32		open_flags;
		__s32		fd_by_id_token_fd;
	};

	struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
+23 −4
Original line number Diff line number Diff line
@@ -4732,6 +4732,8 @@ static int bpf_prog_get_info_by_fd(struct file *file,
	info.recursion_misses = stats.misses;

	info.verified_insns = prog->aux->verified_insns;
	if (prog->aux->btf)
		info.btf_id = btf_obj_id(prog->aux->btf);

	if (!bpf_capable()) {
		info.jited_prog_len = 0;
@@ -4878,8 +4880,6 @@ static int bpf_prog_get_info_by_fd(struct file *file,
		}
	}

	if (prog->aux->btf)
		info.btf_id = btf_obj_id(prog->aux->btf);
	info.attach_btf_id = prog->aux->attach_btf_id;
	if (attach_btf)
		info.attach_btf_obj_id = btf_obj_id(attach_btf);
@@ -5120,15 +5120,34 @@ static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_
	return btf_new_fd(attr, uattr, uattr_size);
}

#define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
#define BPF_BTF_GET_FD_BY_ID_LAST_FIELD fd_by_id_token_fd

static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
{
	struct bpf_token *token = NULL;

	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
		return -EINVAL;

	if (!capable(CAP_SYS_ADMIN))
	if (attr->open_flags & ~BPF_F_TOKEN_FD)
		return -EINVAL;

	if (attr->open_flags & BPF_F_TOKEN_FD) {
		token = bpf_token_get_from_fd(attr->fd_by_id_token_fd);
		if (IS_ERR(token))
			return PTR_ERR(token);
		if (!bpf_token_allow_cmd(token, BPF_BTF_GET_FD_BY_ID)) {
			bpf_token_put(token);
			token = NULL;
		}
	}

	if (!bpf_token_capable(token, CAP_SYS_ADMIN)) {
		bpf_token_put(token);
		return -EPERM;
	}

	bpf_token_put(token);

	return btf_get_fd_by_id(attr->btf_id);
}
+1 −0
Original line number Diff line number Diff line
@@ -1652,6 +1652,7 @@ union bpf_attr {
		};
		__u32		next_id;
		__u32		open_flags;
		__s32		fd_by_id_token_fd;
	};

	struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
+2 −1
Original line number Diff line number Diff line
@@ -1097,7 +1097,7 @@ int bpf_map_get_fd_by_id(__u32 id)
int bpf_btf_get_fd_by_id_opts(__u32 id,
			      const struct bpf_get_fd_by_id_opts *opts)
{
	const size_t attr_sz = offsetofend(union bpf_attr, open_flags);
	const size_t attr_sz = offsetofend(union bpf_attr, fd_by_id_token_fd);
	union bpf_attr attr;
	int fd;

@@ -1107,6 +1107,7 @@ int bpf_btf_get_fd_by_id_opts(__u32 id,
	memset(&attr, 0, attr_sz);
	attr.btf_id = id;
	attr.open_flags = OPTS_GET(opts, open_flags, 0);
	attr.fd_by_id_token_fd = OPTS_GET(opts, token_fd, 0);

	fd = sys_bpf_fd(BPF_BTF_GET_FD_BY_ID, &attr, attr_sz);
	return libbpf_err_errno(fd);
+2 −1
Original line number Diff line number Diff line
@@ -487,9 +487,10 @@ LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
struct bpf_get_fd_by_id_opts {
	size_t sz; /* size of this struct for forward/backward compatibility */
	__u32 open_flags; /* permissions requested for the operation on fd */
	__u32 token_fd;
	size_t :0;
};
#define bpf_get_fd_by_id_opts__last_field open_flags
#define bpf_get_fd_by_id_opts__last_field token_fd

LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
LIBBPF_API int bpf_prog_get_fd_by_id_opts(__u32 id,
Loading