xref: /kernel/linux/linux-6.6/include/linux/bpfptr.h (revision 62306a36)
162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/* A pointer that can point to either kernel or userspace memory. */
362306a36Sopenharmony_ci#ifndef _LINUX_BPFPTR_H
462306a36Sopenharmony_ci#define _LINUX_BPFPTR_H
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/mm.h>
762306a36Sopenharmony_ci#include <linux/sockptr.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_citypedef sockptr_t bpfptr_t;
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic inline bool bpfptr_is_kernel(bpfptr_t bpfptr)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	return bpfptr.is_kernel;
1462306a36Sopenharmony_ci}
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic inline bpfptr_t KERNEL_BPFPTR(void *p)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	return (bpfptr_t) { .kernel = p, .is_kernel = true };
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic inline bpfptr_t USER_BPFPTR(void __user *p)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	return (bpfptr_t) { .user = p };
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic inline bpfptr_t make_bpfptr(u64 addr, bool is_kernel)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	if (is_kernel)
2962306a36Sopenharmony_ci		return KERNEL_BPFPTR((void*) (uintptr_t) addr);
3062306a36Sopenharmony_ci	else
3162306a36Sopenharmony_ci		return USER_BPFPTR(u64_to_user_ptr(addr));
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline bool bpfptr_is_null(bpfptr_t bpfptr)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	if (bpfptr_is_kernel(bpfptr))
3762306a36Sopenharmony_ci		return !bpfptr.kernel;
3862306a36Sopenharmony_ci	return !bpfptr.user;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic inline void bpfptr_add(bpfptr_t *bpfptr, size_t val)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	if (bpfptr_is_kernel(*bpfptr))
4462306a36Sopenharmony_ci		bpfptr->kernel += val;
4562306a36Sopenharmony_ci	else
4662306a36Sopenharmony_ci		bpfptr->user += val;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline int copy_from_bpfptr_offset(void *dst, bpfptr_t src,
5062306a36Sopenharmony_ci					  size_t offset, size_t size)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	if (!bpfptr_is_kernel(src))
5362306a36Sopenharmony_ci		return copy_from_user(dst, src.user + offset, size);
5462306a36Sopenharmony_ci	return copy_from_kernel_nofault(dst, src.kernel + offset, size);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic inline int copy_from_bpfptr(void *dst, bpfptr_t src, size_t size)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return copy_from_bpfptr_offset(dst, src, 0, size);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic inline int copy_to_bpfptr_offset(bpfptr_t dst, size_t offset,
6362306a36Sopenharmony_ci					const void *src, size_t size)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	return copy_to_sockptr_offset((sockptr_t) dst, offset, src, size);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic inline void *kvmemdup_bpfptr(bpfptr_t src, size_t len)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	void *p = kvmalloc(len, GFP_USER | __GFP_NOWARN);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (!p)
7362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
7462306a36Sopenharmony_ci	if (copy_from_bpfptr(p, src, len)) {
7562306a36Sopenharmony_ci		kvfree(p);
7662306a36Sopenharmony_ci		return ERR_PTR(-EFAULT);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	return p;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic inline long strncpy_from_bpfptr(char *dst, bpfptr_t src, size_t count)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	if (bpfptr_is_kernel(src))
8462306a36Sopenharmony_ci		return strncpy_from_kernel_nofault(dst, src.kernel, count);
8562306a36Sopenharmony_ci	return strncpy_from_user(dst, src.user, count);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#endif /* _LINUX_BPFPTR_H */
89