Message ID | 20100115081308.GA14443@heat |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On Fri, Jan 15, 2010 at 12:13 AM, Michael Stone <michael@laptop.org> wrote: > We implement this check by allocating a new flag bit in task_struct->network > and by propagating its semantics throughout the disablenetwork facility. > > Signed-off-by: Michael Stone <michael@laptop.org> > --- > include/linux/prctl.h | 8 +++++--- > kernel/sys.c | 14 +++++++++++++- > security/disablenetwork.c | 15 ++++++++------- > 3 files changed, 26 insertions(+), 11 deletions(-) > > diff --git a/include/linux/prctl.h b/include/linux/prctl.h > index 4eb4110..4fdb417 100644 > --- a/include/linux/prctl.h > +++ b/include/linux/prctl.h > @@ -105,8 +105,10 @@ > /* Get/set process disable-network flags */ > #define PR_SET_NETWORK 35 > #define PR_GET_NETWORK 36 > -# define PR_NETWORK_ON 0 > -# define PR_NETWORK_OFF 1 > -# define PR_NETWORK_ALL_FLAGS 1 > +# define PR_NETWORK_ON 0 > +# define PR_NETWORK_ENABLE_DN 1 > +# define PR_NETWORK_OFF 2 > +# define PR_NETWORK_ALL_FLAGS 3 > +# define PR_NETWORK_DN_FLAGS 3 > > #endif /* _LINUX_PRCTL_H */ > diff --git a/kernel/sys.c b/kernel/sys.c > index 1fadf10..4c7ef83 100644 > --- a/kernel/sys.c > +++ b/kernel/sys.c > @@ -1608,7 +1608,19 @@ long prctl_set_network(unsigned long network_flags) > if (current->network & ~network_flags) > return -EPERM; > > - current->network = network_flags; > + /* Only the superuser may permit a process to enable disablenetwork. */ > + if (!(current->network & PR_NETWORK_ENABLE_DN) && > + network_flags & PR_NETWORK_ENABLE_DN && > + !capable(CAP_SETPCAP)) Please use CAP_NET_ADMIN for this feature (and add the corresponding comment in include/linux/capabilities.h). Thanks Andrew > + return -EPERM; > + > + /* Only dn-enabled processes may activate disablenetwork. */ > + if (!(current->network & PR_NETWORK_OFF) && > + network_flags & PR_NETWORK_OFF && > + !(current->network & PR_NETWORK_ENABLE_DN)) > + return -EPERM; > + > + current->network |= network_flags; > return 0; > } > > diff --git a/security/disablenetwork.c b/security/disablenetwork.c > index 27b88d7..02c0150 100644 > --- a/security/disablenetwork.c > +++ b/security/disablenetwork.c > @@ -19,10 +19,11 @@ > #include <net/sock.h> > #include <linux/socket.h> > #include <linux/disablenetwork.h> > +#include <linux/prctl.h> > > -static inline int maybe_allow(void) > +static inline int maybe_allow(unsigned long network_flags) > { > - if (current->network) > + if ((network_flags & PR_NETWORK_DN_FLAGS) == PR_NETWORK_DN_FLAGS) > return -EPERM; > return 0; > } > @@ -32,7 +33,7 @@ int disablenetwork_security_socket_create(int family, int type, > { > if (family == AF_UNIX) > return 0; > - return maybe_allow(); > + return maybe_allow(current->network); > } > > int disablenetwork_security_socket_bind(struct socket * sock, > @@ -41,7 +42,7 @@ int disablenetwork_security_socket_bind(struct socket * sock, > { > if (address->sa_family == AF_UNIX) > return 0; > - return maybe_allow(); > + return maybe_allow(current->network); > } > > int disablenetwork_security_socket_connect(struct socket * sock, > @@ -50,7 +51,7 @@ int disablenetwork_security_socket_connect(struct socket * sock, > { > if (address->sa_family == AF_UNIX) > return 0; > - return maybe_allow(); > + return maybe_allow(current->network); > } > > int disablenetwork_security_socket_sendmsg(struct socket * sock, > @@ -59,14 +60,14 @@ int disablenetwork_security_socket_sendmsg(struct socket * sock, > /* permit sockets which are PF_UNIX or connected; check others. */ > if (sock->sk->sk_family == PF_UNIX || msg->msg_name == NULL) > return 0; > - return maybe_allow(); > + return maybe_allow(current->network); > } > > int disablenetwork_security_ptrace_access_check(struct task_struct *child, > unsigned int mode) > { > /* does current have networking restrictions not shared by child? */ > - if (current->network & ~child->network) > + if (maybe_allow(current->network) && !maybe_allow(child->network)) > return -EPERM; > return 0; > } > -- > 1.6.6.rc2 > -- 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 Sat, Jan 16, 2010 at 8:48 PM, Michael Stone <michael@laptop.org> wrote: > Andrew Morgan wrote: >> >> Please use CAP_NET_ADMIN for this feature (and add the corresponding >> comment in include/linux/capabilities.h). > > Sure. > However, to make sure I understand the purpose of the adjustment, would you > mind saying a word or two about what considerations cause you to recommend > CAP_NET_ADMIN instead of (or in addition to?) CAP_SETPCAP? If you take a look at the capabilities.h file, you'll see that each of the capabilities is preceded by an explanation of what privilege it enables. CAP_SETPCAP refers to privileged manipulation of capabilities (permission to violate the normal capability rules) and nothing to do with the network. You are adding something akin to a per-process tree firewall setting - deny/enable network access to this process. I think you'll agree that the CAP_NET_ADMIN description is a much better match for this. Cheers Andrew > > Thanks for your feedback, > > Michael > -- 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
Quoting Andrew G. Morgan (morgan@kernel.org): > On Sat, Jan 16, 2010 at 8:48 PM, Michael Stone <michael@laptop.org> wrote: > > Andrew Morgan wrote: > >> > >> Please use CAP_NET_ADMIN for this feature (and add the corresponding > >> comment in include/linux/capabilities.h). > > > > Sure. > > However, to make sure I understand the purpose of the adjustment, would you > > mind saying a word or two about what considerations cause you to recommend > > CAP_NET_ADMIN instead of (or in addition to?) CAP_SETPCAP? > > If you take a look at the capabilities.h file, you'll see that each of > the capabilities is preceded by an explanation of what privilege it > enables. > > CAP_SETPCAP refers to privileged manipulation of capabilities > (permission to violate the normal capability rules) and nothing to do > with the network. > > You are adding something akin to a per-process tree firewall setting - > deny/enable network access to this process. I think I originally suggested CAP_SETPCAP - because it's not deny network access to this process, but deny network access to all child processes as well, even if they are more privileged (through setuid-root or file caps). CAP_NET_ADMIN is probably more straightforward, though. Who's going to think to add CAP_SETPCAP to a binary that is intended to drop network perms, realistically... > I think you'll agree that > the CAP_NET_ADMIN description is a much better match for this. I think it'll be more intuitive to most people so I agree. -serge -- 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/prctl.h b/include/linux/prctl.h index 4eb4110..4fdb417 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -105,8 +105,10 @@ /* Get/set process disable-network flags */ #define PR_SET_NETWORK 35 #define PR_GET_NETWORK 36 -# define PR_NETWORK_ON 0 -# define PR_NETWORK_OFF 1 -# define PR_NETWORK_ALL_FLAGS 1 +# define PR_NETWORK_ON 0 +# define PR_NETWORK_ENABLE_DN 1 +# define PR_NETWORK_OFF 2 +# define PR_NETWORK_ALL_FLAGS 3 +# define PR_NETWORK_DN_FLAGS 3 #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 1fadf10..4c7ef83 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1608,7 +1608,19 @@ long prctl_set_network(unsigned long network_flags) if (current->network & ~network_flags) return -EPERM; - current->network = network_flags; + /* Only the superuser may permit a process to enable disablenetwork. */ + if (!(current->network & PR_NETWORK_ENABLE_DN) && + network_flags & PR_NETWORK_ENABLE_DN && + !capable(CAP_SETPCAP)) + return -EPERM; + + /* Only dn-enabled processes may activate disablenetwork. */ + if (!(current->network & PR_NETWORK_OFF) && + network_flags & PR_NETWORK_OFF && + !(current->network & PR_NETWORK_ENABLE_DN)) + return -EPERM; + + current->network |= network_flags; return 0; } diff --git a/security/disablenetwork.c b/security/disablenetwork.c index 27b88d7..02c0150 100644 --- a/security/disablenetwork.c +++ b/security/disablenetwork.c @@ -19,10 +19,11 @@ #include <net/sock.h> #include <linux/socket.h> #include <linux/disablenetwork.h> +#include <linux/prctl.h> -static inline int maybe_allow(void) +static inline int maybe_allow(unsigned long network_flags) { - if (current->network) + if ((network_flags & PR_NETWORK_DN_FLAGS) == PR_NETWORK_DN_FLAGS) return -EPERM; return 0; } @@ -32,7 +33,7 @@ int disablenetwork_security_socket_create(int family, int type, { if (family == AF_UNIX) return 0; - return maybe_allow(); + return maybe_allow(current->network); } int disablenetwork_security_socket_bind(struct socket * sock, @@ -41,7 +42,7 @@ int disablenetwork_security_socket_bind(struct socket * sock, { if (address->sa_family == AF_UNIX) return 0; - return maybe_allow(); + return maybe_allow(current->network); } int disablenetwork_security_socket_connect(struct socket * sock, @@ -50,7 +51,7 @@ int disablenetwork_security_socket_connect(struct socket * sock, { if (address->sa_family == AF_UNIX) return 0; - return maybe_allow(); + return maybe_allow(current->network); } int disablenetwork_security_socket_sendmsg(struct socket * sock, @@ -59,14 +60,14 @@ int disablenetwork_security_socket_sendmsg(struct socket * sock, /* permit sockets which are PF_UNIX or connected; check others. */ if (sock->sk->sk_family == PF_UNIX || msg->msg_name == NULL) return 0; - return maybe_allow(); + return maybe_allow(current->network); } int disablenetwork_security_ptrace_access_check(struct task_struct *child, unsigned int mode) { /* does current have networking restrictions not shared by child? */ - if (current->network & ~child->network) + if (maybe_allow(current->network) && !maybe_allow(child->network)) return -EPERM; return 0; }
We implement this check by allocating a new flag bit in task_struct->network and by propagating its semantics throughout the disablenetwork facility. Signed-off-by: Michael Stone <michael@laptop.org> --- include/linux/prctl.h | 8 +++++--- kernel/sys.c | 14 +++++++++++++- security/disablenetwork.c | 15 ++++++++------- 3 files changed, 26 insertions(+), 11 deletions(-)