Commit 2cfa46da authored by Linus Torvalds's avatar Linus Torvalds

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()
parents b6509f6a e04ec0de
...@@ -128,21 +128,15 @@ EXPORT_SYMBOL_GPL(af_alg_release); ...@@ -128,21 +128,15 @@ EXPORT_SYMBOL_GPL(af_alg_release);
void af_alg_release_parent(struct sock *sk) void af_alg_release_parent(struct sock *sk)
{ {
struct alg_sock *ask = alg_sk(sk); struct alg_sock *ask = alg_sk(sk);
unsigned int nokey = ask->nokey_refcnt; unsigned int nokey = atomic_read(&ask->nokey_refcnt);
bool last = nokey && !ask->refcnt;
sk = ask->parent; sk = ask->parent;
ask = alg_sk(sk); ask = alg_sk(sk);
local_bh_disable(); if (nokey)
bh_lock_sock(sk); atomic_dec(&ask->nokey_refcnt);
ask->nokey_refcnt -= nokey;
if (!last)
last = !--ask->refcnt;
bh_unlock_sock(sk);
local_bh_enable();
if (last) if (atomic_dec_and_test(&ask->refcnt))
sock_put(sk); sock_put(sk);
} }
EXPORT_SYMBOL_GPL(af_alg_release_parent); EXPORT_SYMBOL_GPL(af_alg_release_parent);
...@@ -187,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -187,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
err = -EBUSY; err = -EBUSY;
lock_sock(sk); lock_sock(sk);
if (ask->refcnt | ask->nokey_refcnt) if (atomic_read(&ask->refcnt))
goto unlock; goto unlock;
swap(ask->type, type); swap(ask->type, type);
...@@ -236,7 +230,7 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, ...@@ -236,7 +230,7 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
int err = -EBUSY; int err = -EBUSY;
lock_sock(sk); lock_sock(sk);
if (ask->refcnt) if (atomic_read(&ask->refcnt) != atomic_read(&ask->nokey_refcnt))
goto unlock; goto unlock;
type = ask->type; type = ask->type;
...@@ -301,12 +295,14 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern) ...@@ -301,12 +295,14 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
if (err) if (err)
goto unlock; goto unlock;
if (nokey || !ask->refcnt++) if (atomic_inc_return_relaxed(&ask->refcnt) == 1)
sock_hold(sk); sock_hold(sk);
ask->nokey_refcnt += nokey; if (nokey) {
atomic_inc(&ask->nokey_refcnt);
atomic_set(&alg_sk(sk2)->nokey_refcnt, 1);
}
alg_sk(sk2)->parent = sk; alg_sk(sk2)->parent = sk;
alg_sk(sk2)->type = type; alg_sk(sk2)->type = type;
alg_sk(sk2)->nokey_refcnt = nokey;
newsock->ops = type->ops; newsock->ops = type->ops;
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
......
...@@ -384,7 +384,7 @@ static int aead_check_key(struct socket *sock) ...@@ -384,7 +384,7 @@ static int aead_check_key(struct socket *sock)
struct alg_sock *ask = alg_sk(sk); struct alg_sock *ask = alg_sk(sk);
lock_sock(sk); lock_sock(sk);
if (ask->refcnt) if (!atomic_read(&ask->nokey_refcnt))
goto unlock_child; goto unlock_child;
psk = ask->parent; psk = ask->parent;
...@@ -396,11 +396,8 @@ static int aead_check_key(struct socket *sock) ...@@ -396,11 +396,8 @@ static int aead_check_key(struct socket *sock)
if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
goto unlock; goto unlock;
if (!pask->refcnt++) atomic_dec(&pask->nokey_refcnt);
sock_hold(psk); atomic_set(&ask->nokey_refcnt, 0);
ask->refcnt = 1;
sock_put(psk);
err = 0; err = 0;
......
...@@ -301,7 +301,7 @@ static int hash_check_key(struct socket *sock) ...@@ -301,7 +301,7 @@ static int hash_check_key(struct socket *sock)
struct alg_sock *ask = alg_sk(sk); struct alg_sock *ask = alg_sk(sk);
lock_sock(sk); lock_sock(sk);
if (ask->refcnt) if (!atomic_read(&ask->nokey_refcnt))
goto unlock_child; goto unlock_child;
psk = ask->parent; psk = ask->parent;
...@@ -313,11 +313,8 @@ static int hash_check_key(struct socket *sock) ...@@ -313,11 +313,8 @@ static int hash_check_key(struct socket *sock)
if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
goto unlock; goto unlock;
if (!pask->refcnt++) atomic_dec(&pask->nokey_refcnt);
sock_hold(psk); atomic_set(&ask->nokey_refcnt, 0);
ask->refcnt = 1;
sock_put(psk);
err = 0; err = 0;
......
...@@ -211,7 +211,7 @@ static int skcipher_check_key(struct socket *sock) ...@@ -211,7 +211,7 @@ static int skcipher_check_key(struct socket *sock)
struct alg_sock *ask = alg_sk(sk); struct alg_sock *ask = alg_sk(sk);
lock_sock(sk); lock_sock(sk);
if (ask->refcnt) if (!atomic_read(&ask->nokey_refcnt))
goto unlock_child; goto unlock_child;
psk = ask->parent; psk = ask->parent;
...@@ -223,11 +223,8 @@ static int skcipher_check_key(struct socket *sock) ...@@ -223,11 +223,8 @@ static int skcipher_check_key(struct socket *sock)
if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
goto unlock; goto unlock;
if (!pask->refcnt++) atomic_dec(&pask->nokey_refcnt);
sock_hold(psk); atomic_set(&ask->nokey_refcnt, 0);
ask->refcnt = 1;
sock_put(psk);
err = 0; err = 0;
......
...@@ -29,8 +29,8 @@ struct alg_sock { ...@@ -29,8 +29,8 @@ struct alg_sock {
struct sock *parent; struct sock *parent;
unsigned int refcnt; atomic_t refcnt;
unsigned int nokey_refcnt; atomic_t nokey_refcnt;
const struct af_alg_type *type; const struct af_alg_type *type;
void *private; void *private;
......
...@@ -335,7 +335,7 @@ static void padata_reorder(struct parallel_data *pd) ...@@ -335,7 +335,7 @@ static void padata_reorder(struct parallel_data *pd)
* *
* Ensure reorder queue is read after pd->lock is dropped so we see * Ensure reorder queue is read after pd->lock is dropped so we see
* new objects from another task in padata_do_serial. Pairs with * new objects from another task in padata_do_serial. Pairs with
* smp_mb__after_atomic in padata_do_serial. * smp_mb in padata_do_serial.
*/ */
smp_mb(); smp_mb();
...@@ -418,7 +418,7 @@ void padata_do_serial(struct padata_priv *padata) ...@@ -418,7 +418,7 @@ void padata_do_serial(struct padata_priv *padata)
* with the trylock of pd->lock in padata_reorder. Pairs with smp_mb * with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
* in padata_reorder. * in padata_reorder.
*/ */
smp_mb__after_atomic(); smp_mb();
padata_reorder(pd); padata_reorder(pd);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment