Skip to content

Commit f4e6587

Browse files
committed
net: split out functions related to registering inflight socket files
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>
1 parent edafcce commit f4e6587

File tree

8 files changed

+174
-131
lines changed

8 files changed

+174
-131
lines changed

include/net/af_unix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
void unix_inflight(struct user_struct *user, struct file *fp);
1212
void unix_notinflight(struct user_struct *user, struct file *fp);
13+
void unix_destruct_scm(struct sk_buff *skb);
1314
void unix_gc(void);
1415
void wait_for_unix_gc(void);
1516
struct sock *unix_get_socket(struct file *filp);

net/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/
1818
obj-$(CONFIG_INET) += ipv4/
1919
obj-$(CONFIG_TLS) += tls/
2020
obj-$(CONFIG_XFRM) += xfrm/
21-
obj-$(CONFIG_UNIX) += unix/
21+
obj-$(CONFIG_UNIX_SCM) += unix/
2222
obj-$(CONFIG_NET) += ipv6/
2323
obj-$(CONFIG_BPFILTER) += bpfilter/
2424
obj-$(CONFIG_PACKET) += packet/

net/unix/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ config UNIX
1919

2020
Say Y unless you know what you are doing.
2121

22+
config UNIX_SCM
23+
bool
24+
depends on UNIX
25+
default y
26+
2227
config UNIX_DIAG
2328
tristate "UNIX: socket monitoring interface"
2429
depends on UNIX

net/unix/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ unix-$(CONFIG_SYSCTL) += sysctl_net_unix.o
1010

1111
obj-$(CONFIG_UNIX_DIAG) += unix_diag.o
1212
unix_diag-y := diag.o
13+
14+
obj-$(CONFIG_UNIX_SCM) += scm.o

net/unix/af_unix.c

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@
119119
#include <linux/freezer.h>
120120
#include <linux/file.h>
121121

122+
#include "scm.h"
123+
122124
struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
123125
EXPORT_SYMBOL_GPL(unix_socket_table);
124126
DEFINE_SPINLOCK(unix_table_lock);
@@ -1486,67 +1488,6 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
14861488
return err;
14871489
}
14881490

1489-
static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1490-
{
1491-
int i;
1492-
1493-
scm->fp = UNIXCB(skb).fp;
1494-
UNIXCB(skb).fp = NULL;
1495-
1496-
for (i = scm->fp->count-1; i >= 0; i--)
1497-
unix_notinflight(scm->fp->user, scm->fp->fp[i]);
1498-
}
1499-
1500-
static void unix_destruct_scm(struct sk_buff *skb)
1501-
{
1502-
struct scm_cookie scm;
1503-
memset(&scm, 0, sizeof(scm));
1504-
scm.pid = UNIXCB(skb).pid;
1505-
if (UNIXCB(skb).fp)
1506-
unix_detach_fds(&scm, skb);
1507-
1508-
/* Alas, it calls VFS */
1509-
/* So fscking what? fput() had been SMP-safe since the last Summer */
1510-
scm_destroy(&scm);
1511-
sock_wfree(skb);
1512-
}
1513-
1514-
/*
1515-
* The "user->unix_inflight" variable is protected by the garbage
1516-
* collection lock, and we just read it locklessly here. If you go
1517-
* over the limit, there might be a tiny race in actually noticing
1518-
* it across threads. Tough.
1519-
*/
1520-
static inline bool too_many_unix_fds(struct task_struct *p)
1521-
{
1522-
struct user_struct *user = current_user();
1523-
1524-
if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
1525-
return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
1526-
return false;
1527-
}
1528-
1529-
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1530-
{
1531-
int i;
1532-
1533-
if (too_many_unix_fds(current))
1534-
return -ETOOMANYREFS;
1535-
1536-
/*
1537-
* Need to duplicate file references for the sake of garbage
1538-
* collection. Otherwise a socket in the fps might become a
1539-
* candidate for GC while the skb is not yet queued.
1540-
*/
1541-
UNIXCB(skb).fp = scm_fp_dup(scm->fp);
1542-
if (!UNIXCB(skb).fp)
1543-
return -ENOMEM;
1544-
1545-
for (i = scm->fp->count - 1; i >= 0; i--)
1546-
unix_inflight(scm->fp->user, scm->fp->fp[i]);
1547-
return 0;
1548-
}
1549-
15501491
static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
15511492
{
15521493
int err = 0;

net/unix/garbage.c

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -86,80 +86,13 @@
8686
#include <net/scm.h>
8787
#include <net/tcp_states.h>
8888

89+
#include "scm.h"
90+
8991
/* Internal data structures and random procedures: */
9092

91-
static LIST_HEAD(gc_inflight_list);
9293
static LIST_HEAD(gc_candidates);
93-
static DEFINE_SPINLOCK(unix_gc_lock);
9494
static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
9595

96-
unsigned int unix_tot_inflight;
97-
98-
struct sock *unix_get_socket(struct file *filp)
99-
{
100-
struct sock *u_sock = NULL;
101-
struct inode *inode = file_inode(filp);
102-
103-
/* Socket ? */
104-
if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
105-
struct socket *sock = SOCKET_I(inode);
106-
struct sock *s = sock->sk;
107-
108-
/* PF_UNIX ? */
109-
if (s && sock->ops && sock->ops->family == PF_UNIX)
110-
u_sock = s;
111-
} else {
112-
/* Could be an io_uring instance */
113-
u_sock = io_uring_get_socket(filp);
114-
}
115-
return u_sock;
116-
}
117-
118-
/* Keep the number of times in flight count for the file
119-
* descriptor if it is for an AF_UNIX socket.
120-
*/
121-
122-
void unix_inflight(struct user_struct *user, struct file *fp)
123-
{
124-
struct sock *s = unix_get_socket(fp);
125-
126-
spin_lock(&unix_gc_lock);
127-
128-
if (s) {
129-
struct unix_sock *u = unix_sk(s);
130-
131-
if (atomic_long_inc_return(&u->inflight) == 1) {
132-
BUG_ON(!list_empty(&u->link));
133-
list_add_tail(&u->link, &gc_inflight_list);
134-
} else {
135-
BUG_ON(list_empty(&u->link));
136-
}
137-
unix_tot_inflight++;
138-
}
139-
user->unix_inflight++;
140-
spin_unlock(&unix_gc_lock);
141-
}
142-
143-
void unix_notinflight(struct user_struct *user, struct file *fp)
144-
{
145-
struct sock *s = unix_get_socket(fp);
146-
147-
spin_lock(&unix_gc_lock);
148-
149-
if (s) {
150-
struct unix_sock *u = unix_sk(s);
151-
152-
BUG_ON(!atomic_long_read(&u->inflight));
153-
BUG_ON(list_empty(&u->link));
154-
155-
if (atomic_long_dec_and_test(&u->inflight))
156-
list_del_init(&u->link);
157-
unix_tot_inflight--;
158-
}
159-
user->unix_inflight--;
160-
spin_unlock(&unix_gc_lock);
161-
}
162-
16396
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
16497
struct sk_buff_head *hitlist)
16598
{

net/unix/scm.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/module.h>
3+
#include <linux/kernel.h>
4+
#include <linux/string.h>
5+
#include <linux/socket.h>
6+
#include <linux/net.h>
7+
#include <linux/fs.h>
8+
#include <net/af_unix.h>
9+
#include <net/scm.h>
10+
#include <linux/init.h>
11+
12+
#include "scm.h"
13+
14+
unsigned int unix_tot_inflight;
15+
EXPORT_SYMBOL(unix_tot_inflight);
16+
17+
LIST_HEAD(gc_inflight_list);
18+
EXPORT_SYMBOL(gc_inflight_list);
19+
20+
DEFINE_SPINLOCK(unix_gc_lock);
21+
EXPORT_SYMBOL(unix_gc_lock);
22+
23+
struct sock *unix_get_socket(struct file *filp)
24+
{
25+
struct sock *u_sock = NULL;
26+
struct inode *inode = file_inode(filp);
27+
28+
/* Socket ? */
29+
if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
30+
struct socket *sock = SOCKET_I(inode);
31+
struct sock *s = sock->sk;
32+
33+
/* PF_UNIX ? */
34+
if (s && sock->ops && sock->ops->family == PF_UNIX)
35+
u_sock = s;
36+
} else {
37+
/* Could be an io_uring instance */
38+
u_sock = io_uring_get_socket(filp);
39+
}
40+
return u_sock;
41+
}
42+
EXPORT_SYMBOL(unix_get_socket);
43+
44+
/* Keep the number of times in flight count for the file
45+
* descriptor if it is for an AF_UNIX socket.
46+
*/
47+
void unix_inflight(struct user_struct *user, struct file *fp)
48+
{
49+
struct sock *s = unix_get_socket(fp);
50+
51+
spin_lock(&unix_gc_lock);
52+
53+
if (s) {
54+
struct unix_sock *u = unix_sk(s);
55+
56+
if (atomic_long_inc_return(&u->inflight) == 1) {
57+
BUG_ON(!list_empty(&u->link));
58+
list_add_tail(&u->link, &gc_inflight_list);
59+
} else {
60+
BUG_ON(list_empty(&u->link));
61+
}
62+
unix_tot_inflight++;
63+
}
64+
user->unix_inflight++;
65+
spin_unlock(&unix_gc_lock);
66+
}
67+
68+
void unix_notinflight(struct user_struct *user, struct file *fp)
69+
{
70+
struct sock *s = unix_get_socket(fp);
71+
72+
spin_lock(&unix_gc_lock);
73+
74+
if (s) {
75+
struct unix_sock *u = unix_sk(s);
76+
77+
BUG_ON(!atomic_long_read(&u->inflight));
78+
BUG_ON(list_empty(&u->link));
79+
80+
if (atomic_long_dec_and_test(&u->inflight))
81+
list_del_init(&u->link);
82+
unix_tot_inflight--;
83+
}
84+
user->unix_inflight--;
85+
spin_unlock(&unix_gc_lock);
86+
}
87+
88+
/*
89+
* The "user->unix_inflight" variable is protected by the garbage
90+
* collection lock, and we just read it locklessly here. If you go
91+
* over the limit, there might be a tiny race in actually noticing
92+
* it across threads. Tough.
93+
*/
94+
static inline bool too_many_unix_fds(struct task_struct *p)
95+
{
96+
struct user_struct *user = current_user();
97+
98+
if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
99+
return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
100+
return false;
101+
}
102+
103+
int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
104+
{
105+
int i;
106+
107+
if (too_many_unix_fds(current))
108+
return -ETOOMANYREFS;
109+
110+
/*
111+
* Need to duplicate file references for the sake of garbage
112+
* collection. Otherwise a socket in the fps might become a
113+
* candidate for GC while the skb is not yet queued.
114+
*/
115+
UNIXCB(skb).fp = scm_fp_dup(scm->fp);
116+
if (!UNIXCB(skb).fp)
117+
return -ENOMEM;
118+
119+
for (i = scm->fp->count - 1; i >= 0; i--)
120+
unix_inflight(scm->fp->user, scm->fp->fp[i]);
121+
return 0;
122+
}
123+
EXPORT_SYMBOL(unix_attach_fds);
124+
125+
void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
126+
{
127+
int i;
128+
129+
scm->fp = UNIXCB(skb).fp;
130+
UNIXCB(skb).fp = NULL;
131+
132+
for (i = scm->fp->count-1; i >= 0; i--)
133+
unix_notinflight(scm->fp->user, scm->fp->fp[i]);
134+
}
135+
EXPORT_SYMBOL(unix_detach_fds);
136+
137+
void unix_destruct_scm(struct sk_buff *skb)
138+
{
139+
struct scm_cookie scm;
140+
141+
memset(&scm, 0, sizeof(scm));
142+
scm.pid = UNIXCB(skb).pid;
143+
if (UNIXCB(skb).fp)
144+
unix_detach_fds(&scm, skb);
145+
146+
/* Alas, it calls VFS */
147+
/* So fscking what? fput() had been SMP-safe since the last Summer */
148+
scm_destroy(&scm);
149+
sock_wfree(skb);
150+
}
151+
EXPORT_SYMBOL(unix_destruct_scm);

net/unix/scm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef NET_UNIX_SCM_H
2+
#define NET_UNIX_SCM_H
3+
4+
extern struct list_head gc_inflight_list;
5+
extern spinlock_t unix_gc_lock;
6+
7+
int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb);
8+
void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb);
9+
10+
#endif

0 commit comments

Comments
 (0)