90 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/* A pointer that can point to either kernel or userspace memory. */3#ifndef _LINUX_BPFPTR_H4#define _LINUX_BPFPTR_H5 6#include <linux/mm.h>7#include <linux/sockptr.h>8 9typedef sockptr_t bpfptr_t;10 11static inline bool bpfptr_is_kernel(bpfptr_t bpfptr)12{13 return bpfptr.is_kernel;14}15 16static inline bpfptr_t KERNEL_BPFPTR(void *p)17{18 return (bpfptr_t) { .kernel = p, .is_kernel = true };19}20 21static inline bpfptr_t USER_BPFPTR(void __user *p)22{23 return (bpfptr_t) { .user = p };24}25 26static inline bpfptr_t make_bpfptr(u64 addr, bool is_kernel)27{28 if (is_kernel)29 return KERNEL_BPFPTR((void*) (uintptr_t) addr);30 else31 return USER_BPFPTR(u64_to_user_ptr(addr));32}33 34static inline bool bpfptr_is_null(bpfptr_t bpfptr)35{36 if (bpfptr_is_kernel(bpfptr))37 return !bpfptr.kernel;38 return !bpfptr.user;39}40 41static inline void bpfptr_add(bpfptr_t *bpfptr, size_t val)42{43 if (bpfptr_is_kernel(*bpfptr))44 bpfptr->kernel += val;45 else46 bpfptr->user += val;47}48 49static inline int copy_from_bpfptr_offset(void *dst, bpfptr_t src,50 size_t offset, size_t size)51{52 if (!bpfptr_is_kernel(src))53 return copy_from_user(dst, src.user + offset, size);54 return copy_from_kernel_nofault(dst, src.kernel + offset, size);55}56 57static inline int copy_from_bpfptr(void *dst, bpfptr_t src, size_t size)58{59 return copy_from_bpfptr_offset(dst, src, 0, size);60}61 62static inline int copy_to_bpfptr_offset(bpfptr_t dst, size_t offset,63 const void *src, size_t size)64{65 return copy_to_sockptr_offset((sockptr_t) dst, offset, src, size);66}67 68static inline void *kvmemdup_bpfptr_noprof(bpfptr_t src, size_t len)69{70 void *p = kvmalloc_noprof(len, GFP_USER | __GFP_NOWARN);71 72 if (!p)73 return ERR_PTR(-ENOMEM);74 if (copy_from_bpfptr(p, src, len)) {75 kvfree(p);76 return ERR_PTR(-EFAULT);77 }78 return p;79}80#define kvmemdup_bpfptr(...) alloc_hooks(kvmemdup_bpfptr_noprof(__VA_ARGS__))81 82static inline long strncpy_from_bpfptr(char *dst, bpfptr_t src, size_t count)83{84 if (bpfptr_is_kernel(src))85 return strncpy_from_kernel_nofault(dst, src.kernel, count);86 return strncpy_from_user(dst, src.user, count);87}88 89#endif /* _LINUX_BPFPTR_H */90