diff options
Diffstat (limited to 'kernel/bpf/helpers.c')
| -rw-r--r-- | kernel/bpf/helpers.c | 135 | 
1 files changed, 113 insertions, 22 deletions
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 8d368fa353f9..9e80efa59a5d 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1423,7 +1423,7 @@ static const struct bpf_func_proto bpf_kptr_xchg_proto = {  #define DYNPTR_SIZE_MASK	0xFFFFFF  #define DYNPTR_RDONLY_BIT	BIT(31) -static bool bpf_dynptr_is_rdonly(const struct bpf_dynptr_kern *ptr) +static bool __bpf_dynptr_is_rdonly(const struct bpf_dynptr_kern *ptr)  {  	return ptr->size & DYNPTR_RDONLY_BIT;  } @@ -1443,11 +1443,18 @@ static enum bpf_dynptr_type bpf_dynptr_get_type(const struct bpf_dynptr_kern *pt  	return (ptr->size & ~(DYNPTR_RDONLY_BIT)) >> DYNPTR_TYPE_SHIFT;  } -u32 bpf_dynptr_get_size(const struct bpf_dynptr_kern *ptr) +u32 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr)  {  	return ptr->size & DYNPTR_SIZE_MASK;  } +static void bpf_dynptr_set_size(struct bpf_dynptr_kern *ptr, u32 new_size) +{ +	u32 metadata = ptr->size & ~DYNPTR_SIZE_MASK; + +	ptr->size = new_size | metadata; +} +  int bpf_dynptr_check_size(u32 size)  {  	return size > DYNPTR_MAX_SIZE ? -E2BIG : 0; @@ -1469,7 +1476,7 @@ void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr)  static int bpf_dynptr_check_off_len(const struct bpf_dynptr_kern *ptr, u32 offset, u32 len)  { -	u32 size = bpf_dynptr_get_size(ptr); +	u32 size = __bpf_dynptr_size(ptr);  	if (len > size || offset > size - len)  		return -E2BIG; @@ -1563,7 +1570,7 @@ BPF_CALL_5(bpf_dynptr_write, const struct bpf_dynptr_kern *, dst, u32, offset, v  	enum bpf_dynptr_type type;  	int err; -	if (!dst->data || bpf_dynptr_is_rdonly(dst)) +	if (!dst->data || __bpf_dynptr_is_rdonly(dst))  		return -EINVAL;  	err = bpf_dynptr_check_off_len(dst, offset, len); @@ -1619,7 +1626,7 @@ BPF_CALL_3(bpf_dynptr_data, const struct bpf_dynptr_kern *, ptr, u32, offset, u3  	if (err)  		return 0; -	if (bpf_dynptr_is_rdonly(ptr)) +	if (__bpf_dynptr_is_rdonly(ptr))  		return 0;  	type = bpf_dynptr_get_type(ptr); @@ -1926,8 +1933,12 @@ __bpf_kfunc void *bpf_refcount_acquire_impl(void *p__refcounted_kptr, void *meta  	 * bpf_refcount type so that it is emitted in vmlinux BTF  	 */  	ref = (struct bpf_refcount *)(p__refcounted_kptr + meta->record->refcount_off); +	if (!refcount_inc_not_zero((refcount_t *)ref)) +		return NULL; -	refcount_inc((refcount_t *)ref); +	/* Verifier strips KF_RET_NULL if input is owned ref, see is_kfunc_ret_null +	 * in verifier.c +	 */  	return (void *)p__refcounted_kptr;  } @@ -1943,7 +1954,7 @@ static int __bpf_list_add(struct bpf_list_node *node, struct bpf_list_head *head  		INIT_LIST_HEAD(h);  	if (!list_empty(n)) {  		/* Only called from BPF prog, no need to migrate_disable */ -		__bpf_obj_drop_impl(n - off, rec); +		__bpf_obj_drop_impl((void *)n - off, rec);  		return -EINVAL;  	} @@ -2025,7 +2036,7 @@ static int __bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node,  	if (!RB_EMPTY_NODE(n)) {  		/* Only called from BPF prog, no need to migrate_disable */ -		__bpf_obj_drop_impl(n - off, rec); +		__bpf_obj_drop_impl((void *)n - off, rec);  		return -EINVAL;  	} @@ -2142,6 +2153,22 @@ __bpf_kfunc struct cgroup *bpf_cgroup_from_id(u64 cgid)  		return NULL;  	return cgrp;  } + +/** + * bpf_task_under_cgroup - wrap task_under_cgroup_hierarchy() as a kfunc, test + * task's membership of cgroup ancestry. + * @task: the task to be tested + * @ancestor: possible ancestor of @task's cgroup + * + * Tests whether @task's default cgroup hierarchy is a descendant of @ancestor. + * It follows all the same rules as cgroup_is_descendant, and only applies + * to the default hierarchy. + */ +__bpf_kfunc long bpf_task_under_cgroup(struct task_struct *task, +				       struct cgroup *ancestor) +{ +	return task_under_cgroup_hierarchy(task, ancestor); +}  #endif /* CONFIG_CGROUPS */  /** @@ -2167,13 +2194,15 @@ __bpf_kfunc struct task_struct *bpf_task_from_pid(s32 pid)   * bpf_dynptr_slice() - Obtain a read-only pointer to the dynptr data.   * @ptr: The dynptr whose data slice to retrieve   * @offset: Offset into the dynptr - * @buffer: User-provided buffer to copy contents into - * @buffer__szk: Size (in bytes) of the buffer. This is the length of the - *		 requested slice. This must be a constant. + * @buffer__opt: User-provided buffer to copy contents into.  May be NULL + * @buffer__szk: Size (in bytes) of the buffer if present. This is the + *               length of the requested slice. This must be a constant.   *   * For non-skb and non-xdp type dynptrs, there is no difference between   * bpf_dynptr_slice and bpf_dynptr_data.   * + *  If buffer__opt is NULL, the call will fail if buffer_opt was needed. + *   * If the intention is to write to the data slice, please use   * bpf_dynptr_slice_rdwr.   * @@ -2190,7 +2219,7 @@ __bpf_kfunc struct task_struct *bpf_task_from_pid(s32 pid)   * direct pointer)   */  __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset, -				   void *buffer, u32 buffer__szk) +				   void *buffer__opt, u32 buffer__szk)  {  	enum bpf_dynptr_type type;  	u32 len = buffer__szk; @@ -2210,15 +2239,17 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset  	case BPF_DYNPTR_TYPE_RINGBUF:  		return ptr->data + ptr->offset + offset;  	case BPF_DYNPTR_TYPE_SKB: -		return skb_header_pointer(ptr->data, ptr->offset + offset, len, buffer); +		return skb_header_pointer(ptr->data, ptr->offset + offset, len, buffer__opt);  	case BPF_DYNPTR_TYPE_XDP:  	{  		void *xdp_ptr = bpf_xdp_pointer(ptr->data, ptr->offset + offset, len);  		if (xdp_ptr)  			return xdp_ptr; -		bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer, len, false); -		return buffer; +		if (!buffer__opt) +			return NULL; +		bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer__opt, len, false); +		return buffer__opt;  	}  	default:  		WARN_ONCE(true, "unknown dynptr type %d\n", type); @@ -2230,13 +2261,15 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset   * bpf_dynptr_slice_rdwr() - Obtain a writable pointer to the dynptr data.   * @ptr: The dynptr whose data slice to retrieve   * @offset: Offset into the dynptr - * @buffer: User-provided buffer to copy contents into - * @buffer__szk: Size (in bytes) of the buffer. This is the length of the - *		 requested slice. This must be a constant. + * @buffer__opt: User-provided buffer to copy contents into. May be NULL + * @buffer__szk: Size (in bytes) of the buffer if present. This is the + *               length of the requested slice. This must be a constant.   *   * For non-skb and non-xdp type dynptrs, there is no difference between   * bpf_dynptr_slice and bpf_dynptr_data.   * + * If buffer__opt is NULL, the call will fail if buffer_opt was needed. + *   * The returned pointer is writable and may point to either directly the dynptr   * data at the requested offset or to the buffer if unable to obtain a direct   * data pointer to (example: the requested slice is to the paged area of an skb @@ -2267,9 +2300,9 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset   * direct pointer)   */  __bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 offset, -					void *buffer, u32 buffer__szk) +					void *buffer__opt, u32 buffer__szk)  { -	if (!ptr->data || bpf_dynptr_is_rdonly(ptr)) +	if (!ptr->data || __bpf_dynptr_is_rdonly(ptr))  		return NULL;  	/* bpf_dynptr_slice_rdwr is the same logic as bpf_dynptr_slice. @@ -2294,7 +2327,59 @@ __bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 o  	 * will be copied out into the buffer and the user will need to call  	 * bpf_dynptr_write() to commit changes.  	 */ -	return bpf_dynptr_slice(ptr, offset, buffer, buffer__szk); +	return bpf_dynptr_slice(ptr, offset, buffer__opt, buffer__szk); +} + +__bpf_kfunc int bpf_dynptr_adjust(struct bpf_dynptr_kern *ptr, u32 start, u32 end) +{ +	u32 size; + +	if (!ptr->data || start > end) +		return -EINVAL; + +	size = __bpf_dynptr_size(ptr); + +	if (start > size || end > size) +		return -ERANGE; + +	ptr->offset += start; +	bpf_dynptr_set_size(ptr, end - start); + +	return 0; +} + +__bpf_kfunc bool bpf_dynptr_is_null(struct bpf_dynptr_kern *ptr) +{ +	return !ptr->data; +} + +__bpf_kfunc bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) +{ +	if (!ptr->data) +		return false; + +	return __bpf_dynptr_is_rdonly(ptr); +} + +__bpf_kfunc __u32 bpf_dynptr_size(const struct bpf_dynptr_kern *ptr) +{ +	if (!ptr->data) +		return -EINVAL; + +	return __bpf_dynptr_size(ptr); +} + +__bpf_kfunc int bpf_dynptr_clone(struct bpf_dynptr_kern *ptr, +				 struct bpf_dynptr_kern *clone__uninit) +{ +	if (!ptr->data) { +		bpf_dynptr_set_null(clone__uninit); +		return -EINVAL; +	} + +	*clone__uninit = *ptr; + +	return 0;  }  __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) @@ -2325,7 +2410,7 @@ BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE)  #endif  BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL)  BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE) +BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL)  BTF_ID_FLAGS(func, bpf_list_push_front_impl)  BTF_ID_FLAGS(func, bpf_list_push_back_impl)  BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) @@ -2341,6 +2426,7 @@ BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)  BTF_ID_FLAGS(func, bpf_cgroup_release, KF_RELEASE)  BTF_ID_FLAGS(func, bpf_cgroup_ancestor, KF_ACQUIRE | KF_RCU | KF_RET_NULL)  BTF_ID_FLAGS(func, bpf_cgroup_from_id, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_task_under_cgroup, KF_RCU)  #endif  BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL)  BTF_SET8_END(generic_btf_ids) @@ -2369,6 +2455,11 @@ BTF_ID_FLAGS(func, bpf_dynptr_slice_rdwr, KF_RET_NULL)  BTF_ID_FLAGS(func, bpf_iter_num_new, KF_ITER_NEW)  BTF_ID_FLAGS(func, bpf_iter_num_next, KF_ITER_NEXT | KF_RET_NULL)  BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY) +BTF_ID_FLAGS(func, bpf_dynptr_adjust) +BTF_ID_FLAGS(func, bpf_dynptr_is_null) +BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly) +BTF_ID_FLAGS(func, bpf_dynptr_size) +BTF_ID_FLAGS(func, bpf_dynptr_clone)  BTF_SET8_END(common_btf_ids)  static const struct btf_kfunc_id_set common_kfunc_set = {  |