cregit-Linux how code gets into the kernel

Release 4.8 net/core/sock_diag.c

Directory: net/core
/* License: GPL */

#include <linux/mutex.h>
#include <linux/socket.h>
#include <linux/skbuff.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
#include <linux/module.h>
#include <net/sock.h>
#include <linux/kernel.h>
#include <linux/tcp.h>
#include <linux/workqueue.h>

#include <linux/inet_diag.h>
#include <linux/sock_diag.h>


static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];

static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
static DEFINE_MUTEX(sock_diag_table_mutex);

static struct workqueue_struct *broadcast_wq;


static u64 sock_gen_cookie(struct sock *sk) { while (1) { u64 res = atomic64_read(&sk->sk_cookie); if (res) return res; res = atomic64_inc_return(&sock_net(sk)->cookie_gen); atomic64_cmpxchg(&sk->sk_cookie, 0, res); } }

Contributors

PersonTokensPropCommitsCommitProp
eric dumazeteric dumazet60100.00%1100.00%
Total60100.00%1100.00%


int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) { u64 res; if (cookie[0] == INET_DIAG_NOCOOKIE && cookie[1] == INET_DIAG_NOCOOKIE) return 0; res = sock_gen_cookie(sk); if ((u32)res != cookie[0] || (u32)(res >> 32) != cookie[1]) return -ESTALE; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov5267.53%133.33%
eric dumazeteric dumazet2532.47%266.67%
Total77100.00%3100.00%

EXPORT_SYMBOL_GPL(sock_diag_check_cookie);
void sock_diag_save_cookie(struct sock *sk, __u32 *cookie) { u64 res = sock_gen_cookie(sk); cookie[0] = (u32)res; cookie[1] = (u32)(res >> 32); }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov3371.74%150.00%
eric dumazeteric dumazet1328.26%150.00%
Total46100.00%2100.00%

EXPORT_SYMBOL_GPL(sock_diag_save_cookie);
int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype) { u32 mem[SK_MEMINFO_VARS]; mem[SK_MEMINFO_RMEM_ALLOC] = sk_rmem_alloc_get(sk); mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf; mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk); mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf; mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc; mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued; mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc); mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len; mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops); return nla_put(skb, attrtype, sizeof(mem), &mem); }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov9168.42%125.00%
eric dumazeteric dumazet2418.05%250.00%
thomas grafthomas graf1813.53%125.00%
Total133100.00%4100.00%

EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, struct sk_buff *skb, int attrtype) { struct sock_fprog_kern *fprog; struct sk_filter *filter; struct nlattr *attr; unsigned int flen; int err = 0; if (!may_report_filterinfo) { nla_reserve(skb, attrtype, 0); return 0; } rcu_read_lock(); filter = rcu_dereference(sk->sk_filter); if (!filter) goto out; fprog = filter->prog->orig_prog; if (!fprog) goto out; flen = bpf_classic_proglen(fprog); attr = nla_reserve(skb, attrtype, flen); if (attr == NULL) { err = -EMSGSIZE; goto out; } memcpy(nla_data(attr), fprog->filter, flen); out: rcu_read_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel11372.44%228.57%
daniel borkmanndaniel borkmann3623.08%228.57%
eric w. biedermaneric w. biederman42.56%114.29%
alexei starovoitovalexei starovoitov31.92%228.57%
Total156100.00%7100.00%

EXPORT_SYMBOL(sock_diag_put_filterinfo); struct broadcast_sk { struct sock *sk; struct work_struct work; };
static size_t sock_diag_nlmsg_size(void) { return NLMSG_ALIGN(sizeof(struct inet_diag_msg) + nla_total_size(sizeof(u8)) /* INET_DIAG_PROTOCOL */ + nla_total_size_64bit(sizeof(struct tcp_info))); /* INET_DIAG_INFO */ }

Contributors

PersonTokensPropCommitsCommitProp
craig gallekcraig gallek3697.30%150.00%
nicolas dichtelnicolas dichtel12.70%150.00%
Total37100.00%2100.00%


static void sock_diag_broadcast_destroy_work(struct work_struct *work) { struct broadcast_sk *bsk = container_of(work, struct broadcast_sk, work); struct sock *sk = bsk->sk; const struct sock_diag_handler *hndl; struct sk_buff *skb; const enum sknetlink_groups group = sock_diag_destroy_group(sk); int err = -1; WARN_ON(group == SKNLGRP_NONE); skb = nlmsg_new(sock_diag_nlmsg_size(), GFP_KERNEL); if (!skb) goto out; mutex_lock(&sock_diag_table_mutex); hndl = sock_diag_handlers[sk->sk_family]; if (hndl && hndl->get_info) err = hndl->get_info(skb, sk); mutex_unlock(&sock_diag_table_mutex); if (!err) nlmsg_multicast(sock_net(sk)->diag_nlsk, skb, 0, group, GFP_KERNEL); else kfree_skb(skb); out: sk_destruct(sk); kfree(bsk); }

Contributors

PersonTokensPropCommitsCommitProp
craig gallekcraig gallek168100.00%1100.00%
Total168100.00%1100.00%


void sock_diag_broadcast_destroy(struct sock *sk) { /* Note, this function is often called from an interrupt context. */ struct broadcast_sk *bsk = kmalloc(sizeof(struct broadcast_sk), GFP_ATOMIC); if (!bsk) return sk_destruct(sk); bsk->sk = sk; INIT_WORK(&bsk->work, sock_diag_broadcast_destroy_work); queue_work(broadcast_wq, &bsk->work); }

Contributors

PersonTokensPropCommitsCommitProp
craig gallekcraig gallek64100.00%1100.00%
Total64100.00%1100.00%


void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) { mutex_lock(&sock_diag_table_mutex); inet_rcv_compat = fn; mutex_unlock(&sock_diag_table_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov38100.00%1100.00%
Total38100.00%1100.00%

EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat);
void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) { mutex_lock(&sock_diag_table_mutex); inet_rcv_compat = NULL; mutex_unlock(&sock_diag_table_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov38100.00%1100.00%
Total38100.00%1100.00%

EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
int sock_diag_register(const struct sock_diag_handler *hndl) { int err = 0; if (hndl->family >= AF_MAX) return -EINVAL; mutex_lock(&sock_diag_table_mutex); if (sock_diag_handlers[hndl->family]) err = -EBUSY; else sock_diag_handlers[hndl->family] = hndl; mutex_unlock(&sock_diag_table_mutex); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov6597.01%133.33%
dan carpenterdan carpenter11.49%133.33%
shan weishan wei11.49%133.33%
Total67100.00%3100.00%

EXPORT_SYMBOL_GPL(sock_diag_register);
void sock_diag_unregister(const struct sock_diag_handler *hnld) { int family = hnld->family; if (family >= AF_MAX) return; mutex_lock(&sock_diag_table_mutex); BUG_ON(sock_diag_handlers[family] != hnld); sock_diag_handlers[family] = NULL; mutex_unlock(&sock_diag_table_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov5296.30%133.33%
dan carpenterdan carpenter11.85%133.33%
shan weishan wei11.85%133.33%
Total54100.00%3100.00%

EXPORT_SYMBOL_GPL(sock_diag_unregister);
static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) { int err; struct sock_diag_req *req = nlmsg_data(nlh); const struct sock_diag_handler *hndl; if (nlmsg_len(nlh) < sizeof(*req)) return -EINVAL; if (req->sdiag_family >= AF_MAX) return -EINVAL; if (sock_diag_handlers[req->sdiag_family] == NULL) request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, NETLINK_SOCK_DIAG, req->sdiag_family); mutex_lock(&sock_diag_table_mutex); hndl = sock_diag_handlers[req->sdiag_family]; if (hndl == NULL) err = -ENOENT; else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) err = hndl->dump(skb, nlh); else if (nlh->nlmsg_type == SOCK_DESTROY && hndl->destroy) err = hndl->destroy(skb, nlh); else err = -EOPNOTSUPP; mutex_unlock(&sock_diag_table_mutex); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov8347.98%116.67%
mathias krausemathias krause4827.75%233.33%
lorenzo colittilorenzo colitti4023.12%116.67%
thomas grafthomas graf10.58%116.67%
shan weishan wei10.58%116.67%
Total173100.00%6100.00%


static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { int ret; switch (nlh->nlmsg_type) { case TCPDIAG_GETSOCK: case DCCPDIAG_GETSOCK: if (inet_rcv_compat == NULL) request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, NETLINK_SOCK_DIAG, AF_INET); mutex_lock(&sock_diag_table_mutex); if (inet_rcv_compat != NULL) ret = inet_rcv_compat(skb, nlh); else ret = -EOPNOTSUPP; mutex_unlock(&sock_diag_table_mutex); return ret; case SOCK_DIAG_BY_FAMILY: case SOCK_DESTROY: return __sock_diag_cmd(skb, nlh); default: return -EINVAL; } }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov10196.19%266.67%
lorenzo colittilorenzo colitti43.81%133.33%
Total105100.00%3100.00%

static DEFINE_MUTEX(sock_diag_mutex);
static void sock_diag_rcv(struct sk_buff *skb) { mutex_lock(&sock_diag_mutex); netlink_rcv_skb(skb, &sock_diag_rcv_msg); mutex_unlock(&sock_diag_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov31100.00%1100.00%
Total31100.00%1100.00%


static int sock_diag_bind(struct net *net, int group) { switch (group) { case SKNLGRP_INET_TCP_DESTROY: case SKNLGRP_INET_UDP_DESTROY: if (!sock_diag_handlers[AF_INET]) request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, NETLINK_SOCK_DIAG, AF_INET); break; case SKNLGRP_INET6_TCP_DESTROY: case SKNLGRP_INET6_UDP_DESTROY: if (!sock_diag_handlers[AF_INET6]) request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, NETLINK_SOCK_DIAG, AF_INET); break; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
craig gallekcraig gallek75100.00%1100.00%
Total75100.00%1100.00%


int sock_diag_destroy(struct sock *sk, int err) { if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) return -EPERM; if (!sk->sk_prot->diag_destroy) return -EOPNOTSUPP; return sk->sk_prot->diag_destroy(sk, err); }

Contributors

PersonTokensPropCommitsCommitProp
lorenzo colittilorenzo colitti57100.00%1100.00%
Total57100.00%1100.00%

EXPORT_SYMBOL_GPL(sock_diag_destroy);
static int __net_init diag_net_init(struct net *net) { struct netlink_kernel_cfg cfg = { .groups = SKNLGRP_MAX, .input = sock_diag_rcv, .bind = sock_diag_bind, .flags = NL_CFG_F_NONROOT_RECV, }; net->diag_nlsk = netlink_kernel_create(net, NETLINK_SOCK_DIAG, &cfg); return net->diag_nlsk == NULL ? -ENOMEM : 0; }

Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov2335.94%125.00%
craig gallekcraig gallek1523.44%125.00%
andrey vaginandrey vagin1320.31%125.00%
pablo neira ayusopablo neira ayuso1320.31%125.00%
Total64100.00%4100.00%


static void __net_exit diag_net_exit(struct net *net) { netlink_kernel_release(net->diag_nlsk); net->diag_nlsk = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
andrey vaginandrey vagin25100.00%1100.00%
Total25100.00%1100.00%

static struct pernet_operations diag_net_ops = { .init = diag_net_init, .exit = diag_net_exit, };
static int __init sock_diag_init(void) { broadcast_wq = alloc_workqueue("sock_diag_events", 0, 0); BUG_ON(!broadcast_wq); return register_pernet_subsys(&diag_net_ops); }

Contributors

PersonTokensPropCommitsCommitProp
craig gallekcraig gallek1751.52%150.00%
andrey vaginandrey vagin1648.48%150.00%
Total33100.00%2100.00%

device_initcall(sock_diag_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
pavel emelianovpavel emelianov71242.76%415.38%
craig gallekcraig gallek40424.26%13.85%
eric dumazeteric dumazet1227.33%415.38%
nicolas dichtelnicolas dichtel1197.15%311.54%
lorenzo colittilorenzo colitti1066.37%13.85%
andrey vaginandrey vagin714.26%13.85%
mathias krausemathias krause482.88%27.69%
daniel borkmanndaniel borkmann362.16%27.69%
thomas grafthomas graf191.14%13.85%
pablo neira ayusopablo neira ayuso130.78%13.85%
shan weishan wei40.24%13.85%
eric w. biedermaneric w. biederman40.24%13.85%
alexei starovoitovalexei starovoitov30.18%27.69%
paul gortmakerpaul gortmaker20.12%13.85%
dan carpenterdan carpenter20.12%13.85%
Total1665100.00%26100.00%
Directory: net/core
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.