Message ID | 20250309132821.103046-3-aleksandr.mikhalitsyn@canonical.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | Add getsockopt(SO_PEERCGROUPID) and fdinfo API to retreive socket's peer cgroup id | expand |
Alexander Mikhalitsyn wrote: > Add SO_PEERCGROUPID which allows to get cgroup_id > for a socket. > > We already have analogical interfaces to retrieve this > information: > - inet_diag: INET_DIAG_CGROUP_ID > - eBPF: bpf_sk_cgroup_id > > Having getsockopt() interface makes sense for many > applications, because using eBPF is not always an option, > while inet_diag has obvious complexety and performance drawbacks > if we only want to get this specific info for one specific socket. > > Cc: linux-kernel@vger.kernel.org > Cc: netdev@vger.kernel.org > Cc: cgroups@vger.kernel.org > Cc: "David S. Miller" <davem@davemloft.net> > Cc: Eric Dumazet <edumazet@google.com> > Cc: Jakub Kicinski <kuba@kernel.org> > Cc: Paolo Abeni <pabeni@redhat.com> > Cc: Willem de Bruijn <willemb@google.com> > Cc: Leon Romanovsky <leon@kernel.org> > Cc: Arnd Bergmann <arnd@arndb.de> > Cc: Christian Brauner <brauner@kernel.org> > Cc: Kuniyuki Iwashima <kuniyu@amazon.com> > Cc: Lennart Poettering <mzxreary@0pointer.de> > Cc: Luca Boccassi <bluca@debian.org> > Cc: Tejun Heo <tj@kernel.org> > Cc: Johannes Weiner <hannes@cmpxchg.org> > Cc: "Michal Koutný" <mkoutny@suse.com> > Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> > --- > arch/alpha/include/uapi/asm/socket.h | 2 + > arch/mips/include/uapi/asm/socket.h | 2 + > arch/parisc/include/uapi/asm/socket.h | 2 + > arch/sparc/include/uapi/asm/socket.h | 2 + > include/uapi/asm-generic/socket.h | 2 + > net/core/sock.c | 17 +++++++ > net/unix/af_unix.c | 63 +++++++++++++++++++++++++ > tools/include/uapi/asm-generic/socket.h | 2 + > 8 files changed, 92 insertions(+) > > diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h > index 3df5f2dd4c0f..58ce457b2c09 100644 > --- a/arch/alpha/include/uapi/asm/socket.h > +++ b/arch/alpha/include/uapi/asm/socket.h > @@ -150,6 +150,8 @@ > > #define SO_RCVPRIORITY 82 > > +#define SO_PEERCGROUPID 83 > + > #if !defined(__KERNEL__) > > #if __BITS_PER_LONG == 64 > diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h > index 22fa8f19924a..823fa67f7d79 100644 > --- a/arch/mips/include/uapi/asm/socket.h > +++ b/arch/mips/include/uapi/asm/socket.h > @@ -161,6 +161,8 @@ > > #define SO_RCVPRIORITY 82 > > +#define SO_PEERCGROUPID 83 > + > #if !defined(__KERNEL__) > > #if __BITS_PER_LONG == 64 > diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h > index aa9cd4b951fe..1ee2e858d177 100644 > --- a/arch/parisc/include/uapi/asm/socket.h > +++ b/arch/parisc/include/uapi/asm/socket.h > @@ -142,6 +142,8 @@ > > #define SO_RCVPRIORITY 0x404D > > +#define SO_PEERCGROUPID 0x404E > + > #if !defined(__KERNEL__) > > #if __BITS_PER_LONG == 64 > diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h > index 5b464a568664..2fe7d0c48a63 100644 > --- a/arch/sparc/include/uapi/asm/socket.h > +++ b/arch/sparc/include/uapi/asm/socket.h > @@ -143,6 +143,8 @@ > > #define SO_RCVPRIORITY 0x005b > > +#define SO_PEERCGROUPID 0x005c > + > #if !defined(__KERNEL__) > > > diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h > index aa5016ff3d91..903904bb537c 100644 > --- a/include/uapi/asm-generic/socket.h > +++ b/include/uapi/asm-generic/socket.h > @@ -145,6 +145,8 @@ > > #define SO_RCVPRIORITY 82 > > +#define SO_PEERCGROUPID 83 > + > #if !defined(__KERNEL__) > > #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) > diff --git a/net/core/sock.c b/net/core/sock.c > index a0598518ce89..6dc0b1a8367b 100644 > --- a/net/core/sock.c > +++ b/net/core/sock.c > @@ -1946,6 +1946,23 @@ int sk_getsockopt(struct sock *sk, int level, int optname, > goto lenout; > } > > +#ifdef CONFIG_SOCK_CGROUP_DATA > + case SO_PEERCGROUPID: > + { > + const struct proto_ops *ops; > + > + if (sk->sk_family != AF_UNIX) > + return -EOPNOTSUPP; > + > + ops = READ_ONCE(sock->ops); > + if (!ops->getsockopt) > + return -EOPNOTSUPP; > + > + return ops->getsockopt(sock, SOL_SOCKET, optname, optval.user, > + optlen.user); > + } > +#endif > + > /* Dubious BSD thing... Probably nobody even uses it, but > * the UNIX standard wants it for whatever reason... -DaveM > */ > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c > index 2b2c0036efc9..3455f38f033d 100644 > --- a/net/unix/af_unix.c > +++ b/net/unix/af_unix.c > @@ -901,6 +901,66 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock) > #define unix_show_fdinfo NULL > #endif > > +static int unix_getsockopt(struct socket *sock, int level, int optname, > + char __user *optval, int __user *optlen) > +{ > + struct sock *sk = sock->sk; > + > + union { > + int val; > + u64 val64; > + } v; > + > + int lv = sizeof(int); > + int len; why the union if the only valid use is a u64? Is this forward looking?
From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> Date: Sun, 9 Mar 2025 14:28:13 +0100 > Add SO_PEERCGROUPID which allows to get cgroup_id > for a socket. This looks useless for SOCK_DGRAM as the server can't have a peer for clients to send() or connect() (see unix_may_send()). Is there any reason to support only the connect()ed peer ? It seems the uAPI group expects to retrieve data per message as SCM_CGROUPID. > > We already have analogical interfaces to retrieve this > information: > - inet_diag: INET_DIAG_CGROUP_ID > - eBPF: bpf_sk_cgroup_id > > Having getsockopt() interface makes sense for many > applications, because using eBPF is not always an option, > while inet_diag has obvious complexety and performance drawbacks > if we only want to get this specific info for one specific socket. [...] > diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c > index 2b2c0036efc9..3455f38f033d 100644 > --- a/net/unix/af_unix.c > +++ b/net/unix/af_unix.c > @@ -901,6 +901,66 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock) > #define unix_show_fdinfo NULL > #endif > > +static int unix_getsockopt(struct socket *sock, int level, int optname, > + char __user *optval, int __user *optlen) > +{ > + struct sock *sk = sock->sk; > + > + union { > + int val; > + u64 val64; As Willem pointed out, simply use val64 only. > + } v; > + > + int lv = sizeof(int); > + int len; > + > + if (level != SOL_SOCKET) > + return -ENOPROTOOPT; > + > + if (get_user(len, optlen)) > + return -EFAULT; > + > + if (len < 0) > + return -EINVAL; > + > + memset(&v, 0, sizeof(v)); > + > + switch (optname) { > +#ifdef CONFIG_SOCK_CGROUP_DATA > + case SO_PEERCGROUPID: > + { > + struct sock *peer; > + u64 peer_cgroup_id = 0; Same remarks in patch 1, reverse xmas tree order, and no initialisation needed. > + > + lv = sizeof(u64); > + if (len < lv) > + return -EINVAL; > + > + peer = unix_peer_get(sk); > + if (!peer) > + return -ENODATA; > + > + peer_cgroup_id = cgroup_id(sock_cgroup_ptr(&peer->sk_cgrp_data)); > + sock_put(peer); > + > + v.val64 = peer_cgroup_id; > + break; > + } > +#endif > + default: > + return -ENOPROTOOPT; > + } > + > + if (len > lv) > + len = lv; > + if (copy_to_user(optval, &v, len)) > + return -EFAULT; > + if (put_user(len, optlen)) > + return -EFAULT; > + > + return 0; > +} > +
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index 3df5f2dd4c0f..58ce457b2c09 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -150,6 +150,8 @@ #define SO_RCVPRIORITY 82 +#define SO_PEERCGROUPID 83 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index 22fa8f19924a..823fa67f7d79 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -161,6 +161,8 @@ #define SO_RCVPRIORITY 82 +#define SO_PEERCGROUPID 83 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index aa9cd4b951fe..1ee2e858d177 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -142,6 +142,8 @@ #define SO_RCVPRIORITY 0x404D +#define SO_PEERCGROUPID 0x404E + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 5b464a568664..2fe7d0c48a63 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -143,6 +143,8 @@ #define SO_RCVPRIORITY 0x005b +#define SO_PEERCGROUPID 0x005c + #if !defined(__KERNEL__) diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index aa5016ff3d91..903904bb537c 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -145,6 +145,8 @@ #define SO_RCVPRIORITY 82 +#define SO_PEERCGROUPID 83 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) diff --git a/net/core/sock.c b/net/core/sock.c index a0598518ce89..6dc0b1a8367b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1946,6 +1946,23 @@ int sk_getsockopt(struct sock *sk, int level, int optname, goto lenout; } +#ifdef CONFIG_SOCK_CGROUP_DATA + case SO_PEERCGROUPID: + { + const struct proto_ops *ops; + + if (sk->sk_family != AF_UNIX) + return -EOPNOTSUPP; + + ops = READ_ONCE(sock->ops); + if (!ops->getsockopt) + return -EOPNOTSUPP; + + return ops->getsockopt(sock, SOL_SOCKET, optname, optval.user, + optlen.user); + } +#endif + /* Dubious BSD thing... Probably nobody even uses it, but * the UNIX standard wants it for whatever reason... -DaveM */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2b2c0036efc9..3455f38f033d 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -901,6 +901,66 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock) #define unix_show_fdinfo NULL #endif +static int unix_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) +{ + struct sock *sk = sock->sk; + + union { + int val; + u64 val64; + } v; + + int lv = sizeof(int); + int len; + + if (level != SOL_SOCKET) + return -ENOPROTOOPT; + + if (get_user(len, optlen)) + return -EFAULT; + + if (len < 0) + return -EINVAL; + + memset(&v, 0, sizeof(v)); + + switch (optname) { +#ifdef CONFIG_SOCK_CGROUP_DATA + case SO_PEERCGROUPID: + { + struct sock *peer; + u64 peer_cgroup_id = 0; + + lv = sizeof(u64); + if (len < lv) + return -EINVAL; + + peer = unix_peer_get(sk); + if (!peer) + return -ENODATA; + + peer_cgroup_id = cgroup_id(sock_cgroup_ptr(&peer->sk_cgrp_data)); + sock_put(peer); + + v.val64 = peer_cgroup_id; + break; + } +#endif + default: + return -ENOPROTOOPT; + } + + if (len > lv) + len = lv; + if (copy_to_user(optval, &v, len)) + return -EFAULT; + if (put_user(len, optlen)) + return -EFAULT; + + return 0; +} + static const struct proto_ops unix_stream_ops = { .family = PF_UNIX, .owner = THIS_MODULE, @@ -910,6 +970,7 @@ static const struct proto_ops unix_stream_ops = { .socketpair = unix_socketpair, .accept = unix_accept, .getname = unix_getname, + .getsockopt = unix_getsockopt, .poll = unix_poll, .ioctl = unix_ioctl, #ifdef CONFIG_COMPAT @@ -935,6 +996,7 @@ static const struct proto_ops unix_dgram_ops = { .socketpair = unix_socketpair, .accept = sock_no_accept, .getname = unix_getname, + .getsockopt = unix_getsockopt, .poll = unix_dgram_poll, .ioctl = unix_ioctl, #ifdef CONFIG_COMPAT @@ -959,6 +1021,7 @@ static const struct proto_ops unix_seqpacket_ops = { .socketpair = unix_socketpair, .accept = unix_accept, .getname = unix_getname, + .getsockopt = unix_getsockopt, .poll = unix_dgram_poll, .ioctl = unix_ioctl, #ifdef CONFIG_COMPAT diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h index aa5016ff3d91..903904bb537c 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -145,6 +145,8 @@ #define SO_RCVPRIORITY 82 +#define SO_PEERCGROUPID 83 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
Add SO_PEERCGROUPID which allows to get cgroup_id for a socket. We already have analogical interfaces to retrieve this information: - inet_diag: INET_DIAG_CGROUP_ID - eBPF: bpf_sk_cgroup_id Having getsockopt() interface makes sense for many applications, because using eBPF is not always an option, while inet_diag has obvious complexety and performance drawbacks if we only want to get this specific info for one specific socket. Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: cgroups@vger.kernel.org Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Willem de Bruijn <willemb@google.com> Cc: Leon Romanovsky <leon@kernel.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Christian Brauner <brauner@kernel.org> Cc: Kuniyuki Iwashima <kuniyu@amazon.com> Cc: Lennart Poettering <mzxreary@0pointer.de> Cc: Luca Boccassi <bluca@debian.org> Cc: Tejun Heo <tj@kernel.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: "Michal Koutný" <mkoutny@suse.com> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> --- arch/alpha/include/uapi/asm/socket.h | 2 + arch/mips/include/uapi/asm/socket.h | 2 + arch/parisc/include/uapi/asm/socket.h | 2 + arch/sparc/include/uapi/asm/socket.h | 2 + include/uapi/asm-generic/socket.h | 2 + net/core/sock.c | 17 +++++++ net/unix/af_unix.c | 63 +++++++++++++++++++++++++ tools/include/uapi/asm-generic/socket.h | 2 + 8 files changed, 92 insertions(+)