mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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. Commita52e95abf7("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-nextd545caca82] Change-Id: I33336ed9c3ee3fb78fe05c4c47b7fd18c6e33ef1 Tested: https://android-review.googlesource.com/270210 Signed-off-by: Lorenzo Colitti <lorenzo@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
Amit Pundir
parent
494cc7175f
commit
85460b112d
@@ -37,7 +37,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
|
||||
struct sk_buff *skb, const 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,
|
||||
const struct inet_diag_req_v2 *r,
|
||||
|
||||
@@ -120,9 +120,13 @@ enum {
|
||||
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_SKV6ONLY
|
||||
#define INET_DIAG_MAX INET_DIAG_MARK
|
||||
|
||||
/* INET_DIAG_MEM */
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ static size_t inet_sk_attr_size(void)
|
||||
+ nla_total_size(1) /* INET_DIAG_SHUTDOWN */
|
||||
+ nla_total_size(1) /* INET_DIAG_TOS */
|
||||
+ nla_total_size(1) /* INET_DIAG_TCLASS */
|
||||
+ nla_total_size(4) /* INET_DIAG_MARK */
|
||||
+ nla_total_size(sizeof(struct inet_diag_meminfo))
|
||||
+ nla_total_size(sizeof(struct inet_diag_msg))
|
||||
+ nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
|
||||
@@ -110,7 +111,8 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
|
||||
struct sk_buff *skb, const 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);
|
||||
const struct tcp_congestion_ops *ca_ops;
|
||||
@@ -160,6 +162,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);
|
||||
|
||||
@@ -258,10 +263,11 @@ static int inet_csk_diag_fill(struct sock *sk,
|
||||
const 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);
|
||||
return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, user_ns,
|
||||
portid, seq, nlmsg_flags, unlh, net_admin);
|
||||
}
|
||||
|
||||
static int inet_twsk_diag_fill(struct sock *sk,
|
||||
@@ -303,8 +309,9 @@ static int inet_twsk_diag_fill(struct sock *sk,
|
||||
|
||||
static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
|
||||
u32 portid, u32 seq, u16 nlmsg_flags,
|
||||
const struct nlmsghdr *unlh)
|
||||
const struct nlmsghdr *unlh, bool net_admin)
|
||||
{
|
||||
struct request_sock *reqsk = inet_reqsk(sk);
|
||||
struct inet_diag_msg *r;
|
||||
struct nlmsghdr *nlh;
|
||||
long tmo;
|
||||
@@ -318,7 +325,7 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
|
||||
inet_diag_msg_common_fill(r, sk);
|
||||
r->idiag_state = TCP_SYN_RECV;
|
||||
r->idiag_timer = 1;
|
||||
r->idiag_retrans = inet_reqsk(sk)->num_retrans;
|
||||
r->idiag_retrans = reqsk->num_retrans;
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) !=
|
||||
offsetof(struct sock, sk_cookie));
|
||||
@@ -330,6 +337,10 @@ static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb,
|
||||
r->idiag_uid = 0;
|
||||
r->idiag_inode = 0;
|
||||
|
||||
if (net_admin && nla_put_u32(skb, INET_DIAG_MARK,
|
||||
inet_rsk(reqsk)->ir_mark))
|
||||
return -EMSGSIZE;
|
||||
|
||||
nlmsg_end(skb, nlh);
|
||||
return 0;
|
||||
}
|
||||
@@ -338,7 +349,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
|
||||
const 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(sk, skb, portid, seq,
|
||||
@@ -346,10 +357,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
|
||||
|
||||
if (sk->sk_state == TCP_NEW_SYN_RECV)
|
||||
return inet_req_diag_fill(sk, skb, portid, seq,
|
||||
nlmsg_flags, unlh);
|
||||
nlmsg_flags, unlh, net_admin);
|
||||
|
||||
return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq,
|
||||
nlmsg_flags, unlh);
|
||||
nlmsg_flags, unlh, net_admin);
|
||||
}
|
||||
|
||||
struct sock *inet_diag_find_one_icsk(struct net *net,
|
||||
@@ -416,7 +427,8 @@ 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,
|
||||
netlink_net_capable(in_skb, CAP_NET_ADMIN));
|
||||
if (err < 0) {
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
nlmsg_free(rep);
|
||||
@@ -777,7 +789,8 @@ static int inet_csk_diag_dump(struct sock *sk,
|
||||
struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
const 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;
|
||||
@@ -785,7 +798,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 void twsk_build_assert(void)
|
||||
@@ -821,6 +835,7 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||||
struct net *net = sock_net(skb->sk);
|
||||
int i, num, s_i, s_num;
|
||||
u32 idiag_states = r->idiag_states;
|
||||
bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
|
||||
|
||||
if (idiag_states & TCPF_SYN_RECV)
|
||||
idiag_states |= TCPF_NEW_SYN_RECV;
|
||||
@@ -862,7 +877,8 @@ void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
|
||||
cb->args[3] > 0)
|
||||
goto next_listen;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -930,7 +946,7 @@ skip_listen_ht:
|
||||
sk_user_ns(NETLINK_CB(cb->skb).sk),
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
cb->nlh);
|
||||
cb->nlh, net_admin);
|
||||
if (res < 0) {
|
||||
spin_unlock_bh(lock);
|
||||
goto done;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
const 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,
|
||||
@@ -75,7 +75,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,
|
||||
netlink_net_capable(in_skb, CAP_NET_ADMIN));
|
||||
if (err < 0) {
|
||||
WARN_ON(err == -EMSGSIZE);
|
||||
kfree_skb(rep);
|
||||
@@ -98,6 +99,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb,
|
||||
{
|
||||
int num, s_num, slot, s_slot;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
|
||||
|
||||
s_slot = cb->args[0];
|
||||
num = s_num = cb->args[1];
|
||||
@@ -132,7 +134,7 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb,
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user