diff options
Diffstat (limited to 'net/tipc/crypto.c')
| -rw-r--r-- | net/tipc/crypto.c | 44 | 
1 files changed, 29 insertions, 15 deletions
diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c index c9391d38de85..b4d9419a015b 100644 --- a/net/tipc/crypto.c +++ b/net/tipc/crypto.c @@ -524,7 +524,7 @@ static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,  		return -EEXIST;  	/* Allocate a new AEAD */ -	tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); +	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);  	if (unlikely(!tmp))  		return -ENOMEM; @@ -597,6 +597,10 @@ static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,  	tmp->cloned = NULL;  	tmp->authsize = TIPC_AES_GCM_TAG_SIZE;  	tmp->key = kmemdup(ukey, tipc_aead_key_size(ukey), GFP_KERNEL); +	if (!tmp->key) { +		tipc_aead_free(&tmp->rcu); +		return -ENOMEM; +	}  	memcpy(&tmp->salt, ukey->key + keylen, TIPC_AES_GCM_SALT_SIZE);  	atomic_set(&tmp->users, 0);  	atomic64_set(&tmp->seqno, 0); @@ -1470,7 +1474,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,  		return -EEXIST;  	/* Allocate crypto */ -	c = kzalloc(sizeof(*c), GFP_ATOMIC); +	c = kzalloc(sizeof(*c), GFP_KERNEL);  	if (!c)  		return -ENOMEM; @@ -1484,7 +1488,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,  	}  	/* Allocate statistic structure */ -	c->stats = alloc_percpu_gfp(struct tipc_crypto_stats, GFP_ATOMIC); +	c->stats = alloc_percpu(struct tipc_crypto_stats);  	if (!c->stats) {  		if (c->wq)  			destroy_workqueue(c->wq); @@ -2285,43 +2289,53 @@ static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)  	u16 key_gen = msg_key_gen(hdr);  	u16 size = msg_data_sz(hdr);  	u8 *data = msg_data(hdr); +	unsigned int keylen; + +	/* Verify whether the size can exist in the packet */ +	if (unlikely(size < sizeof(struct tipc_aead_key) + TIPC_AEAD_KEYLEN_MIN)) { +		pr_debug("%s: message data size is too small\n", rx->name); +		goto exit; +	} + +	keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME))); + +	/* Verify the supplied size values */ +	if (unlikely(size != keylen + sizeof(struct tipc_aead_key) || +		     keylen > TIPC_AEAD_KEY_SIZE_MAX)) { +		pr_debug("%s: invalid MSG_CRYPTO key size\n", rx->name); +		goto exit; +	}  	spin_lock(&rx->lock);  	if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) {  		pr_err("%s: key existed <%p>, gen %d vs %d\n", rx->name,  		       rx->skey, key_gen, rx->key_gen); -		goto exit; +		goto exit_unlock;  	}  	/* Allocate memory for the key */  	skey = kmalloc(size, GFP_ATOMIC);  	if (unlikely(!skey)) {  		pr_err("%s: unable to allocate memory for skey\n", rx->name); -		goto exit; +		goto exit_unlock;  	}  	/* Copy key from msg data */ -	skey->keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME))); +	skey->keylen = keylen;  	memcpy(skey->alg_name, data, TIPC_AEAD_ALG_NAME);  	memcpy(skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32),  	       skey->keylen); -	/* Sanity check */ -	if (unlikely(size != tipc_aead_key_size(skey))) { -		kfree(skey); -		skey = NULL; -		goto exit; -	} -  	rx->key_gen = key_gen;  	rx->skey_mode = msg_key_mode(hdr);  	rx->skey = skey;  	rx->nokey = 0;  	mb(); /* for nokey flag */ -exit: +exit_unlock:  	spin_unlock(&rx->lock); +exit:  	/* Schedule the key attaching on this crypto */  	if (likely(skey && queue_delayed_work(tx->wq, &rx->work, 0)))  		return true; @@ -2447,7 +2461,7 @@ static void tipc_crypto_work_tx(struct work_struct *work)  	}  	/* Lets duplicate it first */ -	skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC); +	skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_KERNEL);  	rcu_read_unlock();  	/* Now, generate new key, initiate & distribute it */  | 
