summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2020-07-23 09:09:08 +0300
committerDavid S. Miller <davem@davemloft.net>2020-07-25 01:41:54 +0300
commit6d04fe15f78acdf8e32329e208552e226f7a8ae6 (patch)
tree90ff9c419f8244651aa420349756cc371d539646 /include
parenta7b75c5a8c41445f33efb663887ff5f5c3b4454b (diff)
downloadlinux-6d04fe15f78acdf8e32329e208552e226f7a8ae6.tar.xz
net: optimize the sockptr_t for unified kernel/user address spaces
For architectures like x86 and arm64 we don't need the separate bit to indicate that a pointer is a kernel pointer as the address spaces are unified. That way the sockptr_t can be reduced to a union of two pointers, which leads to nicer calling conventions. The only caveat is that we need to check that users don't pass in kernel address and thus gain access to kernel memory. Thus the USER_SOCKPTR helper is replaced with a init_user_sockptr function that does this check and returns an error if it fails. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r--include/linux/sockptr.h32
1 files changed, 30 insertions, 2 deletions
diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h
index 700856e13ea0..7d5cdb2b30b5 100644
--- a/include/linux/sockptr.h
+++ b/include/linux/sockptr.h
@@ -8,9 +8,34 @@
#ifndef _LINUX_SOCKPTR_H
#define _LINUX_SOCKPTR_H
+#include <linux/compiler.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
+typedef union {
+ void *kernel;
+ void __user *user;
+} sockptr_t;
+
+static inline bool sockptr_is_kernel(sockptr_t sockptr)
+{
+ return (unsigned long)sockptr.kernel >= TASK_SIZE;
+}
+
+static inline sockptr_t KERNEL_SOCKPTR(void *p)
+{
+ return (sockptr_t) { .kernel = p };
+}
+
+static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
+{
+ if ((unsigned long)p >= TASK_SIZE)
+ return -EFAULT;
+ sp->user = p;
+ return 0;
+}
+#else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
typedef struct {
union {
void *kernel;
@@ -29,10 +54,13 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
return (sockptr_t) { .kernel = p, .is_kernel = true };
}
-static inline sockptr_t USER_SOCKPTR(void __user *p)
+static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
{
- return (sockptr_t) { .user = p };
+ sp->user = p;
+ sp->is_kernel = false;
+ return 0;
}
+#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
static inline bool sockptr_is_null(sockptr_t sockptr)
{