1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* A pointer that can point to either kernel or userspace memory. */ 3 #ifndef _LINUX_BPFPTR_H 4 #define _LINUX_BPFPTR_H 5 6 #include <linux/mm.h> 7 #include <linux/sockptr.h> 8 9 typedef sockptr_t bpfptr_t; 10 11 static inline bool bpfptr_is_kernel(bpfptr_t bpfptr) 12 { 13 return bpfptr.is_kernel; 14 } 15 16 static inline bpfptr_t KERNEL_BPFPTR(void *p) 17 { 18 return (bpfptr_t) { .kernel = p, .is_kernel = true }; 19 } 20 21 static inline bpfptr_t USER_BPFPTR(void __user *p) 22 { 23 return (bpfptr_t) { .user = p }; 24 } 25 26 static inline bpfptr_t make_bpfptr(u64 addr, bool is_kernel) 27 { 28 if (is_kernel) 29 return KERNEL_BPFPTR((void*) (uintptr_t) addr); 30 else 31 return USER_BPFPTR(u64_to_user_ptr(addr)); 32 } 33 34 static 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 41 static inline void bpfptr_add(bpfptr_t *bpfptr, size_t val) 42 { 43 if (bpfptr_is_kernel(*bpfptr)) 44 bpfptr->kernel += val; 45 else 46 bpfptr->user += val; 47 } 48 49 static 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 57 static 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 62 static 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 68 static 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 82 static 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