cregit-Linux how code gets into the kernel

Release 4.7 crypto/af_alg.c

Directory: crypto
/*
 * af_alg: User-space algorithm interface
 *
 * This file provides the user-space API for algorithms.
 *
 * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 */

#include <linux/atomic.h>
#include <crypto/if_alg.h>
#include <linux/crypto.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/rwsem.h>
#include <linux/security.h>


struct alg_type_list {
	
const struct af_alg_type *type;
	
struct list_head list;
};


static atomic_long_t alg_memory_allocated;


static struct proto alg_proto = {
	.name			= "ALG",
	.owner			= THIS_MODULE,
	.memory_allocated	= &alg_memory_allocated,
	.obj_size		= sizeof(struct alg_sock),
};

static LIST_HEAD(alg_types);
static DECLARE_RWSEM(alg_types_sem);


static const struct af_alg_type *alg_get_type(const char *name) { const struct af_alg_type *type = ERR_PTR(-ENOENT); struct alg_type_list *node; down_read(&alg_types_sem); list_for_each_entry(node, &alg_types, list) { if (strcmp(node->type->name, name)) continue; if (try_module_get(node->type->owner)) type = node->type; break; } up_read(&alg_types_sem); return type; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu88100.00%1100.00%
Total88100.00%1100.00%


int af_alg_register_type(const struct af_alg_type *type) { struct alg_type_list *node; int err = -EEXIST; down_write(&alg_types_sem); list_for_each_entry(node, &alg_types, list) { if (!strcmp(node->type->name, type->name)) goto unlock; } node = kmalloc(sizeof(*node), GFP_KERNEL); err = -ENOMEM; if (!node) goto unlock; type->ops->owner = THIS_MODULE; if (type->ops_nokey) type->ops_nokey->owner = THIS_MODULE; node->type = type; list_add(&node->list, &alg_types); err = 0; unlock: up_write(&alg_types_sem); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu137100.00%2100.00%
Total137100.00%2100.00%

EXPORT_SYMBOL_GPL(af_alg_register_type);
int af_alg_unregister_type(const struct af_alg_type *type) { struct alg_type_list *node; int err = -ENOENT; down_write(&alg_types_sem); list_for_each_entry(node, &alg_types, list) { if (strcmp(node->type->name, type->name)) continue; list_del(&node->list); kfree(node); err = 0; break; } up_write(&alg_types_sem); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu81100.00%1100.00%
Total81100.00%1100.00%

EXPORT_SYMBOL_GPL(af_alg_unregister_type);
static void alg_do_release(const struct af_alg_type *type, void *private) { if (!type) return; type->release(private); module_put(type->owner); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu36100.00%1100.00%
Total36100.00%1100.00%


int af_alg_release(struct socket *sock) { if (sock->sk) sock_put(sock->sk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu26100.00%1100.00%
Total26100.00%1100.00%

EXPORT_SYMBOL_GPL(af_alg_release);
void af_alg_release_parent(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); unsigned int nokey = ask->nokey_refcnt; bool last = nokey && !ask->refcnt; sk = ask->parent; ask = alg_sk(sk); lock_sock(sk); ask->nokey_refcnt -= nokey; if (!last) last = !--ask->refcnt; release_sock(sk); if (last) sock_put(sk); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu89100.00%3100.00%
Total89100.00%3100.00%

EXPORT_SYMBOL_GPL(af_alg_release_parent);
static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { const u32 forbidden = CRYPTO_ALG_INTERNAL; struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); struct sockaddr_alg *sa = (void *)uaddr; const struct af_alg_type *type; void *private; int err; if (sock->state == SS_CONNECTED) return -EINVAL; if (addr_len != sizeof(*sa)) return -EINVAL; sa->salg_type[sizeof(sa->salg_type) - 1] = 0; sa->salg_name[sizeof(sa->salg_name) - 1] = 0; type = alg_get_type(sa->salg_type); if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) { request_module("algif-%s", sa->salg_type); type = alg_get_type(sa->salg_type); } if (IS_ERR(type)) return PTR_ERR(type); private = type->bind(sa->salg_name, sa->salg_feat & ~forbidden, sa->salg_mask & ~forbidden); if (IS_ERR(private)) { module_put(type->owner); return PTR_ERR(private); } err = -EBUSY; lock_sock(sk); if (ask->refcnt | ask->nokey_refcnt) goto unlock; swap(ask->type, type); swap(ask->private, private); err = 0; unlock: release_sock(sk); alg_do_release(type, private); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu292100.00%4100.00%
Total292100.00%4100.00%


static int alg_setkey(struct sock *sk, char __user *ukey, unsigned int keylen) { struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type = ask->type; u8 *key; int err; key = sock_kmalloc(sk, keylen, GFP_KERNEL); if (!key) return -ENOMEM; err = -EFAULT; if (copy_from_user(key, ukey, keylen)) goto out; err = type->setkey(ask->private, key, keylen); out: sock_kzfree_s(sk, key, keylen); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu11499.13%150.00%
stephan muellerstephan mueller10.87%150.00%
Total115100.00%2100.00%


static int alg_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type; int err = -EBUSY; lock_sock(sk); if (ask->refcnt) goto unlock; type = ask->type; err = -ENOPROTOOPT; if (level != SOL_ALG || !type) goto unlock; switch (optname) { case ALG_SET_KEY: if (sock->state == SS_CONNECTED) goto unlock; if (!type->setkey) goto unlock; err = alg_setkey(sk, optval, optlen); break; case ALG_SET_AEAD_AUTHSIZE: if (sock->state == SS_CONNECTED) goto unlock; if (!type->setauthsize) goto unlock; err = type->setauthsize(ask->private, optlen); } unlock: release_sock(sk); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu14579.23%266.67%
stephan muellerstephan mueller3820.77%133.33%
Total183100.00%3100.00%


int af_alg_accept(struct sock *sk, struct socket *newsock) { struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type; struct sock *sk2; unsigned int nokey; int err; lock_sock(sk); type = ask->type; err = -EINVAL; if (!type) goto unlock; sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto, 0); err = -ENOMEM; if (!sk2) goto unlock; sock_init_data(newsock, sk2); sock_graft(sk2, newsock); security_sk_clone(sk, sk2); err = type->accept(ask->private, sk2); nokey = err == -ENOKEY; if (nokey && type->accept_nokey) err = type->accept_nokey(ask->private, sk2); if (err) goto unlock; sk2->sk_family = PF_ALG; if (nokey || !ask->refcnt++) sock_hold(sk); ask->nokey_refcnt += nokey; alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; alg_sk(sk2)->nokey_refcnt = nokey; newsock->ops = type->ops; newsock->state = SS_CONNECTED; if (nokey) newsock->ops = type->ops_nokey; err = 0; unlock: release_sock(sk); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu24693.89%562.50%
miloslav trmacmiloslav trmac72.67%112.50%
milan brozmilan broz72.67%112.50%
eric w. biedermaneric w. biederman20.76%112.50%
Total262100.00%8100.00%

EXPORT_SYMBOL_GPL(af_alg_accept);
static int alg_accept(struct socket *sock, struct socket *newsock, int flags) { return af_alg_accept(sock->sk, newsock); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu29100.00%1100.00%
Total29100.00%1100.00%

static const struct proto_ops alg_proto_ops = { .family = PF_ALG, .owner = THIS_MODULE, .connect = sock_no_connect, .socketpair = sock_no_socketpair, .getname = sock_no_getname, .ioctl = sock_no_ioctl, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .getsockopt = sock_no_getsockopt, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, .sendmsg = sock_no_sendmsg, .recvmsg = sock_no_recvmsg, .poll = sock_no_poll, .bind = alg_bind, .release = af_alg_release, .setsockopt = alg_setsockopt, .accept = alg_accept, };
static void alg_sock_destruct(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); alg_do_release(ask->type, ask->private); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu32100.00%1100.00%
Total32100.00%1100.00%


static int alg_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; int err; if (sock->type != SOCK_SEQPACKET) return -ESOCKTNOSUPPORT; if (protocol != 0) return -EPROTONOSUPPORT; err = -ENOMEM; sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto, kern); if (!sk) goto out; sock->ops = &alg_proto_ops; sock_init_data(sock, sk); sk->sk_family = PF_ALG; sk->sk_destruct = alg_sock_destruct; return 0; out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu11398.26%150.00%
eric w. biedermaneric w. biederman21.74%150.00%
Total115100.00%2100.00%

static const struct net_proto_family alg_family = { .family = PF_ALG, .create = alg_create, .owner = THIS_MODULE, };
int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len) { size_t off; ssize_t n; int npages, i; n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off); if (n < 0) return n; npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT; if (WARN_ON(npages == 0)) return -EINVAL; /* Add one extra for linking */ sg_init_table(sgl->sg, npages + 1); for (i = 0, len = n; i < npages; i++) { int plen = min_t(int, len, PAGE_SIZE - off); sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); off = 0; len -= plen; } sg_mark_end(sgl->sg + npages - 1); sgl->npages = npages; return n; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu11565.34%125.00%
al viroal viro3318.75%125.00%
tadeusz struktadeusz struk2011.36%125.00%
linus torvaldslinus torvalds84.55%125.00%
Total176100.00%4100.00%

EXPORT_SYMBOL_GPL(af_alg_make_sg);
void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new) { sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg); }

Contributors

PersonTokensPropCommitsCommitProp
tadeusz struktadeusz struk45100.00%1100.00%
Total45100.00%1100.00%

EXPORT_SYMBOL_GPL(af_alg_link_sg);
void af_alg_free_sg(struct af_alg_sgl *sgl) { int i; for (i = 0; i < sgl->npages; i++) put_page(sgl->pages[i]); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu2668.42%150.00%
tadeusz struktadeusz struk1231.58%150.00%
Total38100.00%2100.00%

EXPORT_SYMBOL_GPL(af_alg_free_sg);
int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) { struct cmsghdr *cmsg; for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL; if (cmsg->cmsg_level != SOL_ALG) continue; switch (cmsg->cmsg_type) { case ALG_SET_IV: if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv))) return -EINVAL; con->iv = (void *)CMSG_DATA(cmsg); if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen + sizeof(*con->iv))) return -EINVAL; break; case ALG_SET_OP: if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) return -EINVAL; con->op = *(u32 *)CMSG_DATA(cmsg); break; case ALG_SET_AEAD_ASSOCLEN: if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32))) return -EINVAL; con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg); break; default: return -EINVAL; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu16580.88%133.33%
stephan muellerstephan mueller3617.65%133.33%
gu zhenggu zheng31.47%133.33%
Total204100.00%3100.00%

EXPORT_SYMBOL_GPL(af_alg_cmsg_send);
int af_alg_wait_for_completion(int err, struct af_alg_completion *completion) { switch (err) { case -EINPROGRESS: case -EBUSY: wait_for_completion(&completion->completion); reinit_completion(&completion->completion); err = completion->err; break; }; return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu5296.30%150.00%
wolfram sangwolfram sang23.70%150.00%
Total54100.00%2100.00%

EXPORT_SYMBOL_GPL(af_alg_wait_for_completion);
void af_alg_complete(struct crypto_async_request *req, int err) { struct af_alg_completion *completion = req->data; if (err == -EINPROGRESS) return; completion->err = err; complete(&completion->completion); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu3681.82%150.00%
rabin vincentrabin vincent818.18%150.00%
Total44100.00%2100.00%

EXPORT_SYMBOL_GPL(af_alg_complete);
static int __init af_alg_init(void) { int err = proto_register(&alg_proto, 0); if (err) goto out; err = sock_register(&alg_family); if (err != 0) goto out_unregister_proto; out: return err; out_unregister_proto: proto_unregister(&alg_proto); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu60100.00%1100.00%
Total60100.00%1100.00%


static void __exit af_alg_exit(void) { sock_unregister(PF_ALG); proto_unregister(&alg_proto); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu20100.00%1100.00%
Total20100.00%1100.00%

module_init(af_alg_init); module_exit(af_alg_exit); MODULE_LICENSE("GPL"); MODULE_ALIAS_NETPROTO(AF_ALG);

Overall Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu218290.31%628.57%
tadeusz struktadeusz struk823.39%29.52%
stephan muellerstephan mueller753.10%314.29%
al viroal viro331.37%14.76%
milan brozmilan broz100.41%14.76%
linus torvaldslinus torvalds80.33%14.76%
rabin vincentrabin vincent80.33%14.76%
miloslav trmacmiloslav trmac70.29%14.76%
eric w. biedermaneric w. biederman40.17%14.76%
gu zhenggu zheng30.12%14.76%
wolfram sangwolfram sang20.08%14.76%
randy dunlaprandy dunlap10.04%14.76%
arun sharmaarun sharma10.04%14.76%
Total2416100.00%21100.00%
Directory: crypto
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}