Message ID | 1358952744-29288-1-git-send-email-rbriggs@redhat.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
From: Richard Guy Briggs <rbriggs@redhat.com> Date: Wed, 23 Jan 2013 09:52:24 -0500 > From: Richard Guy Briggs <rgb@redhat.com> > > Currently netlink socket permissions are controlled by the > NL_CFG_F_NONROOT_{RECV,SEND} flags in the kernel socket configuration or by the > CAP_NET_ADMIN capability of the client. The former allows non-root users > access to the socket. The latter allows all network admin clients access to > the socket. It would be useful to be able to further restrict this access to > send or receive capabilities individually within specific subsystems with a > more targetted capability. Two more flags, NL_CFG_F_CAPABILITY_{RECV,SEND}, > have been added to specifically require a named capability should the subsystem > request it, allowing the client to drop other broad unneeded capabilities. > > Signed-off-by: Richard Guy Briggs <rbriggs@redhat.com> I've been looking at this over and over again the past few days, are you really sure you cannot get the behavior you need within the current framework and using existing facilities? -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Jan 28, 2013 at 10:55:24PM -0500, David Miller wrote: > From: Richard Guy Briggs <rbriggs@redhat.com> > Date: Wed, 23 Jan 2013 09:52:24 -0500 > > > From: Richard Guy Briggs <rgb@redhat.com> > > > > Currently netlink socket permissions are controlled by the > > NL_CFG_F_NONROOT_{RECV,SEND} flags in the kernel socket configuration or by the > > CAP_NET_ADMIN capability of the client. The former allows non-root users > > access to the socket. The latter allows all network admin clients access to > > the socket. It would be useful to be able to further restrict this access to > > send or receive capabilities individually within specific subsystems with a > > more targetted capability. Two more flags, NL_CFG_F_CAPABILITY_{RECV,SEND}, > > have been added to specifically require a named capability should the subsystem > > request it, allowing the client to drop other broad unneeded capabilities. > > > > Signed-off-by: Richard Guy Briggs <rbriggs@redhat.com> > > I've been looking at this over and over again the past few days, > are you really sure you cannot get the behavior you need within > the current framework and using existing facilities? Was there any facility that you can think of or point out that could provide this functionality? At the moment, any process with CAP_NET_ADMIN has full access to this socket. That uses the default service structure provided by netlink. We want to restrict this. Were you thinking along the lines of checking each broadcast subscriber at send time for the capability in question? It would seem more efficient and safer to check them upon subscription. The code changes would also be a bit more complex, at first blush. Could a custom bind function be used instead? I had looked into that. I must admit I like this option better in the long term, but it would also disrupt another subsystem in the process (netfilter). The bind function only accepts a group ID and not a socket against which to check requesting socket owner priveleges. The custom bind function returns void so we have no way of signalling a permissions denial. It is only used by netfilter at the moment. Would you be agreeable to adding a parameter to this function call, and to adding a return value? Could netlink_setsockopt be used? When subscribing to a group, it first checks capabilities, which are limited as described originally above. It then calls the custom bind function if it exists. See paragraph above. Thanks for taking the time to mull this one over, David. - RGB -- Richard Guy Briggs <rbriggs@redhat.com> Senior Software Engineer AMER ENG Base Operating Systems Remote, Canada, Ottawa Voice: 1.647.777.2635 Internal: (81) 32635 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Richard Guy Briggs <rgb@redhat.com> Date: Wed, 30 Jan 2013 13:54:40 -0500 > Was there any facility that you can think of or point out that could > provide this functionality? If you want to provide a pure event stream, why don't you just create a seperate genetlink instance just for this? -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index e0f746b..30daf11 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -31,6 +31,8 @@ extern void netlink_table_ungrab(void); #define NL_CFG_F_NONROOT_RECV (1 << 0) #define NL_CFG_F_NONROOT_SEND (1 << 1) +#define NL_CFG_F_CAPABILITY_RECV (1 << 2) +#define NL_CFG_F_CAPABILITY_SEND (1 << 3) /* optional Netlink kernel configuration parameters */ struct netlink_kernel_cfg { @@ -39,6 +41,8 @@ struct netlink_kernel_cfg { void (*input)(struct sk_buff *skb); struct mutex *cb_mutex; void (*bind)(int group); + int cap_send_requires; + int cap_recv_requires; }; extern struct sock *__netlink_kernel_create(struct net *net, int unit, diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c0353d5..cce1fe3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -127,6 +127,8 @@ struct netlink_table { struct module *module; void (*bind)(int group); int registered; + int cap_send_requires; + int cap_recv_requires; }; static struct netlink_table *nl_table; @@ -552,6 +554,8 @@ static int netlink_release(struct socket *sock) nl_table[sk->sk_protocol].bind = NULL; nl_table[sk->sk_protocol].flags = 0; nl_table[sk->sk_protocol].registered = 0; + nl_table[sk->sk_protocol].cap_send_requires = 0; + nl_table[sk->sk_protocol].cap_recv_requires = 0; } } else if (nlk->subscriptions) { netlink_update_listeners(sk); @@ -611,8 +615,20 @@ retry: static inline int netlink_capable(const struct socket *sock, unsigned int flag) { - return (nl_table[sock->sk->sk_protocol].flags & flag) || - ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); + struct netlink_table *nlt = &nl_table[sock->sk->sk_protocol]; + + switch (flag & nlt->flags) { + case NL_CFG_F_NONROOT_RECV: + case NL_CFG_F_NONROOT_SEND: + return true; + case NL_CFG_F_CAPABILITY_RECV: + return capable(nlt->cap_recv_requires); + case NL_CFG_F_CAPABILITY_SEND: + return capable(nlt->cap_send_requires); + default: + return capable(CAP_NET_ADMIN); + } + return false; } static void @@ -677,7 +693,8 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, /* Only superuser is allowed to listen multicasts */ if (nladdr->nl_groups) { - if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) + if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV | + NL_CFG_F_CAPABILITY_RECV)) return -EPERM; err = netlink_realloc_groups(sk); if (err) @@ -739,7 +756,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, return -EINVAL; /* Only superuser is allowed to send multicasts */ - if (nladdr->nl_groups && !netlink_capable(sock, NL_CFG_F_NONROOT_SEND)) + if (nladdr->nl_groups && + !netlink_capable(sock, NL_CFG_F_NONROOT_SEND | + NL_CFG_F_CAPABILITY_SEND)) return -EPERM; if (!nlk->portid) @@ -1262,7 +1281,8 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, break; case NETLINK_ADD_MEMBERSHIP: case NETLINK_DROP_MEMBERSHIP: { - if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV)) + if (!netlink_capable(sock, NL_CFG_F_NONROOT_RECV | + NL_CFG_F_CAPABILITY_RECV)) return -EPERM; err = netlink_realloc_groups(sk); if (err) @@ -1394,7 +1414,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, dst_group = ffs(addr->nl_groups); err = -EPERM; if ((dst_group || dst_portid) && - !netlink_capable(sock, NL_CFG_F_NONROOT_SEND)) + !netlink_capable(sock, NL_CFG_F_NONROOT_SEND | + NL_CFG_F_CAPABILITY_SEND)) goto out; } else { dst_portid = nlk->dst_portid; @@ -1600,6 +1621,8 @@ __netlink_kernel_create(struct net *net, int unit, struct module *module, if (cfg) { nl_table[unit].bind = cfg->bind; nl_table[unit].flags = cfg->flags; + nl_table[unit].cap_send_requires = cfg->cap_send_requires; + nl_table[unit].cap_recv_requires = cfg->cap_recv_requires; } nl_table[unit].registered = 1; } else {