mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
![Elena Petrova](/assets/img/avatar_default.png)
Extend the user-space RNG interface: 1. Add entropy input via ALG_SET_DRBG_ENTROPY setsockopt option; 2. Add additional data input via sendmsg syscall. This allows DRBG to be tested with test vectors, for example for the purpose of CAVP testing, which otherwise isn't possible. To prevent erroneous use of entropy input, it is hidden under CRYPTO_USER_API_RNG_CAVP config option and requires CAP_SYS_ADMIN to succeed. Signed-off-by: Elena Petrova <lenaptr@google.com> Acked-by: Stephan Müller <smueller@chronox.de> Reviewed-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
247 lines
6.6 KiB
C
247 lines
6.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* if_alg: User-space algorithm interface
|
|
*
|
|
* Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
|
|
*/
|
|
|
|
#ifndef _CRYPTO_IF_ALG_H
|
|
#define _CRYPTO_IF_ALG_H
|
|
|
|
#include <linux/compiler.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/if_alg.h>
|
|
#include <linux/scatterlist.h>
|
|
#include <linux/types.h>
|
|
#include <linux/atomic.h>
|
|
#include <net/sock.h>
|
|
|
|
#include <crypto/aead.h>
|
|
#include <crypto/skcipher.h>
|
|
|
|
#define ALG_MAX_PAGES 16
|
|
|
|
struct crypto_async_request;
|
|
|
|
struct alg_sock {
|
|
/* struct sock must be the first member of struct alg_sock */
|
|
struct sock sk;
|
|
|
|
struct sock *parent;
|
|
|
|
atomic_t refcnt;
|
|
atomic_t nokey_refcnt;
|
|
|
|
const struct af_alg_type *type;
|
|
void *private;
|
|
};
|
|
|
|
struct af_alg_control {
|
|
struct af_alg_iv *iv;
|
|
int op;
|
|
unsigned int aead_assoclen;
|
|
};
|
|
|
|
struct af_alg_type {
|
|
void *(*bind)(const char *name, u32 type, u32 mask);
|
|
void (*release)(void *private);
|
|
int (*setkey)(void *private, const u8 *key, unsigned int keylen);
|
|
int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
|
|
int (*accept)(void *private, struct sock *sk);
|
|
int (*accept_nokey)(void *private, struct sock *sk);
|
|
int (*setauthsize)(void *private, unsigned int authsize);
|
|
|
|
struct proto_ops *ops;
|
|
struct proto_ops *ops_nokey;
|
|
struct module *owner;
|
|
char name[14];
|
|
};
|
|
|
|
struct af_alg_sgl {
|
|
struct scatterlist sg[ALG_MAX_PAGES + 1];
|
|
struct page *pages[ALG_MAX_PAGES];
|
|
unsigned int npages;
|
|
};
|
|
|
|
/* TX SGL entry */
|
|
struct af_alg_tsgl {
|
|
struct list_head list;
|
|
unsigned int cur; /* Last processed SG entry */
|
|
struct scatterlist sg[]; /* Array of SGs forming the SGL */
|
|
};
|
|
|
|
#define MAX_SGL_ENTS ((4096 - sizeof(struct af_alg_tsgl)) / \
|
|
sizeof(struct scatterlist) - 1)
|
|
|
|
/* RX SGL entry */
|
|
struct af_alg_rsgl {
|
|
struct af_alg_sgl sgl;
|
|
struct list_head list;
|
|
size_t sg_num_bytes; /* Bytes of data in that SGL */
|
|
};
|
|
|
|
/**
|
|
* struct af_alg_async_req - definition of crypto request
|
|
* @iocb: IOCB for AIO operations
|
|
* @sk: Socket the request is associated with
|
|
* @first_rsgl: First RX SG
|
|
* @last_rsgl: Pointer to last RX SG
|
|
* @rsgl_list: Track RX SGs
|
|
* @tsgl: Private, per request TX SGL of buffers to process
|
|
* @tsgl_entries: Number of entries in priv. TX SGL
|
|
* @outlen: Number of output bytes generated by crypto op
|
|
* @areqlen: Length of this data structure
|
|
* @cra_u: Cipher request
|
|
*/
|
|
struct af_alg_async_req {
|
|
struct kiocb *iocb;
|
|
struct sock *sk;
|
|
|
|
struct af_alg_rsgl first_rsgl;
|
|
struct af_alg_rsgl *last_rsgl;
|
|
struct list_head rsgl_list;
|
|
|
|
struct scatterlist *tsgl;
|
|
unsigned int tsgl_entries;
|
|
|
|
unsigned int outlen;
|
|
unsigned int areqlen;
|
|
|
|
union {
|
|
struct aead_request aead_req;
|
|
struct skcipher_request skcipher_req;
|
|
} cra_u;
|
|
|
|
/* req ctx trails this struct */
|
|
};
|
|
|
|
/**
|
|
* struct af_alg_ctx - definition of the crypto context
|
|
*
|
|
* The crypto context tracks the input data during the lifetime of an AF_ALG
|
|
* socket.
|
|
*
|
|
* @tsgl_list: Link to TX SGL
|
|
* @iv: IV for cipher operation
|
|
* @aead_assoclen: Length of AAD for AEAD cipher operations
|
|
* @completion: Work queue for synchronous operation
|
|
* @used: TX bytes sent to kernel. This variable is used to
|
|
* ensure that user space cannot cause the kernel
|
|
* to allocate too much memory in sendmsg operation.
|
|
* @rcvused: Total RX bytes to be filled by kernel. This variable
|
|
* is used to ensure user space cannot cause the kernel
|
|
* to allocate too much memory in a recvmsg operation.
|
|
* @more: More data to be expected from user space?
|
|
* @merge: Shall new data from user space be merged into existing
|
|
* SG?
|
|
* @enc: Cryptographic operation to be performed when
|
|
* recvmsg is invoked.
|
|
* @init: True if metadata has been sent.
|
|
* @len: Length of memory allocated for this data structure.
|
|
*/
|
|
struct af_alg_ctx {
|
|
struct list_head tsgl_list;
|
|
|
|
void *iv;
|
|
size_t aead_assoclen;
|
|
|
|
struct crypto_wait wait;
|
|
|
|
size_t used;
|
|
atomic_t rcvused;
|
|
|
|
bool more;
|
|
bool merge;
|
|
bool enc;
|
|
bool init;
|
|
|
|
unsigned int len;
|
|
};
|
|
|
|
int af_alg_register_type(const struct af_alg_type *type);
|
|
int af_alg_unregister_type(const struct af_alg_type *type);
|
|
|
|
int af_alg_release(struct socket *sock);
|
|
void af_alg_release_parent(struct sock *sk);
|
|
int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern);
|
|
|
|
int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len);
|
|
void af_alg_free_sg(struct af_alg_sgl *sgl);
|
|
|
|
static inline struct alg_sock *alg_sk(struct sock *sk)
|
|
{
|
|
return (struct alg_sock *)sk;
|
|
}
|
|
|
|
/**
|
|
* Size of available buffer for sending data from user space to kernel.
|
|
*
|
|
* @sk socket of connection to user space
|
|
* @return number of bytes still available
|
|
*/
|
|
static inline int af_alg_sndbuf(struct sock *sk)
|
|
{
|
|
struct alg_sock *ask = alg_sk(sk);
|
|
struct af_alg_ctx *ctx = ask->private;
|
|
|
|
return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) -
|
|
ctx->used, 0);
|
|
}
|
|
|
|
/**
|
|
* Can the send buffer still be written to?
|
|
*
|
|
* @sk socket of connection to user space
|
|
* @return true => writable, false => not writable
|
|
*/
|
|
static inline bool af_alg_writable(struct sock *sk)
|
|
{
|
|
return PAGE_SIZE <= af_alg_sndbuf(sk);
|
|
}
|
|
|
|
/**
|
|
* Size of available buffer used by kernel for the RX user space operation.
|
|
*
|
|
* @sk socket of connection to user space
|
|
* @return number of bytes still available
|
|
*/
|
|
static inline int af_alg_rcvbuf(struct sock *sk)
|
|
{
|
|
struct alg_sock *ask = alg_sk(sk);
|
|
struct af_alg_ctx *ctx = ask->private;
|
|
|
|
return max_t(int, max_t(int, sk->sk_rcvbuf & PAGE_MASK, PAGE_SIZE) -
|
|
atomic_read(&ctx->rcvused), 0);
|
|
}
|
|
|
|
/**
|
|
* Can the RX buffer still be written to?
|
|
*
|
|
* @sk socket of connection to user space
|
|
* @return true => writable, false => not writable
|
|
*/
|
|
static inline bool af_alg_readable(struct sock *sk)
|
|
{
|
|
return PAGE_SIZE <= af_alg_rcvbuf(sk);
|
|
}
|
|
|
|
unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset);
|
|
void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst,
|
|
size_t dst_offset);
|
|
void af_alg_wmem_wakeup(struct sock *sk);
|
|
int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min);
|
|
int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size,
|
|
unsigned int ivsize);
|
|
ssize_t af_alg_sendpage(struct socket *sock, struct page *page,
|
|
int offset, size_t size, int flags);
|
|
void af_alg_free_resources(struct af_alg_async_req *areq);
|
|
void af_alg_async_cb(struct crypto_async_request *_req, int err);
|
|
__poll_t af_alg_poll(struct file *file, struct socket *sock,
|
|
poll_table *wait);
|
|
struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk,
|
|
unsigned int areqlen);
|
|
int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
|
|
struct af_alg_async_req *areq, size_t maxsize,
|
|
size_t *outlen);
|
|
|
|
#endif /* _CRYPTO_IF_ALG_H */
|