developer | 34e20fa | 2023-11-14 13:49:21 +0800 | [diff] [blame] | 1 | diff --git a/crypto/af_alg.c b/crypto/af_alg.c |
| 2 | index 4a2e91baa..fb6b4f8a0 100644 |
| 3 | --- a/crypto/af_alg.c |
| 4 | +++ b/crypto/af_alg.c |
| 5 | @@ -226,6 +226,30 @@ static int alg_setkey(struct sock *sk, char __user *ukey, |
| 6 | return err; |
| 7 | } |
| 8 | |
| 9 | +static int alg_setentropy(struct sock *sk, char __user *ukey, |
| 10 | + unsigned int entropy_len) |
| 11 | +{ |
| 12 | + struct alg_sock *ask = alg_sk(sk); |
| 13 | + const struct af_alg_type *type = ask->type; |
| 14 | + u8 *entropy; |
| 15 | + int err; |
| 16 | + |
| 17 | + entropy = sock_kmalloc(sk, entropy_len, GFP_KERNEL); |
| 18 | + if (!entropy) |
| 19 | + return -ENOMEM; |
| 20 | + |
| 21 | + err = -EFAULT; |
| 22 | + if (copy_from_user(entropy, ukey, entropy_len)) |
| 23 | + goto out; |
| 24 | + |
| 25 | + err = type->setentropy(ask->private, entropy, entropy_len); |
| 26 | + |
| 27 | +out: |
| 28 | + sock_kzfree_s(sk, entropy, entropy_len); |
| 29 | + |
| 30 | + return err; |
| 31 | +} |
| 32 | + |
| 33 | static int alg_setsockopt(struct socket *sock, int level, int optname, |
| 34 | char __user *optval, unsigned int optlen) |
| 35 | { |
| 36 | @@ -250,7 +274,6 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, |
| 37 | goto unlock; |
| 38 | if (!type->setkey) |
| 39 | goto unlock; |
| 40 | - |
| 41 | err = alg_setkey(sk, optval, optlen); |
| 42 | break; |
| 43 | case ALG_SET_AEAD_AUTHSIZE: |
| 44 | @@ -259,6 +282,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, |
| 45 | if (!type->setauthsize) |
| 46 | goto unlock; |
| 47 | err = type->setauthsize(ask->private, optlen); |
| 48 | + break; |
| 49 | + case ALG_SET_DRBG_ENTROPY: |
| 50 | + if (sock->state == SS_CONNECTED) |
| 51 | + goto unlock; |
| 52 | + if (!type->setentropy) |
| 53 | + goto unlock; |
| 54 | + err = alg_setentropy(sk, optval, optlen); |
| 55 | + break; |
| 56 | + |
| 57 | } |
| 58 | |
| 59 | unlock: |
| 60 | @@ -291,6 +323,11 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern) |
| 61 | security_sock_graft(sk2, newsock); |
| 62 | security_sk_clone(sk, sk2); |
| 63 | |
| 64 | + /* |
| 65 | + * newsock->ops assigned here to allow type->accept call to override |
| 66 | + * them when required. |
| 67 | + */ |
| 68 | + newsock->ops = type->ops; |
| 69 | err = type->accept(ask->private, sk2); |
| 70 | |
| 71 | nokey = err == -ENOKEY; |
| 72 | @@ -309,7 +346,6 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern) |
| 73 | alg_sk(sk2)->parent = sk; |
| 74 | alg_sk(sk2)->type = type; |
| 75 | |
| 76 | - newsock->ops = type->ops; |
| 77 | newsock->state = SS_CONNECTED; |
| 78 | |
| 79 | if (nokey) |
| 80 | diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c |
| 81 | index 22df3799a..bce3aef53 100644 |
| 82 | --- a/crypto/algif_rng.c |
| 83 | +++ b/crypto/algif_rng.c |
| 84 | @@ -38,6 +38,7 @@ |
| 85 | * DAMAGE. |
| 86 | */ |
| 87 | |
| 88 | +#include <linux/capability.h> |
| 89 | #include <linux/module.h> |
| 90 | #include <crypto/rng.h> |
| 91 | #include <linux/random.h> |
| 92 | @@ -53,15 +54,26 @@ struct rng_ctx { |
| 93 | #define MAXSIZE 128 |
| 94 | unsigned int len; |
| 95 | struct crypto_rng *drng; |
| 96 | + u8 *addtl; |
| 97 | + size_t addtl_len; |
| 98 | }; |
| 99 | |
| 100 | -static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
| 101 | - int flags) |
| 102 | +struct rng_parent_ctx { |
| 103 | + struct crypto_rng *drng; |
| 104 | + u8 *entropy; |
| 105 | +}; |
| 106 | + |
| 107 | +static void rng_reset_addtl(struct rng_ctx *ctx) |
| 108 | { |
| 109 | - struct sock *sk = sock->sk; |
| 110 | - struct alg_sock *ask = alg_sk(sk); |
| 111 | - struct rng_ctx *ctx = ask->private; |
| 112 | - int err = -EFAULT; |
| 113 | + kzfree(ctx->addtl); |
| 114 | + ctx->addtl = NULL; |
| 115 | + ctx->addtl_len = 0; |
| 116 | +} |
| 117 | + |
| 118 | +static int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len, |
| 119 | + u8 *addtl, size_t addtl_len) |
| 120 | +{ |
| 121 | + int err = 0; |
| 122 | int genlen = 0; |
| 123 | u8 result[MAXSIZE]; |
| 124 | |
| 125 | @@ -82,7 +94,7 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
| 126 | * seeding as they automatically seed. The X9.31 DRNG will return |
| 127 | * an error if it was not seeded properly. |
| 128 | */ |
| 129 | - genlen = crypto_rng_get_bytes(ctx->drng, result, len); |
| 130 | + genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len); |
| 131 | if (genlen < 0) |
| 132 | return genlen; |
| 133 | |
| 134 | @@ -92,6 +104,63 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
| 135 | return err ? err : len; |
| 136 | } |
| 137 | |
| 138 | +static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
| 139 | + int flags) |
| 140 | +{ |
| 141 | + struct sock *sk = sock->sk; |
| 142 | + struct alg_sock *ask = alg_sk(sk); |
| 143 | + struct rng_ctx *ctx = ask->private; |
| 144 | + |
| 145 | + return _rng_recvmsg(ctx->drng, msg, len, NULL, 0); |
| 146 | +} |
| 147 | + |
| 148 | +static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, |
| 149 | + int flags) |
| 150 | +{ |
| 151 | + struct sock *sk = sock->sk; |
| 152 | + struct alg_sock *ask = alg_sk(sk); |
| 153 | + struct rng_ctx *ctx = ask->private; |
| 154 | + int ret; |
| 155 | + |
| 156 | + lock_sock(sock->sk); |
| 157 | + ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len); |
| 158 | + rng_reset_addtl(ctx); |
| 159 | + release_sock(sock->sk); |
| 160 | + |
| 161 | + return ret; |
| 162 | +} |
| 163 | + |
| 164 | +static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) |
| 165 | +{ |
| 166 | + int err; |
| 167 | + struct alg_sock *ask = alg_sk(sock->sk); |
| 168 | + struct rng_ctx *ctx = ask->private; |
| 169 | + |
| 170 | + lock_sock(sock->sk); |
| 171 | + if (len > MAXSIZE) { |
| 172 | + err = -EMSGSIZE; |
| 173 | + goto unlock; |
| 174 | + } |
| 175 | + |
| 176 | + rng_reset_addtl(ctx); |
| 177 | + ctx->addtl = kmalloc(len, GFP_KERNEL); |
| 178 | + if (!ctx->addtl) { |
| 179 | + err = -ENOMEM; |
| 180 | + goto unlock; |
| 181 | + } |
| 182 | + |
| 183 | + err = memcpy_from_msg(ctx->addtl, msg, len); |
| 184 | + if (err) { |
| 185 | + rng_reset_addtl(ctx); |
| 186 | + goto unlock; |
| 187 | + } |
| 188 | + ctx->addtl_len = len; |
| 189 | + |
| 190 | +unlock: |
| 191 | + release_sock(sock->sk); |
| 192 | + return err ? err : len; |
| 193 | +} |
| 194 | + |
| 195 | static struct proto_ops algif_rng_ops = { |
| 196 | .family = PF_ALG, |
| 197 | |
| 198 | @@ -113,14 +182,53 @@ static struct proto_ops algif_rng_ops = { |
| 199 | .recvmsg = rng_recvmsg, |
| 200 | }; |
| 201 | |
| 202 | +static struct proto_ops __maybe_unused algif_rng_test_ops = { |
| 203 | + .family = PF_ALG, |
| 204 | + |
| 205 | + .connect = sock_no_connect, |
| 206 | + .socketpair = sock_no_socketpair, |
| 207 | + .getname = sock_no_getname, |
| 208 | + .ioctl = sock_no_ioctl, |
| 209 | + .listen = sock_no_listen, |
| 210 | + .shutdown = sock_no_shutdown, |
| 211 | + .mmap = sock_no_mmap, |
| 212 | + .bind = sock_no_bind, |
| 213 | + .accept = sock_no_accept, |
| 214 | + .sendpage = sock_no_sendpage, |
| 215 | + |
| 216 | + .release = af_alg_release, |
| 217 | + .recvmsg = rng_test_recvmsg, |
| 218 | + .sendmsg = rng_test_sendmsg, |
| 219 | +}; |
| 220 | + |
| 221 | static void *rng_bind(const char *name, u32 type, u32 mask) |
| 222 | { |
| 223 | - return crypto_alloc_rng(name, type, mask); |
| 224 | + struct rng_parent_ctx *pctx; |
| 225 | + struct crypto_rng *rng; |
| 226 | + |
| 227 | + pctx = kzalloc(sizeof(*pctx), GFP_KERNEL); |
| 228 | + if (!pctx) |
| 229 | + return ERR_PTR(-ENOMEM); |
| 230 | + |
| 231 | + rng = crypto_alloc_rng(name, type, mask); |
| 232 | + if (IS_ERR(rng)) { |
| 233 | + kfree(pctx); |
| 234 | + return ERR_CAST(rng); |
| 235 | + } |
| 236 | + |
| 237 | + pctx->drng = rng; |
| 238 | + return pctx; |
| 239 | } |
| 240 | |
| 241 | static void rng_release(void *private) |
| 242 | { |
| 243 | - crypto_free_rng(private); |
| 244 | + struct rng_parent_ctx *pctx = private; |
| 245 | + if (unlikely(!pctx)) |
| 246 | + return; |
| 247 | + crypto_free_rng(pctx->drng); |
| 248 | + kzfree(pctx->entropy); |
| 249 | + kzfree(pctx); |
| 250 | + return; |
| 251 | } |
| 252 | |
| 253 | static void rng_sock_destruct(struct sock *sk) |
| 254 | @@ -128,6 +236,7 @@ static void rng_sock_destruct(struct sock *sk) |
| 255 | struct alg_sock *ask = alg_sk(sk); |
| 256 | struct rng_ctx *ctx = ask->private; |
| 257 | |
| 258 | + rng_reset_addtl(ctx); |
| 259 | sock_kfree_s(sk, ctx, ctx->len); |
| 260 | af_alg_release_parent(sk); |
| 261 | } |
| 262 | @@ -135,6 +244,7 @@ static void rng_sock_destruct(struct sock *sk) |
| 263 | static int rng_accept_parent(void *private, struct sock *sk) |
| 264 | { |
| 265 | struct rng_ctx *ctx; |
| 266 | + struct rng_parent_ctx *pctx = private; |
| 267 | struct alg_sock *ask = alg_sk(sk); |
| 268 | unsigned int len = sizeof(*ctx); |
| 269 | |
| 270 | @@ -143,6 +253,8 @@ static int rng_accept_parent(void *private, struct sock *sk) |
| 271 | return -ENOMEM; |
| 272 | |
| 273 | ctx->len = len; |
| 274 | + ctx->addtl = NULL; |
| 275 | + ctx->addtl_len = 0; |
| 276 | |
| 277 | /* |
| 278 | * No seeding done at that point -- if multiple accepts are |
| 279 | @@ -150,20 +262,59 @@ static int rng_accept_parent(void *private, struct sock *sk) |
| 280 | * state of the RNG. |
| 281 | */ |
| 282 | |
| 283 | - ctx->drng = private; |
| 284 | + ctx->drng = pctx->drng; |
| 285 | ask->private = ctx; |
| 286 | sk->sk_destruct = rng_sock_destruct; |
| 287 | |
| 288 | + /* |
| 289 | + * Non NULL pctx->entropy means that CAVP test has been initiated on |
| 290 | + * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops. |
| 291 | + */ |
| 292 | + if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy) |
| 293 | + sk->sk_socket->ops = &algif_rng_test_ops; |
| 294 | return 0; |
| 295 | } |
| 296 | |
| 297 | static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen) |
| 298 | { |
| 299 | + struct rng_parent_ctx *pctx = private; |
| 300 | /* |
| 301 | * Check whether seedlen is of sufficient size is done in RNG |
| 302 | * implementations. |
| 303 | */ |
| 304 | - return crypto_rng_reset(private, seed, seedlen); |
| 305 | + return crypto_rng_reset(pctx->drng, seed, seedlen); |
| 306 | +} |
| 307 | + |
| 308 | +static int __maybe_unused rng_setentropy(void *private, const u8 *entropy, |
| 309 | + unsigned int len) |
| 310 | +{ |
| 311 | + struct rng_parent_ctx *pctx = private; |
| 312 | + u8 *kentropy = NULL; |
| 313 | + int i; |
| 314 | + |
| 315 | + if (!capable(CAP_SYS_ADMIN)) |
| 316 | + return -EACCES; |
| 317 | + |
| 318 | + if (pctx->entropy) |
| 319 | + return -EINVAL; |
| 320 | + |
| 321 | + if (len > MAXSIZE) |
| 322 | + return -EMSGSIZE; |
| 323 | + |
| 324 | + if (len) { |
| 325 | + kentropy = (u8*)kmalloc(len, GFP_KERNEL); |
| 326 | + memcpy(kentropy, entropy, len); |
| 327 | + if (IS_ERR(kentropy)) |
| 328 | + return PTR_ERR(kentropy); |
| 329 | + } |
| 330 | + |
| 331 | + crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len); |
| 332 | + /* |
| 333 | + * Since rng doesn't perform any memory management for the entropy |
| 334 | + * buffer, save kentropy pointer to pctx now to free it after use. |
| 335 | + */ |
| 336 | + pctx->entropy = kentropy; |
| 337 | + return 0; |
| 338 | } |
| 339 | |
| 340 | static const struct af_alg_type algif_type_rng = { |
| 341 | @@ -173,7 +324,10 @@ static const struct af_alg_type algif_type_rng = { |
| 342 | .setkey = rng_setkey, |
| 343 | .ops = &algif_rng_ops, |
| 344 | .name = "rng", |
| 345 | - .owner = THIS_MODULE |
| 346 | + .owner = THIS_MODULE, |
| 347 | +#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP |
| 348 | + .setentropy = rng_setentropy, |
| 349 | +#endif |
| 350 | }; |
| 351 | |
| 352 | static int __init rng_init(void) |
| 353 | diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h |
| 354 | index c1a8d4a41..ca06787f7 100644 |
| 355 | --- a/include/crypto/if_alg.h |
| 356 | +++ b/include/crypto/if_alg.h |
| 357 | @@ -46,6 +46,7 @@ struct af_alg_type { |
| 358 | void *(*bind)(const char *name, u32 type, u32 mask); |
| 359 | void (*release)(void *private); |
| 360 | int (*setkey)(void *private, const u8 *key, unsigned int keylen); |
| 361 | + int (*setentropy)(void *private, const u8 *key, unsigned int keylen); |
| 362 | int (*accept)(void *private, struct sock *sk); |
| 363 | int (*accept_nokey)(void *private, struct sock *sk); |
| 364 | int (*setauthsize)(void *private, unsigned int authsize); |
| 365 | diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h |
| 366 | index 769050771..dc52a11ba 100644 |
| 367 | --- a/include/uapi/linux/if_alg.h |
| 368 | +++ b/include/uapi/linux/if_alg.h |
| 369 | @@ -51,6 +51,7 @@ struct af_alg_iv { |
| 370 | #define ALG_SET_OP 3 |
| 371 | #define ALG_SET_AEAD_ASSOCLEN 4 |
| 372 | #define ALG_SET_AEAD_AUTHSIZE 5 |
| 373 | +#define ALG_SET_DRBG_ENTROPY 6 |
| 374 | |
| 375 | /* Operations */ |
| 376 | #define ALG_OP_DECRYPT 0 |