diff options
author | David S. Miller <davem@davemloft.net> | 2016-01-11 23:55:43 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-01-11 23:55:43 -0500 |
commit | 9d367eddf363553c7668ba92c3b9d187ec4f71f7 (patch) | |
tree | 4f06d334d316390cc9a869ce3e74ec48d32ed0f8 /net/unix | |
parent | b6a0e72ad3cffabaf30b856deb58fbe64a0f36a8 (diff) | |
parent | 03d84a5f83a67e692af00a3d3901e7820e3e84d5 (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.c | 24 | ||||
-rw-r--r-- | net/unix/garbage.c | 13 |
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 | */ | ||
1522 | static 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 | ||
1518 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | 1533 | static 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 | ||
139 | void unix_notinflight(struct file *fp) | 140 | void 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 | ||
156 | static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), | 159 | static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), |