History

bpf: Reject offset refcount acquire arguments

bpf_refcount_acquire() increments the refcount at the caller-supplied pointer plus the refcount field offset, then returns the caller-supplied pointer unchanged. The verifier records the return value as a base pointer to the refcounted object. bpf_list_pop_front() and bpf_rbtree_remove() can return embedded graph-node pointers as PTR_TO_BTF_ID | MEM_ALLOC with a fixed offset equal to the node field offset. Passing such a pointer directly to bpf_refcount_acquire() currently passes the refcounted-kptr type check. That makes the runtime operation start from base + node_off while the verifier models the returned pointer as the object base. Require refcount-acquire arguments to have zero fixed offset by carrying the requirement through check_func_arg_reg_off() to __check_ptr_off_reg(). Programs can still acquire a refcount from a graph-node-derived pointer after normalizing it with container_of().

Yiyang Chen committed 4 months ago

Commit 931a5771 parent 66bb9521 file · +22 −10Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/bpf/verifier.c+22−10
@@ -7996,9 +7996,10 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields) · 7995 unmodified lines
7996 return field;7996 return field;
7997}7997}
7998 7998
7999static int check_func_arg_reg_off(struct bpf_verifier_env *env,7999static int __check_func_arg_reg_off(struct bpf_verifier_env *env,
8000 const struct bpf_reg_state *reg, argno_t argno,8000 const struct bpf_reg_state *reg, argno_t argno,
8001 enum bpf_arg_type arg_type)8001 enum bpf_arg_type arg_type,
8002 bool btf_id_fixed_off_ok)
8002{8003{
8003 u32 type = reg->type;8004 u32 type = reg->type;
8004 8005
@@ -8055,12 +8056,11 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env, · 50 unmodified lines
8055 case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:8056 case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU:
8056 /* When referenced PTR_TO_BTF_ID is passed to release function,8057 /* When referenced PTR_TO_BTF_ID is passed to release function,
8057 * its fixed offset must be 0. In the other cases, fixed offset8058 * its fixed offset must be 0. In the other cases, fixed offset
8058 * can be non-zero. This was already checked above. So pass8059 * can be non-zero unless the caller requires otherwise.
8059 * fixed_off_ok as true to allow fixed offset for all other8060 * var_off always must be 0 for PTR_TO_BTF_ID, hence we still
8060 * cases. var_off always must be 0 for PTR_TO_BTF_ID, hence we8061 * need to do checks instead of returning.
8061 * still need to do checks instead of returning.
8062 */8062 */
8063 return __check_ptr_off_reg(env, reg, argno, true);8063 return __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok);
8064 case PTR_TO_CTX:8064 case PTR_TO_CTX:
8065 /*8065 /*
8066 * Allow fixed and variable offsets for syscall context, but8066 * Allow fixed and variable offsets for syscall context, but
@@ -8076,6 +8076,13 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env, · 9 unmodified lines
8076 }8076 }
8077}8077}
8078 8078
8079static int check_func_arg_reg_off(struct bpf_verifier_env *env,
8080 const struct bpf_reg_state *reg, argno_t argno,
8081 enum bpf_arg_type arg_type)
8082{
8083 return __check_func_arg_reg_off(env, reg, argno, arg_type, true);
8084}
8085
8079static int check_arg_const_str(struct bpf_verifier_env *env,8086static int check_arg_const_str(struct bpf_verifier_env *env,
8080 struct bpf_reg_state *reg, argno_t argno)8087 struct bpf_reg_state *reg, argno_t argno)
8081{8088{
@@ -11947,6 +11954,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ · 3865 unmodified lines
11947 enum bpf_arg_type arg_type = ARG_DONTCARE;11954 enum bpf_arg_type arg_type = ARG_DONTCARE;
11948 argno_t argno = argno_from_arg(i + 1);11955 argno_t argno = argno_from_arg(i + 1);
11949 int regno = reg_from_argno(argno);11956 int regno = reg_from_argno(argno);
11957 bool btf_id_fixed_off_ok = true;
11950 u32 ref_id, type_size;11958 u32 ref_id, type_size;
11951 bool is_ret_buf_sz = false;11959 bool is_ret_buf_sz = false;
11952 int kf_arg_type;11960 int kf_arg_type;
@@ -12120,7 +12128,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ · 167 unmodified lines
12120 case KF_ARG_PTR_TO_MEM:12128 case KF_ARG_PTR_TO_MEM:
12121 case KF_ARG_PTR_TO_MEM_SIZE:12129 case KF_ARG_PTR_TO_MEM_SIZE:
12122 case KF_ARG_PTR_TO_CALLBACK:12130 case KF_ARG_PTR_TO_CALLBACK:
12123 case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
12124 case KF_ARG_PTR_TO_CONST_STR:12131 case KF_ARG_PTR_TO_CONST_STR:
12125 case KF_ARG_PTR_TO_WORKQUEUE:12132 case KF_ARG_PTR_TO_WORKQUEUE:
12126 case KF_ARG_PTR_TO_TIMER:12133 case KF_ARG_PTR_TO_TIMER:
@@ -12134,6 +12141,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ · 7 unmodified lines
12134 case KF_ARG_PTR_TO_CTX:12141 case KF_ARG_PTR_TO_CTX:
12135 arg_type = ARG_PTR_TO_CTX;12142 arg_type = ARG_PTR_TO_CTX;
12136 break;12143 break;
12144 case KF_ARG_PTR_TO_REFCOUNTED_KPTR:
12145 arg_type = ARG_PTR_TO_BTF_ID;
12146 btf_id_fixed_off_ok = false;
12147 break;
12137 default:12148 default:
12138 verifier_bug(env, "unknown kfunc arg type %d", kf_arg_type);12149 verifier_bug(env, "unknown kfunc arg type %d", kf_arg_type);
12139 return -EFAULT;12150 return -EFAULT;
@@ -12141,7 +12152,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ · 1 unmodified line
12141 12152
12142 if (regno == meta->release_regno)12153 if (regno == meta->release_regno)
12143 arg_type |= OBJ_RELEASE;12154 arg_type |= OBJ_RELEASE;
12144 ret = check_func_arg_reg_off(env, reg, argno, arg_type);12155 ret = __check_func_arg_reg_off(env, reg, argno, arg_type,
12156 btf_id_fixed_off_ok);
12145 if (ret < 0)12157 if (ret < 0)
12146 return ret;12158 return ret;
12147 12159