cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

raw_diag.c (6373B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/module.h>
      3
      4#include <linux/inet_diag.h>
      5#include <linux/sock_diag.h>
      6
      7#include <net/inet_sock.h>
      8#include <net/raw.h>
      9#include <net/rawv6.h>
     10
     11#ifdef pr_fmt
     12# undef pr_fmt
     13#endif
     14
     15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     16
     17static struct raw_hashinfo *
     18raw_get_hashinfo(const struct inet_diag_req_v2 *r)
     19{
     20	if (r->sdiag_family == AF_INET) {
     21		return &raw_v4_hashinfo;
     22#if IS_ENABLED(CONFIG_IPV6)
     23	} else if (r->sdiag_family == AF_INET6) {
     24		return &raw_v6_hashinfo;
     25#endif
     26	} else {
     27		return ERR_PTR(-EINVAL);
     28	}
     29}
     30
     31/*
     32 * Due to requirement of not breaking user API we can't simply
     33 * rename @pad field in inet_diag_req_v2 structure, instead
     34 * use helper to figure it out.
     35 */
     36
     37static struct sock *raw_lookup(struct net *net, struct sock *from,
     38			       const struct inet_diag_req_v2 *req)
     39{
     40	struct inet_diag_req_raw *r = (void *)req;
     41	struct sock *sk = NULL;
     42
     43	if (r->sdiag_family == AF_INET)
     44		sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol,
     45				     r->id.idiag_dst[0],
     46				     r->id.idiag_src[0],
     47				     r->id.idiag_if, 0);
     48#if IS_ENABLED(CONFIG_IPV6)
     49	else
     50		sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol,
     51				     (const struct in6_addr *)r->id.idiag_src,
     52				     (const struct in6_addr *)r->id.idiag_dst,
     53				     r->id.idiag_if, 0);
     54#endif
     55	return sk;
     56}
     57
     58static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
     59{
     60	struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
     61	struct sock *sk = NULL, *s;
     62	int slot;
     63
     64	if (IS_ERR(hashinfo))
     65		return ERR_CAST(hashinfo);
     66
     67	read_lock(&hashinfo->lock);
     68	for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
     69		sk_for_each(s, &hashinfo->ht[slot]) {
     70			sk = raw_lookup(net, s, r);
     71			if (sk) {
     72				/*
     73				 * Grab it and keep until we fill
     74				 * diag meaage to be reported, so
     75				 * caller should call sock_put then.
     76				 * We can do that because we're keeping
     77				 * hashinfo->lock here.
     78				 */
     79				sock_hold(sk);
     80				goto out_unlock;
     81			}
     82		}
     83	}
     84out_unlock:
     85	read_unlock(&hashinfo->lock);
     86
     87	return sk ? sk : ERR_PTR(-ENOENT);
     88}
     89
     90static int raw_diag_dump_one(struct netlink_callback *cb,
     91			     const struct inet_diag_req_v2 *r)
     92{
     93	struct sk_buff *in_skb = cb->skb;
     94	struct sk_buff *rep;
     95	struct sock *sk;
     96	struct net *net;
     97	int err;
     98
     99	net = sock_net(in_skb->sk);
    100	sk = raw_sock_get(net, r);
    101	if (IS_ERR(sk))
    102		return PTR_ERR(sk);
    103
    104	rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) +
    105			inet_diag_msg_attrs_size() +
    106			nla_total_size(sizeof(struct inet_diag_meminfo)) + 64,
    107			GFP_KERNEL);
    108	if (!rep) {
    109		sock_put(sk);
    110		return -ENOMEM;
    111	}
    112
    113	err = inet_sk_diag_fill(sk, NULL, rep, cb, r, 0,
    114				netlink_net_capable(in_skb, CAP_NET_ADMIN));
    115	sock_put(sk);
    116
    117	if (err < 0) {
    118		kfree_skb(rep);
    119		return err;
    120	}
    121
    122	err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
    123
    124	return err;
    125}
    126
    127static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
    128			struct netlink_callback *cb,
    129			const struct inet_diag_req_v2 *r,
    130			struct nlattr *bc, bool net_admin)
    131{
    132	if (!inet_diag_bc_sk(bc, sk))
    133		return 0;
    134
    135	return inet_sk_diag_fill(sk, NULL, skb, cb, r, NLM_F_MULTI, net_admin);
    136}
    137
    138static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
    139			  const struct inet_diag_req_v2 *r)
    140{
    141	bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
    142	struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
    143	struct net *net = sock_net(skb->sk);
    144	struct inet_diag_dump_data *cb_data;
    145	int num, s_num, slot, s_slot;
    146	struct sock *sk = NULL;
    147	struct nlattr *bc;
    148
    149	if (IS_ERR(hashinfo))
    150		return;
    151
    152	cb_data = cb->data;
    153	bc = cb_data->inet_diag_nla_bc;
    154	s_slot = cb->args[0];
    155	num = s_num = cb->args[1];
    156
    157	read_lock(&hashinfo->lock);
    158	for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) {
    159		num = 0;
    160
    161		sk_for_each(sk, &hashinfo->ht[slot]) {
    162			struct inet_sock *inet = inet_sk(sk);
    163
    164			if (!net_eq(sock_net(sk), net))
    165				continue;
    166			if (num < s_num)
    167				goto next;
    168			if (sk->sk_family != r->sdiag_family)
    169				goto next;
    170			if (r->id.idiag_sport != inet->inet_sport &&
    171			    r->id.idiag_sport)
    172				goto next;
    173			if (r->id.idiag_dport != inet->inet_dport &&
    174			    r->id.idiag_dport)
    175				goto next;
    176			if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0)
    177				goto out_unlock;
    178next:
    179			num++;
    180		}
    181	}
    182
    183out_unlock:
    184	read_unlock(&hashinfo->lock);
    185
    186	cb->args[0] = slot;
    187	cb->args[1] = num;
    188}
    189
    190static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
    191			      void *info)
    192{
    193	r->idiag_rqueue = sk_rmem_alloc_get(sk);
    194	r->idiag_wqueue = sk_wmem_alloc_get(sk);
    195}
    196
    197#ifdef CONFIG_INET_DIAG_DESTROY
    198static int raw_diag_destroy(struct sk_buff *in_skb,
    199			    const struct inet_diag_req_v2 *r)
    200{
    201	struct net *net = sock_net(in_skb->sk);
    202	struct sock *sk;
    203	int err;
    204
    205	sk = raw_sock_get(net, r);
    206	if (IS_ERR(sk))
    207		return PTR_ERR(sk);
    208	err = sock_diag_destroy(sk, ECONNABORTED);
    209	sock_put(sk);
    210	return err;
    211}
    212#endif
    213
    214static const struct inet_diag_handler raw_diag_handler = {
    215	.dump			= raw_diag_dump,
    216	.dump_one		= raw_diag_dump_one,
    217	.idiag_get_info		= raw_diag_get_info,
    218	.idiag_type		= IPPROTO_RAW,
    219	.idiag_info_size	= 0,
    220#ifdef CONFIG_INET_DIAG_DESTROY
    221	.destroy		= raw_diag_destroy,
    222#endif
    223};
    224
    225static void __always_unused __check_inet_diag_req_raw(void)
    226{
    227	/*
    228	 * Make sure the two structures are identical,
    229	 * except the @pad field.
    230	 */
    231#define __offset_mismatch(m1, m2)			\
    232	(offsetof(struct inet_diag_req_v2, m1) !=	\
    233	 offsetof(struct inet_diag_req_raw, m2))
    234
    235	BUILD_BUG_ON(sizeof(struct inet_diag_req_v2) !=
    236		     sizeof(struct inet_diag_req_raw));
    237	BUILD_BUG_ON(__offset_mismatch(sdiag_family, sdiag_family));
    238	BUILD_BUG_ON(__offset_mismatch(sdiag_protocol, sdiag_protocol));
    239	BUILD_BUG_ON(__offset_mismatch(idiag_ext, idiag_ext));
    240	BUILD_BUG_ON(__offset_mismatch(pad, sdiag_raw_protocol));
    241	BUILD_BUG_ON(__offset_mismatch(idiag_states, idiag_states));
    242	BUILD_BUG_ON(__offset_mismatch(id, id));
    243#undef __offset_mismatch
    244}
    245
    246static int __init raw_diag_init(void)
    247{
    248	return inet_diag_register(&raw_diag_handler);
    249}
    250
    251static void __exit raw_diag_exit(void)
    252{
    253	inet_diag_unregister(&raw_diag_handler);
    254}
    255
    256module_init(raw_diag_init);
    257module_exit(raw_diag_exit);
    258MODULE_LICENSE("GPL");
    259MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */);
    260MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */);