Commit 3f62b3ed08611edc3b68ad7534c991cf0a62c135
Committed by
Greg Kroah-Hartman
1 parent
1cfececcbc
Exists in
smarc-ti-linux-3.14.y
and in
1 other branch
crypto: af_alg - fix backlog handling
commit 7e77bdebff5cb1e9876c561f69710b9ab8fa1f7e upstream. If a request is backlogged, it's complete() handler will get called twice: once with -EINPROGRESS, and once with the final error code. af_alg's complete handler, unlike other users, does not handle the -EINPROGRESS but instead always completes the completion that recvmsg() is waiting on. This can lead to a return to user space while the request is still pending in the driver. If userspace closes the sockets before the requests are handled by the driver, this will lead to use-after-frees (and potential crashes) in the kernel due to the tfm having been freed. The crashes can be easily reproduced (for example) by reducing the max queue length in cryptod.c and running the following (from http://www.chronox.de/libkcapi.html) on AES-NI capable hardware: $ while true; do kcapi -x 1 -e -c '__ecb-aes-aesni' \ -k 00000000000000000000000000000000 \ -p 00000000000000000000000000000000 >/dev/null & done Signed-off-by: Rabin Vincent <rabin.vincent@axis.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 3 additions and 0 deletions Inline Diff
crypto/af_alg.c
1 | /* | 1 | /* |
2 | * af_alg: User-space algorithm interface | 2 | * af_alg: User-space algorithm interface |
3 | * | 3 | * |
4 | * This file provides the user-space API for algorithms. | 4 | * This file provides the user-space API for algorithms. |
5 | * | 5 | * |
6 | * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> | 6 | * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the Free | 9 | * under the terms of the GNU General Public License as published by the Free |
10 | * Software Foundation; either version 2 of the License, or (at your option) | 10 | * Software Foundation; either version 2 of the License, or (at your option) |
11 | * any later version. | 11 | * any later version. |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/atomic.h> | 15 | #include <linux/atomic.h> |
16 | #include <crypto/if_alg.h> | 16 | #include <crypto/if_alg.h> |
17 | #include <linux/crypto.h> | 17 | #include <linux/crypto.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/net.h> | 22 | #include <linux/net.h> |
23 | #include <linux/rwsem.h> | 23 | #include <linux/rwsem.h> |
24 | #include <linux/security.h> | 24 | #include <linux/security.h> |
25 | 25 | ||
26 | struct alg_type_list { | 26 | struct alg_type_list { |
27 | const struct af_alg_type *type; | 27 | const struct af_alg_type *type; |
28 | struct list_head list; | 28 | struct list_head list; |
29 | }; | 29 | }; |
30 | 30 | ||
31 | static atomic_long_t alg_memory_allocated; | 31 | static atomic_long_t alg_memory_allocated; |
32 | 32 | ||
33 | static struct proto alg_proto = { | 33 | static struct proto alg_proto = { |
34 | .name = "ALG", | 34 | .name = "ALG", |
35 | .owner = THIS_MODULE, | 35 | .owner = THIS_MODULE, |
36 | .memory_allocated = &alg_memory_allocated, | 36 | .memory_allocated = &alg_memory_allocated, |
37 | .obj_size = sizeof(struct alg_sock), | 37 | .obj_size = sizeof(struct alg_sock), |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static LIST_HEAD(alg_types); | 40 | static LIST_HEAD(alg_types); |
41 | static DECLARE_RWSEM(alg_types_sem); | 41 | static DECLARE_RWSEM(alg_types_sem); |
42 | 42 | ||
43 | static const struct af_alg_type *alg_get_type(const char *name) | 43 | static const struct af_alg_type *alg_get_type(const char *name) |
44 | { | 44 | { |
45 | const struct af_alg_type *type = ERR_PTR(-ENOENT); | 45 | const struct af_alg_type *type = ERR_PTR(-ENOENT); |
46 | struct alg_type_list *node; | 46 | struct alg_type_list *node; |
47 | 47 | ||
48 | down_read(&alg_types_sem); | 48 | down_read(&alg_types_sem); |
49 | list_for_each_entry(node, &alg_types, list) { | 49 | list_for_each_entry(node, &alg_types, list) { |
50 | if (strcmp(node->type->name, name)) | 50 | if (strcmp(node->type->name, name)) |
51 | continue; | 51 | continue; |
52 | 52 | ||
53 | if (try_module_get(node->type->owner)) | 53 | if (try_module_get(node->type->owner)) |
54 | type = node->type; | 54 | type = node->type; |
55 | break; | 55 | break; |
56 | } | 56 | } |
57 | up_read(&alg_types_sem); | 57 | up_read(&alg_types_sem); |
58 | 58 | ||
59 | return type; | 59 | return type; |
60 | } | 60 | } |
61 | 61 | ||
62 | int af_alg_register_type(const struct af_alg_type *type) | 62 | int af_alg_register_type(const struct af_alg_type *type) |
63 | { | 63 | { |
64 | struct alg_type_list *node; | 64 | struct alg_type_list *node; |
65 | int err = -EEXIST; | 65 | int err = -EEXIST; |
66 | 66 | ||
67 | down_write(&alg_types_sem); | 67 | down_write(&alg_types_sem); |
68 | list_for_each_entry(node, &alg_types, list) { | 68 | list_for_each_entry(node, &alg_types, list) { |
69 | if (!strcmp(node->type->name, type->name)) | 69 | if (!strcmp(node->type->name, type->name)) |
70 | goto unlock; | 70 | goto unlock; |
71 | } | 71 | } |
72 | 72 | ||
73 | node = kmalloc(sizeof(*node), GFP_KERNEL); | 73 | node = kmalloc(sizeof(*node), GFP_KERNEL); |
74 | err = -ENOMEM; | 74 | err = -ENOMEM; |
75 | if (!node) | 75 | if (!node) |
76 | goto unlock; | 76 | goto unlock; |
77 | 77 | ||
78 | type->ops->owner = THIS_MODULE; | 78 | type->ops->owner = THIS_MODULE; |
79 | node->type = type; | 79 | node->type = type; |
80 | list_add(&node->list, &alg_types); | 80 | list_add(&node->list, &alg_types); |
81 | err = 0; | 81 | err = 0; |
82 | 82 | ||
83 | unlock: | 83 | unlock: |
84 | up_write(&alg_types_sem); | 84 | up_write(&alg_types_sem); |
85 | 85 | ||
86 | return err; | 86 | return err; |
87 | } | 87 | } |
88 | EXPORT_SYMBOL_GPL(af_alg_register_type); | 88 | EXPORT_SYMBOL_GPL(af_alg_register_type); |
89 | 89 | ||
90 | int af_alg_unregister_type(const struct af_alg_type *type) | 90 | int af_alg_unregister_type(const struct af_alg_type *type) |
91 | { | 91 | { |
92 | struct alg_type_list *node; | 92 | struct alg_type_list *node; |
93 | int err = -ENOENT; | 93 | int err = -ENOENT; |
94 | 94 | ||
95 | down_write(&alg_types_sem); | 95 | down_write(&alg_types_sem); |
96 | list_for_each_entry(node, &alg_types, list) { | 96 | list_for_each_entry(node, &alg_types, list) { |
97 | if (strcmp(node->type->name, type->name)) | 97 | if (strcmp(node->type->name, type->name)) |
98 | continue; | 98 | continue; |
99 | 99 | ||
100 | list_del(&node->list); | 100 | list_del(&node->list); |
101 | kfree(node); | 101 | kfree(node); |
102 | err = 0; | 102 | err = 0; |
103 | break; | 103 | break; |
104 | } | 104 | } |
105 | up_write(&alg_types_sem); | 105 | up_write(&alg_types_sem); |
106 | 106 | ||
107 | return err; | 107 | return err; |
108 | } | 108 | } |
109 | EXPORT_SYMBOL_GPL(af_alg_unregister_type); | 109 | EXPORT_SYMBOL_GPL(af_alg_unregister_type); |
110 | 110 | ||
111 | static void alg_do_release(const struct af_alg_type *type, void *private) | 111 | static void alg_do_release(const struct af_alg_type *type, void *private) |
112 | { | 112 | { |
113 | if (!type) | 113 | if (!type) |
114 | return; | 114 | return; |
115 | 115 | ||
116 | type->release(private); | 116 | type->release(private); |
117 | module_put(type->owner); | 117 | module_put(type->owner); |
118 | } | 118 | } |
119 | 119 | ||
120 | int af_alg_release(struct socket *sock) | 120 | int af_alg_release(struct socket *sock) |
121 | { | 121 | { |
122 | if (sock->sk) | 122 | if (sock->sk) |
123 | sock_put(sock->sk); | 123 | sock_put(sock->sk); |
124 | return 0; | 124 | return 0; |
125 | } | 125 | } |
126 | EXPORT_SYMBOL_GPL(af_alg_release); | 126 | EXPORT_SYMBOL_GPL(af_alg_release); |
127 | 127 | ||
128 | static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | 128 | static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) |
129 | { | 129 | { |
130 | struct sock *sk = sock->sk; | 130 | struct sock *sk = sock->sk; |
131 | struct alg_sock *ask = alg_sk(sk); | 131 | struct alg_sock *ask = alg_sk(sk); |
132 | struct sockaddr_alg *sa = (void *)uaddr; | 132 | struct sockaddr_alg *sa = (void *)uaddr; |
133 | const struct af_alg_type *type; | 133 | const struct af_alg_type *type; |
134 | void *private; | 134 | void *private; |
135 | 135 | ||
136 | if (sock->state == SS_CONNECTED) | 136 | if (sock->state == SS_CONNECTED) |
137 | return -EINVAL; | 137 | return -EINVAL; |
138 | 138 | ||
139 | if (addr_len != sizeof(*sa)) | 139 | if (addr_len != sizeof(*sa)) |
140 | return -EINVAL; | 140 | return -EINVAL; |
141 | 141 | ||
142 | sa->salg_type[sizeof(sa->salg_type) - 1] = 0; | 142 | sa->salg_type[sizeof(sa->salg_type) - 1] = 0; |
143 | sa->salg_name[sizeof(sa->salg_name) - 1] = 0; | 143 | sa->salg_name[sizeof(sa->salg_name) - 1] = 0; |
144 | 144 | ||
145 | type = alg_get_type(sa->salg_type); | 145 | type = alg_get_type(sa->salg_type); |
146 | if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) { | 146 | if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) { |
147 | request_module("algif-%s", sa->salg_type); | 147 | request_module("algif-%s", sa->salg_type); |
148 | type = alg_get_type(sa->salg_type); | 148 | type = alg_get_type(sa->salg_type); |
149 | } | 149 | } |
150 | 150 | ||
151 | if (IS_ERR(type)) | 151 | if (IS_ERR(type)) |
152 | return PTR_ERR(type); | 152 | return PTR_ERR(type); |
153 | 153 | ||
154 | private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask); | 154 | private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask); |
155 | if (IS_ERR(private)) { | 155 | if (IS_ERR(private)) { |
156 | module_put(type->owner); | 156 | module_put(type->owner); |
157 | return PTR_ERR(private); | 157 | return PTR_ERR(private); |
158 | } | 158 | } |
159 | 159 | ||
160 | lock_sock(sk); | 160 | lock_sock(sk); |
161 | 161 | ||
162 | swap(ask->type, type); | 162 | swap(ask->type, type); |
163 | swap(ask->private, private); | 163 | swap(ask->private, private); |
164 | 164 | ||
165 | release_sock(sk); | 165 | release_sock(sk); |
166 | 166 | ||
167 | alg_do_release(type, private); | 167 | alg_do_release(type, private); |
168 | 168 | ||
169 | return 0; | 169 | return 0; |
170 | } | 170 | } |
171 | 171 | ||
172 | static int alg_setkey(struct sock *sk, char __user *ukey, | 172 | static int alg_setkey(struct sock *sk, char __user *ukey, |
173 | unsigned int keylen) | 173 | unsigned int keylen) |
174 | { | 174 | { |
175 | struct alg_sock *ask = alg_sk(sk); | 175 | struct alg_sock *ask = alg_sk(sk); |
176 | const struct af_alg_type *type = ask->type; | 176 | const struct af_alg_type *type = ask->type; |
177 | u8 *key; | 177 | u8 *key; |
178 | int err; | 178 | int err; |
179 | 179 | ||
180 | key = sock_kmalloc(sk, keylen, GFP_KERNEL); | 180 | key = sock_kmalloc(sk, keylen, GFP_KERNEL); |
181 | if (!key) | 181 | if (!key) |
182 | return -ENOMEM; | 182 | return -ENOMEM; |
183 | 183 | ||
184 | err = -EFAULT; | 184 | err = -EFAULT; |
185 | if (copy_from_user(key, ukey, keylen)) | 185 | if (copy_from_user(key, ukey, keylen)) |
186 | goto out; | 186 | goto out; |
187 | 187 | ||
188 | err = type->setkey(ask->private, key, keylen); | 188 | err = type->setkey(ask->private, key, keylen); |
189 | 189 | ||
190 | out: | 190 | out: |
191 | sock_kfree_s(sk, key, keylen); | 191 | sock_kfree_s(sk, key, keylen); |
192 | 192 | ||
193 | return err; | 193 | return err; |
194 | } | 194 | } |
195 | 195 | ||
196 | static int alg_setsockopt(struct socket *sock, int level, int optname, | 196 | static int alg_setsockopt(struct socket *sock, int level, int optname, |
197 | char __user *optval, unsigned int optlen) | 197 | char __user *optval, unsigned int optlen) |
198 | { | 198 | { |
199 | struct sock *sk = sock->sk; | 199 | struct sock *sk = sock->sk; |
200 | struct alg_sock *ask = alg_sk(sk); | 200 | struct alg_sock *ask = alg_sk(sk); |
201 | const struct af_alg_type *type; | 201 | const struct af_alg_type *type; |
202 | int err = -ENOPROTOOPT; | 202 | int err = -ENOPROTOOPT; |
203 | 203 | ||
204 | lock_sock(sk); | 204 | lock_sock(sk); |
205 | type = ask->type; | 205 | type = ask->type; |
206 | 206 | ||
207 | if (level != SOL_ALG || !type) | 207 | if (level != SOL_ALG || !type) |
208 | goto unlock; | 208 | goto unlock; |
209 | 209 | ||
210 | switch (optname) { | 210 | switch (optname) { |
211 | case ALG_SET_KEY: | 211 | case ALG_SET_KEY: |
212 | if (sock->state == SS_CONNECTED) | 212 | if (sock->state == SS_CONNECTED) |
213 | goto unlock; | 213 | goto unlock; |
214 | if (!type->setkey) | 214 | if (!type->setkey) |
215 | goto unlock; | 215 | goto unlock; |
216 | 216 | ||
217 | err = alg_setkey(sk, optval, optlen); | 217 | err = alg_setkey(sk, optval, optlen); |
218 | } | 218 | } |
219 | 219 | ||
220 | unlock: | 220 | unlock: |
221 | release_sock(sk); | 221 | release_sock(sk); |
222 | 222 | ||
223 | return err; | 223 | return err; |
224 | } | 224 | } |
225 | 225 | ||
226 | int af_alg_accept(struct sock *sk, struct socket *newsock) | 226 | int af_alg_accept(struct sock *sk, struct socket *newsock) |
227 | { | 227 | { |
228 | struct alg_sock *ask = alg_sk(sk); | 228 | struct alg_sock *ask = alg_sk(sk); |
229 | const struct af_alg_type *type; | 229 | const struct af_alg_type *type; |
230 | struct sock *sk2; | 230 | struct sock *sk2; |
231 | int err; | 231 | int err; |
232 | 232 | ||
233 | lock_sock(sk); | 233 | lock_sock(sk); |
234 | type = ask->type; | 234 | type = ask->type; |
235 | 235 | ||
236 | err = -EINVAL; | 236 | err = -EINVAL; |
237 | if (!type) | 237 | if (!type) |
238 | goto unlock; | 238 | goto unlock; |
239 | 239 | ||
240 | sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto); | 240 | sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto); |
241 | err = -ENOMEM; | 241 | err = -ENOMEM; |
242 | if (!sk2) | 242 | if (!sk2) |
243 | goto unlock; | 243 | goto unlock; |
244 | 244 | ||
245 | sock_init_data(newsock, sk2); | 245 | sock_init_data(newsock, sk2); |
246 | sock_graft(sk2, newsock); | 246 | sock_graft(sk2, newsock); |
247 | security_sk_clone(sk, sk2); | 247 | security_sk_clone(sk, sk2); |
248 | 248 | ||
249 | err = type->accept(ask->private, sk2); | 249 | err = type->accept(ask->private, sk2); |
250 | if (err) { | 250 | if (err) { |
251 | sk_free(sk2); | 251 | sk_free(sk2); |
252 | goto unlock; | 252 | goto unlock; |
253 | } | 253 | } |
254 | 254 | ||
255 | sk2->sk_family = PF_ALG; | 255 | sk2->sk_family = PF_ALG; |
256 | 256 | ||
257 | sock_hold(sk); | 257 | sock_hold(sk); |
258 | alg_sk(sk2)->parent = sk; | 258 | alg_sk(sk2)->parent = sk; |
259 | alg_sk(sk2)->type = type; | 259 | alg_sk(sk2)->type = type; |
260 | 260 | ||
261 | newsock->ops = type->ops; | 261 | newsock->ops = type->ops; |
262 | newsock->state = SS_CONNECTED; | 262 | newsock->state = SS_CONNECTED; |
263 | 263 | ||
264 | err = 0; | 264 | err = 0; |
265 | 265 | ||
266 | unlock: | 266 | unlock: |
267 | release_sock(sk); | 267 | release_sock(sk); |
268 | 268 | ||
269 | return err; | 269 | return err; |
270 | } | 270 | } |
271 | EXPORT_SYMBOL_GPL(af_alg_accept); | 271 | EXPORT_SYMBOL_GPL(af_alg_accept); |
272 | 272 | ||
273 | static int alg_accept(struct socket *sock, struct socket *newsock, int flags) | 273 | static int alg_accept(struct socket *sock, struct socket *newsock, int flags) |
274 | { | 274 | { |
275 | return af_alg_accept(sock->sk, newsock); | 275 | return af_alg_accept(sock->sk, newsock); |
276 | } | 276 | } |
277 | 277 | ||
278 | static const struct proto_ops alg_proto_ops = { | 278 | static const struct proto_ops alg_proto_ops = { |
279 | .family = PF_ALG, | 279 | .family = PF_ALG, |
280 | .owner = THIS_MODULE, | 280 | .owner = THIS_MODULE, |
281 | 281 | ||
282 | .connect = sock_no_connect, | 282 | .connect = sock_no_connect, |
283 | .socketpair = sock_no_socketpair, | 283 | .socketpair = sock_no_socketpair, |
284 | .getname = sock_no_getname, | 284 | .getname = sock_no_getname, |
285 | .ioctl = sock_no_ioctl, | 285 | .ioctl = sock_no_ioctl, |
286 | .listen = sock_no_listen, | 286 | .listen = sock_no_listen, |
287 | .shutdown = sock_no_shutdown, | 287 | .shutdown = sock_no_shutdown, |
288 | .getsockopt = sock_no_getsockopt, | 288 | .getsockopt = sock_no_getsockopt, |
289 | .mmap = sock_no_mmap, | 289 | .mmap = sock_no_mmap, |
290 | .sendpage = sock_no_sendpage, | 290 | .sendpage = sock_no_sendpage, |
291 | .sendmsg = sock_no_sendmsg, | 291 | .sendmsg = sock_no_sendmsg, |
292 | .recvmsg = sock_no_recvmsg, | 292 | .recvmsg = sock_no_recvmsg, |
293 | .poll = sock_no_poll, | 293 | .poll = sock_no_poll, |
294 | 294 | ||
295 | .bind = alg_bind, | 295 | .bind = alg_bind, |
296 | .release = af_alg_release, | 296 | .release = af_alg_release, |
297 | .setsockopt = alg_setsockopt, | 297 | .setsockopt = alg_setsockopt, |
298 | .accept = alg_accept, | 298 | .accept = alg_accept, |
299 | }; | 299 | }; |
300 | 300 | ||
301 | static void alg_sock_destruct(struct sock *sk) | 301 | static void alg_sock_destruct(struct sock *sk) |
302 | { | 302 | { |
303 | struct alg_sock *ask = alg_sk(sk); | 303 | struct alg_sock *ask = alg_sk(sk); |
304 | 304 | ||
305 | alg_do_release(ask->type, ask->private); | 305 | alg_do_release(ask->type, ask->private); |
306 | } | 306 | } |
307 | 307 | ||
308 | static int alg_create(struct net *net, struct socket *sock, int protocol, | 308 | static int alg_create(struct net *net, struct socket *sock, int protocol, |
309 | int kern) | 309 | int kern) |
310 | { | 310 | { |
311 | struct sock *sk; | 311 | struct sock *sk; |
312 | int err; | 312 | int err; |
313 | 313 | ||
314 | if (sock->type != SOCK_SEQPACKET) | 314 | if (sock->type != SOCK_SEQPACKET) |
315 | return -ESOCKTNOSUPPORT; | 315 | return -ESOCKTNOSUPPORT; |
316 | if (protocol != 0) | 316 | if (protocol != 0) |
317 | return -EPROTONOSUPPORT; | 317 | return -EPROTONOSUPPORT; |
318 | 318 | ||
319 | err = -ENOMEM; | 319 | err = -ENOMEM; |
320 | sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto); | 320 | sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto); |
321 | if (!sk) | 321 | if (!sk) |
322 | goto out; | 322 | goto out; |
323 | 323 | ||
324 | sock->ops = &alg_proto_ops; | 324 | sock->ops = &alg_proto_ops; |
325 | sock_init_data(sock, sk); | 325 | sock_init_data(sock, sk); |
326 | 326 | ||
327 | sk->sk_family = PF_ALG; | 327 | sk->sk_family = PF_ALG; |
328 | sk->sk_destruct = alg_sock_destruct; | 328 | sk->sk_destruct = alg_sock_destruct; |
329 | 329 | ||
330 | return 0; | 330 | return 0; |
331 | out: | 331 | out: |
332 | return err; | 332 | return err; |
333 | } | 333 | } |
334 | 334 | ||
335 | static const struct net_proto_family alg_family = { | 335 | static const struct net_proto_family alg_family = { |
336 | .family = PF_ALG, | 336 | .family = PF_ALG, |
337 | .create = alg_create, | 337 | .create = alg_create, |
338 | .owner = THIS_MODULE, | 338 | .owner = THIS_MODULE, |
339 | }; | 339 | }; |
340 | 340 | ||
341 | int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, | 341 | int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, |
342 | int write) | 342 | int write) |
343 | { | 343 | { |
344 | unsigned long from = (unsigned long)addr; | 344 | unsigned long from = (unsigned long)addr; |
345 | unsigned long npages; | 345 | unsigned long npages; |
346 | unsigned off; | 346 | unsigned off; |
347 | int err; | 347 | int err; |
348 | int i; | 348 | int i; |
349 | 349 | ||
350 | err = -EFAULT; | 350 | err = -EFAULT; |
351 | if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len)) | 351 | if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len)) |
352 | goto out; | 352 | goto out; |
353 | 353 | ||
354 | off = from & ~PAGE_MASK; | 354 | off = from & ~PAGE_MASK; |
355 | npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 355 | npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
356 | if (npages > ALG_MAX_PAGES) | 356 | if (npages > ALG_MAX_PAGES) |
357 | npages = ALG_MAX_PAGES; | 357 | npages = ALG_MAX_PAGES; |
358 | 358 | ||
359 | err = get_user_pages_fast(from, npages, write, sgl->pages); | 359 | err = get_user_pages_fast(from, npages, write, sgl->pages); |
360 | if (err < 0) | 360 | if (err < 0) |
361 | goto out; | 361 | goto out; |
362 | 362 | ||
363 | npages = err; | 363 | npages = err; |
364 | err = -EINVAL; | 364 | err = -EINVAL; |
365 | if (WARN_ON(npages == 0)) | 365 | if (WARN_ON(npages == 0)) |
366 | goto out; | 366 | goto out; |
367 | 367 | ||
368 | err = 0; | 368 | err = 0; |
369 | 369 | ||
370 | sg_init_table(sgl->sg, npages); | 370 | sg_init_table(sgl->sg, npages); |
371 | 371 | ||
372 | for (i = 0; i < npages; i++) { | 372 | for (i = 0; i < npages; i++) { |
373 | int plen = min_t(int, len, PAGE_SIZE - off); | 373 | int plen = min_t(int, len, PAGE_SIZE - off); |
374 | 374 | ||
375 | sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); | 375 | sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); |
376 | 376 | ||
377 | off = 0; | 377 | off = 0; |
378 | len -= plen; | 378 | len -= plen; |
379 | err += plen; | 379 | err += plen; |
380 | } | 380 | } |
381 | 381 | ||
382 | out: | 382 | out: |
383 | return err; | 383 | return err; |
384 | } | 384 | } |
385 | EXPORT_SYMBOL_GPL(af_alg_make_sg); | 385 | EXPORT_SYMBOL_GPL(af_alg_make_sg); |
386 | 386 | ||
387 | void af_alg_free_sg(struct af_alg_sgl *sgl) | 387 | void af_alg_free_sg(struct af_alg_sgl *sgl) |
388 | { | 388 | { |
389 | int i; | 389 | int i; |
390 | 390 | ||
391 | i = 0; | 391 | i = 0; |
392 | do { | 392 | do { |
393 | put_page(sgl->pages[i]); | 393 | put_page(sgl->pages[i]); |
394 | } while (!sg_is_last(sgl->sg + (i++))); | 394 | } while (!sg_is_last(sgl->sg + (i++))); |
395 | } | 395 | } |
396 | EXPORT_SYMBOL_GPL(af_alg_free_sg); | 396 | EXPORT_SYMBOL_GPL(af_alg_free_sg); |
397 | 397 | ||
398 | int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) | 398 | int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) |
399 | { | 399 | { |
400 | struct cmsghdr *cmsg; | 400 | struct cmsghdr *cmsg; |
401 | 401 | ||
402 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { | 402 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { |
403 | if (!CMSG_OK(msg, cmsg)) | 403 | if (!CMSG_OK(msg, cmsg)) |
404 | return -EINVAL; | 404 | return -EINVAL; |
405 | if (cmsg->cmsg_level != SOL_ALG) | 405 | if (cmsg->cmsg_level != SOL_ALG) |
406 | continue; | 406 | continue; |
407 | 407 | ||
408 | switch(cmsg->cmsg_type) { | 408 | switch(cmsg->cmsg_type) { |
409 | case ALG_SET_IV: | 409 | case ALG_SET_IV: |
410 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv))) | 410 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv))) |
411 | return -EINVAL; | 411 | return -EINVAL; |
412 | con->iv = (void *)CMSG_DATA(cmsg); | 412 | con->iv = (void *)CMSG_DATA(cmsg); |
413 | if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen + | 413 | if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen + |
414 | sizeof(*con->iv))) | 414 | sizeof(*con->iv))) |
415 | return -EINVAL; | 415 | return -EINVAL; |
416 | break; | 416 | break; |
417 | 417 | ||
418 | case ALG_SET_OP: | 418 | case ALG_SET_OP: |
419 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) | 419 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) |
420 | return -EINVAL; | 420 | return -EINVAL; |
421 | con->op = *(u32 *)CMSG_DATA(cmsg); | 421 | con->op = *(u32 *)CMSG_DATA(cmsg); |
422 | break; | 422 | break; |
423 | 423 | ||
424 | default: | 424 | default: |
425 | return -EINVAL; | 425 | return -EINVAL; |
426 | } | 426 | } |
427 | } | 427 | } |
428 | 428 | ||
429 | return 0; | 429 | return 0; |
430 | } | 430 | } |
431 | EXPORT_SYMBOL_GPL(af_alg_cmsg_send); | 431 | EXPORT_SYMBOL_GPL(af_alg_cmsg_send); |
432 | 432 | ||
433 | int af_alg_wait_for_completion(int err, struct af_alg_completion *completion) | 433 | int af_alg_wait_for_completion(int err, struct af_alg_completion *completion) |
434 | { | 434 | { |
435 | switch (err) { | 435 | switch (err) { |
436 | case -EINPROGRESS: | 436 | case -EINPROGRESS: |
437 | case -EBUSY: | 437 | case -EBUSY: |
438 | wait_for_completion(&completion->completion); | 438 | wait_for_completion(&completion->completion); |
439 | reinit_completion(&completion->completion); | 439 | reinit_completion(&completion->completion); |
440 | err = completion->err; | 440 | err = completion->err; |
441 | break; | 441 | break; |
442 | }; | 442 | }; |
443 | 443 | ||
444 | return err; | 444 | return err; |
445 | } | 445 | } |
446 | EXPORT_SYMBOL_GPL(af_alg_wait_for_completion); | 446 | EXPORT_SYMBOL_GPL(af_alg_wait_for_completion); |
447 | 447 | ||
448 | void af_alg_complete(struct crypto_async_request *req, int err) | 448 | void af_alg_complete(struct crypto_async_request *req, int err) |
449 | { | 449 | { |
450 | struct af_alg_completion *completion = req->data; | 450 | struct af_alg_completion *completion = req->data; |
451 | 451 | ||
452 | if (err == -EINPROGRESS) | ||
453 | return; | ||
454 | |||
452 | completion->err = err; | 455 | completion->err = err; |
453 | complete(&completion->completion); | 456 | complete(&completion->completion); |
454 | } | 457 | } |
455 | EXPORT_SYMBOL_GPL(af_alg_complete); | 458 | EXPORT_SYMBOL_GPL(af_alg_complete); |
456 | 459 | ||
457 | static int __init af_alg_init(void) | 460 | static int __init af_alg_init(void) |
458 | { | 461 | { |
459 | int err = proto_register(&alg_proto, 0); | 462 | int err = proto_register(&alg_proto, 0); |
460 | 463 | ||
461 | if (err) | 464 | if (err) |
462 | goto out; | 465 | goto out; |
463 | 466 | ||
464 | err = sock_register(&alg_family); | 467 | err = sock_register(&alg_family); |
465 | if (err != 0) | 468 | if (err != 0) |
466 | goto out_unregister_proto; | 469 | goto out_unregister_proto; |
467 | 470 | ||
468 | out: | 471 | out: |
469 | return err; | 472 | return err; |
470 | 473 | ||
471 | out_unregister_proto: | 474 | out_unregister_proto: |
472 | proto_unregister(&alg_proto); | 475 | proto_unregister(&alg_proto); |
473 | goto out; | 476 | goto out; |
474 | } | 477 | } |
475 | 478 | ||
476 | static void __exit af_alg_exit(void) | 479 | static void __exit af_alg_exit(void) |
477 | { | 480 | { |
478 | sock_unregister(PF_ALG); | 481 | sock_unregister(PF_ALG); |
479 | proto_unregister(&alg_proto); | 482 | proto_unregister(&alg_proto); |
480 | } | 483 | } |
481 | 484 | ||
482 | module_init(af_alg_init); | 485 | module_init(af_alg_init); |
483 | module_exit(af_alg_exit); | 486 | module_exit(af_alg_exit); |
484 | MODULE_LICENSE("GPL"); | 487 | MODULE_LICENSE("GPL"); |
485 | MODULE_ALIAS_NETPROTO(AF_ALG); | 488 | MODULE_ALIAS_NETPROTO(AF_ALG); |
486 | 489 |