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 (4081B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * vsock sock_diag(7) module
      4 *
      5 * Copyright (C) 2017 Red Hat, Inc.
      6 * Author: Stefan Hajnoczi <stefanha@redhat.com>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/sock_diag.h>
     11#include <linux/vm_sockets_diag.h>
     12#include <net/af_vsock.h>
     13
     14static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
     15			u32 portid, u32 seq, u32 flags)
     16{
     17	struct vsock_sock *vsk = vsock_sk(sk);
     18	struct vsock_diag_msg *rep;
     19	struct nlmsghdr *nlh;
     20
     21	nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
     22			flags);
     23	if (!nlh)
     24		return -EMSGSIZE;
     25
     26	rep = nlmsg_data(nlh);
     27	rep->vdiag_family = AF_VSOCK;
     28
     29	/* Lock order dictates that sk_lock is acquired before
     30	 * vsock_table_lock, so we cannot lock here.  Simply don't take
     31	 * sk_lock; sk is guaranteed to stay alive since vsock_table_lock is
     32	 * held.
     33	 */
     34	rep->vdiag_type = sk->sk_type;
     35	rep->vdiag_state = sk->sk_state;
     36	rep->vdiag_shutdown = sk->sk_shutdown;
     37	rep->vdiag_src_cid = vsk->local_addr.svm_cid;
     38	rep->vdiag_src_port = vsk->local_addr.svm_port;
     39	rep->vdiag_dst_cid = vsk->remote_addr.svm_cid;
     40	rep->vdiag_dst_port = vsk->remote_addr.svm_port;
     41	rep->vdiag_ino = sock_i_ino(sk);
     42
     43	sock_diag_save_cookie(sk, rep->vdiag_cookie);
     44
     45	return 0;
     46}
     47
     48static int vsock_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
     49{
     50	struct vsock_diag_req *req;
     51	struct vsock_sock *vsk;
     52	unsigned int bucket;
     53	unsigned int last_i;
     54	unsigned int table;
     55	struct net *net;
     56	unsigned int i;
     57
     58	req = nlmsg_data(cb->nlh);
     59	net = sock_net(skb->sk);
     60
     61	/* State saved between calls: */
     62	table = cb->args[0];
     63	bucket = cb->args[1];
     64	i = last_i = cb->args[2];
     65
     66	/* TODO VMCI pending sockets? */
     67
     68	spin_lock_bh(&vsock_table_lock);
     69
     70	/* Bind table (locally created sockets) */
     71	if (table == 0) {
     72		while (bucket < ARRAY_SIZE(vsock_bind_table)) {
     73			struct list_head *head = &vsock_bind_table[bucket];
     74
     75			i = 0;
     76			list_for_each_entry(vsk, head, bound_table) {
     77				struct sock *sk = sk_vsock(vsk);
     78
     79				if (!net_eq(sock_net(sk), net))
     80					continue;
     81				if (i < last_i)
     82					goto next_bind;
     83				if (!(req->vdiag_states & (1 << sk->sk_state)))
     84					goto next_bind;
     85				if (sk_diag_fill(sk, skb,
     86						 NETLINK_CB(cb->skb).portid,
     87						 cb->nlh->nlmsg_seq,
     88						 NLM_F_MULTI) < 0)
     89					goto done;
     90next_bind:
     91				i++;
     92			}
     93			last_i = 0;
     94			bucket++;
     95		}
     96
     97		table++;
     98		bucket = 0;
     99	}
    100
    101	/* Connected table (accepted connections) */
    102	while (bucket < ARRAY_SIZE(vsock_connected_table)) {
    103		struct list_head *head = &vsock_connected_table[bucket];
    104
    105		i = 0;
    106		list_for_each_entry(vsk, head, connected_table) {
    107			struct sock *sk = sk_vsock(vsk);
    108
    109			/* Skip sockets we've already seen above */
    110			if (__vsock_in_bound_table(vsk))
    111				continue;
    112
    113			if (!net_eq(sock_net(sk), net))
    114				continue;
    115			if (i < last_i)
    116				goto next_connected;
    117			if (!(req->vdiag_states & (1 << sk->sk_state)))
    118				goto next_connected;
    119			if (sk_diag_fill(sk, skb,
    120					 NETLINK_CB(cb->skb).portid,
    121					 cb->nlh->nlmsg_seq,
    122					 NLM_F_MULTI) < 0)
    123				goto done;
    124next_connected:
    125			i++;
    126		}
    127		last_i = 0;
    128		bucket++;
    129	}
    130
    131done:
    132	spin_unlock_bh(&vsock_table_lock);
    133
    134	cb->args[0] = table;
    135	cb->args[1] = bucket;
    136	cb->args[2] = i;
    137
    138	return skb->len;
    139}
    140
    141static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
    142{
    143	int hdrlen = sizeof(struct vsock_diag_req);
    144	struct net *net = sock_net(skb->sk);
    145
    146	if (nlmsg_len(h) < hdrlen)
    147		return -EINVAL;
    148
    149	if (h->nlmsg_flags & NLM_F_DUMP) {
    150		struct netlink_dump_control c = {
    151			.dump = vsock_diag_dump,
    152		};
    153		return netlink_dump_start(net->diag_nlsk, skb, h, &c);
    154	}
    155
    156	return -EOPNOTSUPP;
    157}
    158
    159static const struct sock_diag_handler vsock_diag_handler = {
    160	.family = AF_VSOCK,
    161	.dump = vsock_diag_handler_dump,
    162};
    163
    164static int __init vsock_diag_init(void)
    165{
    166	return sock_diag_register(&vsock_diag_handler);
    167}
    168
    169static void __exit vsock_diag_exit(void)
    170{
    171	sock_diag_unregister(&vsock_diag_handler);
    172}
    173
    174module_init(vsock_diag_init);
    175module_exit(vsock_diag_exit);
    176MODULE_LICENSE("GPL");
    177MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG,
    178			       40 /* AF_VSOCK */);