FAILED: patch "[PATCH] bpf: Make per_cpu_ptr return rdonly PTR_TO_MEM." failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 34d3a78c681e8e7844b43d1a2f4671a04249c821 Mon Sep 17 00:00:00 2001
From: Hao Luo <[email protected]>
Date: Thu, 16 Dec 2021 16:31:50 -0800
Subject: [PATCH] bpf: Make per_cpu_ptr return rdonly PTR_TO_MEM.
Tag the return type of {per, this}_cpu_ptr with RDONLY_MEM. The returned value of this pair of helpers is kernel object, which can not be updated by bpf programs. Previously these two helpers return PTR_OT_MEM for kernel objects of scalar type, which allows one to directly modify the memory. Now with RDONLY_MEM tagging, the verifier will reject programs that write into RDONLY_MEM.
kernel/bpf/helpers.c +2 -2
@@ -682,7 +682,7 @@ BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)const struct bpf_func_proto bpf_per_cpu_ptr_proto = { .func = bpf_per_cpu_ptr, .gpl_only = false, - .ret_type =RET_PTR_TO_MEM_OR_BTF_ID |PTR_MAYBE_NULL , + .ret_type =RET_PTR_TO_MEM_OR_BTF_ID |PTR_MAYBE_NULL |MEM_RDONLY , .arg1_type =ARG_PTR_TO_PERCPU_BTF_ID , .arg2_type =ARG_ANYTHING , };
@@ -695,7 +695,7 @@ BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)const struct bpf_func_proto bpf_this_cpu_ptr_proto = { .func = bpf_this_cpu_ptr, .gpl_only = false, - .ret_type =RET_PTR_TO_MEM_OR_BTF_ID , + .ret_type =RET_PTR_TO_MEM_OR_BTF_ID |MEM_RDONLY , .arg1_type =ARG_PTR_TO_PERCPU_BTF_ID , };
kernel/bpf/verifier.c +26 -4
@@ -4399,15 +4399,30 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regnmark_reg_unknown (env, regs, value_regno); } } - }else if (reg->type ==PTR_TO_MEM ) { + }else if (base_type (reg->type) ==PTR_TO_MEM ) { +bool rdonly_mem =type_is_rdonly_mem (reg->type); + +if (type_may_be_null (reg->type)) { +verbose (env,"R%d invalid mem access '%s'\n" , regno, +reg_type_str (env, reg->type)); +return -EACCES ; + } + +if (t ==BPF_WRITE && rdonly_mem) { +verbose (env,"R%d cannot write into %s\n" , + regno,reg_type_str (env, reg->type)); +return -EACCES ; + } +if (t ==BPF_WRITE && value_regno >=0 &&is_pointer_value (env, value_regno)) {verbose (env,"R%d leaks addr into mem\n" , value_regno);return -EACCES ; } + err =check_mem_region_access (env, regno, off, size, reg->mem_size, false); -if (!err && t ==BPF_READ && value_regno >=0 ) +if (!err && value_regno >=0 && (t ==BPF_READ || rdonly_mem))mark_reg_unknown (env, regs, value_regno); }else if (reg->type ==PTR_TO_CTX ) {enum bpf_reg_type reg_type =SCALAR_VALUE ;
@@ -6654,6 +6669,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0 ].type =PTR_TO_MEM | ret_flag; regs[BPF_REG_0 ].mem_size = tsize; }else { +/* MEM_RDONLY may be carried from ret_flag, but it +* doesn't apply on PTR_TO_BTF_ID. Fold it, otherwise +* it will confuse the check of PTR_TO_BTF_ID in +* check_mem_access(). +*/ + ret_flag &= ~MEM_RDONLY ; + regs[BPF_REG_0 ].type =PTR_TO_BTF_ID | ret_flag; regs[BPF_REG_0 ].btf = meta.ret_btf; regs[BPF_REG_0 ].btf_id = meta.ret_btf_id;
@@ -9455,7 +9477,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)mark_reg_known_zero (env, regs, insn->dst_reg); dst_reg->type = aux->btf_var.reg_type; -switch (dst_reg->type) { +switch (base_type (dst_reg->type)) {case PTR_TO_MEM : dst_reg->mem_size = aux->btf_var.mem_size;break ;
@@ -11678,7 +11700,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env, err = -EINVAL ; goto err_put; } - aux->btf_var.reg_type =PTR_TO_MEM ; + aux->btf_var.reg_type =PTR_TO_MEM |MEM_RDONLY ; aux->btf_var.mem_size = tsize; }else { aux->btf_var.reg_type =PTR_TO_BTF_ID ;