LKML Archive on lore.kernel.org help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, stable@vger.kernel.org, Hannes Reinecke <hare@suse.com>, "David S. Miller" <davem@davemloft.net>, Jens Axboe <axboe@kernel.dk> Subject: [PATCH 4.9 03/32] net: split out functions related to registering inflight socket files Date: Mon, 2 Aug 2021 15:44:23 +0200 [thread overview] Message-ID: <20210802134333.039164482@linuxfoundation.org> (raw) In-Reply-To: <20210802134332.931915241@linuxfoundation.org> From: Jens Axboe <axboe@kernel.dk> commit f4e65870e5cede5ca1ec0006b6c9803994e5f7b8 upstream. We need this functionality for the io_uring file registration, but we cannot rely on it since CONFIG_UNIX can be modular. Move the helpers to a separate file, that's always builtin to the kernel if CONFIG_UNIX is m/y. No functional changes in this patch, just moving code around. Reviewed-by: Hannes Reinecke <hare@suse.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Jens Axboe <axboe@kernel.dk> [ backported to older kernels to get access to unix_gc_lock - gregkh ] Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- include/net/af_unix.h | 1 net/Makefile | 2 net/unix/Kconfig | 5 + net/unix/Makefile | 2 net/unix/af_unix.c | 76 ----------------------- net/unix/garbage.c | 68 --------------------- net/unix/scm.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ net/unix/scm.h | 10 +++ 8 files changed, 184 insertions(+), 141 deletions(-) create mode 100644 net/unix/scm.c create mode 100644 net/unix/scm.h --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -8,6 +8,7 @@ void unix_inflight(struct user_struct *user, struct file *fp); void unix_notinflight(struct user_struct *user, struct file *fp); +void unix_destruct_scm(struct sk_buff *skb); void unix_gc(void); void wait_for_unix_gc(void); struct sock *unix_get_socket(struct file *filp); --- a/net/Makefile +++ b/net/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_NET) += ethernet/ 802/ sch obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_INET) += ipv4/ obj-$(CONFIG_XFRM) += xfrm/ -obj-$(CONFIG_UNIX) += unix/ +obj-$(CONFIG_UNIX_SCM) += unix/ obj-$(CONFIG_NET) += ipv6/ obj-$(CONFIG_PACKET) += packet/ obj-$(CONFIG_NET_KEY) += key/ --- a/net/unix/Kconfig +++ b/net/unix/Kconfig @@ -19,6 +19,11 @@ config UNIX Say Y unless you know what you are doing. +config UNIX_SCM + bool + depends on UNIX + default y + config UNIX_DIAG tristate "UNIX: socket monitoring interface" depends on UNIX --- a/net/unix/Makefile +++ b/net/unix/Makefile @@ -9,3 +9,5 @@ unix-$(CONFIG_SYSCTL) += sysctl_net_unix obj-$(CONFIG_UNIX_DIAG) += unix_diag.o unix_diag-y := diag.o + +obj-$(CONFIG_UNIX_SCM) += scm.o --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -118,6 +118,8 @@ #include <linux/security.h> #include <linux/freezer.h> +#include "scm.h" + struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; EXPORT_SYMBOL_GPL(unix_socket_table); DEFINE_SPINLOCK(unix_table_lock); @@ -1505,80 +1507,6 @@ out: return err; } -static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) -{ - int i; - - scm->fp = UNIXCB(skb).fp; - UNIXCB(skb).fp = NULL; - - for (i = scm->fp->count-1; i >= 0; i--) - unix_notinflight(scm->fp->user, scm->fp->fp[i]); -} - -static void unix_destruct_scm(struct sk_buff *skb) -{ - struct scm_cookie scm; - memset(&scm, 0, sizeof(scm)); - scm.pid = UNIXCB(skb).pid; - if (UNIXCB(skb).fp) - unix_detach_fds(&scm, skb); - - /* Alas, it calls VFS */ - /* So fscking what? fput() had been SMP-safe since the last Summer */ - scm_destroy(&scm); - sock_wfree(skb); -} - -/* - * The "user->unix_inflight" variable is protected by the garbage - * collection lock, and we just read it locklessly here. If you go - * over the limit, there might be a tiny race in actually noticing - * it across threads. Tough. - */ -static inline bool too_many_unix_fds(struct task_struct *p) -{ - struct user_struct *user = current_user(); - - if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) - return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); - return false; -} - -#define MAX_RECURSION_LEVEL 4 - -static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) -{ - int i; - unsigned char max_level = 0; - - if (too_many_unix_fds(current)) - return -ETOOMANYREFS; - - for (i = scm->fp->count - 1; i >= 0; i--) { - struct sock *sk = unix_get_socket(scm->fp->fp[i]); - - if (sk) - max_level = max(max_level, - unix_sk(sk)->recursion_level); - } - if (unlikely(max_level > MAX_RECURSION_LEVEL)) - return -ETOOMANYREFS; - - /* - * Need to duplicate file references for the sake of garbage - * collection. Otherwise a socket in the fps might become a - * candidate for GC while the skb is not yet queued. - */ - UNIXCB(skb).fp = scm_fp_dup(scm->fp); - if (!UNIXCB(skb).fp) - return -ENOMEM; - - for (i = scm->fp->count - 1; i >= 0; i--) - unix_inflight(scm->fp->user, scm->fp->fp[i]); - return max_level; -} - static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) { int err = 0; --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -86,77 +86,13 @@ #include <net/scm.h> #include <net/tcp_states.h> +#include "scm.h" + /* Internal data structures and random procedures: */ -static LIST_HEAD(gc_inflight_list); static LIST_HEAD(gc_candidates); -static DEFINE_SPINLOCK(unix_gc_lock); static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); -unsigned int unix_tot_inflight; - -struct sock *unix_get_socket(struct file *filp) -{ - struct sock *u_sock = NULL; - struct inode *inode = file_inode(filp); - - /* Socket ? */ - if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { - struct socket *sock = SOCKET_I(inode); - struct sock *s = sock->sk; - - /* PF_UNIX ? */ - if (s && sock->ops && sock->ops->family == PF_UNIX) - u_sock = s; - } - return u_sock; -} - -/* Keep the number of times in flight count for the file - * descriptor if it is for an AF_UNIX socket. - */ - -void unix_inflight(struct user_struct *user, struct file *fp) -{ - struct sock *s = unix_get_socket(fp); - - spin_lock(&unix_gc_lock); - - if (s) { - struct unix_sock *u = unix_sk(s); - - if (atomic_long_inc_return(&u->inflight) == 1) { - BUG_ON(!list_empty(&u->link)); - list_add_tail(&u->link, &gc_inflight_list); - } else { - BUG_ON(list_empty(&u->link)); - } - unix_tot_inflight++; - } - user->unix_inflight++; - spin_unlock(&unix_gc_lock); -} - -void unix_notinflight(struct user_struct *user, struct file *fp) -{ - struct sock *s = unix_get_socket(fp); - - spin_lock(&unix_gc_lock); - - if (s) { - struct unix_sock *u = unix_sk(s); - - BUG_ON(!atomic_long_read(&u->inflight)); - BUG_ON(list_empty(&u->link)); - - if (atomic_long_dec_and_test(&u->inflight)) - list_del_init(&u->link); - unix_tot_inflight--; - } - user->unix_inflight--; - spin_unlock(&unix_gc_lock); -} - static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) { --- /dev/null +++ b/net/unix/scm.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/socket.h> +#include <linux/net.h> +#include <linux/fs.h> +#include <net/af_unix.h> +#include <net/scm.h> +#include <linux/init.h> + +#include "scm.h" + +unsigned int unix_tot_inflight; +EXPORT_SYMBOL(unix_tot_inflight); + +LIST_HEAD(gc_inflight_list); +EXPORT_SYMBOL(gc_inflight_list); + +DEFINE_SPINLOCK(unix_gc_lock); +EXPORT_SYMBOL(unix_gc_lock); + +struct sock *unix_get_socket(struct file *filp) +{ + struct sock *u_sock = NULL; + struct inode *inode = file_inode(filp); + + /* Socket ? */ + if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { + struct socket *sock = SOCKET_I(inode); + struct sock *s = sock->sk; + + /* PF_UNIX ? */ + if (s && sock->ops && sock->ops->family == PF_UNIX) + u_sock = s; + } + return u_sock; +} +EXPORT_SYMBOL(unix_get_socket); + +/* Keep the number of times in flight count for the file + * descriptor if it is for an AF_UNIX socket. + */ +void unix_inflight(struct user_struct *user, struct file *fp) +{ + struct sock *s = unix_get_socket(fp); + + spin_lock(&unix_gc_lock); + + if (s) { + struct unix_sock *u = unix_sk(s); + + if (atomic_long_inc_return(&u->inflight) == 1) { + BUG_ON(!list_empty(&u->link)); + list_add_tail(&u->link, &gc_inflight_list); + } else { + BUG_ON(list_empty(&u->link)); + } + unix_tot_inflight++; + } + user->unix_inflight++; + spin_unlock(&unix_gc_lock); +} + +void unix_notinflight(struct user_struct *user, struct file *fp) +{ + struct sock *s = unix_get_socket(fp); + + spin_lock(&unix_gc_lock); + + if (s) { + struct unix_sock *u = unix_sk(s); + + BUG_ON(!atomic_long_read(&u->inflight)); + BUG_ON(list_empty(&u->link)); + + if (atomic_long_dec_and_test(&u->inflight)) + list_del_init(&u->link); + unix_tot_inflight--; + } + user->unix_inflight--; + spin_unlock(&unix_gc_lock); +} + +/* + * The "user->unix_inflight" variable is protected by the garbage + * collection lock, and we just read it locklessly here. If you go + * over the limit, there might be a tiny race in actually noticing + * it across threads. Tough. + */ +static inline bool too_many_unix_fds(struct task_struct *p) +{ + struct user_struct *user = current_user(); + + if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) + return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); + return false; +} + +#define MAX_RECURSION_LEVEL 4 + +int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) +{ + int i; + unsigned char max_level = 0; + + if (too_many_unix_fds(current)) + return -ETOOMANYREFS; + + for (i = scm->fp->count - 1; i >= 0; i--) { + struct sock *sk = unix_get_socket(scm->fp->fp[i]); + + if (sk) + max_level = max(max_level, + unix_sk(sk)->recursion_level); + } + if (unlikely(max_level > MAX_RECURSION_LEVEL)) + return -ETOOMANYREFS; + + /* + * Need to duplicate file references for the sake of garbage + * collection. Otherwise a socket in the fps might become a + * candidate for GC while the skb is not yet queued. + */ + UNIXCB(skb).fp = scm_fp_dup(scm->fp); + if (!UNIXCB(skb).fp) + return -ENOMEM; + + for (i = scm->fp->count - 1; i >= 0; i--) + unix_inflight(scm->fp->user, scm->fp->fp[i]); + return max_level; +} +EXPORT_SYMBOL(unix_attach_fds); + +void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) +{ + int i; + + scm->fp = UNIXCB(skb).fp; + UNIXCB(skb).fp = NULL; + + for (i = scm->fp->count-1; i >= 0; i--) + unix_notinflight(scm->fp->user, scm->fp->fp[i]); +} +EXPORT_SYMBOL(unix_detach_fds); + +void unix_destruct_scm(struct sk_buff *skb) +{ + struct scm_cookie scm; + + memset(&scm, 0, sizeof(scm)); + scm.pid = UNIXCB(skb).pid; + if (UNIXCB(skb).fp) + unix_detach_fds(&scm, skb); + + /* Alas, it calls VFS */ + /* So fscking what? fput() had been SMP-safe since the last Summer */ + scm_destroy(&scm); + sock_wfree(skb); +} +EXPORT_SYMBOL(unix_destruct_scm); --- /dev/null +++ b/net/unix/scm.h @@ -0,0 +1,10 @@ +#ifndef NET_UNIX_SCM_H +#define NET_UNIX_SCM_H + +extern struct list_head gc_inflight_list; +extern spinlock_t unix_gc_lock; + +int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb); +void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb); + +#endif
next prev parent reply other threads:[~2021-08-02 13:48 UTC|newest] Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-08-02 13:44 [PATCH 4.9 00/32] 4.9.278-rc1 review Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 01/32] iommu/amd: Fix backport of 140456f994195b568ecd7fc2287a34eadffef3ca Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 02/32] tipc: Fix backport of b77413446408fdd256599daf00d5be72b5f3e7c6 Greg Kroah-Hartman 2021-08-02 13:44 ` Greg Kroah-Hartman [this message] 2021-08-02 13:44 ` [PATCH 4.9 04/32] af_unix: fix garbage collect vs MSG_PEEK Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 05/32] workqueue: fix UAF in pwq_unbound_release_workfn() Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 06/32] net/802/mrp: fix memleak in mrp_request_join() Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 07/32] net/802/garp: fix memleak in garp_request_join() Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 08/32] sctp: move 198 addresses from unusable to private scope Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 09/32] hfs: add missing clean-up in hfs_fill_super Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 10/32] hfs: fix high memory mapping in hfs_bnode_read Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 11/32] hfs: add lock nesting notation to hfs_find_init Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 12/32] ARM: dts: versatile: Fix up interrupt controller node names Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 13/32] lib/string.c: add multibyte memset functions Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 14/32] ARM: ensure the signal page contains defined contents Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 15/32] x86/kvm: fix vcpu-id indexed array sizes Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 16/32] ocfs2: fix zero out valid data Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 17/32] ocfs2: issue zeroout to EOF blocks Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 18/32] can: usb_8dev: fix memory leak Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 19/32] can: ems_usb: " Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 20/32] can: esd_usb2: " Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 21/32] NIU: fix incorrect error return, missed in previous revert Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 22/32] nfc: nfcsim: fix use after free during module unload Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 23/32] x86/asm: Ensure asm/proto.h can be included stand-alone Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 24/32] cfg80211: Fix possible memory leak in function cfg80211_bss_update Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 25/32] netfilter: conntrack: adjust stop timestamp to real expiry value Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 26/32] netfilter: nft_nat: allow to specify layer 4 protocol NAT only Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 27/32] tipc: fix sleeping in tipc accept routine Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 28/32] mlx4: Fix missing error code in mlx4_load_one() Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 29/32] net: llc: fix skb_over_panic Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 30/32] net/mlx5: Fix flow table chaining Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 31/32] tulip: windbond-840: Fix missing pci_disable_device() in probe and remove Greg Kroah-Hartman 2021-08-02 13:44 ` [PATCH 4.9 32/32] sis900: " Greg Kroah-Hartman 2021-08-03 13:45 ` [PATCH 4.9 00/32] 4.9.278-rc1 review Naresh Kamboju 2021-08-03 19:14 ` Guenter Roeck
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210802134333.039164482@linuxfoundation.org \ --to=gregkh@linuxfoundation.org \ --cc=axboe@kernel.dk \ --cc=davem@davemloft.net \ --cc=hare@suse.com \ --cc=linux-kernel@vger.kernel.org \ --cc=stable@vger.kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).