0001
0002
0003
0004
0005
0006
0007
0008 #ifndef _LINUX_SOCKPTR_H
0009 #define _LINUX_SOCKPTR_H
0010
0011 #include <linux/slab.h>
0012 #include <linux/uaccess.h>
0013
0014 typedef struct {
0015 union {
0016 void *kernel;
0017 void __user *user;
0018 };
0019 bool is_kernel : 1;
0020 } sockptr_t;
0021
0022 static inline bool sockptr_is_kernel(sockptr_t sockptr)
0023 {
0024 return sockptr.is_kernel;
0025 }
0026
0027 static inline sockptr_t KERNEL_SOCKPTR(void *p)
0028 {
0029 return (sockptr_t) { .kernel = p, .is_kernel = true };
0030 }
0031
0032 static inline sockptr_t USER_SOCKPTR(void __user *p)
0033 {
0034 return (sockptr_t) { .user = p };
0035 }
0036
0037 static inline bool sockptr_is_null(sockptr_t sockptr)
0038 {
0039 if (sockptr_is_kernel(sockptr))
0040 return !sockptr.kernel;
0041 return !sockptr.user;
0042 }
0043
0044 static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
0045 size_t offset, size_t size)
0046 {
0047 if (!sockptr_is_kernel(src))
0048 return copy_from_user(dst, src.user + offset, size);
0049 memcpy(dst, src.kernel + offset, size);
0050 return 0;
0051 }
0052
0053 static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
0054 {
0055 return copy_from_sockptr_offset(dst, src, 0, size);
0056 }
0057
0058 static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
0059 const void *src, size_t size)
0060 {
0061 if (!sockptr_is_kernel(dst))
0062 return copy_to_user(dst.user + offset, src, size);
0063 memcpy(dst.kernel + offset, src, size);
0064 return 0;
0065 }
0066
0067 static inline void *memdup_sockptr(sockptr_t src, size_t len)
0068 {
0069 void *p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
0070
0071 if (!p)
0072 return ERR_PTR(-ENOMEM);
0073 if (copy_from_sockptr(p, src, len)) {
0074 kfree(p);
0075 return ERR_PTR(-EFAULT);
0076 }
0077 return p;
0078 }
0079
0080 static inline void *memdup_sockptr_nul(sockptr_t src, size_t len)
0081 {
0082 char *p = kmalloc_track_caller(len + 1, GFP_KERNEL);
0083
0084 if (!p)
0085 return ERR_PTR(-ENOMEM);
0086 if (copy_from_sockptr(p, src, len)) {
0087 kfree(p);
0088 return ERR_PTR(-EFAULT);
0089 }
0090 p[len] = '\0';
0091 return p;
0092 }
0093
0094 static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
0095 {
0096 if (sockptr_is_kernel(src)) {
0097 size_t len = min(strnlen(src.kernel, count - 1) + 1, count);
0098
0099 memcpy(dst, src.kernel, len);
0100 return len;
0101 }
0102 return strncpy_from_user(dst, src.user, count);
0103 }
0104
0105 static inline int check_zeroed_sockptr(sockptr_t src, size_t offset,
0106 size_t size)
0107 {
0108 if (!sockptr_is_kernel(src))
0109 return check_zeroed_user(src.user + offset, size);
0110 return memchr_inv(src.kernel + offset, 0, size) == NULL;
0111 }
0112
0113 #endif