Skip to content

Commit 2cfa46d

Browse files
committed
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto fixes from Herbert Xu: "This fixes two race conditions, one in padata and one in af_alg" * 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: padata: upgrade smp_mb__after_atomic to smp_mb in padata_do_serial crypto: af_alg - fix use-after-free in af_alg_accept() due to bh_lock_sock()
2 parents b6509f6 + e04ec0d commit 2cfa46d

File tree

6 files changed

+24
-37
lines changed

6 files changed

+24
-37
lines changed

crypto/af_alg.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -128,21 +128,15 @@ EXPORT_SYMBOL_GPL(af_alg_release);
128128
void af_alg_release_parent(struct sock *sk)
129129
{
130130
struct alg_sock *ask = alg_sk(sk);
131-
unsigned int nokey = ask->nokey_refcnt;
132-
bool last = nokey && !ask->refcnt;
131+
unsigned int nokey = atomic_read(&ask->nokey_refcnt);
133132

134133
sk = ask->parent;
135134
ask = alg_sk(sk);
136135

137-
local_bh_disable();
138-
bh_lock_sock(sk);
139-
ask->nokey_refcnt -= nokey;
140-
if (!last)
141-
last = !--ask->refcnt;
142-
bh_unlock_sock(sk);
143-
local_bh_enable();
136+
if (nokey)
137+
atomic_dec(&ask->nokey_refcnt);
144138

145-
if (last)
139+
if (atomic_dec_and_test(&ask->refcnt))
146140
sock_put(sk);
147141
}
148142
EXPORT_SYMBOL_GPL(af_alg_release_parent);
@@ -187,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
187181

188182
err = -EBUSY;
189183
lock_sock(sk);
190-
if (ask->refcnt | ask->nokey_refcnt)
184+
if (atomic_read(&ask->refcnt))
191185
goto unlock;
192186

193187
swap(ask->type, type);
@@ -236,7 +230,7 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
236230
int err = -EBUSY;
237231

238232
lock_sock(sk);
239-
if (ask->refcnt)
233+
if (atomic_read(&ask->refcnt) != atomic_read(&ask->nokey_refcnt))
240234
goto unlock;
241235

242236
type = ask->type;
@@ -301,12 +295,14 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
301295
if (err)
302296
goto unlock;
303297

304-
if (nokey || !ask->refcnt++)
298+
if (atomic_inc_return_relaxed(&ask->refcnt) == 1)
305299
sock_hold(sk);
306-
ask->nokey_refcnt += nokey;
300+
if (nokey) {
301+
atomic_inc(&ask->nokey_refcnt);
302+
atomic_set(&alg_sk(sk2)->nokey_refcnt, 1);
303+
}
307304
alg_sk(sk2)->parent = sk;
308305
alg_sk(sk2)->type = type;
309-
alg_sk(sk2)->nokey_refcnt = nokey;
310306

311307
newsock->ops = type->ops;
312308
newsock->state = SS_CONNECTED;

crypto/algif_aead.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ static int aead_check_key(struct socket *sock)
384384
struct alg_sock *ask = alg_sk(sk);
385385

386386
lock_sock(sk);
387-
if (ask->refcnt)
387+
if (!atomic_read(&ask->nokey_refcnt))
388388
goto unlock_child;
389389

390390
psk = ask->parent;
@@ -396,11 +396,8 @@ static int aead_check_key(struct socket *sock)
396396
if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
397397
goto unlock;
398398

399-
if (!pask->refcnt++)
400-
sock_hold(psk);
401-
402-
ask->refcnt = 1;
403-
sock_put(psk);
399+
atomic_dec(&pask->nokey_refcnt);
400+
atomic_set(&ask->nokey_refcnt, 0);
404401

405402
err = 0;
406403

crypto/algif_hash.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ static int hash_check_key(struct socket *sock)
301301
struct alg_sock *ask = alg_sk(sk);
302302

303303
lock_sock(sk);
304-
if (ask->refcnt)
304+
if (!atomic_read(&ask->nokey_refcnt))
305305
goto unlock_child;
306306

307307
psk = ask->parent;
@@ -313,11 +313,8 @@ static int hash_check_key(struct socket *sock)
313313
if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
314314
goto unlock;
315315

316-
if (!pask->refcnt++)
317-
sock_hold(psk);
318-
319-
ask->refcnt = 1;
320-
sock_put(psk);
316+
atomic_dec(&pask->nokey_refcnt);
317+
atomic_set(&ask->nokey_refcnt, 0);
321318

322319
err = 0;
323320

crypto/algif_skcipher.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ static int skcipher_check_key(struct socket *sock)
211211
struct alg_sock *ask = alg_sk(sk);
212212

213213
lock_sock(sk);
214-
if (ask->refcnt)
214+
if (!atomic_read(&ask->nokey_refcnt))
215215
goto unlock_child;
216216

217217
psk = ask->parent;
@@ -223,11 +223,8 @@ static int skcipher_check_key(struct socket *sock)
223223
if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
224224
goto unlock;
225225

226-
if (!pask->refcnt++)
227-
sock_hold(psk);
228-
229-
ask->refcnt = 1;
230-
sock_put(psk);
226+
atomic_dec(&pask->nokey_refcnt);
227+
atomic_set(&ask->nokey_refcnt, 0);
231228

232229
err = 0;
233230

include/crypto/if_alg.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ struct alg_sock {
2929

3030
struct sock *parent;
3131

32-
unsigned int refcnt;
33-
unsigned int nokey_refcnt;
32+
atomic_t refcnt;
33+
atomic_t nokey_refcnt;
3434

3535
const struct af_alg_type *type;
3636
void *private;

kernel/padata.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ static void padata_reorder(struct parallel_data *pd)
335335
*
336336
* Ensure reorder queue is read after pd->lock is dropped so we see
337337
* new objects from another task in padata_do_serial. Pairs with
338-
* smp_mb__after_atomic in padata_do_serial.
338+
* smp_mb in padata_do_serial.
339339
*/
340340
smp_mb();
341341

@@ -418,7 +418,7 @@ void padata_do_serial(struct padata_priv *padata)
418418
* with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
419419
* in padata_reorder.
420420
*/
421-
smp_mb__after_atomic();
421+
smp_mb();
422422

423423
padata_reorder(pd);
424424
}

0 commit comments

Comments
 (0)