.. | .. |
---|
| 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); |
---|