Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/algif_hash.c
26131 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* algif_hash: User-space interface for hash algorithms
4
*
5
* This file provides the user-space API for hash algorithms.
6
*
7
* Copyright (c) 2010 Herbert Xu <[email protected]>
8
*/
9
10
#include <crypto/hash.h>
11
#include <crypto/if_alg.h>
12
#include <linux/init.h>
13
#include <linux/kernel.h>
14
#include <linux/mm.h>
15
#include <linux/module.h>
16
#include <linux/net.h>
17
#include <net/sock.h>
18
19
struct hash_ctx {
20
struct af_alg_sgl sgl;
21
22
u8 *result;
23
24
struct crypto_wait wait;
25
26
unsigned int len;
27
bool more;
28
29
struct ahash_request req;
30
};
31
32
static int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx)
33
{
34
unsigned ds;
35
36
if (ctx->result)
37
return 0;
38
39
ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
40
41
ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
42
if (!ctx->result)
43
return -ENOMEM;
44
45
memset(ctx->result, 0, ds);
46
47
return 0;
48
}
49
50
static void hash_free_result(struct sock *sk, struct hash_ctx *ctx)
51
{
52
unsigned ds;
53
54
if (!ctx->result)
55
return;
56
57
ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
58
59
sock_kzfree_s(sk, ctx->result, ds);
60
ctx->result = NULL;
61
}
62
63
static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
64
size_t ignored)
65
{
66
struct sock *sk = sock->sk;
67
struct alg_sock *ask = alg_sk(sk);
68
struct hash_ctx *ctx = ask->private;
69
ssize_t copied = 0;
70
size_t len, max_pages, npages;
71
bool continuing, need_init = false;
72
int err;
73
74
max_pages = min_t(size_t, ALG_MAX_PAGES,
75
DIV_ROUND_UP(sk->sk_sndbuf, PAGE_SIZE));
76
77
lock_sock(sk);
78
continuing = ctx->more;
79
80
if (!continuing) {
81
/* Discard a previous request that wasn't marked MSG_MORE. */
82
hash_free_result(sk, ctx);
83
if (!msg_data_left(msg))
84
goto done; /* Zero-length; don't start new req */
85
need_init = true;
86
} else if (!msg_data_left(msg)) {
87
/*
88
* No data - finalise the prev req if MSG_MORE so any error
89
* comes out here.
90
*/
91
if (!(msg->msg_flags & MSG_MORE)) {
92
err = hash_alloc_result(sk, ctx);
93
if (err)
94
goto unlock_free_result;
95
ahash_request_set_crypt(&ctx->req, NULL,
96
ctx->result, 0);
97
err = crypto_wait_req(crypto_ahash_final(&ctx->req),
98
&ctx->wait);
99
if (err)
100
goto unlock_free_result;
101
}
102
goto done_more;
103
}
104
105
while (msg_data_left(msg)) {
106
ctx->sgl.sgt.sgl = ctx->sgl.sgl;
107
ctx->sgl.sgt.nents = 0;
108
ctx->sgl.sgt.orig_nents = 0;
109
110
err = -EIO;
111
npages = iov_iter_npages(&msg->msg_iter, max_pages);
112
if (npages == 0)
113
goto unlock_free;
114
115
sg_init_table(ctx->sgl.sgl, npages);
116
117
ctx->sgl.need_unpin = iov_iter_extract_will_pin(&msg->msg_iter);
118
119
err = extract_iter_to_sg(&msg->msg_iter, LONG_MAX,
120
&ctx->sgl.sgt, npages, 0);
121
if (err < 0)
122
goto unlock_free;
123
len = err;
124
sg_mark_end(ctx->sgl.sgt.sgl + ctx->sgl.sgt.nents - 1);
125
126
if (!msg_data_left(msg)) {
127
err = hash_alloc_result(sk, ctx);
128
if (err)
129
goto unlock_free;
130
}
131
132
ahash_request_set_crypt(&ctx->req, ctx->sgl.sgt.sgl,
133
ctx->result, len);
134
135
if (!msg_data_left(msg) && !continuing &&
136
!(msg->msg_flags & MSG_MORE)) {
137
err = crypto_ahash_digest(&ctx->req);
138
} else {
139
if (need_init) {
140
err = crypto_wait_req(
141
crypto_ahash_init(&ctx->req),
142
&ctx->wait);
143
if (err)
144
goto unlock_free;
145
need_init = false;
146
}
147
148
if (msg_data_left(msg) || (msg->msg_flags & MSG_MORE))
149
err = crypto_ahash_update(&ctx->req);
150
else
151
err = crypto_ahash_finup(&ctx->req);
152
continuing = true;
153
}
154
155
err = crypto_wait_req(err, &ctx->wait);
156
if (err)
157
goto unlock_free;
158
159
copied += len;
160
af_alg_free_sg(&ctx->sgl);
161
}
162
163
done_more:
164
ctx->more = msg->msg_flags & MSG_MORE;
165
done:
166
err = 0;
167
unlock:
168
release_sock(sk);
169
return copied ?: err;
170
171
unlock_free:
172
af_alg_free_sg(&ctx->sgl);
173
unlock_free_result:
174
hash_free_result(sk, ctx);
175
ctx->more = false;
176
goto unlock;
177
}
178
179
static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
180
int flags)
181
{
182
struct sock *sk = sock->sk;
183
struct alg_sock *ask = alg_sk(sk);
184
struct hash_ctx *ctx = ask->private;
185
unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
186
bool result;
187
int err;
188
189
if (len > ds)
190
len = ds;
191
else if (len < ds)
192
msg->msg_flags |= MSG_TRUNC;
193
194
lock_sock(sk);
195
result = ctx->result;
196
err = hash_alloc_result(sk, ctx);
197
if (err)
198
goto unlock;
199
200
ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
201
202
if (!result && !ctx->more) {
203
err = crypto_wait_req(crypto_ahash_init(&ctx->req),
204
&ctx->wait);
205
if (err)
206
goto unlock;
207
}
208
209
if (!result || ctx->more) {
210
ctx->more = false;
211
err = crypto_wait_req(crypto_ahash_final(&ctx->req),
212
&ctx->wait);
213
if (err)
214
goto unlock;
215
}
216
217
err = memcpy_to_msg(msg, ctx->result, len);
218
219
unlock:
220
hash_free_result(sk, ctx);
221
release_sock(sk);
222
223
return err ?: len;
224
}
225
226
static int hash_accept(struct socket *sock, struct socket *newsock,
227
struct proto_accept_arg *arg)
228
{
229
struct sock *sk = sock->sk;
230
struct alg_sock *ask = alg_sk(sk);
231
struct hash_ctx *ctx = ask->private;
232
struct ahash_request *req = &ctx->req;
233
struct crypto_ahash *tfm;
234
struct sock *sk2;
235
struct alg_sock *ask2;
236
struct hash_ctx *ctx2;
237
char *state;
238
bool more;
239
int err;
240
241
tfm = crypto_ahash_reqtfm(req);
242
state = kmalloc(crypto_ahash_statesize(tfm), GFP_KERNEL);
243
err = -ENOMEM;
244
if (!state)
245
goto out;
246
247
lock_sock(sk);
248
more = ctx->more;
249
err = more ? crypto_ahash_export(req, state) : 0;
250
release_sock(sk);
251
252
if (err)
253
goto out_free_state;
254
255
err = af_alg_accept(ask->parent, newsock, arg);
256
if (err)
257
goto out_free_state;
258
259
sk2 = newsock->sk;
260
ask2 = alg_sk(sk2);
261
ctx2 = ask2->private;
262
ctx2->more = more;
263
264
if (!more)
265
goto out_free_state;
266
267
err = crypto_ahash_import(&ctx2->req, state);
268
269
out_free_state:
270
kfree_sensitive(state);
271
272
out:
273
return err;
274
}
275
276
static struct proto_ops algif_hash_ops = {
277
.family = PF_ALG,
278
279
.connect = sock_no_connect,
280
.socketpair = sock_no_socketpair,
281
.getname = sock_no_getname,
282
.ioctl = sock_no_ioctl,
283
.listen = sock_no_listen,
284
.shutdown = sock_no_shutdown,
285
.mmap = sock_no_mmap,
286
.bind = sock_no_bind,
287
288
.release = af_alg_release,
289
.sendmsg = hash_sendmsg,
290
.recvmsg = hash_recvmsg,
291
.accept = hash_accept,
292
};
293
294
static int hash_check_key(struct socket *sock)
295
{
296
int err = 0;
297
struct sock *psk;
298
struct alg_sock *pask;
299
struct crypto_ahash *tfm;
300
struct sock *sk = sock->sk;
301
struct alg_sock *ask = alg_sk(sk);
302
303
lock_sock(sk);
304
if (!atomic_read(&ask->nokey_refcnt))
305
goto unlock_child;
306
307
psk = ask->parent;
308
pask = alg_sk(ask->parent);
309
tfm = pask->private;
310
311
err = -ENOKEY;
312
lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
313
if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
314
goto unlock;
315
316
atomic_dec(&pask->nokey_refcnt);
317
atomic_set(&ask->nokey_refcnt, 0);
318
319
err = 0;
320
321
unlock:
322
release_sock(psk);
323
unlock_child:
324
release_sock(sk);
325
326
return err;
327
}
328
329
static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
330
size_t size)
331
{
332
int err;
333
334
err = hash_check_key(sock);
335
if (err)
336
return err;
337
338
return hash_sendmsg(sock, msg, size);
339
}
340
341
static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
342
size_t ignored, int flags)
343
{
344
int err;
345
346
err = hash_check_key(sock);
347
if (err)
348
return err;
349
350
return hash_recvmsg(sock, msg, ignored, flags);
351
}
352
353
static int hash_accept_nokey(struct socket *sock, struct socket *newsock,
354
struct proto_accept_arg *arg)
355
{
356
int err;
357
358
err = hash_check_key(sock);
359
if (err)
360
return err;
361
362
return hash_accept(sock, newsock, arg);
363
}
364
365
static struct proto_ops algif_hash_ops_nokey = {
366
.family = PF_ALG,
367
368
.connect = sock_no_connect,
369
.socketpair = sock_no_socketpair,
370
.getname = sock_no_getname,
371
.ioctl = sock_no_ioctl,
372
.listen = sock_no_listen,
373
.shutdown = sock_no_shutdown,
374
.mmap = sock_no_mmap,
375
.bind = sock_no_bind,
376
377
.release = af_alg_release,
378
.sendmsg = hash_sendmsg_nokey,
379
.recvmsg = hash_recvmsg_nokey,
380
.accept = hash_accept_nokey,
381
};
382
383
static void *hash_bind(const char *name, u32 type, u32 mask)
384
{
385
return crypto_alloc_ahash(name, type, mask);
386
}
387
388
static void hash_release(void *private)
389
{
390
crypto_free_ahash(private);
391
}
392
393
static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
394
{
395
return crypto_ahash_setkey(private, key, keylen);
396
}
397
398
static void hash_sock_destruct(struct sock *sk)
399
{
400
struct alg_sock *ask = alg_sk(sk);
401
struct hash_ctx *ctx = ask->private;
402
403
hash_free_result(sk, ctx);
404
sock_kfree_s(sk, ctx, ctx->len);
405
af_alg_release_parent(sk);
406
}
407
408
static int hash_accept_parent_nokey(void *private, struct sock *sk)
409
{
410
struct crypto_ahash *tfm = private;
411
struct alg_sock *ask = alg_sk(sk);
412
struct hash_ctx *ctx;
413
unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
414
415
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
416
if (!ctx)
417
return -ENOMEM;
418
419
ctx->result = NULL;
420
ctx->len = len;
421
ctx->more = false;
422
crypto_init_wait(&ctx->wait);
423
424
ask->private = ctx;
425
426
ahash_request_set_tfm(&ctx->req, tfm);
427
ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
428
crypto_req_done, &ctx->wait);
429
430
sk->sk_destruct = hash_sock_destruct;
431
432
return 0;
433
}
434
435
static int hash_accept_parent(void *private, struct sock *sk)
436
{
437
struct crypto_ahash *tfm = private;
438
439
if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
440
return -ENOKEY;
441
442
return hash_accept_parent_nokey(private, sk);
443
}
444
445
static const struct af_alg_type algif_type_hash = {
446
.bind = hash_bind,
447
.release = hash_release,
448
.setkey = hash_setkey,
449
.accept = hash_accept_parent,
450
.accept_nokey = hash_accept_parent_nokey,
451
.ops = &algif_hash_ops,
452
.ops_nokey = &algif_hash_ops_nokey,
453
.name = "hash",
454
.owner = THIS_MODULE
455
};
456
457
static int __init algif_hash_init(void)
458
{
459
return af_alg_register_type(&algif_type_hash);
460
}
461
462
static void __exit algif_hash_exit(void)
463
{
464
int err = af_alg_unregister_type(&algif_type_hash);
465
BUG_ON(err);
466
}
467
468
module_init(algif_hash_init);
469
module_exit(algif_hash_exit);
470
MODULE_DESCRIPTION("Userspace interface for hash algorithms");
471
MODULE_LICENSE("GPL");
472
473