~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/include/linux/sockptr.h

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0-only */
  2 /*
  3  * Copyright (c) 2020 Christoph Hellwig.
  4  *
  5  * Support for "universal" pointers that can point to either kernel or userspace
  6  * memory.
  7  */
  8 #ifndef _LINUX_SOCKPTR_H
  9 #define _LINUX_SOCKPTR_H
 10 
 11 #include <linux/slab.h>
 12 #include <linux/uaccess.h>
 13 
 14 typedef struct {
 15         union {
 16                 void            *kernel;
 17                 void __user     *user;
 18         };
 19         bool            is_kernel : 1;
 20 } sockptr_t;
 21 
 22 static inline bool sockptr_is_kernel(sockptr_t sockptr)
 23 {
 24         return sockptr.is_kernel;
 25 }
 26 
 27 static inline sockptr_t KERNEL_SOCKPTR(void *p)
 28 {
 29         return (sockptr_t) { .kernel = p, .is_kernel = true };
 30 }
 31 
 32 static inline sockptr_t USER_SOCKPTR(void __user *p)
 33 {
 34         return (sockptr_t) { .user = p };
 35 }
 36 
 37 static inline bool sockptr_is_null(sockptr_t sockptr)
 38 {
 39         if (sockptr_is_kernel(sockptr))
 40                 return !sockptr.kernel;
 41         return !sockptr.user;
 42 }
 43 
 44 static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
 45                 size_t offset, size_t size)
 46 {
 47         if (!sockptr_is_kernel(src))
 48                 return copy_from_user(dst, src.user + offset, size);
 49         memcpy(dst, src.kernel + offset, size);
 50         return 0;
 51 }
 52 
 53 /* Deprecated.
 54  * This is unsafe, unless caller checked user provided optlen.
 55  * Prefer copy_safe_from_sockptr() instead.
 56  */
 57 static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
 58 {
 59         return copy_from_sockptr_offset(dst, src, 0, size);
 60 }
 61 
 62 /**
 63  * copy_safe_from_sockptr: copy a struct from sockptr
 64  * @dst:   Destination address, in kernel space. This buffer must be @ksize
 65  *         bytes long.
 66  * @ksize: Size of @dst struct.
 67  * @optval: Source address. (in user or kernel space)
 68  * @optlen: Size of @optval data.
 69  *
 70  * Returns:
 71  *  * -EINVAL: @optlen < @ksize
 72  *  * -EFAULT: access to userspace failed.
 73  *  * 0 : @ksize bytes were copied
 74  */
 75 static inline int copy_safe_from_sockptr(void *dst, size_t ksize,
 76                                          sockptr_t optval, unsigned int optlen)
 77 {
 78         if (optlen < ksize)
 79                 return -EINVAL;
 80         return copy_from_sockptr(dst, optval, ksize);
 81 }
 82 
 83 static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
 84                 sockptr_t src, size_t usize)
 85 {
 86         size_t size = min(ksize, usize);
 87         size_t rest = max(ksize, usize) - size;
 88 
 89         if (!sockptr_is_kernel(src))
 90                 return copy_struct_from_user(dst, ksize, src.user, size);
 91 
 92         if (usize < ksize) {
 93                 memset(dst + size, 0, rest);
 94         } else if (usize > ksize) {
 95                 char *p = src.kernel;
 96 
 97                 while (rest--) {
 98                         if (*p++)
 99                                 return -E2BIG;
100                 }
101         }
102         memcpy(dst, src.kernel, size);
103         return 0;
104 }
105 
106 static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
107                 const void *src, size_t size)
108 {
109         if (!sockptr_is_kernel(dst))
110                 return copy_to_user(dst.user + offset, src, size);
111         memcpy(dst.kernel + offset, src, size);
112         return 0;
113 }
114 
115 static inline int copy_to_sockptr(sockptr_t dst, const void *src, size_t size)
116 {
117         return copy_to_sockptr_offset(dst, 0, src, size);
118 }
119 
120 static inline void *memdup_sockptr_noprof(sockptr_t src, size_t len)
121 {
122         void *p = kmalloc_track_caller_noprof(len, GFP_USER | __GFP_NOWARN);
123 
124         if (!p)
125                 return ERR_PTR(-ENOMEM);
126         if (copy_from_sockptr(p, src, len)) {
127                 kfree(p);
128                 return ERR_PTR(-EFAULT);
129         }
130         return p;
131 }
132 #define memdup_sockptr(...)     alloc_hooks(memdup_sockptr_noprof(__VA_ARGS__))
133 
134 static inline void *memdup_sockptr_nul_noprof(sockptr_t src, size_t len)
135 {
136         char *p = kmalloc_track_caller_noprof(len + 1, GFP_KERNEL);
137 
138         if (!p)
139                 return ERR_PTR(-ENOMEM);
140         if (copy_from_sockptr(p, src, len)) {
141                 kfree(p);
142                 return ERR_PTR(-EFAULT);
143         }
144         p[len] = '\0';
145         return p;
146 }
147 #define memdup_sockptr_nul(...) alloc_hooks(memdup_sockptr_nul_noprof(__VA_ARGS__))
148 
149 static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
150 {
151         if (sockptr_is_kernel(src)) {
152                 size_t len = min(strnlen(src.kernel, count - 1) + 1, count);
153 
154                 memcpy(dst, src.kernel, len);
155                 return len;
156         }
157         return strncpy_from_user(dst, src.user, count);
158 }
159 
160 static inline int check_zeroed_sockptr(sockptr_t src, size_t offset,
161                                        size_t size)
162 {
163         if (!sockptr_is_kernel(src))
164                 return check_zeroed_user(src.user + offset, size);
165         return memchr_inv(src.kernel + offset, 0, size) == NULL;
166 }
167 
168 #endif /* _LINUX_SOCKPTR_H */
169 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php