net: diag: allow socket bytecode filters to match socket marks
This allows a privileged process to filter by socket mark when dumping sockets via INET_DIAG_BY_FAMILY. This is useful on systems that use mark-based routing such as Android. The ability to filter socket marks requires CAP_NET_ADMIN, which is consistent with other privileged operations allowed by the SOCK_DIAG interface such as the ability to destroy sockets and the ability to inspect BPF filters attached to packet sockets. Tested: https://android-review.googlesource.com/261350 Signed-off-by: Lorenzo Colitti <lorenzo@google.com> Acked-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
627cc4add5
commit
a52e95abf7
@ -73,6 +73,7 @@ enum {
|
|||||||
INET_DIAG_BC_S_COND,
|
INET_DIAG_BC_S_COND,
|
||||||
INET_DIAG_BC_D_COND,
|
INET_DIAG_BC_D_COND,
|
||||||
INET_DIAG_BC_DEV_COND, /* u32 ifindex */
|
INET_DIAG_BC_DEV_COND, /* u32 ifindex */
|
||||||
|
INET_DIAG_BC_MARK_COND,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct inet_diag_hostcond {
|
struct inet_diag_hostcond {
|
||||||
@ -82,6 +83,11 @@ struct inet_diag_hostcond {
|
|||||||
__be32 addr[0];
|
__be32 addr[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct inet_diag_markcond {
|
||||||
|
__u32 mark;
|
||||||
|
__u32 mask;
|
||||||
|
};
|
||||||
|
|
||||||
/* Base info structure. It contains socket identity (addrs/ports/cookie)
|
/* Base info structure. It contains socket identity (addrs/ports/cookie)
|
||||||
* and, alas, the information shown by netstat. */
|
* and, alas, the information shown by netstat. */
|
||||||
struct inet_diag_msg {
|
struct inet_diag_msg {
|
||||||
|
@ -45,6 +45,7 @@ struct inet_diag_entry {
|
|||||||
u16 family;
|
u16 family;
|
||||||
u16 userlocks;
|
u16 userlocks;
|
||||||
u32 ifindex;
|
u32 ifindex;
|
||||||
|
u32 mark;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_MUTEX(inet_diag_table_mutex);
|
static DEFINE_MUTEX(inet_diag_table_mutex);
|
||||||
@ -580,6 +581,14 @@ static int inet_diag_bc_run(const struct nlattr *_bc,
|
|||||||
yes = 0;
|
yes = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case INET_DIAG_BC_MARK_COND: {
|
||||||
|
struct inet_diag_markcond *cond;
|
||||||
|
|
||||||
|
cond = (struct inet_diag_markcond *)(op + 1);
|
||||||
|
if ((entry->mark & cond->mask) != cond->mark)
|
||||||
|
yes = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yes) {
|
if (yes) {
|
||||||
@ -624,6 +633,12 @@ int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk)
|
|||||||
entry.dport = ntohs(inet->inet_dport);
|
entry.dport = ntohs(inet->inet_dport);
|
||||||
entry.ifindex = sk->sk_bound_dev_if;
|
entry.ifindex = sk->sk_bound_dev_if;
|
||||||
entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0;
|
entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0;
|
||||||
|
if (sk_fullsock(sk))
|
||||||
|
entry.mark = sk->sk_mark;
|
||||||
|
else if (sk->sk_state == TCP_NEW_SYN_RECV)
|
||||||
|
entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark;
|
||||||
|
else
|
||||||
|
entry.mark = 0;
|
||||||
|
|
||||||
return inet_diag_bc_run(bc, &entry);
|
return inet_diag_bc_run(bc, &entry);
|
||||||
}
|
}
|
||||||
@ -706,8 +721,17 @@ static bool valid_port_comparison(const struct inet_diag_bc_op *op,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int inet_diag_bc_audit(const struct nlattr *attr)
|
static bool valid_markcond(const struct inet_diag_bc_op *op, int len,
|
||||||
|
int *min_len)
|
||||||
{
|
{
|
||||||
|
*min_len += sizeof(struct inet_diag_markcond);
|
||||||
|
return len >= *min_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int inet_diag_bc_audit(const struct nlattr *attr,
|
||||||
|
const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
bool net_admin = netlink_net_capable(skb, CAP_NET_ADMIN);
|
||||||
const void *bytecode, *bc;
|
const void *bytecode, *bc;
|
||||||
int bytecode_len, len;
|
int bytecode_len, len;
|
||||||
|
|
||||||
@ -738,6 +762,12 @@ static int inet_diag_bc_audit(const struct nlattr *attr)
|
|||||||
if (!valid_port_comparison(bc, len, &min_len))
|
if (!valid_port_comparison(bc, len, &min_len))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
case INET_DIAG_BC_MARK_COND:
|
||||||
|
if (!net_admin)
|
||||||
|
return -EPERM;
|
||||||
|
if (!valid_markcond(bc, len, &min_len))
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
case INET_DIAG_BC_AUTO:
|
case INET_DIAG_BC_AUTO:
|
||||||
case INET_DIAG_BC_JMP:
|
case INET_DIAG_BC_JMP:
|
||||||
case INET_DIAG_BC_NOP:
|
case INET_DIAG_BC_NOP:
|
||||||
@ -1030,7 +1060,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||||||
|
|
||||||
attr = nlmsg_find_attr(nlh, hdrlen,
|
attr = nlmsg_find_attr(nlh, hdrlen,
|
||||||
INET_DIAG_REQ_BYTECODE);
|
INET_DIAG_REQ_BYTECODE);
|
||||||
err = inet_diag_bc_audit(attr);
|
err = inet_diag_bc_audit(attr, skb);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1061,7 +1091,7 @@ static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h)
|
|||||||
|
|
||||||
attr = nlmsg_find_attr(h, hdrlen,
|
attr = nlmsg_find_attr(h, hdrlen,
|
||||||
INET_DIAG_REQ_BYTECODE);
|
INET_DIAG_REQ_BYTECODE);
|
||||||
err = inet_diag_bc_audit(attr);
|
err = inet_diag_bc_audit(attr, skb);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user