Blame view

crypto/algif_hash.c 9.58 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);
6de62f15b   Herbert Xu   crypto: algif_has...
284
  	if (ask->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
295
296
297
298
299
300
301
302
303
304
305
  		goto unlock;
  
  	if (!pask->refcnt++)
  		sock_hold(psk);
  
  	ask->refcnt = 1;
  	sock_put(psk);
  
  	err = 0;
  
  unlock:
  	release_sock(psk);
ad46d7e33   Herbert Xu   crypto: algif_has...
306
307
  unlock_child:
  	release_sock(sk);
6de62f15b   Herbert Xu   crypto: algif_has...
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
345
346
347
348
  
  	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 ...
349
  			     int flags, bool kern)
6de62f15b   Herbert Xu   crypto: algif_has...
350
351
352
353
354
355
  {
  	int err;
  
  	err = hash_check_key(sock);
  	if (err)
  		return err;
cdfbabfb2   David Howells   net: Work around ...
356
  	return hash_accept(sock, newsock, flags, kern);
6de62f15b   Herbert Xu   crypto: algif_has...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  }
  
  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...
372
373
374
375
376
377
378
  
  	.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...
379
380
  static void *hash_bind(const char *name, u32 type, u32 mask)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
381
  	return crypto_alloc_ahash(name, type, mask);
fe869cdb8   Herbert Xu   crypto: algif_has...
382
383
384
385
  }
  
  static void hash_release(void *private)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
386
  	crypto_free_ahash(private);
fe869cdb8   Herbert Xu   crypto: algif_has...
387
388
389
390
  }
  
  static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
391
  	return crypto_ahash_setkey(private, key, keylen);
fe869cdb8   Herbert Xu   crypto: algif_has...
392
  }
f1d84af18   Herbert Xu   crypto: algif_has...
393
  static void hash_sock_destruct(struct sock *sk)
fe869cdb8   Herbert Xu   crypto: algif_has...
394
395
396
  {
  	struct alg_sock *ask = alg_sk(sk);
  	struct hash_ctx *ctx = ask->private;
493b2ed3f   Herbert Xu   crypto: algif_has...
397
  	hash_free_result(sk, ctx);
fe869cdb8   Herbert Xu   crypto: algif_has...
398
  	sock_kfree_s(sk, ctx, ctx->len);
6de62f15b   Herbert Xu   crypto: algif_has...
399
400
  	af_alg_release_parent(sk);
  }
f1d84af18   Herbert Xu   crypto: algif_has...
401
  static int hash_accept_parent_nokey(void *private, struct sock *sk)
fe869cdb8   Herbert Xu   crypto: algif_has...
402
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
403
  	struct crypto_ahash *tfm = private;
fe869cdb8   Herbert Xu   crypto: algif_has...
404
  	struct alg_sock *ask = alg_sk(sk);
9fa68f620   Eric Biggers   crypto: hash - pr...
405
406
  	struct hash_ctx *ctx;
  	unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
fe869cdb8   Herbert Xu   crypto: algif_has...
407
408
409
410
  
  	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
  	if (!ctx)
  		return -ENOMEM;
493b2ed3f   Herbert Xu   crypto: algif_has...
411
  	ctx->result = NULL;
fe869cdb8   Herbert Xu   crypto: algif_has...
412
413
  	ctx->len = len;
  	ctx->more = 0;
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
414
  	crypto_init_wait(&ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
415
416
  
  	ask->private = ctx;
9fa68f620   Eric Biggers   crypto: hash - pr...
417
  	ahash_request_set_tfm(&ctx->req, tfm);
fe869cdb8   Herbert Xu   crypto: algif_has...
418
  	ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
2c3f8b162   Gilad Ben-Yossef   crypto: algif - m...
419
  				   crypto_req_done, &ctx->wait);
fe869cdb8   Herbert Xu   crypto: algif_has...
420
421
422
423
424
  
  	sk->sk_destruct = hash_sock_destruct;
  
  	return 0;
  }
6de62f15b   Herbert Xu   crypto: algif_has...
425
426
  static int hash_accept_parent(void *private, struct sock *sk)
  {
9fa68f620   Eric Biggers   crypto: hash - pr...
427
  	struct crypto_ahash *tfm = private;
6de62f15b   Herbert Xu   crypto: algif_has...
428

9fa68f620   Eric Biggers   crypto: hash - pr...
429
  	if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
6de62f15b   Herbert Xu   crypto: algif_has...
430
  		return -ENOKEY;
f1d84af18   Herbert Xu   crypto: algif_has...
431
  	return hash_accept_parent_nokey(private, sk);
6de62f15b   Herbert Xu   crypto: algif_has...
432
  }
fe869cdb8   Herbert Xu   crypto: algif_has...
433
434
435
436
437
  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...
438
  	.accept_nokey	=	hash_accept_parent_nokey,
fe869cdb8   Herbert Xu   crypto: algif_has...
439
  	.ops		=	&algif_hash_ops,
6de62f15b   Herbert Xu   crypto: algif_has...
440
  	.ops_nokey	=	&algif_hash_ops_nokey,
fe869cdb8   Herbert Xu   crypto: algif_has...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  	.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");