Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/types.h>
0003 #include <linux/spinlock.h>
0004 #include <linux/sock_diag.h>
0005 #include <linux/unix_diag.h>
0006 #include <linux/skbuff.h>
0007 #include <linux/module.h>
0008 #include <linux/uidgid.h>
0009 #include <net/netlink.h>
0010 #include <net/af_unix.h>
0011 #include <net/tcp_states.h>
0012 #include <net/sock.h>
0013 
0014 static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb)
0015 {
0016     /* might or might not have a hash table lock */
0017     struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr);
0018 
0019     if (!addr)
0020         return 0;
0021 
0022     return nla_put(nlskb, UNIX_DIAG_NAME,
0023                addr->len - offsetof(struct sockaddr_un, sun_path),
0024                addr->name->sun_path);
0025 }
0026 
0027 static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
0028 {
0029     struct dentry *dentry = unix_sk(sk)->path.dentry;
0030 
0031     if (dentry) {
0032         struct unix_diag_vfs uv = {
0033             .udiag_vfs_ino = d_backing_inode(dentry)->i_ino,
0034             .udiag_vfs_dev = dentry->d_sb->s_dev,
0035         };
0036 
0037         return nla_put(nlskb, UNIX_DIAG_VFS, sizeof(uv), &uv);
0038     }
0039 
0040     return 0;
0041 }
0042 
0043 static int sk_diag_dump_peer(struct sock *sk, struct sk_buff *nlskb)
0044 {
0045     struct sock *peer;
0046     int ino;
0047 
0048     peer = unix_peer_get(sk);
0049     if (peer) {
0050         unix_state_lock(peer);
0051         ino = sock_i_ino(peer);
0052         unix_state_unlock(peer);
0053         sock_put(peer);
0054 
0055         return nla_put_u32(nlskb, UNIX_DIAG_PEER, ino);
0056     }
0057 
0058     return 0;
0059 }
0060 
0061 static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
0062 {
0063     struct sk_buff *skb;
0064     struct nlattr *attr;
0065     u32 *buf;
0066     int i;
0067 
0068     if (sk->sk_state == TCP_LISTEN) {
0069         spin_lock(&sk->sk_receive_queue.lock);
0070 
0071         attr = nla_reserve(nlskb, UNIX_DIAG_ICONS,
0072                    sk->sk_receive_queue.qlen * sizeof(u32));
0073         if (!attr)
0074             goto errout;
0075 
0076         buf = nla_data(attr);
0077         i = 0;
0078         skb_queue_walk(&sk->sk_receive_queue, skb) {
0079             struct sock *req, *peer;
0080 
0081             req = skb->sk;
0082             /*
0083              * The state lock is outer for the same sk's
0084              * queue lock. With the other's queue locked it's
0085              * OK to lock the state.
0086              */
0087             unix_state_lock_nested(req);
0088             peer = unix_sk(req)->peer;
0089             buf[i++] = (peer ? sock_i_ino(peer) : 0);
0090             unix_state_unlock(req);
0091         }
0092         spin_unlock(&sk->sk_receive_queue.lock);
0093     }
0094 
0095     return 0;
0096 
0097 errout:
0098     spin_unlock(&sk->sk_receive_queue.lock);
0099     return -EMSGSIZE;
0100 }
0101 
0102 static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb)
0103 {
0104     struct unix_diag_rqlen rql;
0105 
0106     if (sk->sk_state == TCP_LISTEN) {
0107         rql.udiag_rqueue = sk->sk_receive_queue.qlen;
0108         rql.udiag_wqueue = sk->sk_max_ack_backlog;
0109     } else {
0110         rql.udiag_rqueue = (u32) unix_inq_len(sk);
0111         rql.udiag_wqueue = (u32) unix_outq_len(sk);
0112     }
0113 
0114     return nla_put(nlskb, UNIX_DIAG_RQLEN, sizeof(rql), &rql);
0115 }
0116 
0117 static int sk_diag_dump_uid(struct sock *sk, struct sk_buff *nlskb)
0118 {
0119     uid_t uid = from_kuid_munged(sk_user_ns(nlskb->sk), sock_i_uid(sk));
0120     return nla_put(nlskb, UNIX_DIAG_UID, sizeof(uid_t), &uid);
0121 }
0122 
0123 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
0124         u32 portid, u32 seq, u32 flags, int sk_ino)
0125 {
0126     struct nlmsghdr *nlh;
0127     struct unix_diag_msg *rep;
0128 
0129     nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
0130             flags);
0131     if (!nlh)
0132         return -EMSGSIZE;
0133 
0134     rep = nlmsg_data(nlh);
0135     rep->udiag_family = AF_UNIX;
0136     rep->udiag_type = sk->sk_type;
0137     rep->udiag_state = sk->sk_state;
0138     rep->pad = 0;
0139     rep->udiag_ino = sk_ino;
0140     sock_diag_save_cookie(sk, rep->udiag_cookie);
0141 
0142     if ((req->udiag_show & UDIAG_SHOW_NAME) &&
0143         sk_diag_dump_name(sk, skb))
0144         goto out_nlmsg_trim;
0145 
0146     if ((req->udiag_show & UDIAG_SHOW_VFS) &&
0147         sk_diag_dump_vfs(sk, skb))
0148         goto out_nlmsg_trim;
0149 
0150     if ((req->udiag_show & UDIAG_SHOW_PEER) &&
0151         sk_diag_dump_peer(sk, skb))
0152         goto out_nlmsg_trim;
0153 
0154     if ((req->udiag_show & UDIAG_SHOW_ICONS) &&
0155         sk_diag_dump_icons(sk, skb))
0156         goto out_nlmsg_trim;
0157 
0158     if ((req->udiag_show & UDIAG_SHOW_RQLEN) &&
0159         sk_diag_show_rqlen(sk, skb))
0160         goto out_nlmsg_trim;
0161 
0162     if ((req->udiag_show & UDIAG_SHOW_MEMINFO) &&
0163         sock_diag_put_meminfo(sk, skb, UNIX_DIAG_MEMINFO))
0164         goto out_nlmsg_trim;
0165 
0166     if (nla_put_u8(skb, UNIX_DIAG_SHUTDOWN, sk->sk_shutdown))
0167         goto out_nlmsg_trim;
0168 
0169     if ((req->udiag_show & UDIAG_SHOW_UID) &&
0170         sk_diag_dump_uid(sk, skb))
0171         goto out_nlmsg_trim;
0172 
0173     nlmsg_end(skb, nlh);
0174     return 0;
0175 
0176 out_nlmsg_trim:
0177     nlmsg_cancel(skb, nlh);
0178     return -EMSGSIZE;
0179 }
0180 
0181 static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
0182         u32 portid, u32 seq, u32 flags)
0183 {
0184     int sk_ino;
0185 
0186     unix_state_lock(sk);
0187     sk_ino = sock_i_ino(sk);
0188     unix_state_unlock(sk);
0189 
0190     if (!sk_ino)
0191         return 0;
0192 
0193     return sk_diag_fill(sk, skb, req, portid, seq, flags, sk_ino);
0194 }
0195 
0196 static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
0197 {
0198     struct net *net = sock_net(skb->sk);
0199     int num, s_num, slot, s_slot;
0200     struct unix_diag_req *req;
0201 
0202     req = nlmsg_data(cb->nlh);
0203 
0204     s_slot = cb->args[0];
0205     num = s_num = cb->args[1];
0206 
0207     for (slot = s_slot; slot < UNIX_HASH_SIZE; s_num = 0, slot++) {
0208         struct sock *sk;
0209 
0210         num = 0;
0211         spin_lock(&net->unx.table.locks[slot]);
0212         sk_for_each(sk, &net->unx.table.buckets[slot]) {
0213             if (num < s_num)
0214                 goto next;
0215             if (!(req->udiag_states & (1 << sk->sk_state)))
0216                 goto next;
0217             if (sk_diag_dump(sk, skb, req,
0218                      NETLINK_CB(cb->skb).portid,
0219                      cb->nlh->nlmsg_seq,
0220                      NLM_F_MULTI) < 0) {
0221                 spin_unlock(&net->unx.table.locks[slot]);
0222                 goto done;
0223             }
0224 next:
0225             num++;
0226         }
0227         spin_unlock(&net->unx.table.locks[slot]);
0228     }
0229 done:
0230     cb->args[0] = slot;
0231     cb->args[1] = num;
0232 
0233     return skb->len;
0234 }
0235 
0236 static struct sock *unix_lookup_by_ino(struct net *net, unsigned int ino)
0237 {
0238     struct sock *sk;
0239     int i;
0240 
0241     for (i = 0; i < UNIX_HASH_SIZE; i++) {
0242         spin_lock(&net->unx.table.locks[i]);
0243         sk_for_each(sk, &net->unx.table.buckets[i]) {
0244             if (ino == sock_i_ino(sk)) {
0245                 sock_hold(sk);
0246                 spin_unlock(&net->unx.table.locks[i]);
0247                 return sk;
0248             }
0249         }
0250         spin_unlock(&net->unx.table.locks[i]);
0251     }
0252     return NULL;
0253 }
0254 
0255 static int unix_diag_get_exact(struct sk_buff *in_skb,
0256                    const struct nlmsghdr *nlh,
0257                    struct unix_diag_req *req)
0258 {
0259     struct net *net = sock_net(in_skb->sk);
0260     unsigned int extra_len;
0261     struct sk_buff *rep;
0262     struct sock *sk;
0263     int err;
0264 
0265     err = -EINVAL;
0266     if (req->udiag_ino == 0)
0267         goto out_nosk;
0268 
0269     sk = unix_lookup_by_ino(net, req->udiag_ino);
0270     err = -ENOENT;
0271     if (sk == NULL)
0272         goto out_nosk;
0273 
0274     err = sock_diag_check_cookie(sk, req->udiag_cookie);
0275     if (err)
0276         goto out;
0277 
0278     extra_len = 256;
0279 again:
0280     err = -ENOMEM;
0281     rep = nlmsg_new(sizeof(struct unix_diag_msg) + extra_len, GFP_KERNEL);
0282     if (!rep)
0283         goto out;
0284 
0285     err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).portid,
0286                nlh->nlmsg_seq, 0, req->udiag_ino);
0287     if (err < 0) {
0288         nlmsg_free(rep);
0289         extra_len += 256;
0290         if (extra_len >= PAGE_SIZE)
0291             goto out;
0292 
0293         goto again;
0294     }
0295     err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
0296 
0297 out:
0298     if (sk)
0299         sock_put(sk);
0300 out_nosk:
0301     return err;
0302 }
0303 
0304 static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
0305 {
0306     int hdrlen = sizeof(struct unix_diag_req);
0307 
0308     if (nlmsg_len(h) < hdrlen)
0309         return -EINVAL;
0310 
0311     if (h->nlmsg_flags & NLM_F_DUMP) {
0312         struct netlink_dump_control c = {
0313             .dump = unix_diag_dump,
0314         };
0315         return netlink_dump_start(sock_net(skb->sk)->diag_nlsk, skb, h, &c);
0316     } else
0317         return unix_diag_get_exact(skb, h, nlmsg_data(h));
0318 }
0319 
0320 static const struct sock_diag_handler unix_diag_handler = {
0321     .family = AF_UNIX,
0322     .dump = unix_diag_handler_dump,
0323 };
0324 
0325 static int __init unix_diag_init(void)
0326 {
0327     return sock_diag_register(&unix_diag_handler);
0328 }
0329 
0330 static void __exit unix_diag_exit(void)
0331 {
0332     sock_diag_unregister(&unix_diag_handler);
0333 }
0334 
0335 module_init(unix_diag_init);
0336 module_exit(unix_diag_exit);
0337 MODULE_LICENSE("GPL");
0338 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */);