diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2016-09-07 11:42:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-09-08 19:13:09 -0400 |
commit | d545caca827b65aab557a9e9dcdcf1e5a3823c2d (patch) | |
tree | 1ec87b39e2490acc3f435d650d6ddc6e594300cf | |
parent | 74f13c80e210ff5a9e7b13b9853d8a866972f385 (diff) |
net: inet: diag: expose the socket mark to privileged processes.
This adds the capability for a process that has CAP_NET_ADMIN on
a socket to see the socket mark in socket dumps.
Commit a52e95abf772 ("net: diag: allow socket bytecode filters to
match socket marks") recently gave privileged processes the
ability to filter socket dumps based on mark. This patch is
complementary: it ensures that the mark is also passed to
userspace in the socket's netlink attributes. It is useful for
tools like ss which display information about sockets.
Tested: https://android-review.googlesource.com/270210
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/inet_diag.h | 4 | ||||
-rw-r--r-- | include/uapi/linux/inet_diag.h | 1 | ||||
-rw-r--r-- | net/ipv4/inet_diag.c | 49 | ||||
-rw-r--r-- | net/ipv4/udp_diag.c | 10 | ||||
-rw-r--r-- | net/sctp/sctp_diag.c | 20 |
5 files changed, 56 insertions, 28 deletions
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index feb04ea20f11..65da430e260f 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h | |||
@@ -37,7 +37,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, | |||
37 | struct sk_buff *skb, const struct inet_diag_req_v2 *req, | 37 | struct sk_buff *skb, const struct inet_diag_req_v2 *req, |
38 | struct user_namespace *user_ns, | 38 | struct user_namespace *user_ns, |
39 | u32 pid, u32 seq, u16 nlmsg_flags, | 39 | u32 pid, u32 seq, u16 nlmsg_flags, |
40 | const struct nlmsghdr *unlh); | 40 | const struct nlmsghdr *unlh, bool net_admin); |
41 | void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, | 41 | void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, |
42 | struct netlink_callback *cb, | 42 | struct netlink_callback *cb, |
43 | const struct inet_diag_req_v2 *r, | 43 | const struct inet_diag_req_v2 *r, |
@@ -56,7 +56,7 @@ void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk); | |||
56 | 56 | ||
57 | int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, | 57 | int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, |
58 | struct inet_diag_msg *r, int ext, | 58 | struct inet_diag_msg *r, int ext, |
59 | struct user_namespace *user_ns); | 59 | struct user_namespace *user_ns, bool net_admin); |
60 | 60 | ||
61 | extern int inet_diag_register(const struct inet_diag_handler *handler); | 61 | extern int inet_diag_register(const struct inet_diag_handler *handler); |
62 | extern void inet_diag_unregister(const struct inet_diag_handler *handler); | 62 | extern void inet_diag_unregister(const struct inet_diag_handler *handler); |
diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h index 5581206a08ae..b5c366f87b3e 100644 --- a/include/uapi/linux/inet_diag.h +++ b/include/uapi/linux/inet_diag.h | |||
@@ -123,6 +123,7 @@ enum { | |||
123 | INET_DIAG_LOCALS, | 123 | INET_DIAG_LOCALS, |
124 | INET_DIAG_PEERS, | 124 | INET_DIAG_PEERS, |
125 | INET_DIAG_PAD, | 125 | INET_DIAG_PAD, |
126 | INET_DIAG_MARK, | ||
126 | __INET_DIAG_MAX, | 127 | __INET_DIAG_MAX, |
127 | }; | 128 | }; |
128 | 129 | ||
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index abfbe492ebfe..e4d16fc5bbb3 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
@@ -99,6 +99,7 @@ static size_t inet_sk_attr_size(void) | |||
99 | + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ | 99 | + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ |
100 | + nla_total_size(1) /* INET_DIAG_TOS */ | 100 | + nla_total_size(1) /* INET_DIAG_TOS */ |
101 | + nla_total_size(1) /* INET_DIAG_TCLASS */ | 101 | + nla_total_size(1) /* INET_DIAG_TCLASS */ |
102 | + nla_total_size(4) /* INET_DIAG_MARK */ | ||
102 | + nla_total_size(sizeof(struct inet_diag_meminfo)) | 103 | + nla_total_size(sizeof(struct inet_diag_meminfo)) |
103 | + nla_total_size(sizeof(struct inet_diag_msg)) | 104 | + nla_total_size(sizeof(struct inet_diag_msg)) |
104 | + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) | 105 | + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) |
@@ -109,7 +110,8 @@ static size_t inet_sk_attr_size(void) | |||
109 | 110 | ||
110 | int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, | 111 | int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, |
111 | struct inet_diag_msg *r, int ext, | 112 | struct inet_diag_msg *r, int ext, |
112 | struct user_namespace *user_ns) | 113 | struct user_namespace *user_ns, |
114 | bool net_admin) | ||
113 | { | 115 | { |
114 | const struct inet_sock *inet = inet_sk(sk); | 116 | const struct inet_sock *inet = inet_sk(sk); |
115 | 117 | ||
@@ -136,6 +138,9 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, | |||
136 | } | 138 | } |
137 | #endif | 139 | #endif |
138 | 140 | ||
141 | if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark)) | ||
142 | goto errout; | ||
143 | |||
139 | r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); | 144 | r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); |
140 | r->idiag_inode = sock_i_ino(sk); | 145 | r->idiag_inode = sock_i_ino(sk); |
141 | 146 | ||
@@ -149,7 +154,8 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, | |||
149 | struct sk_buff *skb, const struct inet_diag_req_v2 *req, | 154 | struct sk_buff *skb, const struct inet_diag_req_v2 *req, |
150 | struct user_namespace *user_ns, | 155 | struct user_namespace *user_ns, |
151 | u32 portid, u32 seq, u16 nlmsg_flags, | 156 | u32 portid, u32 seq, u16 nlmsg_flags, |
152 | const struct nlmsghdr *unlh) | 157 | const struct nlmsghdr *unlh, |
158 | bool net_admin) | ||
153 | { | 159 | { |
154 | const struct tcp_congestion_ops *ca_ops; | 160 | const struct tcp_congestion_ops *ca_ops; |
155 | const struct inet_diag_handler *handler; | 161 | const struct inet_diag_handler *handler; |
@@ -175,7 +181,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, | |||
175 | r->idiag_timer = 0; | 181 | r->idiag_timer = 0; |
176 | r->idiag_retrans = 0; | 182 | r->idiag_retrans = 0; |
177 | 183 | ||
178 | if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns)) | 184 | if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin)) |
179 | goto errout; | 185 | goto errout; |
180 | 186 | ||
181 | if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { | 187 | if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { |
@@ -274,10 +280,11 @@ static int inet_csk_diag_fill(struct sock *sk, | |||
274 | const struct inet_diag_req_v2 *req, | 280 | const struct inet_diag_req_v2 *req, |
275 | struct user_namespace *user_ns, | 281 | struct user_namespace *user_ns, |
276 | u32 portid, u32 seq, u16 nlmsg_flags, | 282 | u32 portid, u32 seq, u16 nlmsg_flags, |
277 | const struct nlmsghdr *unlh) | 283 | const struct nlmsghdr *unlh, |
284 | bool net_admin) | ||
278 | { | 285 | { |
279 | return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, | 286 | return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, user_ns, |
280 | user_ns, portid, seq, nlmsg_flags, unlh); | 287 | portid, seq, nlmsg_flags, unlh, net_admin); |
281 | } | 288 | } |
282 | 289 | ||
283 | static int inet_twsk_diag_fill(struct sock *sk, | 290 | static int inet_twsk_diag_fill(struct sock *sk, |
@@ -319,8 +326,9 @@ static int inet_twsk_diag_fill(struct sock *sk, | |||
319 | 326 | ||
320 | static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, | 327 | static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, |
321 | u32 portid, u32 seq, u16 nlmsg_flags, | 328 | u32 portid, u32 seq, u16 nlmsg_flags, |
322 | const struct nlmsghdr *unlh) | 329 | const struct nlmsghdr *unlh, bool net_admin) |
323 | { | 330 | { |
331 | struct request_sock *reqsk = inet_reqsk(sk); | ||
324 | struct inet_diag_msg *r; | 332 | struct inet_diag_msg *r; |
325 | struct nlmsghdr *nlh; | 333 | struct nlmsghdr *nlh; |
326 | long tmo; | 334 | long tmo; |
@@ -334,7 +342,7 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, | |||
334 | inet_diag_msg_common_fill(r, sk); | 342 | inet_diag_msg_common_fill(r, sk); |
335 | r->idiag_state = TCP_SYN_RECV; | 343 | r->idiag_state = TCP_SYN_RECV; |
336 | r->idiag_timer = 1; | 344 | r->idiag_timer = 1; |
337 | r->idiag_retrans = inet_reqsk(sk)->num_retrans; | 345 | r->idiag_retrans = reqsk->num_retrans; |
338 | 346 | ||
339 | BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) != | 347 | BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) != |
340 | offsetof(struct sock, sk_cookie)); | 348 | offsetof(struct sock, sk_cookie)); |
@@ -346,6 +354,10 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, | |||
346 | r->idiag_uid = 0; | 354 | r->idiag_uid = 0; |
347 | r->idiag_inode = 0; | 355 | r->idiag_inode = 0; |
348 | 356 | ||
357 | if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, | ||
358 | inet_rsk(reqsk)->ir_mark)) | ||
359 | return -EMSGSIZE; | ||
360 | |||
349 | nlmsg_end(skb, nlh); | 361 | nlmsg_end(skb, nlh); |
350 | return 0; | 362 | return 0; |
351 | } | 363 | } |
@@ -354,7 +366,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, | |||
354 | const struct inet_diag_req_v2 *r, | 366 | const struct inet_diag_req_v2 *r, |
355 | struct user_namespace *user_ns, | 367 | struct user_namespace *user_ns, |
356 | u32 portid, u32 seq, u16 nlmsg_flags, | 368 | u32 portid, u32 seq, u16 nlmsg_flags, |
357 | const struct nlmsghdr *unlh) | 369 | const struct nlmsghdr *unlh, bool net_admin) |
358 | { | 370 | { |
359 | if (sk->sk_state == TCP_TIME_WAIT) | 371 | if (sk->sk_state == TCP_TIME_WAIT) |
360 | return inet_twsk_diag_fill(sk, skb, portid, seq, | 372 | return inet_twsk_diag_fill(sk, skb, portid, seq, |
@@ -362,10 +374,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, | |||
362 | 374 | ||
363 | if (sk->sk_state == TCP_NEW_SYN_RECV) | 375 | if (sk->sk_state == TCP_NEW_SYN_RECV) |
364 | return inet_req_diag_fill(sk, skb, portid, seq, | 376 | return inet_req_diag_fill(sk, skb, portid, seq, |
365 | nlmsg_flags, unlh); | 377 | nlmsg_flags, unlh, net_admin); |
366 | 378 | ||
367 | return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, | 379 | return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, |
368 | nlmsg_flags, unlh); | 380 | nlmsg_flags, unlh, net_admin); |
369 | } | 381 | } |
370 | 382 | ||
371 | struct sock *inet_diag_find_one_icsk(struct net *net, | 383 | struct sock *inet_diag_find_one_icsk(struct net *net, |
@@ -435,7 +447,8 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, | |||
435 | err = sk_diag_fill(sk, rep, req, | 447 | err = sk_diag_fill(sk, rep, req, |
436 | sk_user_ns(NETLINK_CB(in_skb).sk), | 448 | sk_user_ns(NETLINK_CB(in_skb).sk), |
437 | NETLINK_CB(in_skb).portid, | 449 | NETLINK_CB(in_skb).portid, |
438 | nlh->nlmsg_seq, 0, nlh); | 450 | nlh->nlmsg_seq, 0, nlh, |
451 | netlink_net_capable(in_skb, CAP_NET_ADMIN)); | ||
439 | if (err < 0) { | 452 | if (err < 0) { |
440 | WARN_ON(err == -EMSGSIZE); | 453 | WARN_ON(err == -EMSGSIZE); |
441 | nlmsg_free(rep); | 454 | nlmsg_free(rep); |
@@ -796,7 +809,8 @@ static int inet_csk_diag_dump(struct sock *sk, | |||
796 | struct sk_buff *skb, | 809 | struct sk_buff *skb, |
797 | struct netlink_callback *cb, | 810 | struct netlink_callback *cb, |
798 | const struct inet_diag_req_v2 *r, | 811 | const struct inet_diag_req_v2 *r, |
799 | const struct nlattr *bc) | 812 | const struct nlattr *bc, |
813 | bool net_admin) | ||
800 | { | 814 | { |
801 | if (!inet_diag_bc_sk(bc, sk)) | 815 | if (!inet_diag_bc_sk(bc, sk)) |
802 | return 0; | 816 | return 0; |
@@ -804,7 +818,8 @@ static int inet_csk_diag_dump(struct sock *sk, | |||
804 | return inet_csk_diag_fill(sk, skb, r, | 818 | return inet_csk_diag_fill(sk, skb, r, |
805 | sk_user_ns(NETLINK_CB(cb->skb).sk), | 819 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
806 | NETLINK_CB(cb->skb).portid, | 820 | NETLINK_CB(cb->skb).portid, |
807 | cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); | 821 | cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, |
822 | net_admin); | ||
808 | } | 823 | } |
809 | 824 | ||
810 | static void twsk_build_assert(void) | 825 | static void twsk_build_assert(void) |
@@ -840,6 +855,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, | |||
840 | struct net *net = sock_net(skb->sk); | 855 | struct net *net = sock_net(skb->sk); |
841 | int i, num, s_i, s_num; | 856 | int i, num, s_i, s_num; |
842 | u32 idiag_states = r->idiag_states; | 857 | u32 idiag_states = r->idiag_states; |
858 | bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); | ||
843 | 859 | ||
844 | if (idiag_states & TCPF_SYN_RECV) | 860 | if (idiag_states & TCPF_SYN_RECV) |
845 | idiag_states |= TCPF_NEW_SYN_RECV; | 861 | idiag_states |= TCPF_NEW_SYN_RECV; |
@@ -880,7 +896,8 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, | |||
880 | cb->args[3] > 0) | 896 | cb->args[3] > 0) |
881 | goto next_listen; | 897 | goto next_listen; |
882 | 898 | ||
883 | if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) { | 899 | if (inet_csk_diag_dump(sk, skb, cb, r, |
900 | bc, net_admin) < 0) { | ||
884 | spin_unlock_bh(&ilb->lock); | 901 | spin_unlock_bh(&ilb->lock); |
885 | goto done; | 902 | goto done; |
886 | } | 903 | } |
@@ -948,7 +965,7 @@ skip_listen_ht: | |||
948 | sk_user_ns(NETLINK_CB(cb->skb).sk), | 965 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
949 | NETLINK_CB(cb->skb).portid, | 966 | NETLINK_CB(cb->skb).portid, |
950 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 967 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
951 | cb->nlh); | 968 | cb->nlh, net_admin); |
952 | if (res < 0) { | 969 | if (res < 0) { |
953 | spin_unlock_bh(lock); | 970 | spin_unlock_bh(lock); |
954 | goto done; | 971 | goto done; |
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 58b79c0c0d69..9a89c10a55f0 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c | |||
@@ -20,7 +20,7 @@ | |||
20 | static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, | 20 | static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, |
21 | struct netlink_callback *cb, | 21 | struct netlink_callback *cb, |
22 | const struct inet_diag_req_v2 *req, | 22 | const struct inet_diag_req_v2 *req, |
23 | struct nlattr *bc) | 23 | struct nlattr *bc, bool net_admin) |
24 | { | 24 | { |
25 | if (!inet_diag_bc_sk(bc, sk)) | 25 | if (!inet_diag_bc_sk(bc, sk)) |
26 | return 0; | 26 | return 0; |
@@ -28,7 +28,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, | |||
28 | return inet_sk_diag_fill(sk, NULL, skb, req, | 28 | return inet_sk_diag_fill(sk, NULL, skb, req, |
29 | sk_user_ns(NETLINK_CB(cb->skb).sk), | 29 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
30 | NETLINK_CB(cb->skb).portid, | 30 | NETLINK_CB(cb->skb).portid, |
31 | cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); | 31 | cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, net_admin); |
32 | } | 32 | } |
33 | 33 | ||
34 | static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, | 34 | static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, |
@@ -76,7 +76,8 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, | |||
76 | err = inet_sk_diag_fill(sk, NULL, rep, req, | 76 | err = inet_sk_diag_fill(sk, NULL, rep, req, |
77 | sk_user_ns(NETLINK_CB(in_skb).sk), | 77 | sk_user_ns(NETLINK_CB(in_skb).sk), |
78 | NETLINK_CB(in_skb).portid, | 78 | NETLINK_CB(in_skb).portid, |
79 | nlh->nlmsg_seq, 0, nlh); | 79 | nlh->nlmsg_seq, 0, nlh, |
80 | netlink_net_capable(in_skb, CAP_NET_ADMIN)); | ||
80 | if (err < 0) { | 81 | if (err < 0) { |
81 | WARN_ON(err == -EMSGSIZE); | 82 | WARN_ON(err == -EMSGSIZE); |
82 | kfree_skb(rep); | 83 | kfree_skb(rep); |
@@ -97,6 +98,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, | |||
97 | struct netlink_callback *cb, | 98 | struct netlink_callback *cb, |
98 | const struct inet_diag_req_v2 *r, struct nlattr *bc) | 99 | const struct inet_diag_req_v2 *r, struct nlattr *bc) |
99 | { | 100 | { |
101 | bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); | ||
100 | struct net *net = sock_net(skb->sk); | 102 | struct net *net = sock_net(skb->sk); |
101 | int num, s_num, slot, s_slot; | 103 | int num, s_num, slot, s_slot; |
102 | 104 | ||
@@ -132,7 +134,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, | |||
132 | r->id.idiag_dport) | 134 | r->id.idiag_dport) |
133 | goto next; | 135 | goto next; |
134 | 136 | ||
135 | if (sk_diag_dump(sk, skb, cb, r, bc) < 0) { | 137 | if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) { |
136 | spin_unlock_bh(&hslot->lock); | 138 | spin_unlock_bh(&hslot->lock); |
137 | goto done; | 139 | goto done; |
138 | } | 140 | } |
diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c index f3508aa75815..807158e32f5f 100644 --- a/net/sctp/sctp_diag.c +++ b/net/sctp/sctp_diag.c | |||
@@ -106,7 +106,8 @@ static int inet_sctp_diag_fill(struct sock *sk, struct sctp_association *asoc, | |||
106 | const struct inet_diag_req_v2 *req, | 106 | const struct inet_diag_req_v2 *req, |
107 | struct user_namespace *user_ns, | 107 | struct user_namespace *user_ns, |
108 | int portid, u32 seq, u16 nlmsg_flags, | 108 | int portid, u32 seq, u16 nlmsg_flags, |
109 | const struct nlmsghdr *unlh) | 109 | const struct nlmsghdr *unlh, |
110 | bool net_admin) | ||
110 | { | 111 | { |
111 | struct sctp_endpoint *ep = sctp_sk(sk)->ep; | 112 | struct sctp_endpoint *ep = sctp_sk(sk)->ep; |
112 | struct list_head *addr_list; | 113 | struct list_head *addr_list; |
@@ -133,7 +134,7 @@ static int inet_sctp_diag_fill(struct sock *sk, struct sctp_association *asoc, | |||
133 | r->idiag_retrans = 0; | 134 | r->idiag_retrans = 0; |
134 | } | 135 | } |
135 | 136 | ||
136 | if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns)) | 137 | if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin)) |
137 | goto errout; | 138 | goto errout; |
138 | 139 | ||
139 | if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) { | 140 | if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) { |
@@ -203,6 +204,7 @@ struct sctp_comm_param { | |||
203 | struct netlink_callback *cb; | 204 | struct netlink_callback *cb; |
204 | const struct inet_diag_req_v2 *r; | 205 | const struct inet_diag_req_v2 *r; |
205 | const struct nlmsghdr *nlh; | 206 | const struct nlmsghdr *nlh; |
207 | bool net_admin; | ||
206 | }; | 208 | }; |
207 | 209 | ||
208 | static size_t inet_assoc_attr_size(struct sctp_association *asoc) | 210 | static size_t inet_assoc_attr_size(struct sctp_association *asoc) |
@@ -219,6 +221,7 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc) | |||
219 | + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ | 221 | + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ |
220 | + nla_total_size(1) /* INET_DIAG_TOS */ | 222 | + nla_total_size(1) /* INET_DIAG_TOS */ |
221 | + nla_total_size(1) /* INET_DIAG_TCLASS */ | 223 | + nla_total_size(1) /* INET_DIAG_TCLASS */ |
224 | + nla_total_size(4) /* INET_DIAG_MARK */ | ||
222 | + nla_total_size(addrlen * asoc->peer.transport_count) | 225 | + nla_total_size(addrlen * asoc->peer.transport_count) |
223 | + nla_total_size(addrlen * addrcnt) | 226 | + nla_total_size(addrlen * addrcnt) |
224 | + nla_total_size(sizeof(struct inet_diag_meminfo)) | 227 | + nla_total_size(sizeof(struct inet_diag_meminfo)) |
@@ -256,7 +259,8 @@ static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p) | |||
256 | err = inet_sctp_diag_fill(sk, assoc, rep, req, | 259 | err = inet_sctp_diag_fill(sk, assoc, rep, req, |
257 | sk_user_ns(NETLINK_CB(in_skb).sk), | 260 | sk_user_ns(NETLINK_CB(in_skb).sk), |
258 | NETLINK_CB(in_skb).portid, | 261 | NETLINK_CB(in_skb).portid, |
259 | nlh->nlmsg_seq, 0, nlh); | 262 | nlh->nlmsg_seq, 0, nlh, |
263 | commp->net_admin); | ||
260 | release_sock(sk); | 264 | release_sock(sk); |
261 | if (err < 0) { | 265 | if (err < 0) { |
262 | WARN_ON(err == -EMSGSIZE); | 266 | WARN_ON(err == -EMSGSIZE); |
@@ -310,7 +314,8 @@ static int sctp_tsp_dump(struct sctp_transport *tsp, void *p) | |||
310 | sk_user_ns(NETLINK_CB(cb->skb).sk), | 314 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
311 | NETLINK_CB(cb->skb).portid, | 315 | NETLINK_CB(cb->skb).portid, |
312 | cb->nlh->nlmsg_seq, | 316 | cb->nlh->nlmsg_seq, |
313 | NLM_F_MULTI, cb->nlh) < 0) { | 317 | NLM_F_MULTI, cb->nlh, |
318 | commp->net_admin) < 0) { | ||
314 | cb->args[3] = 1; | 319 | cb->args[3] = 1; |
315 | err = 2; | 320 | err = 2; |
316 | goto release; | 321 | goto release; |
@@ -320,7 +325,8 @@ static int sctp_tsp_dump(struct sctp_transport *tsp, void *p) | |||
320 | if (inet_sctp_diag_fill(sk, assoc, skb, r, | 325 | if (inet_sctp_diag_fill(sk, assoc, skb, r, |
321 | sk_user_ns(NETLINK_CB(cb->skb).sk), | 326 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
322 | NETLINK_CB(cb->skb).portid, | 327 | NETLINK_CB(cb->skb).portid, |
323 | cb->nlh->nlmsg_seq, 0, cb->nlh) < 0) { | 328 | cb->nlh->nlmsg_seq, 0, cb->nlh, |
329 | commp->net_admin) < 0) { | ||
324 | err = 2; | 330 | err = 2; |
325 | goto release; | 331 | goto release; |
326 | } | 332 | } |
@@ -375,7 +381,7 @@ static int sctp_ep_dump(struct sctp_endpoint *ep, void *p) | |||
375 | sk_user_ns(NETLINK_CB(cb->skb).sk), | 381 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
376 | NETLINK_CB(cb->skb).portid, | 382 | NETLINK_CB(cb->skb).portid, |
377 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 383 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
378 | cb->nlh) < 0) { | 384 | cb->nlh, commp->net_admin) < 0) { |
379 | err = 2; | 385 | err = 2; |
380 | goto out; | 386 | goto out; |
381 | } | 387 | } |
@@ -412,6 +418,7 @@ static int sctp_diag_dump_one(struct sk_buff *in_skb, | |||
412 | .skb = in_skb, | 418 | .skb = in_skb, |
413 | .r = req, | 419 | .r = req, |
414 | .nlh = nlh, | 420 | .nlh = nlh, |
421 | .net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN), | ||
415 | }; | 422 | }; |
416 | 423 | ||
417 | if (req->sdiag_family == AF_INET) { | 424 | if (req->sdiag_family == AF_INET) { |
@@ -447,6 +454,7 @@ static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, | |||
447 | .skb = skb, | 454 | .skb = skb, |
448 | .cb = cb, | 455 | .cb = cb, |
449 | .r = r, | 456 | .r = r, |
457 | .net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN), | ||
450 | }; | 458 | }; |
451 | 459 | ||
452 | /* eps hashtable dumps | 460 | /* eps hashtable dumps |