Skip to content

Commit 6de62f1

Browse files
committed
crypto: algif_hash - Require setkey before accept(2)
Hash implementations that require a key may crash if you use them without setting a key. This patch adds the necessary checks so that if you do attempt to use them without a key that we return -ENOKEY instead of proceeding. This patch also adds a compatibility path to support old applications that do acept(2) before setkey. Cc: [email protected] Signed-off-by: Herbert Xu <[email protected]>
1 parent a5596d6 commit 6de62f1

File tree

1 file changed

+193
-8
lines changed

1 file changed

+193
-8
lines changed

crypto/algif_hash.c

Lines changed: 193 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ struct hash_ctx {
3434
struct ahash_request req;
3535
};
3636

37+
struct algif_hash_tfm {
38+
struct crypto_ahash *hash;
39+
bool has_key;
40+
};
41+
3742
static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
3843
size_t ignored)
3944
{
@@ -235,38 +240,192 @@ static struct proto_ops algif_hash_ops = {
235240
.accept = hash_accept,
236241
};
237242

243+
static int hash_check_key(struct socket *sock)
244+
{
245+
int err;
246+
struct sock *psk;
247+
struct alg_sock *pask;
248+
struct algif_hash_tfm *tfm;
249+
struct sock *sk = sock->sk;
250+
struct alg_sock *ask = alg_sk(sk);
251+
252+
if (ask->refcnt)
253+
return 0;
254+
255+
psk = ask->parent;
256+
pask = alg_sk(ask->parent);
257+
tfm = pask->private;
258+
259+
err = -ENOKEY;
260+
lock_sock(psk);
261+
if (!tfm->has_key)
262+
goto unlock;
263+
264+
if (!pask->refcnt++)
265+
sock_hold(psk);
266+
267+
ask->refcnt = 1;
268+
sock_put(psk);
269+
270+
err = 0;
271+
272+
unlock:
273+
release_sock(psk);
274+
275+
return err;
276+
}
277+
278+
static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
279+
size_t size)
280+
{
281+
int err;
282+
283+
err = hash_check_key(sock);
284+
if (err)
285+
return err;
286+
287+
return hash_sendmsg(sock, msg, size);
288+
}
289+
290+
static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page,
291+
int offset, size_t size, int flags)
292+
{
293+
int err;
294+
295+
err = hash_check_key(sock);
296+
if (err)
297+
return err;
298+
299+
return hash_sendpage(sock, page, offset, size, flags);
300+
}
301+
302+
static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
303+
size_t ignored, int flags)
304+
{
305+
int err;
306+
307+
err = hash_check_key(sock);
308+
if (err)
309+
return err;
310+
311+
return hash_recvmsg(sock, msg, ignored, flags);
312+
}
313+
314+
static int hash_accept_nokey(struct socket *sock, struct socket *newsock,
315+
int flags)
316+
{
317+
int err;
318+
319+
err = hash_check_key(sock);
320+
if (err)
321+
return err;
322+
323+
return hash_accept(sock, newsock, flags);
324+
}
325+
326+
static struct proto_ops algif_hash_ops_nokey = {
327+
.family = PF_ALG,
328+
329+
.connect = sock_no_connect,
330+
.socketpair = sock_no_socketpair,
331+
.getname = sock_no_getname,
332+
.ioctl = sock_no_ioctl,
333+
.listen = sock_no_listen,
334+
.shutdown = sock_no_shutdown,
335+
.getsockopt = sock_no_getsockopt,
336+
.mmap = sock_no_mmap,
337+
.bind = sock_no_bind,
338+
.setsockopt = sock_no_setsockopt,
339+
.poll = sock_no_poll,
340+
341+
.release = af_alg_release,
342+
.sendmsg = hash_sendmsg_nokey,
343+
.sendpage = hash_sendpage_nokey,
344+
.recvmsg = hash_recvmsg_nokey,
345+
.accept = hash_accept_nokey,
346+
};
347+
238348
static void *hash_bind(const char *name, u32 type, u32 mask)
239349
{
240-
return crypto_alloc_ahash(name, type, mask);
350+
struct algif_hash_tfm *tfm;
351+
struct crypto_ahash *hash;
352+
353+
tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
354+
if (!tfm)
355+
return ERR_PTR(-ENOMEM);
356+
357+
hash = crypto_alloc_ahash(name, type, mask);
358+
if (IS_ERR(hash)) {
359+
kfree(tfm);
360+
return ERR_CAST(hash);
361+
}
362+
363+
tfm->hash = hash;
364+
365+
return tfm;
241366
}
242367

243368
static void hash_release(void *private)
244369
{
245-
crypto_free_ahash(private);
370+
struct algif_hash_tfm *tfm = private;
371+
372+
crypto_free_ahash(tfm->hash);
373+
kfree(tfm);
246374
}
247375

248376
static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
249377
{
250-
return crypto_ahash_setkey(private, key, keylen);
378+
struct algif_hash_tfm *tfm = private;
379+
int err;
380+
381+
err = crypto_ahash_setkey(tfm->hash, key, keylen);
382+
tfm->has_key = !err;
383+
384+
return err;
251385
}
252386

253-
static void hash_sock_destruct(struct sock *sk)
387+
static void hash_sock_destruct_common(struct sock *sk)
254388
{
255389
struct alg_sock *ask = alg_sk(sk);
256390
struct hash_ctx *ctx = ask->private;
257391

258392
sock_kzfree_s(sk, ctx->result,
259393
crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)));
260394
sock_kfree_s(sk, ctx, ctx->len);
395+
}
396+
397+
static void hash_sock_destruct(struct sock *sk)
398+
{
399+
hash_sock_destruct_common(sk);
261400
af_alg_release_parent(sk);
262401
}
263402

264-
static int hash_accept_parent(void *private, struct sock *sk)
403+
static void hash_release_parent_nokey(struct sock *sk)
404+
{
405+
struct alg_sock *ask = alg_sk(sk);
406+
407+
if (!ask->refcnt) {
408+
sock_put(ask->parent);
409+
return;
410+
}
411+
412+
af_alg_release_parent(sk);
413+
}
414+
415+
static void hash_sock_destruct_nokey(struct sock *sk)
416+
{
417+
hash_sock_destruct_common(sk);
418+
hash_release_parent_nokey(sk);
419+
}
420+
421+
static int hash_accept_parent_common(void *private, struct sock *sk)
265422
{
266423
struct hash_ctx *ctx;
267424
struct alg_sock *ask = alg_sk(sk);
268-
unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private);
269-
unsigned ds = crypto_ahash_digestsize(private);
425+
struct algif_hash_tfm *tfm = private;
426+
struct crypto_ahash *hash = tfm->hash;
427+
unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
428+
unsigned ds = crypto_ahash_digestsize(hash);
270429

271430
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
272431
if (!ctx)
@@ -286,7 +445,7 @@ static int hash_accept_parent(void *private, struct sock *sk)
286445

287446
ask->private = ctx;
288447

289-
ahash_request_set_tfm(&ctx->req, private);
448+
ahash_request_set_tfm(&ctx->req, hash);
290449
ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
291450
af_alg_complete, &ctx->completion);
292451

@@ -295,12 +454,38 @@ static int hash_accept_parent(void *private, struct sock *sk)
295454
return 0;
296455
}
297456

457+
static int hash_accept_parent(void *private, struct sock *sk)
458+
{
459+
struct algif_hash_tfm *tfm = private;
460+
461+
if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash))
462+
return -ENOKEY;
463+
464+
return hash_accept_parent_common(private, sk);
465+
}
466+
467+
static int hash_accept_parent_nokey(void *private, struct sock *sk)
468+
{
469+
int err;
470+
471+
err = hash_accept_parent_common(private, sk);
472+
if (err)
473+
goto out;
474+
475+
sk->sk_destruct = hash_sock_destruct_nokey;
476+
477+
out:
478+
return err;
479+
}
480+
298481
static const struct af_alg_type algif_type_hash = {
299482
.bind = hash_bind,
300483
.release = hash_release,
301484
.setkey = hash_setkey,
302485
.accept = hash_accept_parent,
486+
.accept_nokey = hash_accept_parent_nokey,
303487
.ops = &algif_hash_ops,
488+
.ops_nokey = &algif_hash_ops_nokey,
304489
.name = "hash",
305490
.owner = THIS_MODULE
306491
};

0 commit comments

Comments
 (0)