Thread (9 messages) 9 messages, 4 authors, 21h ago

Re: [PATCH v2] net: add sock_open() with flags for socket creation

From: Alex Goltsev <hidden>
Date: 2026-06-21 11:05:52
Also in: lkml
Subsystem: networking [general], networking [sockets], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Kuniyuki Iwashima, Willem de Bruijn, Linus Torvalds

From a9316957e594708dfb4258ad968fe88666c9b736 Mon Sep 17 00:00:00 2001
From: 0-x-0-0 <redacted>
Date: Sun, 21 Jun 2026 13:24:29 +0300
Subject: [PATCH v2] net: add sock_open() with flags for socket creation

---
Changes in V2:
- Replaced the use of plain integer constants for flags with proper
enums to improve readability and type safety.
- `sock_open` is intentionally left as a regular exported symbol rather
than being moved to a header as `static inline`. This is because it
dereferences `current->nsproxy->net_ns`, which would require pulling
in heavy headers like <linux/sched.h> and <linux/nsproxy.h> into the
already widely-used <linux/net.h>, causing unnecessary header bloat
and potential circular dependencies.
- Introduced two new creation flags for specialized use cases within
kernel modules:

* SOCK_CREATE_NOLSM: This flag allows a kernel module to bypass
LSM hooks during socket creation. This
enables a micro-optimization for kernel-internal sockets where
the security check is known *a priori* to be a no-op (e.g., for
specific configurations or high-performance paths).
This is safe because the API is restricted to in-kernel (LKM)
contexts only, and does not weaken the security boundary for
user-triggered socket creation.

* SOCK_CREATE_NOWARN: This flag suppresses the standard warning
messages on creation failure. This is useful for callers in the
kernel that probe for protocol support and handle the error
gracefully, without wanting to pollute the kernel log with
misleading warnings.

Signed-off-by: Alexander Goltsev <redacted>
---
include/linux/net.h | 22 ++++++++
net/socket.c | 133 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 134 insertions(+), 21 deletions(-)
diff --git a/include/linux/net.h b/include/linux/net.h
index f268f395c..6367c00db 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -116,6 +116,22 @@ enum sock_shutdown_cmd {
SHUT_RDWR,
};
+/**
+ * enum sock_create_flags - socket creation flags
+ * @SOCK_CREATE_KERN: creates a kernel socket
+ * @SOCK_CREATE_USER: creates a regular socket
+ * @SOCK_CREATE_LITE: creates a lite socket
+ * @SOCK_CREATE_NOLSM: disables LSM
+ * @SOCK_CREATE_NOWARN: disables warning
+ */
+enum sock_create_flags {
+ SOCK_CREATE_KERN = BIT(0),
+ SOCK_CREATE_USER = BIT(1),
+ SOCK_CREATE_LITE = BIT(2),
+ SOCK_CREATE_NOLSM = BIT(3),
+ SOCK_CREATE_NOWARN = BIT(4),
+};
+
struct socket_wq {
/* Note: wait MUST be first field of socket_wq */
wait_queue_head_t wait;
@@ -275,6 +291,12 @@ void sock_unregister(int family);
bool sock_is_registered(int family);
int __sock_create(struct net *net, int family, int type, int proto,
struct socket **res, int kern);
+int __sock_create_flags(struct net *net, int family, int type, int protocol,
+ struct socket **res, int kern, int flags);
+int __sock_create_lite_flags(int family, int type, int protocol,
+ struct socket **res, int flags);
+int sock_open(struct net *net, int family,
+ int type, int protocol, struct socket **res, int flags);
int sock_create(int family, int type, int proto, struct socket **res);
int sock_create_kern(struct net *net, int family, int type, int proto,
struct socket **res);
int sock_create_lite(int family, int type, int proto, struct socket **res);
diff --git a/net/socket.c b/net/socket.c
index 63c69a0fa..2359fd5bf 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1425,26 +1425,28 @@ static long sock_ioctl(struct file *file,
unsigned cmd, unsigned long arg)
}
/**
- * sock_create_lite - creates a socket
+ * __sock_create_lite_flags - creates a socket (with flags)
* @family: protocol family (AF_INET, ...)
* @type: communication type (SOCK_STREAM, ...)
* @protocol: protocol (0, ...)
* @res: new socket
+ * @flags: defines socket creation flags
*
* Creates a new socket and assigns it to @res, passing through LSM.
* The new socket initialization is not complete, see kernel_accept().
* Returns 0 or an error. On failure @res is set to %NULL.
* This function internally uses GFP_KERNEL.
*/
-
-int sock_create_lite(int family, int type, int protocol, struct socket **res)
+int __sock_create_lite_flags(int family, int type, int protocol,
struct socket **res, int flags)
{
int err;
struct socket *sock = NULL;
- err = security_socket_create(family, type, protocol, 1);
- if (err)
- goto out;
+ if (!(flags & SOCK_CREATE_NOLSM)) {
+ err = security_socket_create(family, type, protocol, 1);
+ if (err)
+ goto out;
+ }
sock = sock_alloc();
if (!sock) {
@@ -1453,9 +1455,11 @@ int sock_create_lite(int family, int type, int
protocol, struct socket **res)
}
sock->type = type;
- err = security_socket_post_create(sock, family, type, protocol, 1);
- if (err)
- goto out_release;
+ if (!(flags & SOCK_CREATE_NOLSM)) {
+ err = security_socket_post_create(sock, family, type, protocol, 1);
+ if (err)
+ goto out_release;
+ }
out:
*res = sock;
@@ -1465,6 +1469,25 @@ int sock_create_lite(int family, int type, int
protocol, struct socket **res)
sock = NULL;
goto out;
}
+EXPORT_SYMBOL(__sock_create_lite_flags);
+
+/**
+ * sock_create_lite - creates a socket
+ * @family: protocol family (AF_INET, ...)
+ * @type: communication type (SOCK_STREAM, ...)
+ * @protocol: protocol (0, ...)
+ * @res: new socket
+ *
+ * Creates a new socket and assigns it to @res, passing through LSM.
+ * The new socket initialization is not complete, see kernel_accept().
+ * Returns 0 or an error. On failure @res is set to %NULL.
+ * This function internally uses GFP_KERNEL.
+ */
+
+int sock_create_lite(int family, int type, int protocol, struct socket **res)
+{
+ return __sock_create_lite_flags(family, type, protocol, res, 0);
+}
EXPORT_SYMBOL(sock_create_lite);
/* No kernel lock held - perfect */
@@ -1563,22 +1586,23 @@ int sock_wake_async(struct socket_wq *wq, int
how, int band)
EXPORT_SYMBOL(sock_wake_async);
/**
- * __sock_create - creates a socket
+ * __sock_create_flags - creates a socket (with flags)
* @net: net namespace
* @family: protocol family (AF_INET, ...)
* @type: communication type (SOCK_STREAM, ...)
* @protocol: protocol (0, ...)
* @res: new socket
* @kern: boolean for kernel space sockets
+ * @flags: defines socket creation flags
*
* Creates a new socket and assigns it to @res, passing through LSM.
* Returns 0 or an error. On failure @res is set to %NULL. @kern must
* be set to true if the socket resides in kernel space.
* This function internally uses GFP_KERNEL.
*/
-
-int __sock_create(struct net *net, int family, int type, int protocol,
- struct socket **res, int kern)
+int __sock_create_flags(struct net *net, int family,
+ int type, int protocol, struct socket **res,
+ int kern, int flags)
{
int err;
struct socket *sock;
@@ -1598,14 +1622,18 @@ int __sock_create(struct net *net, int family,
int type, int protocol,
deadlock in module load.
*/
if (family == PF_INET && type == SOCK_PACKET) {
- pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
+ if (!(flags & SOCK_CREATE_NOWARN)) {
+ pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
current->comm);
+ }
family = PF_PACKET;
}
- err = security_socket_create(family, type, protocol, kern);
- if (err)
- return err;
+ if (!(flags & SOCK_CREATE_NOLSM)) {
+ err = security_socket_create(family, type, protocol, kern);
+ if (err)
+ return err;
+ }
/*
* Allocate the socket and allow the family to set things up. if
@@ -1614,7 +1642,8 @@ int __sock_create(struct net *net, int family,
int type, int protocol,
*/
sock = sock_alloc();
if (!sock) {
- net_warn_ratelimited("socket: no more sockets\n");
+ if (!(flags & SOCK_CREATE_NOWARN))
+ net_warn_ratelimited("socket: no more sockets\n");
return -ENFILE; /* Not exactly a match, but its the
closest posix thing */
}
@@ -1671,9 +1700,12 @@ int __sock_create(struct net *net, int family,
int type, int protocol,
* module can have its refcnt decremented
*/
module_put(pf->owner);
- err = security_socket_post_create(sock, family, type, protocol, kern);
- if (err)
- goto out_sock_release;
+
+ if (!(flags & SOCK_CREATE_NOLSM)) {
+ err = security_socket_post_create(sock, family, type, protocol, kern);
+ if (err)
+ goto out_sock_release;
+ }
*res = sock;
return 0;
@@ -1691,6 +1723,28 @@ int __sock_create(struct net *net, int family,
int type, int protocol,
rcu_read_unlock();
goto out_sock_release;
}
+EXPORT_SYMBOL(__sock_create_flags);
+
+/**
+ * __sock_create - creates a socket
+ * @net: net namespace
+ * @family: protocol family (AF_INET, ...)
+ * @type: communication type (SOCK_STREAM, ...)
+ * @protocol: protocol (0, ...)
+ * @res: new socket
+ * @kern: boolean for kernel space sockets
+ *
+ * Creates a new socket and assigns it to @res, passing through LSM.
+ * Returns 0 or an error. On failure @res is set to %NULL. @kern must
+ * be set to true if the socket resides in kernel space.
+ * This function internally uses GFP_KERNEL.
+ */
+
+int __sock_create(struct net *net, int family, int type, int protocol,
+ struct socket **res, int kern)
+{
+ return __sock_create_flags(net, family, type, protocol, res, kern, 0);
+}
EXPORT_SYMBOL(__sock_create);
/**
@@ -1710,6 +1764,43 @@ int sock_create(int family, int type, int
protocol, struct socket **res)
}
EXPORT_SYMBOL(sock_create);
+/**
+ * sock_open - creates a socket (with flags)
+ * @net: net namespace (may be NULL in non-SOCK_CREATE_KERN modes)
+ * @family: protocol family (AF_INET, ...)
+ * @type: communication type (SOCK_STREAM, ...)
+ * @protocol: protocol (0, ...)
+ * @res: new socket
+ * @flags: socket creation flags
+ *
+ * Unified entry point for socket creation with flags.
+ * Returns 0 or an error. This function internally uses GFP_KERNEL.
+ */
+int sock_open(struct net *net, int family,
+ int type, int protocol, struct socket **res,
+ int flags)
+{
+ int type_bits = flags & (SOCK_CREATE_KERN | SOCK_CREATE_USER |
SOCK_CREATE_LITE);
+ int optional_flags = flags & ~(SOCK_CREATE_KERN | SOCK_CREATE_USER |
SOCK_CREATE_LITE);
+
+ if (type_bits == 0 || (type_bits & (type_bits - 1)) != 0)
+ return -EINVAL;
+
+ if (optional_flags & ~(SOCK_CREATE_NOLSM | SOCK_CREATE_NOWARN))
+ return -EINVAL;
+
+ switch (type_bits) {
+ case SOCK_CREATE_KERN: return __sock_create_flags(net, family, type, protocol,
+ res, 1, optional_flags);
+ case SOCK_CREATE_USER: return __sock_create_flags(current->nsproxy->net_ns,
+ family, type, protocol, res, 0, optional_flags);
+ case SOCK_CREATE_LITE: return __sock_create_lite_flags(family,
+ type, protocol, res, optional_flags);
+ default: return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(sock_open);
+
/**
* sock_create_kern - creates a socket (kernel space)
* @net: net namespace
-- 
2.47.3
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help