Blame view

crypto/algif_hash.c 9.59 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
fe869cdb8   Herbert Xu   crypto: algif_has...
2
3
4
5
6
7
  /*
   * algif_hash: User-space interface for hash algorithms
   *
   * This file provides the user-space API for hash algorithms.
   *
   * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
fe869cdb8   Herbert Xu   crypto: algif_has...
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   */
  
  #include <crypto/hash.h>
  #include <crypto/if_alg.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/net.h>
  #include <net/sock.h>
  
  struct hash_ctx {
  	struct af_alg_sgl sgl;
  
  	u8 *result;
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
23
  	struct crypto_wait wait;
fe869cdb8   Herbert Xu   crypto: algif_has...
24
25
26
27
28
29
  
  	unsigned int len;
  	bool more;
  
  	struct ahash_request req;
  };
493b2ed3f   Herbert Xu   crypto: algif_has...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  static int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx)
  {
  	unsigned ds;
  
  	if (ctx->result)
  		return 0;
  
  	ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
  
  	ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
  	if (!ctx->result)
  		return -ENOMEM;
  
  	memset(ctx->result, 0, ds);
  
  	return 0;
  }
  
  static void hash_free_result(struct sock *sk, struct hash_ctx *ctx)
  {
  	unsigned ds;
  
  	if (!ctx->result)
  		return;
  
  	ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
  
  	sock_kzfree_s(sk, ctx->result, ds);
  	ctx->result = NULL;
  }
1b7841404   Ying Xue   net: Remove iocb ...
60
61
  static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
  			size_t ignored)
fe869cdb8   Herbert Xu   crypto: algif_has...
62
63
64
65
66
  {
  	int limit = ALG_MAX_PAGES * PAGE_SIZE;
  	struct sock *sk = sock->sk;
  	struct alg_sock *ask = alg_sk(sk);
  	struct hash_ctx *ctx = ask->private;
fe869cdb8   Herbert Xu   crypto: algif_has...
67
68
69
70
71
72
73
74
  	long copied = 0;
  	int err;
  
  	if (limit > sk->sk_sndbuf)
  		limit = sk->sk_sndbuf;
  
  	lock_sock(sk);
  	if (!ctx->more) {
493b2ed3f   Herbert Xu   crypto: algif_has...
75
76
  		if ((msg->msg_flags & MSG_MORE))
  			hash_free_result(sk, ctx);
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
77
  		err = crypto_wait_req(crypto_ahash_init(&ctx->req), &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
78
79
80
81
82
  		if (err)
  			goto unlock;
  	}
  
  	ctx->more = 0;
01e97e651   Al Viro   new helper: msg_d...
83
84
  	while (msg_data_left(msg)) {
  		int len = msg_data_left(msg);
fe869cdb8   Herbert Xu   crypto: algif_has...
85

1d10eb2f1   Al Viro   crypto: switch af...
86
87
  		if (len > limit)
  			len = limit;
fe869cdb8   Herbert Xu   crypto: algif_has...
88

1d10eb2f1   Al Viro   crypto: switch af...
89
90
91
92
93
  		len = af_alg_make_sg(&ctx->sgl, &msg->msg_iter, len);
  		if (len < 0) {
  			err = copied ? 0 : len;
  			goto unlock;
  		}
fe869cdb8   Herbert Xu   crypto: algif_has...
94

1d10eb2f1   Al Viro   crypto: switch af...
95
  		ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, len);
fe869cdb8   Herbert Xu   crypto: algif_has...
96

2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
97
98
  		err = crypto_wait_req(crypto_ahash_update(&ctx->req),
  				      &ctx->wait);
1d10eb2f1   Al Viro   crypto: switch af...
99
100
101
  		af_alg_free_sg(&ctx->sgl);
  		if (err)
  			goto unlock;
fe869cdb8   Herbert Xu   crypto: algif_has...
102

1d10eb2f1   Al Viro   crypto: switch af...
103
104
  		copied += len;
  		iov_iter_advance(&msg->msg_iter, len);
fe869cdb8   Herbert Xu   crypto: algif_has...
105
106
107
108
109
110
  	}
  
  	err = 0;
  
  	ctx->more = msg->msg_flags & MSG_MORE;
  	if (!ctx->more) {
493b2ed3f   Herbert Xu   crypto: algif_has...
111
112
113
  		err = hash_alloc_result(sk, ctx);
  		if (err)
  			goto unlock;
fe869cdb8   Herbert Xu   crypto: algif_has...
114
  		ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
115
116
  		err = crypto_wait_req(crypto_ahash_final(&ctx->req),
  				      &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  	}
  
  unlock:
  	release_sock(sk);
  
  	return err ?: copied;
  }
  
  static ssize_t hash_sendpage(struct socket *sock, struct page *page,
  			     int offset, size_t size, int flags)
  {
  	struct sock *sk = sock->sk;
  	struct alg_sock *ask = alg_sk(sk);
  	struct hash_ctx *ctx = ask->private;
  	int err;
d3f7d56a7   Shawn Landden   net: update consu...
132
133
  	if (flags & MSG_SENDPAGE_NOTLAST)
  		flags |= MSG_MORE;
fe869cdb8   Herbert Xu   crypto: algif_has...
134
135
136
  	lock_sock(sk);
  	sg_init_table(ctx->sgl.sg, 1);
  	sg_set_page(ctx->sgl.sg, page, size, offset);
493b2ed3f   Herbert Xu   crypto: algif_has...
137
138
139
140
141
142
  	if (!(flags & MSG_MORE)) {
  		err = hash_alloc_result(sk, ctx);
  		if (err)
  			goto unlock;
  	} else if (!ctx->more)
  		hash_free_result(sk, ctx);
fe869cdb8   Herbert Xu   crypto: algif_has...
143
144
145
146
147
148
149
150
151
152
  	ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, ctx->result, size);
  
  	if (!(flags & MSG_MORE)) {
  		if (ctx->more)
  			err = crypto_ahash_finup(&ctx->req);
  		else
  			err = crypto_ahash_digest(&ctx->req);
  	} else {
  		if (!ctx->more) {
  			err = crypto_ahash_init(&ctx->req);
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
153
  			err = crypto_wait_req(err, &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
154
155
156
157
158
159
  			if (err)
  				goto unlock;
  		}
  
  		err = crypto_ahash_update(&ctx->req);
  	}
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
160
  	err = crypto_wait_req(err, &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
161
162
163
164
165
166
167
168
169
170
  	if (err)
  		goto unlock;
  
  	ctx->more = flags & MSG_MORE;
  
  unlock:
  	release_sock(sk);
  
  	return err ?: size;
  }
1b7841404   Ying Xue   net: Remove iocb ...
171
172
  static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
  			int flags)
fe869cdb8   Herbert Xu   crypto: algif_has...
173
174
175
176
177
  {
  	struct sock *sk = sock->sk;
  	struct alg_sock *ask = alg_sk(sk);
  	struct hash_ctx *ctx = ask->private;
  	unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
493b2ed3f   Herbert Xu   crypto: algif_has...
178
  	bool result;
fe869cdb8   Herbert Xu   crypto: algif_has...
179
180
181
182
183
184
185
186
  	int err;
  
  	if (len > ds)
  		len = ds;
  	else if (len < ds)
  		msg->msg_flags |= MSG_TRUNC;
  
  	lock_sock(sk);
493b2ed3f   Herbert Xu   crypto: algif_has...
187
188
189
190
191
192
  	result = ctx->result;
  	err = hash_alloc_result(sk, ctx);
  	if (err)
  		goto unlock;
  
  	ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
8acf7a106   Herbert Xu   crypto: algif_has...
193
  	if (!result && !ctx->more) {
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
194
195
  		err = crypto_wait_req(crypto_ahash_init(&ctx->req),
  				      &ctx->wait);
a8348bca2   Herbert Xu   crypto: algif_has...
196
197
198
199
200
  		if (err)
  			goto unlock;
  	}
  
  	if (!result || ctx->more) {
fe869cdb8   Herbert Xu   crypto: algif_has...
201
  		ctx->more = 0;
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
202
203
  		err = crypto_wait_req(crypto_ahash_final(&ctx->req),
  				      &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
204
205
206
  		if (err)
  			goto unlock;
  	}
7eab8d9e8   Al Viro   new helper: memcp...
207
  	err = memcpy_to_msg(msg, ctx->result, len);
fe869cdb8   Herbert Xu   crypto: algif_has...
208
209
  
  unlock:
a8348bca2   Herbert Xu   crypto: algif_has...
210
  	hash_free_result(sk, ctx);
fe869cdb8   Herbert Xu   crypto: algif_has...
211
212
213
214
  	release_sock(sk);
  
  	return err ?: len;
  }
cdfbabfb2   David Howells   net: Work around ...
215
216
  static int hash_accept(struct socket *sock, struct socket *newsock, int flags,
  		       bool kern)
fe869cdb8   Herbert Xu   crypto: algif_has...
217
218
219
220
221
  {
  	struct sock *sk = sock->sk;
  	struct alg_sock *ask = alg_sk(sk);
  	struct hash_ctx *ctx = ask->private;
  	struct ahash_request *req = &ctx->req;
b68a7ec1e   Kees Cook   crypto: hash - Re...
222
  	char state[HASH_MAX_STATESIZE];
fe869cdb8   Herbert Xu   crypto: algif_has...
223
224
225
  	struct sock *sk2;
  	struct alg_sock *ask2;
  	struct hash_ctx *ctx2;
4afa5f961   Herbert Xu   crypto: algif_has...
226
  	bool more;
fe869cdb8   Herbert Xu   crypto: algif_has...
227
  	int err;
4afa5f961   Herbert Xu   crypto: algif_has...
228
229
230
231
  	lock_sock(sk);
  	more = ctx->more;
  	err = more ? crypto_ahash_export(req, state) : 0;
  	release_sock(sk);
fe869cdb8   Herbert Xu   crypto: algif_has...
232
233
  	if (err)
  		return err;
cdfbabfb2   David Howells   net: Work around ...
234
  	err = af_alg_accept(ask->parent, newsock, kern);
fe869cdb8   Herbert Xu   crypto: algif_has...
235
236
237
238
239
240
  	if (err)
  		return err;
  
  	sk2 = newsock->sk;
  	ask2 = alg_sk(sk2);
  	ctx2 = ask2->private;
4afa5f961   Herbert Xu   crypto: algif_has...
241
242
243
244
  	ctx2->more = more;
  
  	if (!more)
  		return err;
fe869cdb8   Herbert Xu   crypto: algif_has...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  
  	err = crypto_ahash_import(&ctx2->req, state);
  	if (err) {
  		sock_orphan(sk2);
  		sock_put(sk2);
  	}
  
  	return err;
  }
  
  static struct proto_ops algif_hash_ops = {
  	.family		=	PF_ALG,
  
  	.connect	=	sock_no_connect,
  	.socketpair	=	sock_no_socketpair,
  	.getname	=	sock_no_getname,
  	.ioctl		=	sock_no_ioctl,
  	.listen		=	sock_no_listen,
  	.shutdown	=	sock_no_shutdown,
  	.getsockopt	=	sock_no_getsockopt,
  	.mmap		=	sock_no_mmap,
  	.bind		=	sock_no_bind,
  	.setsockopt	=	sock_no_setsockopt,
fe869cdb8   Herbert Xu   crypto: algif_has...
268
269
270
271
272
273
274
  
  	.release	=	af_alg_release,
  	.sendmsg	=	hash_sendmsg,
  	.sendpage	=	hash_sendpage,
  	.recvmsg	=	hash_recvmsg,
  	.accept		=	hash_accept,
  };
6de62f15b   Herbert Xu   crypto: algif_has...
275
276
  static int hash_check_key(struct socket *sock)
  {
ad46d7e33   Herbert Xu   crypto: algif_has...
277
  	int err = 0;
6de62f15b   Herbert Xu   crypto: algif_has...
278
279
  	struct sock *psk;
  	struct alg_sock *pask;
9fa68f620   Eric Biggers   crypto: hash - pr...
280
  	struct crypto_ahash *tfm;
6de62f15b   Herbert Xu   crypto: algif_has...
281
282
  	struct sock *sk = sock->sk;
  	struct alg_sock *ask = alg_sk(sk);
ad46d7e33   Herbert Xu   crypto: algif_has...
283
  	lock_sock(sk);
cc0f67835   Herbert Xu   crypto: af_alg - ...
284
  	if (!atomic_read(&ask->nokey_refcnt))
ad46d7e33   Herbert Xu   crypto: algif_has...
285
  		goto unlock_child;
6de62f15b   Herbert Xu   crypto: algif_has...
286
287
288
289
290
291
  
  	psk = ask->parent;
  	pask = alg_sk(ask->parent);
  	tfm = pask->private;
  
  	err = -ENOKEY;
ad46d7e33   Herbert Xu   crypto: algif_has...
292
  	lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
9fa68f620   Eric Biggers   crypto: hash - pr...
293
  	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
6de62f15b   Herbert Xu   crypto: algif_has...
294
  		goto unlock;
cc0f67835   Herbert Xu   crypto: af_alg - ...
295
296
  	atomic_dec(&pask->nokey_refcnt);
  	atomic_set(&ask->nokey_refcnt, 0);
6de62f15b   Herbert Xu   crypto: algif_has...
297
298
299
300
301
  
  	err = 0;
  
  unlock:
  	release_sock(psk);
ad46d7e33   Herbert Xu   crypto: algif_has...
302
303
  unlock_child:
  	release_sock(sk);
6de62f15b   Herbert Xu   crypto: algif_has...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  
  	return err;
  }
  
  static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
  			      size_t size)
  {
  	int err;
  
  	err = hash_check_key(sock);
  	if (err)
  		return err;
  
  	return hash_sendmsg(sock, msg, size);
  }
  
  static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page,
  				   int offset, size_t size, int flags)
  {
  	int err;
  
  	err = hash_check_key(sock);
  	if (err)
  		return err;
  
  	return hash_sendpage(sock, page, offset, size, flags);
  }
  
  static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
  			      size_t ignored, int flags)
  {
  	int err;
  
  	err = hash_check_key(sock);
  	if (err)
  		return err;
  
  	return hash_recvmsg(sock, msg, ignored, flags);
  }
  
  static int hash_accept_nokey(struct socket *sock, struct socket *newsock,
cdfbabfb2   David Howells   net: Work around ...
345
  			     int flags, bool kern)
6de62f15b   Herbert Xu   crypto: algif_has...
346
347
348
349
350
351
  {
  	int err;
  
  	err = hash_check_key(sock);
  	if (err)
  		return err;
cdfbabfb2   David Howells   net: Work around ...
352
  	return hash_accept(sock, newsock, flags, kern);
6de62f15b   Herbert Xu   crypto: algif_has...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  }
  
  static struct proto_ops algif_hash_ops_nokey = {
  	.family		=	PF_ALG,
  
  	.connect	=	sock_no_connect,
  	.socketpair	=	sock_no_socketpair,
  	.getname	=	sock_no_getname,
  	.ioctl		=	sock_no_ioctl,
  	.listen		=	sock_no_listen,
  	.shutdown	=	sock_no_shutdown,
  	.getsockopt	=	sock_no_getsockopt,
  	.mmap		=	sock_no_mmap,
  	.bind		=	sock_no_bind,
  	.setsockopt	=	sock_no_setsockopt,
6de62f15b   Herbert Xu   crypto: algif_has...
368
369
370
371
372
373
374
  
  	.release	=	af_alg_release,
  	.sendmsg	=	hash_sendmsg_nokey,
  	.sendpage	=	hash_sendpage_nokey,
  	.recvmsg	=	hash_recvmsg_nokey,
  	.accept		=	hash_accept_nokey,
  };
fe869cdb8   Herbert Xu   crypto: algif_has...
375
376
  static void *hash_bind(const char *name, u32 type, u32 mask)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
377
  	return crypto_alloc_ahash(name, type, mask);
fe869cdb8   Herbert Xu   crypto: algif_has...
378
379
380
381
  }
  
  static void hash_release(void *private)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
382
  	crypto_free_ahash(private);
fe869cdb8   Herbert Xu   crypto: algif_has...
383
384
385
386
  }
  
  static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
387
  	return crypto_ahash_setkey(private, key, keylen);
fe869cdb8   Herbert Xu   crypto: algif_has...
388
  }
f1d84af18   Herbert Xu   crypto: algif_has...
389
  static void hash_sock_destruct(struct sock *sk)
fe869cdb8   Herbert Xu   crypto: algif_has...
390
391
392
  {
  	struct alg_sock *ask = alg_sk(sk);
  	struct hash_ctx *ctx = ask->private;
493b2ed3f   Herbert Xu   crypto: algif_has...
393
  	hash_free_result(sk, ctx);
fe869cdb8   Herbert Xu   crypto: algif_has...
394
  	sock_kfree_s(sk, ctx, ctx->len);
6de62f15b   Herbert Xu   crypto: algif_has...
395
396
  	af_alg_release_parent(sk);
  }
f1d84af18   Herbert Xu   crypto: algif_has...
397
  static int hash_accept_parent_nokey(void *private, struct sock *sk)
fe869cdb8   Herbert Xu   crypto: algif_has...
398
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
399
  	struct crypto_ahash *tfm = private;
fe869cdb8   Herbert Xu   crypto: algif_has...
400
  	struct alg_sock *ask = alg_sk(sk);
9fa68f620   Eric Biggers   crypto: hash - pr...
401
402
  	struct hash_ctx *ctx;
  	unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
fe869cdb8   Herbert Xu   crypto: algif_has...
403
404
405
406
  
  	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
  	if (!ctx)
  		return -ENOMEM;
493b2ed3f   Herbert Xu   crypto: algif_has...
407
  	ctx->result = NULL;
fe869cdb8   Herbert Xu   crypto: algif_has...
408
409
  	ctx->len = len;
  	ctx->more = 0;
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
410
  	crypto_init_wait(&ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
411
412
  
  	ask->private = ctx;
9fa68f620   Eric Biggers   crypto: hash - pr...
413
  	ahash_request_set_tfm(&ctx->req, tfm);
fe869cdb8   Herbert Xu   crypto: algif_has...
414
  	ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
415
  				   crypto_req_done, &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
416
417
418
419
420
  
  	sk->sk_destruct = hash_sock_destruct;
  
  	return 0;
  }
6de62f15b   Herbert Xu   crypto: algif_has...
421
422
  static int hash_accept_parent(void *private, struct sock *sk)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
423
  	struct crypto_ahash *tfm = private;
6de62f15b   Herbert Xu   crypto: algif_has...
424

9fa68f620   Eric Biggers   crypto: hash - pr...
425
  	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
6de62f15b   Herbert Xu   crypto: algif_has...
426
  		return -ENOKEY;
f1d84af18   Herbert Xu   crypto: algif_has...
427
  	return hash_accept_parent_nokey(private, sk);
6de62f15b   Herbert Xu   crypto: algif_has...
428
  }
fe869cdb8   Herbert Xu   crypto: algif_has...
429
430
431
432
433
  static const struct af_alg_type algif_type_hash = {
  	.bind		=	hash_bind,
  	.release	=	hash_release,
  	.setkey		=	hash_setkey,
  	.accept		=	hash_accept_parent,
6de62f15b   Herbert Xu   crypto: algif_has...
434
  	.accept_nokey	=	hash_accept_parent_nokey,
fe869cdb8   Herbert Xu   crypto: algif_has...
435
  	.ops		=	&algif_hash_ops,
6de62f15b   Herbert Xu   crypto: algif_has...
436
  	.ops_nokey	=	&algif_hash_ops_nokey,
fe869cdb8   Herbert Xu   crypto: algif_has...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  	.name		=	"hash",
  	.owner		=	THIS_MODULE
  };
  
  static int __init algif_hash_init(void)
  {
  	return af_alg_register_type(&algif_type_hash);
  }
  
  static void __exit algif_hash_exit(void)
  {
  	int err = af_alg_unregister_type(&algif_type_hash);
  	BUG_ON(err);
  }
  
  module_init(algif_hash_init);
  module_exit(algif_hash_exit);
  MODULE_LICENSE("GPL");