diff options
| author | Lorenzo Colitti <lorenzo@google.com> | 2016-08-24 15:46:26 +0900 |
|---|---|---|
| committer | Mister Oyster <oysterized@gmail.com> | 2017-04-11 10:57:35 +0200 |
| commit | 97c4ac5df7dc16baad461a84b5826503bf391537 (patch) | |
| tree | 8a2bc49b8e8003e39c6ce11dd7598b68074e019a /net | |
| parent | e2c138779969ffafe92ef46cd36af6f05e3f4b46 (diff) | |
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.
[backport of net-next a52e95abf772b43c9226e9a72d3c1353903ba96f]
Change-Id: If4609026882ef283a619b8bf24c0127f1f18ce6a
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>
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv4/inet_diag.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 2e6bee08c..d60accaa7 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -49,6 +49,7 @@ struct inet_diag_entry { struct in6_addr daddr_storage; /* for IPv4-mapped-IPv6 addresses */ #endif u32 ifindex; + u32 mark; }; static DEFINE_MUTEX(inet_diag_table_mutex); @@ -532,6 +533,14 @@ static int inet_diag_bc_run(const struct nlattr *_bc, yes = 0; 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) { @@ -570,6 +579,7 @@ int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk) entry.dport = ntohs(inet->inet_dport); entry.ifindex = sk->sk_bound_dev_if; entry.userlocks = sk->sk_userlocks; + entry.mark = sk->sk_mark; return inet_diag_bc_run(bc, &entry); } @@ -652,8 +662,17 @@ static inline bool valid_port_comparison(const struct inet_diag_bc_op *op, 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; int bytecode_len, len; @@ -685,6 +704,12 @@ static int inet_diag_bc_audit(const struct nlattr *attr) if (!valid_port_comparison(bc, len, &min_len)) return -EINVAL; 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_JMP: case INET_DIAG_BC_NOP: @@ -751,6 +776,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw, entry.sport = tw->tw_num; entry.dport = ntohs(tw->tw_dport); entry.userlocks = 0; + entry.mark = 0; if (!inet_diag_bc_run(bc, &entry)) return 0; @@ -1173,7 +1199,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) attr = nlmsg_find_attr(nlh, hdrlen, INET_DIAG_REQ_BYTECODE); - err = inet_diag_bc_audit(attr); + err = inet_diag_bc_audit(attr, skb); if (err) return err; } @@ -1204,7 +1230,7 @@ static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h) attr = nlmsg_find_attr(h, hdrlen, INET_DIAG_REQ_BYTECODE); - err = inet_diag_bc_audit(attr); + err = inet_diag_bc_audit(attr, skb); if (err) return err; } |
