/* 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 16struct 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); 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 sg_table sgt; struct scatterlist sgl[ALG_MAX_PAGES + 1]; bool need_unpin;};/* 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 * @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 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 * @state: Existing state for continuing 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. * @write: True if we are in the middle of a write. * @init: True if metadata has been sent. * @len: Length of memory allocated for this data structure. * @inflight: Non-zero when requests are in flight, for debugging only. */struct af_alg_ctx { struct list_head tsgl_list; void *iv; void *state; size_t aead_assoclen; struct crypto_wait wait; size_t used; atomic_t rcvused; bool more:1, merge:1, enc:1, write:1, init:1; unsigned int len; unsigned int inflight;};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, struct proto_accept_arg *arg);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);void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst);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);void af_alg_free_resources(struct af_alg_async_req *areq);__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);/* * Mask used to disable unsupported algorithm implementations. * * This is the same as FSCRYPT_CRYPTOAPI_MASK in fs/crypto/fscrypt_private.h. * In additions to the motivations there, this API is exposed to userspace * that might not be fully trusted. */#define AF_ALG_CRYPTOAPI_MASK \ (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \ CRYPTO_ALG_KERN_DRIVER_ONLY)#endif /* _CRYPTO_IF_ALG_H */
/* 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 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);
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 sg_table sgt;
struct scatterlist sgl[ALG_MAX_PAGES + 1];
bool need_unpin;
};
/* 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
* @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 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
* @state: Existing state for continuing 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.
* @write: True if we are in the middle of a write.
* @init: True if metadata has been sent.
* @len: Length of memory allocated for this data structure.
* @inflight: Non-zero when requests are in flight, for debugging only.
*/
struct af_alg_ctx {
struct list_head tsgl_list;
void *iv;
void *state;
size_t aead_assoclen;
struct crypto_wait wait;
size_t used;
atomic_t rcvused;
bool more:1,
merge:1,
enc:1,
write:1,
init:1;
unsigned int len;
unsigned int inflight;
};
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,
struct proto_accept_arg *arg);
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);
void af_alg_pull_tsgl(struct sock *sk, size_t used, struct scatterlist *dst);
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);
void af_alg_free_resources(struct af_alg_async_req *areq);
__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);
/*
* Mask used to disable unsupported algorithm implementations.
*
* This is the same as FSCRYPT_CRYPTOAPI_MASK in fs/crypto/fscrypt_private.h.
* In additions to the motivations there, this API is exposed to userspace
* that might not be fully trusted.
*/
#define AF_ALG_CRYPTOAPI_MASK \
(CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \
CRYPTO_ALG_KERN_DRIVER_ONLY)
#endif /* _CRYPTO_IF_ALG_H */