aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/af_alg.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2015-12-29 22:47:53 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2016-01-18 05:16:09 -0500
commitc840ac6af3f8713a71b4d2363419145760bd6044 (patch)
treec2b3d5d10f5c7eccaec249337e6c3b8821567662 /crypto/af_alg.c
parentdd504589577d8e8e70f51f997ad487a4cb6c026f (diff)
crypto: af_alg - Disallow bind/setkey/... after accept(2)
Each af_alg parent socket obtained by socket(2) corresponds to a tfm object once bind(2) has succeeded. An accept(2) call on that parent socket creates a context which then uses the tfm object. Therefore as long as any child sockets created by accept(2) exist the parent socket must not be modified or freed. This patch guarantees this by using locks and a reference count on the parent socket. Any attempt to modify the parent socket will fail with EBUSY. Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/af_alg.c')
-rw-r--r--crypto/af_alg.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index a8e7aa3e257b..7b5b5926c767 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -125,6 +125,23 @@ int af_alg_release(struct socket *sock)
125} 125}
126EXPORT_SYMBOL_GPL(af_alg_release); 126EXPORT_SYMBOL_GPL(af_alg_release);
127 127
128void af_alg_release_parent(struct sock *sk)
129{
130 struct alg_sock *ask = alg_sk(sk);
131 bool last;
132
133 sk = ask->parent;
134 ask = alg_sk(sk);
135
136 lock_sock(sk);
137 last = !--ask->refcnt;
138 release_sock(sk);
139
140 if (last)
141 sock_put(sk);
142}
143EXPORT_SYMBOL_GPL(af_alg_release_parent);
144
128static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 145static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
129{ 146{
130 const u32 forbidden = CRYPTO_ALG_INTERNAL; 147 const u32 forbidden = CRYPTO_ALG_INTERNAL;
@@ -133,6 +150,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
133 struct sockaddr_alg *sa = (void *)uaddr; 150 struct sockaddr_alg *sa = (void *)uaddr;
134 const struct af_alg_type *type; 151 const struct af_alg_type *type;
135 void *private; 152 void *private;
153 int err;
136 154
137 if (sock->state == SS_CONNECTED) 155 if (sock->state == SS_CONNECTED)
138 return -EINVAL; 156 return -EINVAL;
@@ -160,16 +178,22 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
160 return PTR_ERR(private); 178 return PTR_ERR(private);
161 } 179 }
162 180
181 err = -EBUSY;
163 lock_sock(sk); 182 lock_sock(sk);
183 if (ask->refcnt)
184 goto unlock;
164 185
165 swap(ask->type, type); 186 swap(ask->type, type);
166 swap(ask->private, private); 187 swap(ask->private, private);
167 188
189 err = 0;
190
191unlock:
168 release_sock(sk); 192 release_sock(sk);
169 193
170 alg_do_release(type, private); 194 alg_do_release(type, private);
171 195
172 return 0; 196 return err;
173} 197}
174 198
175static int alg_setkey(struct sock *sk, char __user *ukey, 199static int alg_setkey(struct sock *sk, char __user *ukey,
@@ -202,11 +226,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
202 struct sock *sk = sock->sk; 226 struct sock *sk = sock->sk;
203 struct alg_sock *ask = alg_sk(sk); 227 struct alg_sock *ask = alg_sk(sk);
204 const struct af_alg_type *type; 228 const struct af_alg_type *type;
205 int err = -ENOPROTOOPT; 229 int err = -EBUSY;
206 230
207 lock_sock(sk); 231 lock_sock(sk);
232 if (ask->refcnt)
233 goto unlock;
234
208 type = ask->type; 235 type = ask->type;
209 236
237 err = -ENOPROTOOPT;
210 if (level != SOL_ALG || !type) 238 if (level != SOL_ALG || !type)
211 goto unlock; 239 goto unlock;
212 240
@@ -264,7 +292,8 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
264 292
265 sk2->sk_family = PF_ALG; 293 sk2->sk_family = PF_ALG;
266 294
267 sock_hold(sk); 295 if (!ask->refcnt++)
296 sock_hold(sk);
268 alg_sk(sk2)->parent = sk; 297 alg_sk(sk2)->parent = sk;
269 alg_sk(sk2)->type = type; 298 alg_sk(sk2)->type = type;
270 299