aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2016-08-24 15:46:26 +0900
committerMister Oyster <oysterized@gmail.com>2017-04-11 10:57:35 +0200
commit97c4ac5df7dc16baad461a84b5826503bf391537 (patch)
tree8a2bc49b8e8003e39c6ce11dd7598b68074e019a /net
parente2c138779969ffafe92ef46cd36af6f05e3f4b46 (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.c32
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;
}