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.

[backport of net-next d545caca827b65aab557a9e9dcdcf1e5a3823c2d]

Change-Id: I0c9708aae5ab8dfa296b8a1e6aecceb2a382415a
Tested: https://android-review.googlesource.com/270210
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Git-commit: 37249459aab0efae6ee7e11d12fc8f790dd32ebc
Git-repo: https://android.googlesource.com/kernel/common.git
Signed-off-by: Srinivasarao P <spathi@codeaurora.org>
This commit is contained in:
Lorenzo Colitti 2016-09-08 00:42:25 +09:00 committed by syphyr
parent e567849255
commit 85c311cf8d
4 changed files with 37 additions and 16 deletions

View File

@ -36,7 +36,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
struct sk_buff *skb, struct inet_diag_req_v2 *req,
struct user_namespace *user_ns,
u32 pid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh);
const struct nlmsghdr *unlh, bool net_admin);
void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb,
struct netlink_callback *cb, struct inet_diag_req_v2 *r,
struct nlattr *bc);

View File

@ -117,9 +117,16 @@ enum {
INET_DIAG_TCLASS,
INET_DIAG_SKMEMINFO,
INET_DIAG_SHUTDOWN,
INET_DIAG_DCTCPINFO,
INET_DIAG_PROTOCOL, /* response attribute only */
INET_DIAG_SKV6ONLY,
INET_DIAG_LOCALS,
INET_DIAG_PEERS,
INET_DIAG_PAD,
INET_DIAG_MARK,
};
#define INET_DIAG_MAX INET_DIAG_SHUTDOWN
#define INET_DIAG_MAX INET_DIAG_MARK
/* INET_DIAG_MEM */

View File

@ -91,7 +91,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
struct sk_buff *skb, struct inet_diag_req_v2 *req,
struct user_namespace *user_ns,
u32 portid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh)
const struct nlmsghdr *unlh, bool net_admin)
{
const struct inet_sock *inet = inet_sk(sk);
struct inet_diag_msg *r;
@ -152,6 +152,9 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
}
#endif
if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark))
goto errout;
r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
r->idiag_inode = sock_i_ino(sk);
@ -231,10 +234,11 @@ static int inet_csk_diag_fill(struct sock *sk,
struct sk_buff *skb, struct inet_diag_req_v2 *req,
struct user_namespace *user_ns,
u32 portid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh)
const struct nlmsghdr *unlh,
bool net_admin)
{
return inet_sk_diag_fill(sk, inet_csk(sk),
skb, req, user_ns, portid, seq, nlmsg_flags, unlh);
skb, req, user_ns, portid, seq, nlmsg_flags, unlh, net_admin);
}
static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
@ -297,13 +301,14 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
struct inet_diag_req_v2 *r,
struct user_namespace *user_ns,
u32 portid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh)
const struct nlmsghdr *unlh, bool net_admin)
{
if (sk->sk_state == TCP_TIME_WAIT)
return inet_twsk_diag_fill((struct inet_timewait_sock *)sk,
skb, r, portid, seq, nlmsg_flags,
unlh);
return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, nlmsg_flags, unlh);
return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, nlmsg_flags,
unlh, net_admin);
}
struct sock *inet_diag_find_one_icsk(struct net *net,
@ -376,7 +381,9 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
err = sk_diag_fill(sk, rep, req,
sk_user_ns(NETLINK_CB(in_skb).sk),
NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0, nlh);
nlh->nlmsg_seq, 0, nlh,
ns_capable(sock_net(in_skb->sk)->user_ns,
CAP_NET_ADMIN));
if (err < 0) {
WARN_ON(err == -EMSGSIZE);
nlmsg_free(rep);
@ -731,7 +738,8 @@ static int inet_csk_diag_dump(struct sock *sk,
struct sk_buff *skb,
struct netlink_callback *cb,
struct inet_diag_req_v2 *r,
const struct nlattr *bc)
const struct nlattr *bc,
bool net_admin)
{
if (!inet_diag_bc_sk(bc, sk))
return 0;
@ -739,7 +747,8 @@ static int inet_csk_diag_dump(struct sock *sk,
return inet_csk_diag_fill(sk, skb, r,
sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh,
net_admin);
}
static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
@ -944,6 +953,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
int i, num;
int s_i, s_num;
struct net *net = sock_net(skb->sk);
bool net_admin = ns_capable(net->user_ns, CAP_NET_ADMIN);
s_i = cb->args[1];
s_num = num = cb->args[2];
@ -984,7 +994,8 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
cb->args[3] > 0)
goto syn_recv;
if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
if (inet_csk_diag_dump(sk, skb, cb, r,
bc, net_admin) < 0) {
spin_unlock_bh(&ilb->lock);
goto done;
}
@ -1051,7 +1062,8 @@ skip_listen_ht:
if (r->id.idiag_dport != inet->inet_dport &&
r->id.idiag_dport)
goto next_normal;
if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
if (inet_csk_diag_dump(sk, skb, cb, r,
bc, net_admin) < 0) {
spin_unlock_bh(lock);
goto done;
}

View File

@ -20,7 +20,7 @@
static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
struct netlink_callback *cb, struct inet_diag_req_v2 *req,
struct nlattr *bc)
struct nlattr *bc, bool net_admin)
{
if (!inet_diag_bc_sk(bc, sk))
return 0;
@ -28,7 +28,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
return inet_sk_diag_fill(sk, NULL, skb, req,
sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, net_admin);
}
static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
@ -74,7 +74,8 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
err = inet_sk_diag_fill(sk, NULL, rep, req,
sk_user_ns(NETLINK_CB(in_skb).sk),
NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0, nlh);
nlh->nlmsg_seq, 0, nlh,
ns_capable(net->user_ns, CAP_NET_ADMIN));
if (err < 0) {
WARN_ON(err == -EMSGSIZE);
kfree_skb(rep);
@ -96,6 +97,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin
{
int num, s_num, slot, s_slot;
struct net *net = sock_net(skb->sk);
bool net_admin = ns_capable(net->user_ns, CAP_NET_ADMIN);
s_slot = cb->args[0];
num = s_num = cb->args[1];
@ -130,7 +132,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin
r->id.idiag_dport)
goto next;
if (sk_diag_dump(sk, skb, cb, r, bc) < 0) {
if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) {
spin_unlock_bh(&hslot->lock);
goto done;
}