Commit 182f7df7 authored by Eduard Zingerman's avatar Eduard Zingerman Committed by Alexei Starovoitov
Browse files

bpf: attribute __arg_untrusted for global function parameters



Add support for PTR_TO_BTF_ID | PTR_UNTRUSTED global function
parameters. Anything is allowed to pass to such parameters, as these
are read-only and probe read instructions would protect against
invalid memory access.

Suggested-by: default avatarAlexei Starovoitov <alexei.starovoitov@gmail.com>
Acked-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250704230354.1323244-5-eddyz87@gmail.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent f1f5d6f2
Loading
Loading
Loading
Loading
+33 −5
Original line number Diff line number Diff line
@@ -7649,8 +7649,9 @@ enum btf_arg_tag {
	ARG_TAG_CTX	  = BIT_ULL(0),
	ARG_TAG_NONNULL   = BIT_ULL(1),
	ARG_TAG_TRUSTED   = BIT_ULL(2),
	ARG_TAG_NULLABLE = BIT_ULL(3),
	ARG_TAG_ARENA	 = BIT_ULL(4),
	ARG_TAG_UNTRUSTED = BIT_ULL(3),
	ARG_TAG_NULLABLE  = BIT_ULL(4),
	ARG_TAG_ARENA	  = BIT_ULL(5),
};

/* Process BTF of a function to produce high-level expectation of function
@@ -7758,6 +7759,8 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
				tags |= ARG_TAG_CTX;
			} else if (strcmp(tag, "trusted") == 0) {
				tags |= ARG_TAG_TRUSTED;
			} else if (strcmp(tag, "untrusted") == 0) {
				tags |= ARG_TAG_UNTRUSTED;
			} else if (strcmp(tag, "nonnull") == 0) {
				tags |= ARG_TAG_NONNULL;
			} else if (strcmp(tag, "nullable") == 0) {
@@ -7818,6 +7821,31 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
			sub->args[i].btf_id = kern_type_id;
			continue;
		}
		if (tags & ARG_TAG_UNTRUSTED) {
			struct btf *vmlinux_btf;
			int kern_type_id;

			if (tags & ~ARG_TAG_UNTRUSTED) {
				bpf_log(log, "arg#%d untrusted cannot be combined with any other tags\n", i);
				return -EINVAL;
			}

			kern_type_id = btf_get_ptr_to_btf_id(log, i, btf, t);
			if (kern_type_id < 0)
				return kern_type_id;

			vmlinux_btf = bpf_get_btf_vmlinux();
			ref_t = btf_type_by_id(vmlinux_btf, kern_type_id);
			if (!btf_type_is_struct(ref_t)) {
				tname = __btf_name_by_offset(vmlinux_btf, t->name_off);
				bpf_log(log, "arg#%d has type %s '%s', but only struct types are allowed\n",
					i, btf_type_str(ref_t), tname);
				return -EINVAL;
			}
			sub->args[i].arg_type = ARG_PTR_TO_BTF_ID | PTR_UNTRUSTED;
			sub->args[i].btf_id = kern_type_id;
			continue;
		}
		if (tags & ARG_TAG_ARENA) {
			if (tags & ~ARG_TAG_ARENA) {
				bpf_log(log, "arg#%d arena cannot be combined with any other tags\n", i);
+6 −0
Original line number Diff line number Diff line
@@ -10437,6 +10437,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
				bpf_log(log, "R%d is not a scalar\n", regno);
				return -EINVAL;
			}
		} else if (arg->arg_type & PTR_UNTRUSTED) {
			/*
			 * Anything is allowed for untrusted arguments, as these are
			 * read-only and probe read instructions would protect against
			 * invalid memory access.
			 */
		} else if (arg->arg_type == ARG_PTR_TO_CTX) {
			ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
			if (ret < 0)