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

diag.c (6436B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/module.h>
      3#include <linux/sock_diag.h>
      4#include <linux/net.h>
      5#include <linux/netdevice.h>
      6#include <linux/packet_diag.h>
      7#include <linux/percpu.h>
      8#include <net/net_namespace.h>
      9#include <net/sock.h>
     10
     11#include "internal.h"
     12
     13static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb)
     14{
     15	struct packet_diag_info pinfo;
     16
     17	pinfo.pdi_index = po->ifindex;
     18	pinfo.pdi_version = po->tp_version;
     19	pinfo.pdi_reserve = po->tp_reserve;
     20	pinfo.pdi_copy_thresh = po->copy_thresh;
     21	pinfo.pdi_tstamp = po->tp_tstamp;
     22
     23	pinfo.pdi_flags = 0;
     24	if (po->running)
     25		pinfo.pdi_flags |= PDI_RUNNING;
     26	if (po->auxdata)
     27		pinfo.pdi_flags |= PDI_AUXDATA;
     28	if (po->origdev)
     29		pinfo.pdi_flags |= PDI_ORIGDEV;
     30	if (po->has_vnet_hdr)
     31		pinfo.pdi_flags |= PDI_VNETHDR;
     32	if (po->tp_loss)
     33		pinfo.pdi_flags |= PDI_LOSS;
     34
     35	return nla_put(nlskb, PACKET_DIAG_INFO, sizeof(pinfo), &pinfo);
     36}
     37
     38static int pdiag_put_mclist(const struct packet_sock *po, struct sk_buff *nlskb)
     39{
     40	struct nlattr *mca;
     41	struct packet_mclist *ml;
     42
     43	mca = nla_nest_start_noflag(nlskb, PACKET_DIAG_MCLIST);
     44	if (!mca)
     45		return -EMSGSIZE;
     46
     47	rtnl_lock();
     48	for (ml = po->mclist; ml; ml = ml->next) {
     49		struct packet_diag_mclist *dml;
     50
     51		dml = nla_reserve_nohdr(nlskb, sizeof(*dml));
     52		if (!dml) {
     53			rtnl_unlock();
     54			nla_nest_cancel(nlskb, mca);
     55			return -EMSGSIZE;
     56		}
     57
     58		dml->pdmc_index = ml->ifindex;
     59		dml->pdmc_type = ml->type;
     60		dml->pdmc_alen = ml->alen;
     61		dml->pdmc_count = ml->count;
     62		BUILD_BUG_ON(sizeof(dml->pdmc_addr) != sizeof(ml->addr));
     63		memcpy(dml->pdmc_addr, ml->addr, sizeof(ml->addr));
     64	}
     65
     66	rtnl_unlock();
     67	nla_nest_end(nlskb, mca);
     68
     69	return 0;
     70}
     71
     72static int pdiag_put_ring(struct packet_ring_buffer *ring, int ver, int nl_type,
     73		struct sk_buff *nlskb)
     74{
     75	struct packet_diag_ring pdr;
     76
     77	if (!ring->pg_vec)
     78		return 0;
     79
     80	pdr.pdr_block_size = ring->pg_vec_pages << PAGE_SHIFT;
     81	pdr.pdr_block_nr = ring->pg_vec_len;
     82	pdr.pdr_frame_size = ring->frame_size;
     83	pdr.pdr_frame_nr = ring->frame_max + 1;
     84
     85	if (ver > TPACKET_V2) {
     86		pdr.pdr_retire_tmo = ring->prb_bdqc.retire_blk_tov;
     87		pdr.pdr_sizeof_priv = ring->prb_bdqc.blk_sizeof_priv;
     88		pdr.pdr_features = ring->prb_bdqc.feature_req_word;
     89	} else {
     90		pdr.pdr_retire_tmo = 0;
     91		pdr.pdr_sizeof_priv = 0;
     92		pdr.pdr_features = 0;
     93	}
     94
     95	return nla_put(nlskb, nl_type, sizeof(pdr), &pdr);
     96}
     97
     98static int pdiag_put_rings_cfg(struct packet_sock *po, struct sk_buff *skb)
     99{
    100	int ret;
    101
    102	mutex_lock(&po->pg_vec_lock);
    103	ret = pdiag_put_ring(&po->rx_ring, po->tp_version,
    104			PACKET_DIAG_RX_RING, skb);
    105	if (!ret)
    106		ret = pdiag_put_ring(&po->tx_ring, po->tp_version,
    107				PACKET_DIAG_TX_RING, skb);
    108	mutex_unlock(&po->pg_vec_lock);
    109
    110	return ret;
    111}
    112
    113static int pdiag_put_fanout(struct packet_sock *po, struct sk_buff *nlskb)
    114{
    115	int ret = 0;
    116
    117	mutex_lock(&fanout_mutex);
    118	if (po->fanout) {
    119		u32 val;
    120
    121		val = (u32)po->fanout->id | ((u32)po->fanout->type << 16);
    122		ret = nla_put_u32(nlskb, PACKET_DIAG_FANOUT, val);
    123	}
    124	mutex_unlock(&fanout_mutex);
    125
    126	return ret;
    127}
    128
    129static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
    130			struct packet_diag_req *req,
    131			bool may_report_filterinfo,
    132			struct user_namespace *user_ns,
    133			u32 portid, u32 seq, u32 flags, int sk_ino)
    134{
    135	struct nlmsghdr *nlh;
    136	struct packet_diag_msg *rp;
    137	struct packet_sock *po = pkt_sk(sk);
    138
    139	nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rp), flags);
    140	if (!nlh)
    141		return -EMSGSIZE;
    142
    143	rp = nlmsg_data(nlh);
    144	rp->pdiag_family = AF_PACKET;
    145	rp->pdiag_type = sk->sk_type;
    146	rp->pdiag_num = ntohs(po->num);
    147	rp->pdiag_ino = sk_ino;
    148	sock_diag_save_cookie(sk, rp->pdiag_cookie);
    149
    150	if ((req->pdiag_show & PACKET_SHOW_INFO) &&
    151			pdiag_put_info(po, skb))
    152		goto out_nlmsg_trim;
    153
    154	if ((req->pdiag_show & PACKET_SHOW_INFO) &&
    155	    nla_put_u32(skb, PACKET_DIAG_UID,
    156			from_kuid_munged(user_ns, sock_i_uid(sk))))
    157		goto out_nlmsg_trim;
    158
    159	if ((req->pdiag_show & PACKET_SHOW_MCLIST) &&
    160			pdiag_put_mclist(po, skb))
    161		goto out_nlmsg_trim;
    162
    163	if ((req->pdiag_show & PACKET_SHOW_RING_CFG) &&
    164			pdiag_put_rings_cfg(po, skb))
    165		goto out_nlmsg_trim;
    166
    167	if ((req->pdiag_show & PACKET_SHOW_FANOUT) &&
    168			pdiag_put_fanout(po, skb))
    169		goto out_nlmsg_trim;
    170
    171	if ((req->pdiag_show & PACKET_SHOW_MEMINFO) &&
    172	    sock_diag_put_meminfo(sk, skb, PACKET_DIAG_MEMINFO))
    173		goto out_nlmsg_trim;
    174
    175	if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
    176	    sock_diag_put_filterinfo(may_report_filterinfo, sk, skb,
    177				     PACKET_DIAG_FILTER))
    178		goto out_nlmsg_trim;
    179
    180	nlmsg_end(skb, nlh);
    181	return 0;
    182
    183out_nlmsg_trim:
    184	nlmsg_cancel(skb, nlh);
    185	return -EMSGSIZE;
    186}
    187
    188static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
    189{
    190	int num = 0, s_num = cb->args[0];
    191	struct packet_diag_req *req;
    192	struct net *net;
    193	struct sock *sk;
    194	bool may_report_filterinfo;
    195
    196	net = sock_net(skb->sk);
    197	req = nlmsg_data(cb->nlh);
    198	may_report_filterinfo = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
    199
    200	mutex_lock(&net->packet.sklist_lock);
    201	sk_for_each(sk, &net->packet.sklist) {
    202		if (!net_eq(sock_net(sk), net))
    203			continue;
    204		if (num < s_num)
    205			goto next;
    206
    207		if (sk_diag_fill(sk, skb, req,
    208				 may_report_filterinfo,
    209				 sk_user_ns(NETLINK_CB(cb->skb).sk),
    210				 NETLINK_CB(cb->skb).portid,
    211				 cb->nlh->nlmsg_seq, NLM_F_MULTI,
    212				 sock_i_ino(sk)) < 0)
    213			goto done;
    214next:
    215		num++;
    216	}
    217done:
    218	mutex_unlock(&net->packet.sklist_lock);
    219	cb->args[0] = num;
    220
    221	return skb->len;
    222}
    223
    224static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
    225{
    226	int hdrlen = sizeof(struct packet_diag_req);
    227	struct net *net = sock_net(skb->sk);
    228	struct packet_diag_req *req;
    229
    230	if (nlmsg_len(h) < hdrlen)
    231		return -EINVAL;
    232
    233	req = nlmsg_data(h);
    234	/* Make it possible to support protocol filtering later */
    235	if (req->sdiag_protocol)
    236		return -EINVAL;
    237
    238	if (h->nlmsg_flags & NLM_F_DUMP) {
    239		struct netlink_dump_control c = {
    240			.dump = packet_diag_dump,
    241		};
    242		return netlink_dump_start(net->diag_nlsk, skb, h, &c);
    243	} else
    244		return -EOPNOTSUPP;
    245}
    246
    247static const struct sock_diag_handler packet_diag_handler = {
    248	.family = AF_PACKET,
    249	.dump = packet_diag_handler_dump,
    250};
    251
    252static int __init packet_diag_init(void)
    253{
    254	return sock_diag_register(&packet_diag_handler);
    255}
    256
    257static void __exit packet_diag_exit(void)
    258{
    259	sock_diag_unregister(&packet_diag_handler);
    260}
    261
    262module_init(packet_diag_init);
    263module_exit(packet_diag_exit);
    264MODULE_LICENSE("GPL");
    265MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17 /* AF_PACKET */);