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 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 else 31 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 else 46 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(bpfptr_t src, size_t len) 69{ 70 void *p = kvmalloc(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 81static inline long strncpy_from_bpfptr(char *dst, bpfptr_t src, size_t count) 82{ 83 if (bpfptr_is_kernel(src)) 84 return strncpy_from_kernel_nofault(dst, src.kernel, count); 85 return strncpy_from_user(dst, src.user, count); 86} 87 88#endif /* _LINUX_BPFPTR_H */ 89