aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-01-11 23:55:43 -0500
committerDavid S. Miller <davem@davemloft.net>2016-01-11 23:55:43 -0500
commit9d367eddf363553c7668ba92c3b9d187ec4f71f7 (patch)
tree4f06d334d316390cc9a869ce3e74ec48d32ed0f8 /net/unix
parentb6a0e72ad3cffabaf30b856deb58fbe64a0f36a8 (diff)
parent03d84a5f83a67e692af00a3d3901e7820e3e84d5 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts: drivers/net/bonding/bond_main.c drivers/net/ethernet/mellanox/mlxsw/spectrum.h drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c The bond_main.c and mellanox switch conflicts were cases of overlapping changes. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix')
-rw-r--r--net/unix/af_unix.c24
-rw-r--r--net/unix/garbage.c13
2 files changed, 28 insertions, 9 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e6d35569f757..c5bf5ef2bf89 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1513,6 +1513,21 @@ static void unix_destruct_scm(struct sk_buff *skb)
1513 sock_wfree(skb); 1513 sock_wfree(skb);
1514} 1514}
1515 1515
1516/*
1517 * The "user->unix_inflight" variable is protected by the garbage
1518 * collection lock, and we just read it locklessly here. If you go
1519 * over the limit, there might be a tiny race in actually noticing
1520 * it across threads. Tough.
1521 */
1522static inline bool too_many_unix_fds(struct task_struct *p)
1523{
1524 struct user_struct *user = current_user();
1525
1526 if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
1527 return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
1528 return false;
1529}
1530
1516#define MAX_RECURSION_LEVEL 4 1531#define MAX_RECURSION_LEVEL 4
1517 1532
1518static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) 1533static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
@@ -1521,6 +1536,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1521 unsigned char max_level = 0; 1536 unsigned char max_level = 0;
1522 int unix_sock_count = 0; 1537 int unix_sock_count = 0;
1523 1538
1539 if (too_many_unix_fds(current))
1540 return -ETOOMANYREFS;
1541
1524 for (i = scm->fp->count - 1; i >= 0; i--) { 1542 for (i = scm->fp->count - 1; i >= 0; i--) {
1525 struct sock *sk = unix_get_socket(scm->fp->fp[i]); 1543 struct sock *sk = unix_get_socket(scm->fp->fp[i]);
1526 1544
@@ -1542,10 +1560,8 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1542 if (!UNIXCB(skb).fp) 1560 if (!UNIXCB(skb).fp)
1543 return -ENOMEM; 1561 return -ENOMEM;
1544 1562
1545 if (unix_sock_count) { 1563 for (i = scm->fp->count - 1; i >= 0; i--)
1546 for (i = scm->fp->count - 1; i >= 0; i--) 1564 unix_inflight(scm->fp->fp[i]);
1547 unix_inflight(scm->fp->fp[i]);
1548 }
1549 return max_level; 1565 return max_level;
1550} 1566}
1551 1567
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index a73a226f2d33..8fcdc2283af5 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -120,11 +120,11 @@ void unix_inflight(struct file *fp)
120{ 120{
121 struct sock *s = unix_get_socket(fp); 121 struct sock *s = unix_get_socket(fp);
122 122
123 spin_lock(&unix_gc_lock);
124
123 if (s) { 125 if (s) {
124 struct unix_sock *u = unix_sk(s); 126 struct unix_sock *u = unix_sk(s);
125 127
126 spin_lock(&unix_gc_lock);
127
128 if (atomic_long_inc_return(&u->inflight) == 1) { 128 if (atomic_long_inc_return(&u->inflight) == 1) {
129 BUG_ON(!list_empty(&u->link)); 129 BUG_ON(!list_empty(&u->link));
130 list_add_tail(&u->link, &gc_inflight_list); 130 list_add_tail(&u->link, &gc_inflight_list);
@@ -132,25 +132,28 @@ void unix_inflight(struct file *fp)
132 BUG_ON(list_empty(&u->link)); 132 BUG_ON(list_empty(&u->link));
133 } 133 }
134 unix_tot_inflight++; 134 unix_tot_inflight++;
135 spin_unlock(&unix_gc_lock);
136 } 135 }
136 fp->f_cred->user->unix_inflight++;
137 spin_unlock(&unix_gc_lock);
137} 138}
138 139
139void unix_notinflight(struct file *fp) 140void unix_notinflight(struct file *fp)
140{ 141{
141 struct sock *s = unix_get_socket(fp); 142 struct sock *s = unix_get_socket(fp);
142 143
144 spin_lock(&unix_gc_lock);
145
143 if (s) { 146 if (s) {
144 struct unix_sock *u = unix_sk(s); 147 struct unix_sock *u = unix_sk(s);
145 148
146 spin_lock(&unix_gc_lock);
147 BUG_ON(list_empty(&u->link)); 149 BUG_ON(list_empty(&u->link));
148 150
149 if (atomic_long_dec_and_test(&u->inflight)) 151 if (atomic_long_dec_and_test(&u->inflight))
150 list_del_init(&u->link); 152 list_del_init(&u->link);
151 unix_tot_inflight--; 153 unix_tot_inflight--;
152 spin_unlock(&unix_gc_lock);
153 } 154 }
155 fp->f_cred->user->unix_inflight--;
156 spin_unlock(&unix_gc_lock);
154} 157}
155 158
156static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), 159static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),