| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | #include <linux/types.h> |
|---|
| 2 | 3 | #include <linux/spinlock.h> |
|---|
| 3 | 4 | #include <linux/sock_diag.h> |
|---|
| 4 | 5 | #include <linux/unix_diag.h> |
|---|
| 5 | 6 | #include <linux/skbuff.h> |
|---|
| 6 | 7 | #include <linux/module.h> |
|---|
| 8 | +#include <linux/uidgid.h> |
|---|
| 7 | 9 | #include <net/netlink.h> |
|---|
| 8 | 10 | #include <net/af_unix.h> |
|---|
| 9 | 11 | #include <net/tcp_states.h> |
|---|
| 12 | +#include <net/sock.h> |
|---|
| 10 | 13 | |
|---|
| 11 | 14 | static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb) |
|---|
| 12 | 15 | { |
|---|
| .. | .. |
|---|
| 110 | 113 | return nla_put(nlskb, UNIX_DIAG_RQLEN, sizeof(rql), &rql); |
|---|
| 111 | 114 | } |
|---|
| 112 | 115 | |
|---|
| 116 | +static int sk_diag_dump_uid(struct sock *sk, struct sk_buff *nlskb, |
|---|
| 117 | + struct user_namespace *user_ns) |
|---|
| 118 | +{ |
|---|
| 119 | + uid_t uid = from_kuid_munged(user_ns, sock_i_uid(sk)); |
|---|
| 120 | + return nla_put(nlskb, UNIX_DIAG_UID, sizeof(uid_t), &uid); |
|---|
| 121 | +} |
|---|
| 122 | + |
|---|
| 113 | 123 | static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req, |
|---|
| 114 | | - u32 portid, u32 seq, u32 flags, int sk_ino) |
|---|
| 124 | + struct user_namespace *user_ns, |
|---|
| 125 | + u32 portid, u32 seq, u32 flags, int sk_ino) |
|---|
| 115 | 126 | { |
|---|
| 116 | 127 | struct nlmsghdr *nlh; |
|---|
| 117 | 128 | struct unix_diag_msg *rep; |
|---|
| .. | .. |
|---|
| 156 | 167 | if (nla_put_u8(skb, UNIX_DIAG_SHUTDOWN, sk->sk_shutdown)) |
|---|
| 157 | 168 | goto out_nlmsg_trim; |
|---|
| 158 | 169 | |
|---|
| 170 | + if ((req->udiag_show & UDIAG_SHOW_UID) && |
|---|
| 171 | + sk_diag_dump_uid(sk, skb, user_ns)) |
|---|
| 172 | + goto out_nlmsg_trim; |
|---|
| 173 | + |
|---|
| 159 | 174 | nlmsg_end(skb, nlh); |
|---|
| 160 | 175 | return 0; |
|---|
| 161 | 176 | |
|---|
| .. | .. |
|---|
| 165 | 180 | } |
|---|
| 166 | 181 | |
|---|
| 167 | 182 | static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req, |
|---|
| 168 | | - u32 portid, u32 seq, u32 flags) |
|---|
| 183 | + struct user_namespace *user_ns, |
|---|
| 184 | + u32 portid, u32 seq, u32 flags) |
|---|
| 169 | 185 | { |
|---|
| 170 | 186 | int sk_ino; |
|---|
| 171 | 187 | |
|---|
| .. | .. |
|---|
| 176 | 192 | if (!sk_ino) |
|---|
| 177 | 193 | return 0; |
|---|
| 178 | 194 | |
|---|
| 179 | | - return sk_diag_fill(sk, skb, req, portid, seq, flags, sk_ino); |
|---|
| 195 | + return sk_diag_fill(sk, skb, req, user_ns, portid, seq, flags, sk_ino); |
|---|
| 180 | 196 | } |
|---|
| 181 | 197 | |
|---|
| 182 | 198 | static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) |
|---|
| .. | .. |
|---|
| 204 | 220 | goto next; |
|---|
| 205 | 221 | if (!(req->udiag_states & (1 << sk->sk_state))) |
|---|
| 206 | 222 | goto next; |
|---|
| 207 | | - if (sk_diag_dump(sk, skb, req, |
|---|
| 223 | + if (sk_diag_dump(sk, skb, req, sk_user_ns(skb->sk), |
|---|
| 208 | 224 | NETLINK_CB(cb->skb).portid, |
|---|
| 209 | 225 | cb->nlh->nlmsg_seq, |
|---|
| 210 | 226 | NLM_F_MULTI) < 0) |
|---|
| .. | .. |
|---|
| 272 | 288 | if (!rep) |
|---|
| 273 | 289 | goto out; |
|---|
| 274 | 290 | |
|---|
| 275 | | - err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).portid, |
|---|
| 291 | + err = sk_diag_fill(sk, rep, req, sk_user_ns(NETLINK_CB(in_skb).sk), |
|---|
| 292 | + NETLINK_CB(in_skb).portid, |
|---|
| 276 | 293 | nlh->nlmsg_seq, 0, req->udiag_ino); |
|---|
| 277 | 294 | if (err < 0) { |
|---|
| 278 | 295 | nlmsg_free(rep); |
|---|