Blame view
crypto/algif_skcipher.c
9.6 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
8ff590903 crypto: algif_skc... |
2 3 4 5 6 7 8 |
/* * algif_skcipher: User-space interface for skcipher algorithms * * This file provides the user-space API for symmetric key ciphers. * * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> * |
e870456d8 crypto: algif_skc... |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
* The following concept of the memory management is used: * * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is * filled by user space with the data submitted via sendpage/sendmsg. Filling * up the TX SGL does not cause a crypto operation -- the data will only be * tracked by the kernel. Upon receipt of one recvmsg call, the caller must * provide a buffer which is tracked with the RX SGL. * * During the processing of the recvmsg operation, the cipher request is * allocated and prepared. As part of the recvmsg operation, the processed * TX buffers are extracted from the TX SGL into a separate SGL. * * After the completion of the crypto operation, the RX SGL and the cipher * request is released. The extracted TX SGL parts are released together with * the RX SGL release. |
8ff590903 crypto: algif_skc... |
24 25 26 27 28 29 30 31 32 33 34 35 |
*/ #include <crypto/scatterwalk.h> #include <crypto/skcipher.h> #include <crypto/if_alg.h> #include <linux/init.h> #include <linux/list.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/net.h> #include <net/sock.h> |
1b7841404 net: Remove iocb ... |
36 37 |
static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) |
8ff590903 crypto: algif_skc... |
38 39 40 |
{ struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); |
6454c2b83 crypto: algif_skc... |
41 42 |
struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); |
f8d33fac8 crypto: skcipher ... |
43 |
struct crypto_skcipher *tfm = pask->private; |
0d96e4bab crypto: algif_skc... |
44 |
unsigned ivsize = crypto_skcipher_ivsize(tfm); |
8ff590903 crypto: algif_skc... |
45 |
|
2d97591ef crypto: af_alg - ... |
46 |
return af_alg_sendmsg(sock, msg, size, ivsize); |
a596999b7 crypto: algif - c... |
47 |
} |
e870456d8 crypto: algif_skc... |
48 49 |
static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) |
a596999b7 crypto: algif - c... |
50 51 52 |
{ struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); |
ec69bbfb9 crypto: algif_skc... |
53 54 |
struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); |
2d97591ef crypto: af_alg - ... |
55 |
struct af_alg_ctx *ctx = ask->private; |
f8d33fac8 crypto: skcipher ... |
56 |
struct crypto_skcipher *tfm = pask->private; |
5b0fe9552 crypto: algif_skc... |
57 |
unsigned int bs = crypto_skcipher_chunksize(tfm); |
2d97591ef crypto: af_alg - ... |
58 |
struct af_alg_async_req *areq; |
e870456d8 crypto: algif_skc... |
59 60 |
int err = 0; size_t len = 0; |
ec69bbfb9 crypto: algif_skc... |
61 |
|
f3c802a1f crypto: algif_aea... |
62 63 |
if (!ctx->init || (ctx->more && ctx->used < bs)) { err = af_alg_wait_for_data(sk, flags, bs); |
11edb5559 crypto: af_alg - ... |
64 65 66 |
if (err) return err; } |
e870456d8 crypto: algif_skc... |
67 |
/* Allocate cipher request for current operation. */ |
2d97591ef crypto: af_alg - ... |
68 69 70 71 |
areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + crypto_skcipher_reqsize(tfm)); if (IS_ERR(areq)) return PTR_ERR(areq); |
a596999b7 crypto: algif - c... |
72 |
|
e870456d8 crypto: algif_skc... |
73 |
/* convert iovecs of output buffers into RX SGL */ |
7cf819547 crypto: algif_skc... |
74 |
err = af_alg_get_rsgl(sk, msg, flags, areq, ctx->used, &len); |
2d97591ef crypto: af_alg - ... |
75 76 |
if (err) goto free; |
a596999b7 crypto: algif - c... |
77 |
|
e870456d8 crypto: algif_skc... |
78 79 80 81 82 83 84 85 86 87 88 |
/* * If more buffers are to be expected to be processed, process only * full block size buffers. */ if (ctx->more || len < ctx->used) len -= len % bs; /* * Create a per request TX SGL for this request which tracks the * SG entries from the global TX SGL. */ |
2d97591ef crypto: af_alg - ... |
89 |
areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0); |
e870456d8 crypto: algif_skc... |
90 91 |
if (!areq->tsgl_entries) areq->tsgl_entries = 1; |
76e43e37a treewide: Use arr... |
92 93 |
areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), areq->tsgl_entries), |
e870456d8 crypto: algif_skc... |
94 95 96 97 98 99 |
GFP_KERNEL); if (!areq->tsgl) { err = -ENOMEM; goto free; } sg_init_table(areq->tsgl, areq->tsgl_entries); |
2d97591ef crypto: af_alg - ... |
100 |
af_alg_pull_tsgl(sk, len, areq->tsgl, 0); |
e870456d8 crypto: algif_skc... |
101 102 |
/* Initialize the crypto operation */ |
2d97591ef crypto: af_alg - ... |
103 104 105 |
skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, areq->first_rsgl.sgl.sg, len, ctx->iv); |
e870456d8 crypto: algif_skc... |
106 107 108 |
if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { /* AIO operation */ |
7d2c3f54e crypto: af_alg - ... |
109 |
sock_hold(sk); |
e870456d8 crypto: algif_skc... |
110 |
areq->iocb = msg->msg_iocb; |
d53c51357 crypto: af_alg - ... |
111 112 113 |
/* Remember output size that will be generated. */ areq->outlen = len; |
2d97591ef crypto: af_alg - ... |
114 |
skcipher_request_set_callback(&areq->cra_u.skcipher_req, |
e870456d8 crypto: algif_skc... |
115 |
CRYPTO_TFM_REQ_MAY_SLEEP, |
2d97591ef crypto: af_alg - ... |
116 117 118 119 |
af_alg_async_cb, areq); err = ctx->enc ? crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); |
7d2c3f54e crypto: af_alg - ... |
120 121 |
/* AIO operation in progress */ |
2a05b029c crypto: algif_skc... |
122 |
if (err == -EINPROGRESS) |
7d2c3f54e crypto: af_alg - ... |
123 |
return -EIOCBQUEUED; |
7d2c3f54e crypto: af_alg - ... |
124 125 |
sock_put(sk); |
e870456d8 crypto: algif_skc... |
126 127 |
} else { /* Synchronous operation */ |
2d97591ef crypto: af_alg - ... |
128 |
skcipher_request_set_callback(&areq->cra_u.skcipher_req, |
e870456d8 crypto: algif_skc... |
129 130 |
CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG, |
2c3f8b162 crypto: algif - m... |
131 132 |
crypto_req_done, &ctx->wait); err = crypto_wait_req(ctx->enc ? |
2d97591ef crypto: af_alg - ... |
133 134 |
crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), |
2c3f8b162 crypto: algif - m... |
135 |
&ctx->wait); |
e870456d8 crypto: algif_skc... |
136 |
} |
033f46b3c crypto: algif - e... |
137 |
|
e870456d8 crypto: algif_skc... |
138 |
|
a596999b7 crypto: algif - c... |
139 |
free: |
7d2c3f54e crypto: af_alg - ... |
140 |
af_alg_free_resources(areq); |
e870456d8 crypto: algif_skc... |
141 142 |
return err ? err : len; |
a596999b7 crypto: algif - c... |
143 |
} |
e870456d8 crypto: algif_skc... |
144 145 |
static int skcipher_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) |
8ff590903 crypto: algif_skc... |
146 147 |
{ struct sock *sk = sock->sk; |
e870456d8 crypto: algif_skc... |
148 |
int ret = 0; |
8ff590903 crypto: algif_skc... |
149 150 |
lock_sock(sk); |
01e97e651 new helper: msg_d... |
151 |
while (msg_data_left(msg)) { |
e870456d8 crypto: algif_skc... |
152 153 154 155 156 157 158 |
int err = _skcipher_recvmsg(sock, msg, ignored, flags); /* * This error covers -EIOCBQUEUED which implies that we can * only handle one AIO request. If the caller wants to have * multiple AIO requests in parallel, he must make multiple * separate AIO calls. |
5703c826b crypto: algif - r... |
159 160 |
* * Also return the error if no data has been processed so far. |
e870456d8 crypto: algif_skc... |
161 162 |
*/ if (err <= 0) { |
5703c826b crypto: algif - r... |
163 |
if (err == -EIOCBQUEUED || !ret) |
e870456d8 crypto: algif_skc... |
164 165 |
ret = err; goto out; |
1d10eb2f1 crypto: switch af... |
166 |
} |
e870456d8 crypto: algif_skc... |
167 |
ret += err; |
8ff590903 crypto: algif_skc... |
168 |
} |
e870456d8 crypto: algif_skc... |
169 |
out: |
2d97591ef crypto: af_alg - ... |
170 |
af_alg_wmem_wakeup(sk); |
8ff590903 crypto: algif_skc... |
171 |
release_sock(sk); |
e870456d8 crypto: algif_skc... |
172 |
return ret; |
a596999b7 crypto: algif - c... |
173 |
} |
8ff590903 crypto: algif_skc... |
174 |
|
8ff590903 crypto: algif_skc... |
175 176 177 178 179 180 181 182 183 |
static struct proto_ops algif_skcipher_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, |
8ff590903 crypto: algif_skc... |
184 185 186 |
.mmap = sock_no_mmap, .bind = sock_no_bind, .accept = sock_no_accept, |
8ff590903 crypto: algif_skc... |
187 188 189 |
.release = af_alg_release, .sendmsg = skcipher_sendmsg, |
2d97591ef crypto: af_alg - ... |
190 |
.sendpage = af_alg_sendpage, |
8ff590903 crypto: algif_skc... |
191 |
.recvmsg = skcipher_recvmsg, |
a11e1d432 Revert changes to... |
192 |
.poll = af_alg_poll, |
8ff590903 crypto: algif_skc... |
193 |
}; |
a0fa2d037 crypto: algif_skc... |
194 195 |
static int skcipher_check_key(struct socket *sock) { |
1822793a5 crypto: algif_skc... |
196 |
int err = 0; |
a0fa2d037 crypto: algif_skc... |
197 198 |
struct sock *psk; struct alg_sock *pask; |
f8d33fac8 crypto: skcipher ... |
199 |
struct crypto_skcipher *tfm; |
a0fa2d037 crypto: algif_skc... |
200 201 |
struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); |
1822793a5 crypto: algif_skc... |
202 |
lock_sock(sk); |
34c86f4c4 crypto: af_alg - ... |
203 |
if (!atomic_read(&ask->nokey_refcnt)) |
1822793a5 crypto: algif_skc... |
204 |
goto unlock_child; |
a0fa2d037 crypto: algif_skc... |
205 206 207 208 209 210 |
psk = ask->parent; pask = alg_sk(ask->parent); tfm = pask->private; err = -ENOKEY; |
1822793a5 crypto: algif_skc... |
211 |
lock_sock_nested(psk, SINGLE_DEPTH_NESTING); |
f8d33fac8 crypto: skcipher ... |
212 |
if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) |
a0fa2d037 crypto: algif_skc... |
213 |
goto unlock; |
34c86f4c4 crypto: af_alg - ... |
214 215 |
atomic_dec(&pask->nokey_refcnt); atomic_set(&ask->nokey_refcnt, 0); |
a0fa2d037 crypto: algif_skc... |
216 217 218 219 220 |
err = 0; unlock: release_sock(psk); |
1822793a5 crypto: algif_skc... |
221 222 |
unlock_child: release_sock(sk); |
a0fa2d037 crypto: algif_skc... |
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
return err; } static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg, size_t size) { int err; err = skcipher_check_key(sock); if (err) return err; return skcipher_sendmsg(sock, msg, size); } static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, int offset, size_t size, int flags) { int err; err = skcipher_check_key(sock); if (err) return err; |
2d97591ef crypto: af_alg - ... |
247 |
return af_alg_sendpage(sock, page, offset, size, flags); |
a0fa2d037 crypto: algif_skc... |
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
} static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { int err; err = skcipher_check_key(sock); if (err) return err; return skcipher_recvmsg(sock, msg, ignored, flags); } static struct proto_ops algif_skcipher_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, |
a0fa2d037 crypto: algif_skc... |
271 272 273 |
.mmap = sock_no_mmap, .bind = sock_no_bind, .accept = sock_no_accept, |
a0fa2d037 crypto: algif_skc... |
274 275 276 277 278 |
.release = af_alg_release, .sendmsg = skcipher_sendmsg_nokey, .sendpage = skcipher_sendpage_nokey, .recvmsg = skcipher_recvmsg_nokey, |
a11e1d432 Revert changes to... |
279 |
.poll = af_alg_poll, |
a0fa2d037 crypto: algif_skc... |
280 |
}; |
8ff590903 crypto: algif_skc... |
281 282 |
static void *skcipher_bind(const char *name, u32 type, u32 mask) { |
f8d33fac8 crypto: skcipher ... |
283 |
return crypto_alloc_skcipher(name, type, mask); |
8ff590903 crypto: algif_skc... |
284 285 286 287 |
} static void skcipher_release(void *private) { |
f8d33fac8 crypto: skcipher ... |
288 |
crypto_free_skcipher(private); |
8ff590903 crypto: algif_skc... |
289 290 291 292 |
} static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) { |
f8d33fac8 crypto: skcipher ... |
293 |
return crypto_skcipher_setkey(private, key, keylen); |
8ff590903 crypto: algif_skc... |
294 295 296 297 298 |
} static void skcipher_sock_destruct(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); |
2d97591ef crypto: af_alg - ... |
299 |
struct af_alg_ctx *ctx = ask->private; |
e870456d8 crypto: algif_skc... |
300 301 |
struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); |
f8d33fac8 crypto: skcipher ... |
302 |
struct crypto_skcipher *tfm = pask->private; |
a596999b7 crypto: algif - c... |
303 |
|
2d97591ef crypto: af_alg - ... |
304 |
af_alg_pull_tsgl(sk, ctx->used, NULL, 0); |
0d96e4bab crypto: algif_skc... |
305 |
sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); |
8ff590903 crypto: algif_skc... |
306 307 308 |
sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); } |
d7b65aee1 crypto: algif_skc... |
309 |
static int skcipher_accept_parent_nokey(void *private, struct sock *sk) |
8ff590903 crypto: algif_skc... |
310 |
{ |
2d97591ef crypto: af_alg - ... |
311 |
struct af_alg_ctx *ctx; |
8ff590903 crypto: algif_skc... |
312 |
struct alg_sock *ask = alg_sk(sk); |
f8d33fac8 crypto: skcipher ... |
313 |
struct crypto_skcipher *tfm = private; |
e870456d8 crypto: algif_skc... |
314 |
unsigned int len = sizeof(*ctx); |
8ff590903 crypto: algif_skc... |
315 316 317 318 |
ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) return -ENOMEM; |
21dfbcd1f crypto: algif_aea... |
319 |
memset(ctx, 0, len); |
8ff590903 crypto: algif_skc... |
320 |
|
f8d33fac8 crypto: skcipher ... |
321 |
ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(tfm), |
8ff590903 crypto: algif_skc... |
322 323 324 325 326 |
GFP_KERNEL); if (!ctx->iv) { sock_kfree_s(sk, ctx, len); return -ENOMEM; } |
f8d33fac8 crypto: skcipher ... |
327 |
memset(ctx->iv, 0, crypto_skcipher_ivsize(tfm)); |
8ff590903 crypto: algif_skc... |
328 |
|
e870456d8 crypto: algif_skc... |
329 |
INIT_LIST_HEAD(&ctx->tsgl_list); |
8ff590903 crypto: algif_skc... |
330 |
ctx->len = len; |
2c3f8b162 crypto: algif - m... |
331 |
crypto_init_wait(&ctx->wait); |
8ff590903 crypto: algif_skc... |
332 333 |
ask->private = ctx; |
8ff590903 crypto: algif_skc... |
334 335 336 337 |
sk->sk_destruct = skcipher_sock_destruct; return 0; } |
a0fa2d037 crypto: algif_skc... |
338 339 |
static int skcipher_accept_parent(void *private, struct sock *sk) { |
f8d33fac8 crypto: skcipher ... |
340 |
struct crypto_skcipher *tfm = private; |
a0fa2d037 crypto: algif_skc... |
341 |
|
f8d33fac8 crypto: skcipher ... |
342 |
if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) |
a0fa2d037 crypto: algif_skc... |
343 |
return -ENOKEY; |
d7b65aee1 crypto: algif_skc... |
344 |
return skcipher_accept_parent_nokey(private, sk); |
a0fa2d037 crypto: algif_skc... |
345 |
} |
8ff590903 crypto: algif_skc... |
346 347 348 349 350 |
static const struct af_alg_type algif_type_skcipher = { .bind = skcipher_bind, .release = skcipher_release, .setkey = skcipher_setkey, .accept = skcipher_accept_parent, |
a0fa2d037 crypto: algif_skc... |
351 |
.accept_nokey = skcipher_accept_parent_nokey, |
8ff590903 crypto: algif_skc... |
352 |
.ops = &algif_skcipher_ops, |
a0fa2d037 crypto: algif_skc... |
353 |
.ops_nokey = &algif_skcipher_ops_nokey, |
8ff590903 crypto: algif_skc... |
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
.name = "skcipher", .owner = THIS_MODULE }; static int __init algif_skcipher_init(void) { return af_alg_register_type(&algif_type_skcipher); } static void __exit algif_skcipher_exit(void) { int err = af_alg_unregister_type(&algif_type_skcipher); BUG_ON(err); } module_init(algif_skcipher_init); module_exit(algif_skcipher_exit); MODULE_LICENSE("GPL"); |