Here's version 4 of my disablenetwork facility and a recap of the significant
design choices so far:
1. Per Ulrich's request, we provide the initial userland interface through
prctl() rather than through *rlimit() (or through sys_disablenetwork()).
2. Per Alan's request, we use the existing security_*() hook callsites to
integrate the access control logic into the networking subsystem.
3. The access control state and logic are now conditionally compiled under
the CONFIG_SECURITY_DISABLENETWORK option. The interface calls return
-ENOSYS when this symbol is not defined.
4. In order to interoperate with as easily as possible with existing LSMs, we
store our state in a new (conditionally compiled) task_struct field named
current->network rather than in current->security. The access control
logic is called directly from the appropriate security_*() hook
implementations in security/security.c, as was done for IMA.
5. Per GeoffX's suggestion, the interface functions now take pointers to user
memory rather than passing the value of the flag field back and forth
directly. This permits prctl(PR_GET_NETWORK) to return an error code.
6. At the moment, we exempt all local networking which requires action by
both the sender and receiver and which has discretionary access control
comparable to regular Unix filesystem DAC.
In practice, this means that we leave all unix sockets, sysv IPC, and
kill()/killpg() alone.
We intercept ptrace() because it's effect on the receiver is "involuntary"
and we intercept socket_create(), socket_bind(), socket_connect(), and
socket_sendmsg() because they're not otherwise access-controlled.
sendmsg() on previously connected sockets is exempted.
7. The documentation, kconfig option, and access control logic are named
"disablenetwork" because that's the name of the functionality. The fact
that it's exposed through prctl is incidental to its purpose and semantics
and may become less exclusively true in the future, e.g., if we decide
that we want a /proc interface for reading the networking restrictions of
other processes.
Further suggestions?
Regards,
Michael
Michael Stone (3):
Security: Add disablenetwork interface. (v4)
Security: Implement disablenetwork semantics. (v4)
Security: Document disablenetwork. (v4)
Documentation/disablenetwork.txt | 84 ++++++++++++++++++++++++++++++++++++++
include/linux/disablenetwork.h | 22 ++++++++++
include/linux/prctl.h | 7 +++
include/linux/prctl_network.h | 7 +++
include/linux/sched.h | 4 ++
kernel/sys.c | 53 ++++++++++++++++++++++++
security/Kconfig | 11 +++++
security/Makefile | 1 +
security/disablenetwork.c | 73 +++++++++++++++++++++++++++++++++
security/security.c | 76 ++++++++++++++++++++++++++++++++--
10 files changed, 333 insertions(+), 5 deletions(-)
create mode 100644 Documentation/disablenetwork.txt
create mode 100644 include/linux/disablenetwork.h
create mode 100644 include/linux/prctl_network.h
create mode 100644 security/disablenetwork.c
Daniel Bernstein has observed [1] that security-conscious userland processes
may benefit from the ability to irrevocably remove their ability to create,
bind, connect to, or send messages except in the case of previously connected
sockets or AF_UNIX filesystem sockets.
This patch provides
* a new configuration option named CONFIG_SECURITY_DISABLENETWORK,
* a new prctl option-pair (PR_SET_NETWORK, PR_GET_NETWORK),
* a new prctl(PR_SET_NETWORK) flag named PR_NETWORK_OFF, and
* a new task_struct flags field named "network"
Signed-off-by: Michael Stone <[email protected]>
---
include/linux/prctl.h | 7 +++++
include/linux/prctl_network.h | 7 +++++
include/linux/sched.h | 4 +++
kernel/sys.c | 53 +++++++++++++++++++++++++++++++++++++++++
security/Kconfig | 11 ++++++++
5 files changed, 82 insertions(+), 0 deletions(-)
create mode 100644 include/linux/prctl_network.h
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index a3baeb2..4eb4110 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -102,4 +102,11 @@
#define PR_MCE_KILL_GET 34
+/* 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
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/prctl_network.h b/include/linux/prctl_network.h
new file mode 100644
index 0000000..d18f8cb
--- /dev/null
+++ b/include/linux/prctl_network.h
@@ -0,0 +1,7 @@
+#ifndef _LINUX_PRCTL_NETWORK_H
+#define _LINUX_PRCTL_NETWORK_H
+
+extern long prctl_get_network(unsigned long*);
+extern long prctl_set_network(unsigned long*);
+
+#endif /* _LINUX_PRCTL_NETWORK_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f2f842d..6fcaef8 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1403,6 +1403,10 @@ struct task_struct {
#endif
seccomp_t seccomp;
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ unsigned long network;
+#endif
+
/* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
diff --git a/kernel/sys.c b/kernel/sys.c
index 26a6b73..b48f021 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -35,6 +35,7 @@
#include <linux/cpu.h>
#include <linux/ptrace.h>
#include <linux/fs_struct.h>
+#include <linux/prctl_network.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -1578,6 +1579,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
error = PR_MCE_KILL_DEFAULT;
break;
+ case PR_SET_NETWORK:
+ error = prctl_set_network((unsigned long*)arg2);
+ break;
+ case PR_GET_NETWORK:
+ error = prctl_get_network((unsigned long*)arg2);
+ break;
default:
error = -EINVAL;
break;
@@ -1585,6 +1592,52 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
return error;
}
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+
+long prctl_get_network(unsigned long* user)
+{
+ return put_user(current->network, user);
+}
+
+long prctl_set_network(unsigned long* user)
+{
+ unsigned long network_flags;
+ long ret;
+
+ ret = -EFAULT;
+ if (copy_from_user(&network_flags, user, sizeof(network_flags)))
+ goto out;
+
+ ret = -EINVAL;
+ if (network_flags & ~PR_NETWORK_ALL_FLAGS)
+ goto out;
+
+ /* only dropping access is permitted */
+ ret = -EPERM;
+ if (current->network & ~network_flags)
+ goto out;
+
+ current->network = network_flags;
+ ret = 0;
+
+out:
+ return ret;
+}
+
+#else
+
+long prctl_get_network(unsigned long* user)
+{
+ return -ENOSYS;
+}
+
+long prctl_set_network(unsigned long* user)
+{
+ return -ENOSYS;
+}
+
+#endif /* ! CONFIG_SECURITY_DISABLENETWORK */
+
SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
struct getcpu_cache __user *, unused)
{
diff --git a/security/Kconfig b/security/Kconfig
index 226b955..afd7f76 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -137,6 +137,17 @@ config LSM_MMAP_MIN_ADDR
this low address space will need the permission specific to the
systems running LSM.
+config SECURITY_DISABLENETWORK
+ bool "Socket and networking discretionary access control"
+ depends on SECURITY_NETWORK
+ help
+ This enables processes to drop networking privileges via
+ prctl(PR_SET_NETWORK, PR_NETWORK_OFF).
+
+ See Documentation/disablenetwork.txt for more information.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
--
1.6.6.rc2
Implement security_* hooks for socket_create, socket_bind, socket_connect,
socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
process with networking restrictions. Exempt AF_UNIX sockets.
Signed-off-by: Michael Stone <[email protected]>
---
include/linux/disablenetwork.h | 22 +++++++++++
security/Makefile | 1 +
security/disablenetwork.c | 73 ++++++++++++++++++++++++++++++++++++++
security/security.c | 76 +++++++++++++++++++++++++++++++++++++---
4 files changed, 167 insertions(+), 5 deletions(-)
create mode 100644 include/linux/disablenetwork.h
create mode 100644 security/disablenetwork.c
diff --git a/include/linux/disablenetwork.h b/include/linux/disablenetwork.h
new file mode 100644
index 0000000..8a7bcc2
--- /dev/null
+++ b/include/linux/disablenetwork.h
@@ -0,0 +1,22 @@
+#ifndef __LINUX_DISABLENETWORK_H
+#define __LINUX_DISABLENETWORK_H
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+
+int disablenetwork_security_socket_create(int family, int type,
+ int protocol, int kern);
+int disablenetwork_security_socket_bind(struct socket *sock,
+ struct sockaddr *address,
+ int addrlen);
+int disablenetwork_security_socket_connect(struct socket *sock,
+ struct sockaddr *address,
+ int addrlen);
+int disablenetwork_security_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg,
+ int size);
+int disablenetwork_security_ptrace_access_check(struct task_struct *child,
+ unsigned int mode);
+
+#endif /* CONFIG_SECURITY_DISABLENETWORK */
+
+#endif /* ! __LINUX_DISABLENETWORK_H */
diff --git a/security/Makefile b/security/Makefile
index da20a19..2f23b60 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_AUDIT) += lsm_audit.o
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
+obj-$(CONFIG_SECURITY_DISABLENETWORK) += disablenetwork.o
# Object integrity file lists
subdir-$(CONFIG_IMA) += integrity/ima
diff --git a/security/disablenetwork.c b/security/disablenetwork.c
new file mode 100644
index 0000000..f45ddfc
--- /dev/null
+++ b/security/disablenetwork.c
@@ -0,0 +1,73 @@
+/*
+ * disablenetwork security hooks.
+ *
+ * Copyright (C) 2008-2009 Michael Stone <[email protected]>
+ *
+ * Implements the disablenetwork discretionary access control logic underlying
+ * the prctl(PRCTL_SET_NETWORK, PR_NETWORK_OFF) interface.
+ *
+ * See Documentation/disablenetwork.txt for more information.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <net/sock.h>
+#include <linux/socket.h>
+#include <linux/disablenetwork.h>
+
+static inline int maybe_allow(void)
+{
+ if (current->network)
+ return -EPERM;
+ return 0;
+}
+
+int disablenetwork_security_socket_create(int family, int type,
+ int protocol, int kern)
+{
+ if (family == AF_UNIX)
+ return 0;
+ return maybe_allow();
+}
+
+int disablenetwork_security_socket_bind(struct socket * sock,
+ struct sockaddr * address,
+ int addrlen)
+{
+ if (address->sa_family == AF_UNIX)
+ return 0;
+ return maybe_allow();
+}
+
+int disablenetwork_security_socket_connect(struct socket * sock,
+ struct sockaddr * address,
+ int addrlen)
+{
+ if (address->sa_family == AF_UNIX)
+ return 0;
+ return maybe_allow();
+}
+
+int disablenetwork_security_socket_sendmsg(struct socket * sock,
+ struct msghdr * msg, int size)
+{
+ if (sock->sk->sk_family != PF_UNIX &&
+ current->network &&
+ (msg->msg_name != NULL || msg->msg_namelen != 0))
+ return -EPERM;
+ return 0;
+}
+
+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)
+ return -EPERM;
+ return 0;
+}
diff --git a/security/security.c b/security/security.c
index 24e060b..40ac615 100644
--- a/security/security.c
+++ b/security/security.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/security.h>
#include <linux/ima.h>
+#include <linux/disablenetwork.h>
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
@@ -130,7 +131,20 @@ int register_security(struct security_operations *ops)
int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
- return security_ops->ptrace_access_check(child, mode);
+ int ret = 0;
+
+ ret = security_ops->ptrace_access_check(child, mode);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ ret = disablenetwork_security_ptrace_access_check(child, mode);
+ if (ret)
+ goto out;
+#endif
+
+out:
+ return ret;
}
int security_ptrace_traceme(struct task_struct *parent)
@@ -1054,7 +1068,20 @@ EXPORT_SYMBOL(security_unix_may_send);
int security_socket_create(int family, int type, int protocol, int kern)
{
- return security_ops->socket_create(family, type, protocol, kern);
+ int ret = 0;
+
+ ret = security_ops->socket_create(family, type, protocol, kern);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ ret = disablenetwork_security_socket_create(family, type, protocol, kern);
+ if (ret)
+ goto out;
+#endif
+
+out:
+ return ret;
}
int security_socket_post_create(struct socket *sock, int family,
@@ -1066,12 +1093,38 @@ int security_socket_post_create(struct socket *sock, int family,
int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
- return security_ops->socket_bind(sock, address, addrlen);
+ int ret = 0;
+
+ ret = security_ops->socket_bind(sock, address, addrlen);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ ret = disablenetwork_security_socket_bind(sock, address, addrlen);
+ if (ret)
+ goto out;
+#endif
+
+out:
+ return ret;
}
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
- return security_ops->socket_connect(sock, address, addrlen);
+ int ret = 0;
+
+ ret = security_ops->socket_connect(sock, address, addrlen);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ ret = disablenetwork_security_socket_connect(sock, address, addrlen);
+ if (ret)
+ goto out;
+#endif
+
+out:
+ return ret;
}
int security_socket_listen(struct socket *sock, int backlog)
@@ -1086,7 +1139,20 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
{
- return security_ops->socket_sendmsg(sock, msg, size);
+ int ret = 0;
+
+ ret = security_ops->socket_sendmsg(sock, msg, size);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ ret = disablenetwork_security_socket_sendmsg(sock, msg, size);
+ if (ret)
+ goto out;
+#endif
+
+out:
+ return ret;
}
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
--
1.6.6.rc2
Explain the purpose, implementation, and semantics of the disablenetwork
facility.
Also reference some example userland clients.
Signed-off-by: Michael Stone <[email protected]>
---
Documentation/disablenetwork.txt | 84 ++++++++++++++++++++++++++++++++++++++
1 files changed, 84 insertions(+), 0 deletions(-)
create mode 100644 Documentation/disablenetwork.txt
diff --git a/Documentation/disablenetwork.txt b/Documentation/disablenetwork.txt
new file mode 100644
index 0000000..c885502
--- /dev/null
+++ b/Documentation/disablenetwork.txt
@@ -0,0 +1,84 @@
+Disablenetwork Purpose
+----------------------
+
+Daniel Bernstein has observed [1] that security-conscious userland processes
+may benefit from the ability to irrevocably remove their ability to create,
+bind, connect to, or send messages except in the case of previously connected
+sockets or AF_UNIX filesystem sockets.
+
+This facility is particularly attractive to security platforms like OLPC
+Bitfrost [2] and to isolation programs like Rainbow [3] and Plash [4] because:
+
+ * it integrates well with standard techniques for writing privilege-separated
+ Unix programs
+
+ * it integrates well with the need to perform limited socket I/O, e.g., when
+ running X clients
+
+ * it's available to unprivileged programs
+
+ * it's a discretionary feature available to all of distributors,
+ administrators, authors, and users
+
+ * its effect is entirely local, rather than global (like netfilter)
+
+ * it's simple enough to have some hope of being used correctly
+
+
+Implementation
+--------------
+
+The initial userland interface for accessing the disablenetwork functionality
+is provided through the prctl() framework via a new pair of options named
+PR_{GET,SET}_NETWORK and a new flag named PR_NETWORK_OFF.
+
+The PR_{GET,SET}_NETWORK options access and modify a new (conditionally
+compiled) task_struct flags field named "network".
+
+Finally, the pre-existing
+
+ security_socket_create(),
+ security_socket_bind(),
+ security_socket_connect(),
+ security_socket_sendmsg(), and
+ security_ptrace_access_check()
+
+security hooks are modified to call the corresponding disablenetwork_*
+discretionary access control functions. These functions return -EPERM or 0 as
+described below.
+
+Semantics
+---------
+
+current->network is a task_struct flags field which is preserved across all
+variants of fork() and exec().
+
+Writes which attempt to clear bits in current->network return -EPERM.
+
+The default value for current->network is named PR_NETWORK_ON and is defined
+to be 0.
+
+Presently, only one flag is defined: PR_NETWORK_OFF.
+
+More flags may be defined in the future if they become needed.
+
+Attempts to set undefined flags result in -EINVAL.
+
+When PR_NETWORK_OFF is set, the disablenetwork security hooks for socket(),
+bind(), connect(), sendmsg(), and ptrace() will return -EPERM or 0.
+
+Exceptions are made for
+
+ * processes manipulating an AF_UNIX socket or,
+ * processes calling sendmsg() on a previously connected socket
+ (i.e. one with msg.msg_name == NULL && msg.msg_namelen == 0) or
+ * processes calling ptrace() on a target process which shares every
+ networking restriction flag set in current->network.
+
+References
+----------
+
+[1]: http://cr.yp.to/unix/disablenetwork.html
+[2]: http://wiki.laptop.org/go/OLPC_Bitfrost
+[3]: http://wiki.laptop.org/go/Rainbow
+[4]: http://plash.beasts.org/
--
1.6.6.rc2
Michael Stone wrote:
> +int disablenetwork_security_socket_sendmsg(struct socket * sock,
> + struct msghdr * msg, int size)
> +{
> + if (sock->sk->sk_family != PF_UNIX &&
> + current->network &&
> + (msg->msg_name != NULL || msg->msg_namelen != 0))
> + return -EPERM;
> + return 0;
> +}
I think we should accept msg->msg_name != NULL || msg->msg_namelen != 0
if the socket is connection oriented protocols (e.g. TCP).
struct sockaddr_in addr = { ... };
int fd = socket(PF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockadr *) &addr, sizeof(addr));
prctl( ... );
sendmsg(fd, (struct sockadr *) &addr, sizeof(addr));
Tetsuo Handa wrote
> sendmsg(fd, (struct sockadr *) &addr, sizeof(addr));
I meant
sendto(fd, buffer, len, 0, (struct sockadr *) &addr, sizeof(addr));
Michael Stone wrote:
> +Exceptions are made for
> + * processes calling sendmsg() on a previously connected socket
> + (i.e. one with msg.msg_name == NULL && msg.msg_namelen == 0) or
What should we do for non connection oriented protocols (e.g. UDP)
but destination is already configured by previous connect() request?
struct sockaddr_in addr = { ... };
int fd2 = socket(PF_INET, SOCK_DGRAM, 0);
connect(fd2, (struct sockadr *) &addr, sizeof(addr));
prctl( ... );
sendto(fd2, buffer, len, 0, NULL, 0); /* Should we allow this? */
sendto(fd2, buffer, len, 0, (struct sockadr *) &addr, sizeof(addr)); /* Should we reject this? */
Quoting Michael Stone ([email protected]):
> Daniel Bernstein has observed [1] that security-conscious userland processes
> may benefit from the ability to irrevocably remove their ability to create,
> bind, connect to, or send messages except in the case of previously connected
> sockets or AF_UNIX filesystem sockets.
>
> This patch provides
>
> * a new configuration option named CONFIG_SECURITY_DISABLENETWORK,
> * a new prctl option-pair (PR_SET_NETWORK, PR_GET_NETWORK),
> * a new prctl(PR_SET_NETWORK) flag named PR_NETWORK_OFF, and
> * a new task_struct flags field named "network"
>
> Signed-off-by: Michael Stone <[email protected]>
> ---
> include/linux/prctl.h | 7 +++++
> include/linux/prctl_network.h | 7 +++++
> include/linux/sched.h | 4 +++
> kernel/sys.c | 53 +++++++++++++++++++++++++++++++++++++++++
> security/Kconfig | 11 ++++++++
> 5 files changed, 82 insertions(+), 0 deletions(-)
> create mode 100644 include/linux/prctl_network.h
>
> diff --git a/include/linux/prctl.h b/include/linux/prctl.h
> index a3baeb2..4eb4110 100644
> --- a/include/linux/prctl.h
> +++ b/include/linux/prctl.h
> @@ -102,4 +102,11 @@
>
> #define PR_MCE_KILL_GET 34
>
> +/* 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
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/include/linux/prctl_network.h b/include/linux/prctl_network.h
> new file mode 100644
> index 0000000..d18f8cb
> --- /dev/null
> +++ b/include/linux/prctl_network.h
> @@ -0,0 +1,7 @@
> +#ifndef _LINUX_PRCTL_NETWORK_H
> +#define _LINUX_PRCTL_NETWORK_H
> +
> +extern long prctl_get_network(unsigned long*);
> +extern long prctl_set_network(unsigned long*);
> +
> +#endif /* _LINUX_PRCTL_NETWORK_H */
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index f2f842d..6fcaef8 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1403,6 +1403,10 @@ struct task_struct {
> #endif
> seccomp_t seccomp;
>
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + unsigned long network;
> +#endif
> +
> /* Thread group tracking */
> u32 parent_exec_id;
> u32 self_exec_id;
> diff --git a/kernel/sys.c b/kernel/sys.c
> index 26a6b73..b48f021 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -35,6 +35,7 @@
> #include <linux/cpu.h>
> #include <linux/ptrace.h>
> #include <linux/fs_struct.h>
> +#include <linux/prctl_network.h>
>
> #include <linux/compat.h>
> #include <linux/syscalls.h>
> @@ -1578,6 +1579,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> else
> error = PR_MCE_KILL_DEFAULT;
> break;
> + case PR_SET_NETWORK:
> + error = prctl_set_network((unsigned long*)arg2);
> + break;
> + case PR_GET_NETWORK:
> + error = prctl_get_network((unsigned long*)arg2);
> + break;
Is there any reason not to handle these in
disablenetwork_security_prctl()
?
Other than that, this looks quite good to me... (No need to
initialize ret=0 in your security_* updates, to get pedantic,
that's all I noticed)
I'll give it a closer look on monday before I ack.
thanks,
-serge
> index 26a6b73..b48f021 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -35,6 +35,7 @@
> #include <linux/cpu.h>
> #include <linux/ptrace.h>
> #include <linux/fs_struct.h>
> +#include <linux/prctl_network.h>
>
> #include <linux/compat.h>
> #include <linux/syscalls.h>
Something seems to be wrong with whitespace here. Damaged patch?
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Michael Stone wrote:
> Further suggestions?
I expect that the future figure of this "disablenetwork" functionality becomes
"disablesyscall" functionality.
What about defining two types of masks, one is applied throughout the rest of
the task_struct's lifetime (inheritable mask), the other is cleared when
execve() succeeds (local mask)?
When an application is sure that "I know I don't need to call execve()" or
"I know execve()d programs need not to call ...()" or "I want execve()d
programs not to call ...()", the application sets inheritable mask.
When an application is not sure about what syscalls the execve()d programs
will call but is sure that "I know I don't need to call ...()", the application
sets local mask.
When I started TOMOYO project in 2003, I implemented above two types of masks.
I found that the characteristics of task_struct (i.e. duplicated upon fork(),
modified upon execve(), deleted upon exit()) suits well for implementing
discretionary dropping privileges.
Application writers know better what syscalls the application will call than
application users. I think that combination of policy based access control
(which restricts operations from outside applications, like SELinux, Smack,
TOMOYO) and voluntary access control (which restricts operations from inside
applications, like disablenetwork) is a good choice. Above two types of masks
can give application writers chance to drop unneeded privileges (in other
words, chance to disable unneeded syscalls).
On Sun 2009-12-27 17:36:48, Tetsuo Handa wrote:
> Michael Stone wrote:
> > Further suggestions?
>
> I expect that the future figure of this "disablenetwork" functionality becomes
> "disablesyscall" functionality.
>
> What about defining two types of masks, one is applied throughout the rest of
> the task_struct's lifetime (inheritable mask), the other is cleared when
> execve() succeeds (local mask)?
>
> When an application is sure that "I know I don't need to call execve()" or
> "I know execve()d programs need not to call ...()" or "I want execve()d
> programs not to call ...()", the application sets inheritable mask.
> When an application is not sure about what syscalls the execve()d programs
> will call but is sure that "I know I don't need to call ...()", the application
> sets local mask.
Syscalls are very wrong granularity for security system. But easy to
implement, see seccomp.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Sun, Dec 27, 2009 at 05:36:48PM +0900, Tetsuo Handa wrote:
> Application writers know better what syscalls the application will call than
> application users.
Aren't you forgetting about libc? Seriously, any interface along the
lines of "pass a set of syscall numbers to kernel" is DOA:
* syscall numbers are architecture-dependent
* there are socketcall-style multiplexors (sys_ipc, anyone?)
* libc is free to substitute one for another
* libc is free to do so in arch-specific manner
* libc is free to do so in kernel-revision-specific manner
* libc is free to do so in libc-revision-specific manner
(... and does all of the above)
* new syscalls get added
* e.g. on sparc64 32bit task can issue 64bit syscalls
On Sun, 27 Dec 2009 17:36:48 +0900, Tetsuo Handa said:
> What about defining two types of masks, one is applied throughout the rest of
> the task_struct's lifetime (inheritable mask), the other is cleared when
> execve() succeeds (local mask)?
A mask of permitted syscalls. You've re-invented SECCOMP. ;)
> When an application is sure that "I know I don't need to call execve()" or
OK, you *might* know that. Or more likely you just *think* you know that - ever
had a library routine do an execve() call behind your back?). Or glibc
decides to do a clone2() call behind your back instead of execve(),
except on ARM where it does either a clone_nommu47() or clone_backflip() :)
> "I know execve()d programs need not to call ...()"
Unless you've done a code review of the exec'ed program, you don't know.
The big problem is that it's *not* sufficient to just run an strace or two
of normal runs and proclaim "this is the set of syscalls I need" - you need
to check all the error paths in all the shared libraries too. It's no fun
when a program errors out, tries to do a syslog() of the fact - and then
*that* errors out too, causing the program to go into an infinite loop trying
to report the previous syslog() call just failed...
> "I want execve()d programs not to call ...()",
Congrats - you just re-invented the Sendmail capabilities bug. ;)
This stuff is harder than it looks, especially when you realize that
syscall-granularity is almost certainly not the right security model.
> Application writers know better what syscalls the application will call than
> application users.
But the application user will know better than the writer what *actual*
security constraints need to be applied. "I don't care *what* syscalls the
program uses, it's not allowed to access resource XYZ".
Pavel Machek wrote:
> Syscalls are very wrong granularity for security system. But easy to
> implement, see seccomp.
Quoting from http://en.wikipedia.org/wiki/Seccomp
> It allows a process to make a one-way transition into a "secure" state where
> it cannot make any system calls except exit(), read() and write() to
> already-open file descriptors.
I think seccomp() is too much restricted to apply for general applications.
Most applications will need some other syscalls in addition to exit(), read()
and write(). Most applications cannot use seccomp().
What I want to do is similar to seccomp(), but allows userland process to
forbid some syscalls like execve(), mount(), chroot(), link(), unlink(),
socket(), bind(), listen() etc. selectively.
Al Viro wrote:
>> Application writers know better what syscalls the application will call than
>> application users.
>
> Aren't you forgetting about libc? Seriously, any interface along the
> lines of "pass a set of syscall numbers to kernel" is DOA:
We can determine what syscalls we need from application's code and libc's code,
can't we?
Otherwise, I think disablenetwork can't be used. If we simply forbid use of
sendmsg() because application's code doesn't use UDP sockets, DNS requests (UDP
port 53) by libc's code cannot be handled and applications will stop working.
We must know what syscalls we need to allow when we forbid some syscalls.
> * syscall numbers are architecture-dependent
> * there are socketcall-style multiplexors (sys_ipc, anyone?)
> * libc is free to substitute one for another
> * libc is free to do so in arch-specific manner
> * libc is free to do so in kernel-revision-specific manner
> * libc is free to do so in libc-revision-specific manner
> (... and does all of the above)
> * new syscalls get added
> * e.g. on sparc64 32bit task can issue 64bit syscalls
I don't mean to tell the kernel by "syscall numbers".
To be able to handle socketcall-style multiplexors, we will need a hook inside
each syscall functions.
On Sun, Dec 27, 2009 at 08:49:17PM +0900, Tetsuo Handa wrote:
> We can determine what syscalls we need from application's code and libc's code,
> can't we?
_Which_ libc? And no, I'm not talking about other implementations; even
glibc is more than enough. It changes and it *does* change the set of
syscalls used to implement given function.
I'm not disagreeing about what's seccomp worth, BTW.
On Sun, Dec 27, 2009 at 05:36:48PM +0900, Tetsuo Handa wrote:
> Michael Stone wrote:
> > Further suggestions?
>
> I expect that the future figure of this "disablenetwork" functionality becomes
> "disablesyscall" functionality.
That's basically apparmor. I believe it has been re-submitted
recently.
-Andi
--
[email protected] -- Speaking for myself only.
Quoting Tetsuo Handa ([email protected]):
> Pavel Machek wrote:
> > Syscalls are very wrong granularity for security system. But easy to
> > implement, see seccomp.
>
> Quoting from http://en.wikipedia.org/wiki/Seccomp
> > It allows a process to make a one-way transition into a "secure" state where
> > it cannot make any system calls except exit(), read() and write() to
> > already-open file descriptors.
>
> I think seccomp() is too much restricted to apply for general applications.
> Most applications will need some other syscalls in addition to exit(), read()
> and write(). Most applications cannot use seccomp().
>
> What I want to do is similar to seccomp(), but allows userland process to
> forbid some syscalls like execve(), mount(), chroot(), link(), unlink(),
> socket(), bind(), listen() etc. selectively.
The nice thing about the disablenetwork module is that (AFAICS so far)
it actually is safe for an unprivileged user to do. I can't think of
any setuid-root software which, if started with restricted-network by
an unprivileged user, would become unsafe rather than simply failing (*1).
Adding syscalls becomes much scarier.
-serge
*1 - Michael Stone, without looking back over the patches, do you also
restrict opening netlink sockets? Should we worry about preventing
an error message from being sent to the audit daemon?
Serge Hallyn writes:
> Michael Stone, without looking back over the patches, do you also
> restrict opening netlink sockets?
The current version of the patch restricts netlink sockets which were not bound
to an address before calling disablenetwork(). It does so primarily on the
grounds of "fail safe", due to the following sorts of discussions and
observations:
http://kerneltrap.org/mailarchive/linux-kernel/2007/12/7/493793/thread
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-5461
http://marc.info/?l=linux-kernel&m=125448727130301&w=2
I would be willing to entertain an argument that some kind of exemption for
AF_NETLINK ought to be introduced but I'd need to hear some more details before
I could implement it and before I could satisfy myself that the result was
sound.
> Should we worry about preventing an error message from being sent to the
> audit daemon?
I've considered the matter and I don't see much to worry about at this time.
The first reason why I'm not too worried is that anyone in a position to use
disablenetwork for nefarious purposes is also probably able to use ptrace(),
kill(), and/or LD_PRELOAD to similar ends.
The second reason why I'm not too worried is that I believe it to be
straightforward to use the pre-existing MAC frameworks to prevent individually
important processes from dropping networking privileges.
Do you have a specific concern in mind not addressed by either of these
observations?
Regards,
Michael
Tetsuo Handa wrote:
> I expect that the future figure of this "disablenetwork" functionality
> becomes "disablesyscall" functionality.
Thanks for the suggestion, but I'm not interested in pursuing a generic
disablesyscall facility at this time.
Michael
Quoting Michael Stone ([email protected]):
> Serge Hallyn writes:
>
>> Michael Stone, without looking back over the patches, do you also
>> restrict opening netlink sockets?
>
> The current version of the patch restricts netlink sockets which were not bound
> to an address before calling disablenetwork(). It does so primarily on the
> grounds of "fail safe", due to the following sorts of discussions and
> observations:
>
> http://kerneltrap.org/mailarchive/linux-kernel/2007/12/7/493793/thread
> http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-5461
> http://marc.info/?l=linux-kernel&m=125448727130301&w=2
>
> I would be willing to entertain an argument that some kind of exemption for
> AF_NETLINK ought to be introduced but I'd need to hear some more details before
> I could implement it and before I could satisfy myself that the result was
> sound.
>
>> Should we worry about preventing an error message from being sent to the
>> audit daemon?
>
> I've considered the matter and I don't see much to worry about at this
> time.
I don't either, because I don't know of userspace programs other than
/bin/login (and I'm guessing at that) using netlink to send audit messages,
but I could be wrong, and there could be "important software" out there
that does so.
> The first reason why I'm not too worried is that anyone in a position to use
> disablenetwork for nefarious purposes is also probably able to use ptrace(),
> kill(), and/or LD_PRELOAD to similar ends.
How do you mean? I thought that disabling network was a completely
unprivileged operation? And subsequently executing a setuid-root
application won't reset the flag.
> The second reason why I'm not too worried is that I believe it to be
> straightforward to use the pre-existing MAC frameworks to prevent individually
> important processes from dropping networking privileges.
>
> Do you have a specific concern in mind not addressed by either of these
> observations?
Near as I can tell the worst one could do would be to prevent remote
admins from getting useful audit messages, which could give you unlimited
time to keep re-trying the server, on your quest to a brute-force attack
of some sort, i.e. restarting the server with random passwords, and now
no audit msg about the wrong password gets generated, so you're free to
exhaust the space of valid passwords.
Not saying I'm all that worried about it - just something that came to
mind.
-serge
Tetsuo Handa wrote:
> Michael Stone wrote:
>> +Exceptions are made for
>> + * processes calling sendmsg() on a previously connected socket
>> + (i.e. one with msg.msg_name == NULL && msg.msg_namelen == 0) or
>
> What should we do for non connection oriented protocols (e.g. UDP)
> but destination is already configured by previous connect() request?
>
> struct sockaddr_in addr = { ... };
> int fd2 = socket(PF_INET, SOCK_DGRAM, 0);
> connect(fd2, (struct sockadr *) &addr, sizeof(addr));
> prctl( ... );
> sendto(fd2, buffer, len, 0, NULL, 0); /* Should we allow this? */
This call should be allowed. man 2 send states that this call is equivalent to
send(fd2, buffer, len, 0)
and, since the flags field is 0, to
write(fd2, buffer, len)
which are both clearly permitted.
> sendto(fd2, buffer, len, 0, (struct sockadr *) &addr, sizeof(addr)); /* Should we reject this? */
It is reasonable to reject this call because it is not required to be
equivalent to a send() or write() call.
(In fact, the current UDP implementation unconditionally uses the addr argument
passed to sendmsg in favor of the socket addr whenever it exists.)
However, it might also be reasonable to permit the send when the call would be
equivalent to a permitted send() or write() call: for example, when the socket
destination address exists and matches the message destination address.
Unfortunately, I don't think that we have an appropriate generic address
comparison function for deciding this equivalence. Am I mistaken?
Regards, and thanks for your questions,
Michael
P.S. - I would be happy to include a brief explanatory comment in the code
defining this test since this is by far the most complex test in the patch. Any
suggestions on what it might say?
Serge Hallyn writes:
> Michael Stone writes:
>> The first reason why I'm not too worried is that anyone in a position to use
>> disablenetwork for nefarious purposes is also probably able to use ptrace(),
>> kill(), and/or LD_PRELOAD to similar ends.
>
> How do you mean?
I meant that, with the current interface, to set disablenetwork for pid P, you
have either be pid P or to have been one of P's ancestors. In either case, you
have lots of opportunity to mess with P's environment.
> I thought that disabling network was a completely
> unprivileged operation? And subsequently executing a setuid-root
> application won't reset the flag.
Correct and correct for the current patches.
>> The second reason why I'm not too worried is that I believe it to be
>> straightforward to use the pre-existing MAC frameworks to prevent individually
>> important processes from dropping networking privileges.
>>
>> Do you have a specific concern in mind not addressed by either of these
>> observations?
>
> Near as I can tell the worst one could do would be to prevent remote
> admins from getting useful audit messages, which could give you unlimited
> time to keep re-trying the server, on your quest to a brute-force attack
> of some sort, i.e. restarting the server with random passwords, and now
> no audit msg about the wrong password gets generated, so you're free to
> exhaust the space of valid passwords.
>
> Not saying I'm all that worried about it - just something that came to
> mind.
I'll think about it further. Fortunately, there's no need to be hasty. :)
Michael
> >I thought that disabling network was a completely
> >unprivileged operation? And subsequently executing a setuid-root
> >application won't reset the flag.
>
> Correct and correct for the current patches.
Then you are introducing a security problem. User can now mess with
setuid0 binary.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi!
> > I think seccomp() is too much restricted to apply for general applications.
> > Most applications will need some other syscalls in addition to exit(), read()
> > and write(). Most applications cannot use seccomp().
> >
> > What I want to do is similar to seccomp(), but allows userland process to
> > forbid some syscalls like execve(), mount(), chroot(), link(), unlink(),
> > socket(), bind(), listen() etc. selectively.
>
> The nice thing about the disablenetwork module is that (AFAICS so far)
> it actually is safe for an unprivileged user to do. I can't think of
> any setuid-root software which, if started with restricted-network by
> an unprivileged user, would become unsafe rather than simply
> failing.
"I can't see" is not strong enough test, I'd say.
For example, I can easily imagine something like pam falling back to
local authentication when network is unavailable. If you disable
network for su...
It would be also extremely easy to DoS something like sendmail -- if
it forks into background and then serves other users' requests.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Pavel Machek wrote:
> "I can't see" is not strong enough test, I'd say.
>
> For example, I can easily imagine something like pam falling back to
> local authentication when network is unavailable. If you disable
> network for su...
>
> It would be also extremely easy to DoS something like sendmail -- if
> it forks into background and then serves other users' requests.
Pavel,
I spent some time this afternoon reflecting on the scenarios that you sketched
above. This reflection resulted in three concrete responses:
1. Anyone depending on their network for authentication already has to deal
with availability faults. disablenetwork doesn't change anything
fundamental there.
2. Anyone able to use disablenetwork to block a privilege escalation via su
or to influence sendmail will be able to disrupt the privilege escalation
or mail transfer by manipulating the ancestors of su or sendmail in plenty
of other ways including, for example, via ptrace(), kill(), manipulation
of PATH, manipulation of X11 events and IPC, manipulation of TTYs, and so
on.
3. As I pointed out before, disablenetwork _is_ controlled by a build-time
configuration option, its use _is_ still subject to any existing MAC
policy, and it _is_ easy to control for simply by talking to a
known-unrestricted process over an unrestricted IPC channel like a Unix
socket.
and a short meta-response:
As I see it, the whole point of isolation facilities like disablenetwork is
to convert _nasty_ faults like secrecy and integrity faults into _local_
availability faults. Consequently, it is completely unsurprising that we
can't meet stringent availability goals via isolation without either relaxing
our other security goals or falling back to strong assumptions about the
state of our initial environment.
However, we should not therefore ignore the bottom line which is that
the additional isolation enabled by disablenetwork represents an excellent
security risk/reward tradeoff for many people and should be made more widely
available to these people on these grounds.
Regards,
Michael
P.S. - Thanks again for your assistance in thinking through these scenarios and
in refining the security case for the disablenetwork feature.
Hi!
> >"I can't see" is not strong enough test, I'd say.
> >
> >For example, I can easily imagine something like pam falling back to
> >local authentication when network is unavailable. If you disable
> >network for su...
> >
> >It would be also extremely easy to DoS something like sendmail -- if
> >it forks into background and then serves other users' requests.
>
> Pavel,
>
> I spent some time this afternoon reflecting on the scenarios that you sketched
> above. This reflection resulted in three concrete responses:
There's more. You are introducing security holes. Don't.
> 1. Anyone depending on their network for authentication already has to deal
> with availability faults. disablenetwork doesn't change anything
> fundamental there.
Actually it does. Policy may well be "If the network works, noone can
log in locally, because administration is normally done over
network. If the network fails, larger set of people is allowed in,
because something clearly went wrong and we want anyone going around
to fix it."
> 2. Anyone able to use disablenetwork to block a privilege escalation via su
> or to influence sendmail will be able to disrupt the privilege escalation
> or mail transfer by manipulating the ancestors of su or sendmail in plenty
> of other ways including, for example, via ptrace(), kill(), manipulation
> of PATH, manipulation of X11 events and IPC, manipulation of TTYs, and so
> on.
Please learn how setuid works. No, you can't ptrace su. Yes, su has to
deal with poisonous PATH. setuid programs are generally carefully
written to handle _known_ problems. You are adding disablenetwork that
they'll need to handle, and that's bad.
> 3. As I pointed out before, disablenetwork _is_ controlled by a build-time
> configuration option, its use _is_ still subject to any existing MAC
CONFIG_ADD_SECURITY_HOLE is still bad idea.
You should either:
a) make disablenetwork reset to "enablenetwork" during setuid exec
or
b) disallow setuid execs for tasks that have network disabled.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Mon, 28 Dec 2009 11:10:06 +0100, Pavel Machek said:
> a) make disablenetwork reset to "enablenetwork" during setuid exec
That won't work either. If you only make it 'setuid==0' binaries, you still
break 'setuid-FOO' binaries that require the net. If you just check the setuid
bit, it allows a trivial escape by creating a setuid-yourself binary and using
that to exec something else (now with network access, because we apparently
don't have a way to remember the previous setting).
> b) disallow setuid execs for tasks that have network disabled.
This is probably safer...
> Pavel,
>
> I spent some time this afternoon reflecting on the scenarios that you sketched
> above. This reflection resulted in three concrete responses:
> There's more. You are introducing security holes. Don't.
My users care about things like stopping compromised processes from leaking
their documents or sending spam; they do not use the network in the ways you
seem to be concerned about.
> 1. Anyone depending on their network for authentication already has to deal
> with availability faults. disablenetwork doesn't change anything
> fundamental there.
> Actually it does. Policy may well be "If the network works, noone can
> log in locally, because administration is normally done over
> network. If the network fails, larger set of people is allowed in,
> because something clearly went wrong and we want anyone going around
> to fix it."
Have you actually seen this security policy in real life? I ask because it
seems quite far-fetched to me. Networks are just too easy to attack. Seems to
me, from this casual description, that you're just asking to be ARP- or
DNS-poisoned and rooted with this one.
> 2. Anyone able to use disablenetwork to block a privilege escalation via su
> or to influence sendmail will be able to disrupt the privilege escalation
> or mail transfer by manipulating the ancestors of su or sendmail in plenty
> of other ways including, for example, via ptrace(), kill(), manipulation
> of PATH, manipulation of X11 events and IPC, manipulation of TTYs, and so
> on.
> Please learn how setuid works.
I am quite familiar with how setuid works. I was suggesting a number of ways to
modify the behavior of su's *ancestors*; not su. (I apoligize that my writing
was not more clear on this point.)
In retrospect, substituting "abort()" for "disablenetwork()" better explains my
point. Who can call disablenetwork() to cause a problem who can't just as well
have called abort() or kill(0, SIGSTOP) at the same time?
Still, I take your point that there may be people out there who have written
configurations for setuid executables under the belief that their networks are
reliable and available in the presence of attackers.
>> 3. As I pointed out before, disablenetwork _is_ controlled by a build-time
>> configuration option, its use _is_ still subject to any existing MAC
>
> CONFIG_ADD_SECURITY_HOLE is still bad idea.
Perhaps for your users. For me and for the users of my software, having
CONFIGURE_SECURITY_DISABLENETWORK is far better than not having it because it
permits us to close many other far more significant holes.
> You should either:
> a) make disablenetwork reset to "enablenetwork" during setuid exec
> b) disallow setuid execs for tasks that have network disabled.
Neither of these work. The first is incorrect because a disablenetwork'ed
process could transmit anything it wants through ping. The second is one that I
feel is unsafe because I don't feel that I can predict its consequences.
However, there's a third option that I think might work. What do you think of
treating being network-disabled the same way we treat RLIMIT_NOFILE? That is,
what about:
c) permit capable processes (such as euid 0) to remove networking restrictions
by further calls to prctl(PR_SET_NETWORK)?
Regards,
Michael
Quoting Pavel Machek ([email protected]):
> Hi!
>
> > > I think seccomp() is too much restricted to apply for general applications.
> > > Most applications will need some other syscalls in addition to exit(), read()
> > > and write(). Most applications cannot use seccomp().
> > >
> > > What I want to do is similar to seccomp(), but allows userland process to
> > > forbid some syscalls like execve(), mount(), chroot(), link(), unlink(),
> > > socket(), bind(), listen() etc. selectively.
> >
> > The nice thing about the disablenetwork module is that (AFAICS so far)
> > it actually is safe for an unprivileged user to do. I can't think of
> > any setuid-root software which, if started with restricted-network by
> > an unprivileged user, would become unsafe rather than simply
> > failing.
>
> "I can't see" is not strong enough test, I'd say.
>
> For example, I can easily imagine something like pam falling back to
> local authentication when network is unavailable. If you disable
> network for su...
>
> It would be also extremely easy to DoS something like sendmail -- if
> it forks into background and then serves other users' requests.
But you can just as easily unplug the network cable (or flip the
wireless switch). So in the case of authentication, either your
nsswitch.conf says to fall back to files, or it doesn't - in either
case it's what you expected...
Michael, a few possibilities have been brought up. To toss in
one more, what about making a separate capability CAP_NETWORK_REENABLE,
and requiring that in order to reset prctl(PR_SET_NETWORK) or
whatever? Then if you don't want to allow that, you can drop
CAP_NETWORK_REENABLE from your bounding set, and you'll never
be able to reset it.
It's not just a silly extra step - dropping CAP_NETWORK_REENABLE
from your bounding set requires privilege, so now we are at
least saying that it takes privilege to allow a less-privileged
process to stop a more-privileged process from regaining network
requires privilege later.
That specific example isn't good - the problem is, someone has to sit
there knowing to do the prctl(PR_SET_NETWORK). It doesn't do anything
to prevent the nefarious unprivileged user from doing
prctl(PR_DROP_NETWORK) and then running a setuid-root daemon, and if the
daemon doesn't know about PR_SET_NETWORK then it still will run without
priv.
So I prefer a similar but slightly different construct - the key
being requiring privilege to be able to say "it's ok to deny privileged
software network". We can either
1. introduce a sysctl which says whether or not setuid-root
re-enables network by default,
or
2. add an extra bit to your per-task network data, which
again says "for root we re-enable network" or not.
or heck
3. make it a boot flag.
In any case, the idea would be that on your bitfrost systems init, or
some early privileged process, would say "for me and all my children,
if an unprivileged process does PR_DROP_NETWORK then that holds even
for setuid-root programs.
-serge
Quoting Serge E. Hallyn ([email protected]):
> Quoting Michael Stone ([email protected]):
> > Daniel Bernstein has observed [1] that security-conscious userland processes
> > may benefit from the ability to irrevocably remove their ability to create,
> > bind, connect to, or send messages except in the case of previously connected
> > sockets or AF_UNIX filesystem sockets.
> >
> > This patch provides
> >
> > * a new configuration option named CONFIG_SECURITY_DISABLENETWORK,
> > * a new prctl option-pair (PR_SET_NETWORK, PR_GET_NETWORK),
> > * a new prctl(PR_SET_NETWORK) flag named PR_NETWORK_OFF, and
> > * a new task_struct flags field named "network"
> >
> > Signed-off-by: Michael Stone <[email protected]>
> > ---
> > include/linux/prctl.h | 7 +++++
> > include/linux/prctl_network.h | 7 +++++
> > include/linux/sched.h | 4 +++
> > kernel/sys.c | 53 +++++++++++++++++++++++++++++++++++++++++
> > security/Kconfig | 11 ++++++++
> > 5 files changed, 82 insertions(+), 0 deletions(-)
> > create mode 100644 include/linux/prctl_network.h
> >
> > diff --git a/include/linux/prctl.h b/include/linux/prctl.h
> > index a3baeb2..4eb4110 100644
> > --- a/include/linux/prctl.h
> > +++ b/include/linux/prctl.h
> > @@ -102,4 +102,11 @@
> >
> > #define PR_MCE_KILL_GET 34
> >
> > +/* 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
> > +
> > #endif /* _LINUX_PRCTL_H */
> > diff --git a/include/linux/prctl_network.h b/include/linux/prctl_network.h
> > new file mode 100644
> > index 0000000..d18f8cb
> > --- /dev/null
> > +++ b/include/linux/prctl_network.h
> > @@ -0,0 +1,7 @@
> > +#ifndef _LINUX_PRCTL_NETWORK_H
> > +#define _LINUX_PRCTL_NETWORK_H
> > +
> > +extern long prctl_get_network(unsigned long*);
> > +extern long prctl_set_network(unsigned long*);
> > +
> > +#endif /* _LINUX_PRCTL_NETWORK_H */
> > diff --git a/include/linux/sched.h b/include/linux/sched.h
> > index f2f842d..6fcaef8 100644
> > --- a/include/linux/sched.h
> > +++ b/include/linux/sched.h
> > @@ -1403,6 +1403,10 @@ struct task_struct {
> > #endif
> > seccomp_t seccomp;
> >
> > +#ifdef CONFIG_SECURITY_DISABLENETWORK
> > + unsigned long network;
> > +#endif
> > +
> > /* Thread group tracking */
> > u32 parent_exec_id;
> > u32 self_exec_id;
> > diff --git a/kernel/sys.c b/kernel/sys.c
> > index 26a6b73..b48f021 100644
> > --- a/kernel/sys.c
> > +++ b/kernel/sys.c
> > @@ -35,6 +35,7 @@
> > #include <linux/cpu.h>
> > #include <linux/ptrace.h>
> > #include <linux/fs_struct.h>
> > +#include <linux/prctl_network.h>
> >
> > #include <linux/compat.h>
> > #include <linux/syscalls.h>
> > @@ -1578,6 +1579,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> > else
> > error = PR_MCE_KILL_DEFAULT;
> > break;
> > + case PR_SET_NETWORK:
> > + error = prctl_set_network((unsigned long*)arg2);
> > + break;
> > + case PR_GET_NETWORK:
> > + error = prctl_get_network((unsigned long*)arg2);
> > + break;
>
> Is there any reason not to handle these in
> disablenetwork_security_prctl()
> ?
>
> Other than that, this looks quite good to me... (No need to
> initialize ret=0 in your security_* updates, to get pedantic,
> that's all I noticed)
>
> I'll give it a closer look on monday before I ack.
But I'm going to wait to see a response (or new patch) about moving
this code to disablenetwork_security_prctl().
thanks,
-serge
On Mon 2009-12-28 09:37:24, [email protected] wrote:
> On Mon, 28 Dec 2009 11:10:06 +0100, Pavel Machek said:
>
> > a) make disablenetwork reset to "enablenetwork" during setuid exec
>
> That won't work either. If you only make it 'setuid==0' binaries, you still
> break 'setuid-FOO' binaries that require the net. If you just check the setuid
> bit, it allows a trivial escape by creating a setuid-yourself binary and using
> that to exec something else (now with network access, because we apparently
> don't have a way to remember the previous setting).
it is really only required for binaries setuid to someone else, but
that would be too ugly. (Plus, as someone said, ping is great for
leaking data out.)
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
>> 1. Anyone depending on their network for authentication already has to deal
>> with availability faults. disablenetwork doesn't change anything
>> fundamental there.
>
>> Actually it does. Policy may well be "If the network works, noone can
>> log in locally, because administration is normally done over
>> network. If the network fails, larger set of people is allowed in,
>> because something clearly went wrong and we want anyone going around
>> to fix it."
>
> Have you actually seen this security policy in real life? I ask because it
> seems quite far-fetched to me. Networks are just too easy to attack. Seems to
> me, from this casual description, that you're just asking to be ARP- or
> DNS-poisoned and rooted with this one.
It is little far-fetched; but it would make sense on 'secure' network,
where you can't do arp attacks. You can bet that someone out there
does it.
>> Please learn how setuid works.
>
> I am quite familiar with how setuid works. I was suggesting a number of ways to
> modify the behavior of su's *ancestors*; not su. (I apoligize that my writing
> was not more clear on this point.)
>
> In retrospect, substituting "abort()" for "disablenetwork()" better explains my
> point. Who can call disablenetwork() to cause a problem who can't just as well
> have called abort() or kill(0, SIGSTOP) at the same time?
You can't sigstop sendmail, right?
> Still, I take your point that there may be people out there who have written
> configurations for setuid executables under the belief that their networks are
> reliable and available in the presence of attackers.
Good.
>> You should either:
>
>> a) make disablenetwork reset to "enablenetwork" during setuid exec
>> b) disallow setuid execs for tasks that have network disabled.
>
> Neither of these work. The first is incorrect because a disablenetwork'ed
> process could transmit anything it wants through ping. The second is one that I
> feel is unsafe because I don't feel that I can predict its
>consequences.
Ok, you could just remove ping from your systems, but I see, b) is
better solution.
Why do you think it is unsafe? Its clearly secure, at least from 'user
can't attack other users on shared machine'...
It may cause some failures, but given how rare setuid stuff is these
days, I doubt it.
> However, there's a third option that I think might work. What do you think of
> treating being network-disabled the same way we treat RLIMIT_NOFILE? That is,
> what about:
>
> c) permit capable processes (such as euid 0) to remove networking restrictions
> by further calls to prctl(PR_SET_NETWORK)?
I'm afraid that does not help... you'd have to audit/modify existing
setuid programs to keep system secure. No-no.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Mon, 28 Dec 2009 11:31:09 EST, Michael Stone said:
> > Actually it does. Policy may well be "If the network works, noone can
> > log in locally, because administration is normally done over
> > network. If the network fails, larger set of people is allowed in,
> > because something clearly went wrong and we want anyone going around
> > to fix it."
>
> Have you actually seen this security policy in real life? I ask because it
> seems quite far-fetched to me. Networks are just too easy to attack. Seems to
> me, from this casual description, that you're just asking to be ARP- or
> DNS-poisoned and rooted with this one.
Actually, I've seen a *lot* of similar "if things fail, more people can login
to fix it" policies. For instance, a default Fedora box will require a root
password to login - but if you can't get to multi-user because the box is
scrozzled and boot into single user, no root password is required.
So if you're using Fedora and LDAP authentication, and reboot to single-user
to fix an LDAP issue, you do in fact have that policy in real life...
(And before you start shouting "but that's a stupid config to make root login
depend on LDAP", note that for many Microsoft Active Directory shops, they add
machines with Administrator rights for an Active Directory group, and then
disable local Administrator, which is exactly the same thing... Stupid or
not, it's a *very* common policy.)
On Mon, 28 Dec 2009 21:55:11 +0100, Pavel Machek said:
> it is really only required for binaries setuid to someone else, but
> that would be too ugly. (Plus, as someone said, ping is great for
> leaking data out.)
Hmm... How is it "too ugly"? It's just a 'euid != uid' comparison? Or
am I missing some contortion required?
On Mon, Dec 28, 2009 at 3:55 PM, Pavel Machek <[email protected]> wrote:
> On Mon 2009-12-28 09:37:24, [email protected] wrote:
>> On Mon, 28 Dec 2009 11:10:06 +0100, Pavel Machek said:
>>
>> > a) make disablenetwork reset to "enablenetwork" during setuid exec
>>
>> That won't work either. ?If you only make it 'setuid==0' binaries, you still
>> break 'setuid-FOO' binaries that require the net. If you just check the setuid
>> bit, it allows a trivial escape by creating a setuid-yourself binary and using
>> that to exec something else (now with network access, because we apparently
>> don't have a way to remember the previous setting).
>
>
> it is really only required for binaries setuid to someone else, but
> that would be too ugly. (Plus, as someone said, ping is great for
> leaking data out.)
No, this is not sufficient; one needs only to find a setuid process
that can be convinced to run a program with the original (pre-suid)
privileges. For example, one could invoke gpg (older versions setuid
so it can lock memory, executes user code for the passphrase input
agent) or pulseaudio (in some cases setuid to go realtime, loads user
plugins) or screen (setuid for sharing sessions, obviously executes
user programs) or at/cron (did you remember to deny access to these?)
...
Or one can target a non-root setuid program that may have security
holes - how about nethack?
While in modern distros these uses of setuid may be rare, they can
exist, and under the old security model they were safe. Not so
anymore. As such, re-enabling network access upon executing a setuid
program is not acceptable.
That said, I do feel this is a separate issue. The process should
first drop its ability to suid; then it can freely apply additional
restrictions without there being any risk of breaking setuid
applications.
In short, how does this sound:
* Add an API to allow processes to permanently revoke their own
ability to gain privileges from setuid-exec
* Add this disablenetwork facility, conditional on dropping
setuid-exec abilities
This also paves the way for:
* Allow processes that have dropped said suid ability to freely create
new namespaces (and chroot)
Which, combined with doing whatever audits are necessary to allow
cross-network-namespace uses of unix domain sockets, actually
eliminates the need for the disablenetwork API. :)
Pavel writes:
> Policy may well be "If the network works, noone can
> log in locally, because administration is normally done over
> network. If the network fails, larger set of people is allowed in,
> because something clearly went wrong and we want anyone going around
> to fix it."
Michael Stone writes:
> Have you actually seen this security policy in real life?
Pavel responds:
> Actually, I've seen a *lot* of similar [..] policies.
OK, so to translate: it sounds like the answer is No, you
haven't seen this policy in real life.
More to the point, the real question is whether this policy
is embedded in code anywhere such that Michael's mechanism would
introduce a new security hole, and if so, whether the cost of
that would outweigh the benefit of his mechanism. I think the
answer is, No, no one even has a plausible story for how this
policy might appear in some legacy executable that would then
be newly subvertible due to Michael Stone's policy. First off,
this sounds like a pretty wacko policy. Second, it's unlikely
to be embedded in a setuid-root executable that anyone can
execute. Third, if there were such a setuid-root executable
(which I've already argued is in fantasy land, but let's suppose
pigs could fly and such a thing existed in practice), there are
other ways to attack it: such as by using up all available
file descriptors and then forking and execing that executable.
Fourth, even if it existed, it would be a very rare one-off
site-specific thing. But most importantly, we're way off the
rails onto speculation. Of course you can always imagine some
conceivable scenario under which any new mechanism might have
unwanted side effects -- that's just the nature of any complex
system -- but I don't see any reasonable argument at all that
Michael's mechanism will cause more harm than good.
Bottom lien: I agree with Michael Stone. I think this
objection is weak.
I think what Michael is trying to do has the potential to be very
valuable and should be supported, and this is not a convincing
argument against it.
On Mon, 28 Dec 2009 22:10:28 GMT, David Wagner said:
> Pavel responds:
> > Actually, I've seen a *lot* of similar [..] policies.
No, that was me, not Pavel.
> OK, so to translate: it sounds like the answer is No, you
> haven't seen this policy in real life.
As I point out in subsequent paragraphs, I *have* in fact seen systems that
implement essentially the same semantics.
> More to the point, the real question is whether this policy
> is embedded in code anywhere such that Michael's mechanism would
> introduce a new security hole, and if so, whether the cost of
> that would outweigh the benefit of his mechanism.
Granted - but "is it embedded in code anywhere" is different from "does
anybody use such a policy". The semantic is used by many shops, but isn't
embedded in code anywhere that I know of - it's always done via system
config.
Take a standard stock Fedora install. Configure it to use LDAP for user
authentication. Screw up the config with a typo. Reboot to single user to fix,
you get a # prompt without entering a password. You now have Pavel's policy:
> "If the network works, noone can
> log in locally, because administration is normally done over
> network. If the network fails, larger set of people is allowed in,
> because something clearly went wrong and we want anyone going around
> to fix it."
So yes, it *does* exist in the real world - unless there are *zero* Fedora
boxes that use LDAP, and haven't manually changed the init config to run
sulogin on a single-user boot.
> I think what Michael is trying to do has the potential to be very
> valuable and should be supported, and this is not a convincing
> argument against it.
In case you didn't notice, I've been on the "this looks sane if we can actually
do it correctly" side of the fence. Michael's code isn't something I'd
personally run, because it doesn't address the threat models I worry about -
but I see the value for those people who do worry about them.
And hey, maybe we'll get lucky and we'll get the ability to have a stacker
that does MAC LSM + targeted add-ons, because in my world, the easiest fix
is the distributed SELinux 'mls' policy plus an add-on LSM - even though it's
likely that most of the stuff I want *could* be done via SELinux policy, in
many cases 20 lines of C is easier than retrofitting a policy patch or getting
the policy patch pushed upstream...
Out of curiosity, any of the other security types here ever included "getting
the damned semi-clued auditor who insists on cargo-cult checklists out of your
office" as part of your threat model? Only a half-smiley on this one...
> Granted - but "is it embedded in code anywhere" is different from "does
> anybody use such a policy".
OK, that's fine. But "is it embedded in code anywhere" is the
question that matters to this thread. And not just in code "anywhere",
but in code in a setuid-root executable that would become vulnerable if
Michael's scheme is introduced (yet is not already vulnerable today).
To refresh: the original context was that Pavel objected to Michael's
disablenetwork scheme on the basis that it could introduce new security
vulnerabilities, if some setuid-root program somewhere is written to
enforce a specific policy. So, to my way of thinking, the only reason to
spend any energy on this question at all is to determine whether Pavel's
objection is persuasive. I'm arguing the objection is not persuasive.
And I'm suggesting that we focus on the question that matters, rather
than getting distracted by imprecise phrasing Michael may have used when
he asked the question.
(Sorry for the misattribution, by the way; I attempted to clean up
the quoting and made it worse! Sorry.)
> Out of curiosity, any of the other security types here ever included "getting
> the damned semi-clued auditor who insists on cargo-cult checklists out of your
> office" as part of your threat model? Only a half-smiley on this one...
Sure. :-) One big catch-phrase that covers a lot of this ground is
'compliance'. Recently there seems to be considerable discussion
among security professionals about the tension between 'compliance' and
'security', and whether increased attention to 'compliance' benefits
'security' or is in the end a distraction.
Serge Hallyn wrote:
> Is there any reason not to handle these in
> disablenetwork_security_prctl()
> ?
I'm afraid that I don't understand what you're asking here. Are you just saying
that you'd like me to rename the functions that implement the interface logic
to something that begins with "disablenetwork_"?
Regards, and thanks for all your help,
Michael
Pavel Machek wrote:
>> index 26a6b73..b48f021 100644
>> --- a/kernel/sys.c
>> +++ b/kernel/sys.c
>> @@ -35,6 +35,7 @@
>> #include <linux/cpu.h>
>> #include <linux/ptrace.h>
>> #include <linux/fs_struct.h>
>> +#include <linux/prctl_network.h>
>>
>> #include <linux/compat.h>
>> #include <linux/syscalls.h>
>
> Something seems to be wrong with whitespace here. Damaged patch?
Nope; kernel/sys.c has a newline there:
http://repo.or.cz/w/linux-2.6.git/blob/HEAD:/kernel/sys.c#l36
Shall I remove it?
Michael
On Tue, 29 Dec 2009 00:42:55 GMT, David Wagner said:
> Sure. :-) One big catch-phrase that covers a lot of this ground is
> 'compliance'. Recently there seems to be considerable discussion
> among security professionals about the tension between 'compliance' and
> 'security', and whether increased attention to 'compliance' benefits
> 'security' or is in the end a distraction.
There's what I can administer effectively, there's what the most junior admin
in my shop can administer effectively, what the DBA's will accept, and what
our auditors insist on. Every once in a while, all four actually line up,
but then my alarm clock goes off and it's another Monday in the office :)
Serge,
I think that Pavel's point, at its strongest and most general, could be
rephrased as:
"Adding *any* interesting isolation facility to the kernel breaks backwards
compatibility for *some* program [in a way that violates security goals]."
The reason is the one that I identified in my previous note:
"The purpose of isolation facilities is to create membranes inside which
grievous security faults are converted into availability faults."
The question then is simply:
"How do we want to deal with the compatibility-breaking changes created by
introducing new isolation facilities?"
So far, I've seen the following suggestions:
a) setuid restores pre-isolation semantics
- Doesn't work for me because it violates the security guarantee of the
isolation primitive
b) setuid is an escape-hatch
- Probably the cleanest in the long-run
- Doesn't, by itself, suffice for Pavel since it violates backwards
compatibility
c) signal to the kernel through a privileged mechanism that
backwards-incompatible isolation may or may not be used
- No problems seen so far.
I would be happy with (c), assuming we can agree on an appropriate signalling
mechanism and default.
So far, two defaults have been proposed:
default-deny incompatible isolation (Pavel)
default-permit incompatible isolation (Michael)
So far, several signalling mechanisms have been proposed:
1) enabling a kernel config option implies default-permit
- My favorite; apparently insufficient for Pavel?
2) default-deny; disablesuid grants disablenetwork
- "disablesuid" is my name for the idea of dropping the privilege of
exec'ing setuid binaries
- Suggested by Pavel and supported by several others.
- I think it has the same backwards-compatibility problem as
disablenetwork: disablesuid is an isolation primitive.
3) default-deny; dropping a capability from the bounding set grants "permit"
- Suggested by Serge; seems nicely fine-grained but rather indirect
4) default-deny; setting a sysctl implies permit
- Suggested by Serge; works fine for me
5) default-deny; setting a kernel boot argument implies permit
- Suggested by Serge; I like the sysctl better.
I am happiest with (1) and, if (1) isn't good enough, with (4).
Pavel, what do you think of (4)?
Regards,
Michael
P.S. - I'd be happy to know more about existing precedent on introducing
compatibility-breaking changes if any comes to mind. (For example, how were the
Linux-specific rlimits handled?)
P.P.S. - On a completely unrelated note: imagine trying to use SELinux (or your
favorite MAC framework) to restrict the use of prctl(PR_SET_NETWORK,
PR_NETWORK_OFF). Am I right that sys_prctl() contains a
time-of-check-to-time-of-use (TOCTTOU) race (with security_task_prctl() as the
check and with prctl_set_network() as the use) as a result of the actual
argument being passed by address rather than by value?
Quoting Michael Stone ([email protected]):
> Serge Hallyn wrote:
> >Is there any reason not to handle these in
> > disablenetwork_security_prctl()
> >?
>
> I'm afraid that I don't understand what you're asking here. Are you just saying
> that you'd like me to rename the functions that implement the interface logic
> to something that begins with "disablenetwork_"?
Sorry, for some reason I was thinking you still had a
security_operations *disablenetwork_ops. But you don't, so
my comment is silly. Please ignore.
> Regards, and thanks for all your help,
My pleasure, and thanks for the patience.
-serge
Quoting Michael Stone ([email protected]):
> Serge,
>
> I think that Pavel's point, at its strongest and most general, could be
> rephrased as:
>
> "Adding *any* interesting isolation facility to the kernel breaks backwards
> compatibility for *some* program [in a way that violates security goals]."
>
> The reason is the one that I identified in my previous note:
>
> "The purpose of isolation facilities is to create membranes inside which
> grievous security faults are converted into availability faults."
>
> The question then is simply:
>
> "How do we want to deal with the compatibility-breaking changes created by
> introducing new isolation facilities?"
>
> So far, I've seen the following suggestions:
>
> a) setuid restores pre-isolation semantics
>
> - Doesn't work for me because it violates the security guarantee of the
> isolation primitive
>
> b) setuid is an escape-hatch
>
> - Probably the cleanest in the long-run
>
> - Doesn't, by itself, suffice for Pavel since it violates backwards
> compatibility
>
> c) signal to the kernel through a privileged mechanism that
> backwards-incompatible isolation may or may not be used
>
> - No problems seen so far.
>
> I would be happy with (c), assuming we can agree on an appropriate signalling
> mechanism and default.
>
> So far, two defaults have been proposed:
>
> default-deny incompatible isolation (Pavel)
> default-permit incompatible isolation (Michael)
>
> So far, several signalling mechanisms have been proposed:
>
> 1) enabling a kernel config option implies default-permit
>
> - My favorite; apparently insufficient for Pavel?
default under what conditions? any setuid? setuid-root?
> 2) default-deny; disablesuid grants disablenetwork
>
> - "disablesuid" is my name for the idea of dropping the privilege of
> exec'ing setuid binaries
>
> - Suggested by Pavel and supported by several others.
>
> - I think it has the same backwards-compatibility problem as
> disablenetwork: disablesuid is an isolation primitive.
>
> 3) default-deny; dropping a capability from the bounding set grants "permit"
>
> - Suggested by Serge; seems nicely fine-grained but rather indirect
Actually I think it's the opposite of what you said here: so long as the
capability is in pE, you can regain network. So it would require a privileged
process early on (like init or login) to remove the capability from the
bounding set (bc doing so requires CAP_SETPCAP), but once that was done,
the resulting process and it's children could not require the capability,
and, without the capability, could not regain network. Point being that
privileged userspace had to actively allow userspace to trap a setuid root
binary without networking.
I think during exec we can simply check for this capability in pE, and
if present then re-enable network if turned off. Then setuid-root binaries
will raise that bit (if it's in the bounding set) automatically. Now,
that means setuid-nonroot binaries will not reset network. Though you
could make that happen by doing setcap cap_net_allownet+pe /the/file.
Does that suffice?
> 4) default-deny; setting a sysctl implies permit
>
> - Suggested by Serge; works fine for me
That still leaves the question of when we re-allow network. Any
setuid?
> 5) default-deny; setting a kernel boot argument implies permit
>
> - Suggested by Serge; I like the sysctl better.
>
> I am happiest with (1) and, if (1) isn't good enough, with (4).
>
> Pavel, what do you think of (4)?
>
> Regards,
>
> Michael
>
> P.S. - I'd be happy to know more about existing precedent on introducing
> compatibility-breaking changes if any comes to mind. (For example, how were the
> Linux-specific rlimits handled?)
>
> P.P.S. - On a completely unrelated note: imagine trying to use SELinux (or your
> favorite MAC framework) to restrict the use of prctl(PR_SET_NETWORK,
> PR_NETWORK_OFF). Am I right that sys_prctl() contains a
> time-of-check-to-time-of-use (TOCTTOU) race (with security_task_prctl() as the
> check and with prctl_set_network() as the use) as a result of the actual
> argument being passed by address rather than by value?
I'm probably misunderstanding your question, but just in case I'm not: the
answer is that you wouldn't use the prctl interface anyway. You would strictly
use domain transitions. Instead of doing prctl(PR_SET_NETWORK, PR_NETWORK_OFF)
you would move yourself from the user_u:user_r:network_allowed domain to the
user_u:user_r:network_disallowed domain.
-serge
Quoting Bryan Donlan ([email protected]):
> On Mon, Dec 28, 2009 at 3:55 PM, Pavel Machek <[email protected]> wrote:
> > On Mon 2009-12-28 09:37:24, [email protected] wrote:
> >> On Mon, 28 Dec 2009 11:10:06 +0100, Pavel Machek said:
> >>
> >> > a) make disablenetwork reset to "enablenetwork" during setuid exec
> >>
> >> That won't work either. ?If you only make it 'setuid==0' binaries, you still
> >> break 'setuid-FOO' binaries that require the net. If you just check the setuid
> >> bit, it allows a trivial escape by creating a setuid-yourself binary and using
> >> that to exec something else (now with network access, because we apparently
> >> don't have a way to remember the previous setting).
> >
> >
> > it is really only required for binaries setuid to someone else, but
> > that would be too ugly. (Plus, as someone said, ping is great for
> > leaking data out.)
>
> No, this is not sufficient; one needs only to find a setuid process
> that can be convinced to run a program with the original (pre-suid)
> privileges. For example, one could invoke gpg (older versions setuid
> so it can lock memory, executes user code for the passphrase input
> agent) or pulseaudio (in some cases setuid to go realtime, loads user
> plugins) or screen (setuid for sharing sessions, obviously executes
> user programs) or at/cron (did you remember to deny access to these?)
> ...
>
> Or one can target a non-root setuid program that may have security
> holes - how about nethack?
>
> While in modern distros these uses of setuid may be rare, they can
> exist, and under the old security model they were safe. Not so
> anymore. As such, re-enabling network access upon executing a setuid
> program is not acceptable.
>
> That said, I do feel this is a separate issue. The process should
> first drop its ability to suid; then it can freely apply additional
> restrictions without there being any risk of breaking setuid
> applications.
>
> In short, how does this sound:
> * Add an API to allow processes to permanently revoke their own
> ability to gain privileges from setuid-exec
Well, this is possible now, but requires privilege: Remove
any bit not in pP from the bounding set.
Removing the requirement for privilege to do so has some conerns. Do we
force a task to then run with absolutely no capabilities, or can it just
stop itself from gaining new ones? If the latter, then we are close to
re-raising the sendmail-capabilities bug. The main difference would be
that you must already have the capbilities you want to keep, but I'm
not convinced that's sufficient.
A function which can be called without privilege, which empties out
all capability sets and the bounding set, that may be safe. Still might
cause a setuid-root app which is running as root but with no privilege
to be confused and mess up the system...
> * Add this disablenetwork facility, conditional on dropping
> setuid-exec abilities
>
> This also paves the way for:
> * Allow processes that have dropped said suid ability to freely create
> new namespaces (and chroot)
>
> Which, combined with doing whatever audits are necessary to allow
> cross-network-namespace uses of unix domain sockets, actually
> eliminates the need for the disablenetwork API. :)
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Michael Stone <[email protected]> writes:
> Serge,
>
> I think that Pavel's point, at its strongest and most general, could be
> rephrased as:
>
> "Adding *any* interesting isolation facility to the kernel breaks backwards
> compatibility for *some* program [in a way that violates security goals]."
*some* privileged program.
> The reason is the one that I identified in my previous note:
>
> "The purpose of isolation facilities is to create membranes inside which
> grievous security faults are converted into availability faults."
>
> The question then is simply:
>
> "How do we want to deal with the compatibility-breaking changes created by
> introducing new isolation facilities?"
You have a very peculiar taxonomy of the suggestions,
that fails to capture the concerns.
I strongly recommend working out a way to disable
setuid exec. Ideally we would use capabilities to
achieve this.
Serge can we have a capability that unprivelged processes
normally have an can drop without privelege?
I can see one of two possible reasons you are avoiding the
suggestion to disable setuid root.
- You have a use for setuid root executables in your contained
environment. If you do what is that use?
- Disabling suid root executables is an indirect path to your
goal.
The problem with the disable_network semantics you want
is that they allow you to perform a denial of service attack
on privileged users. An unprivileged DOS attack is unsuitable
for a general purpose feature in a general purpose kernel.
Your sysctl, your boot option, your Kconfig option all fail
to be viable options for the same reason. Your facility is
only valid in an audited userspace.
Disabling setuid-exec especially to a subset of processes is
valid in an unaudited userspace as it does not allow propagating
the DOS to privileged processes.
Eric
Quoting Eric W. Biederman ([email protected]):
> Michael Stone <[email protected]> writes:
>
> > Serge,
> >
> > I think that Pavel's point, at its strongest and most general, could be
> > rephrased as:
> >
> > "Adding *any* interesting isolation facility to the kernel breaks backwards
> > compatibility for *some* program [in a way that violates security goals]."
>
> *some* privileged program.
>
> > The reason is the one that I identified in my previous note:
> >
> > "The purpose of isolation facilities is to create membranes inside which
> > grievous security faults are converted into availability faults."
> >
> > The question then is simply:
> >
> > "How do we want to deal with the compatibility-breaking changes created by
> > introducing new isolation facilities?"
>
> You have a very peculiar taxonomy of the suggestions,
> that fails to capture the concerns.
>
> I strongly recommend working out a way to disable
> setuid exec. Ideally we would use capabilities to
> achieve this.
>
> Serge can we have a capability that unprivelged processes
> normally have an can drop without privelege?
David Madore suggested such a system several years ago:
http://lkml.org/lkml/2006/9/5/246
I have two comments on the idea:
1. We don't want to complicate the current capabilities
concepts and API, so if we do something like this,
we should make sure not to try to store these
unprivileged capabilities with the current privilege
capabilities.
2. This in itself does nothing to address the problem of
unprivileged tasks denying privilege from privileged
programs, thereby threatening the system.
In my last email last night I detailed a way to use regular
capabilities to make the prctl(PR_SET_NETWORK, PR_DROP_NET)
safer.
We could generalize that a bit:
1. we add a set of 'user_capabilities' like 'network', 'open',
etc, which are the rights to do an unprivileged network socket
create, file open, etc.
2. For each user_capability, we add a new 'CAP_REGAIN_$userpriv'
POSIX capability.
3. When a file is executed, we always add CAP_REGAIN_* to the
file permitted and effective sets. That means that after
exec, they will always be in pE.
4. So long as CAP_REGAIN_foo is in pE toward the end of exec,
we re-enable the user_capability foo.
5. A privileged program can remove CAP_REGAIN_foo from the
capability bounding set. It, and all it's children, will then
not have CAP_REGAIN_foo in pE after exec, so that if userspace
has removed foo from the user_capabilities set, it will not
be returned.
So, again, /bin/login, or pam, or /sbin/init can drop
CAP_REGAIN_* from its bounding set if userspace is designed
with that functionality in mind, in other words the distro or
admin trusts that privileged programs won't ruin the system if
they are denied certain features.
> I can see one of two possible reasons you are avoiding the
> suggestion to disable setuid root.
> - You have a use for setuid root executables in your contained
> environment. If you do what is that use?
I don't think Michael was avoiding that. Rather, we haven't quite
spelled out what it means to disable setuid root, and we haven't
(to my satisfaction) detailed how setuid root would undo the
prctl(PR_SET_NETWORK, PR_DROP_NET) - i.e. is it only on a
privilege-granting setuid-root, or all setuids?
Eric, let me specifically point out a 'disable setuid-root'
problem on linux: root still owns most of the system even when
it's not privileged. So does "disable setuid-root" mean
we don't allow exec of setuid-root binaries at all, or that
we don't setuid to root, or that we just don't raise privileges
for setuid-root?
> - Disabling suid root executables is an indirect path to your
> goal.
>
> The problem with the disable_network semantics you want
> is that they allow you to perform a denial of service attack
> on privileged users. An unprivileged DOS attack is unsuitable
> for a general purpose feature in a general purpose kernel.
Though to be honest I'm still unconvinced that the disablenetwork
is dangerous. I think long-term a more general solution like what
I outlined above might be good, but short-term a sysctl that
turns on or off the ability to drop network would suffice imo.
For ultra-secure sites at three-letter government agencies, we
could also provide a boot arg that disables the feature altogether,
and of course a grub password and IMA/EVM/trusted-boot could
ensure the boot arg isn't messed with.
> Your sysctl, your boot option, your Kconfig option all fail
> to be viable options for the same reason. Your facility is
> only valid in an audited userspace.
>
> Disabling setuid-exec especially to a subset of processes is
> valid in an unaudited userspace as it does not allow propagating
> the DOS to privileged processes.
-serge
On Tue, Dec 29, 2009 at 10:11 AM, Serge E. Hallyn <[email protected]> wrote:
> Eric, let me specifically point out a 'disable setuid-root'
> problem on linux: root still owns most of the system even when
> it's not privileged. ?So does "disable setuid-root" mean
> we don't allow exec of setuid-root binaries at all, or that
> we don't setuid to root, or that we just don't raise privileges
> for setuid-root?
I, for one, think it would be best to handle it exactly like the
nosuid mount option - that is, pretend the file doesn't have any
setuid bits set. There's no reason to deny execution; if the process
would otherwise be able to execute it, it can also copy the file to
make a non-suid version and execute that instead. And some programs
can operate with reduced function without setuid. For example, screen
comes to mind; it needs root to share screen sessions between multiple
users, but can operate for a single user just fine without root, and
indeed the latter is usually the default configuration.
Eric Biederman writes:
> Serge,
>
> Michael Stone <[email protected]> writes:
>> I think that Pavel's point, at its strongest and most general, could be
>> rephrased as:
>>
>> "Adding *any* interesting isolation facility to the kernel breaks backwards
>> compatibility for *some* program [in a way that violates security goals]."
>
>*some* privileged program.
Your amendment is a good one; it makes the statement better reflect your and
Pavel's concern. Thanks.
>> The reason is the one that I identified in my previous note:
>>
>> "The purpose of isolation facilities is to create membranes inside which
>> grievous security faults are converted into availability faults."
>>
>> The question then is simply:
>>
>> "How do we want to deal with the compatibility-breaking changes created by
>> introducing new isolation facilities?"
> You have a very peculiar taxonomy of the suggestions,
> that fails to capture the concerns.
Do you agree with my assessment that this is fundamentally a
backwards-compatibility problem with security consequences?
> I strongly recommend working out a way to disable
> setuid exec. Ideally we would use capabilities to
> achieve this.
>
> ...
>
> I can see one of two possible reasons you are avoiding the
> suggestion to disable setuid root...
Heard and understood. I'll start thinking about how to do it (and about what
the consequences might be). However, those aren't my reasons for wariness.
My reasons have to do with history, preparation, and logic:
1. I first began playing with disablenetwork about two years ago and I missed
both the need to restrict ptrace and the fact that the interaction with
privileged executables would be a problem for other people.
2. With disablenetwork, I was already building on clear (if slightly
incomplete) design by djb. We have none of that prep work here.
3. We have definite reasons, laid out by my argument above about the general
compatibility cost of isolation facilities, to suspect that disablesuid
in any form will break at least one other interesting use case. I don't
know what that use case is yet but I'm fairly sure that it exists.
> The problem with the disable_network semantics you want
> is that they allow you to perform a denial of service attack
> on privileged users. An unprivileged DOS attack is unsuitable
> for a general purpose feature in a general purpose kernel.
Then where did rlimits come from? rlimits *can* DoS privileged processes and
people are pretty much okay with the idea. People who are concerned can raise
the rlimits in their privileged processes and get on with life.
Second, as you point out, I am willing to audit and to modify my setuid
executables *in exchange* for having a kernel that changes in useful ways.
Obviously, not everyone is willing to pay this upkeep.
At any rate, I hope all this helps make my position clearer. I'll think more
about your suggestions.
Regards,
Michael
Serge Hallyn writes:
> Quoting Michael Stone ([email protected]):
> So far, two defaults have been proposed:
>
> default-deny incompatible isolation (Pavel)
> default-permit incompatible isolation (Michael)
>
> So far, several signalling mechanisms have been proposed:
>
>> 1) enabling a kernel config option implies default-permit
>>
>> - My favorite; apparently insufficient for Pavel?
>
> default under what conditions? any setuid? setuid-root?
My favorite option is that CONFIGURE_SECURITY_DISABLENETWORK causes
disablenetwork to function like djb describes: unprivileged and irrevocable.
(I don't have any setuid executables that I'm worried about breaking; only ones
that I think /should/ be broken and aren't, like ping.)
> 2) default-deny; disablesuid grants disablenetwork
>
> - "disablesuid" is my name for the idea of dropping the privilege of
> exec'ing setuid binaries
>
> - Suggested by Pavel and supported by several others.
>
> - I think it has the same backwards-compatibility problem as
> disablenetwork: disablesuid is an isolation primitive.
>
> 3) default-deny; dropping a capability from the bounding set grants "permit"
>
> - Suggested by Serge; seems nicely fine-grained but rather indirect
>
> Actually I think it's the opposite of what you said here: so long as the
> capability is in pE, you can regain network. So it would require a privileged
> process early on (like init or login) to remove the capability from the
> bounding set (bc doing so requires CAP_SETPCAP), but once that was done,
> the resulting process and it's children could not require the capability,
> and, without the capability, could not regain network. Point being that
> privileged userspace had to actively allow userspace to trap a setuid root
> binary without networking.
What I wrote accurately (if confusingly; sorry!) reflects what you suggest: by
default, the kernel should deny processes from irrevocably dropping networking
privilege until signalled that this is acceptable by the privileged mechanism
of dropping your cap from the bounding set.
> I think during exec we can simply check for this capability in pE, and
> if present then re-enable network if turned off. Then setuid-root binaries
> will raise that bit (if it's in the bounding set) automatically. Now,
> that means setuid-nonroot binaries will not reset network. Though you
> could make that happen by doing setcap cap_net_allownet+pe /the/file.
> Does that suffice?
I think I could live with it.
I find it weird that, if I call disablenetwork on a system *without* dropping
your capability, sendto(...) will fail but execve(['/bin/ping', '...']) will
succeed.
Still, it will do what I need.
>> 4) default-deny; setting a sysctl implies permit
>>
>> - Suggested by Serge; works fine for me
>
>That still leaves the question of when we re-allow network. Any
>setuid?
My intention was that prctl(PR_SET_NETWORK, PR_NETWORK_OFF) would return
-ENOTSUP or similar until the sysctl was enabled, at which point it would work
as I specified.
("As I specified" means one of "irrevocable" or "like rlimits; can be relaxed
by explicit action by privileged processes")
>> P.P.S. - On a completely unrelated note: imagine trying to use SELinux (or your
>> favorite MAC framework) to restrict the use of prctl(PR_SET_NETWORK,
>> PR_NETWORK_OFF). Am I right that sys_prctl() contains a
>> time-of-check-to-time-of-use (TOCTTOU) race (with security_task_prctl() as the
>> check and with prctl_set_network() as the use) as a result of the actual
>> argument being passed by address rather than by value?
>
> I'm probably misunderstanding your question, but just in case I'm not: the
> answer is that you wouldn't use the prctl interface anyway. You would strictly
> use domain transitions. Instead of doing prctl(PR_SET_NETWORK, PR_NETWORK_OFF)
> you would move yourself from the user_u:user_r:network_allowed domain to the
> user_u:user_r:network_disallowed domain.
You misunderstood; sorry I wasn't more clear. :)
I was really saying:
Suppose process A and process B create a share a memory segment containing an
unsigned long pointed to by.
unsigned long *flags;
Can't process A call prctl(PR_SET_NETWORK, flags) while, on another
processor, process B is twiddling bits in *flags so that
security_task_prctl() sees the bits that process A wrote and
prctl_set_network() sees the bits that process B wrote?
i.e. isn't there a TOCTTOU race [1] here in every prctl option that uses a
pointer argument? if not, what stops the race?
Regards,
Michael
[1]: http://en.wikipedia.org/wiki/Time-of-check-to-time-of-use
Quoting Bryan Donlan ([email protected]):
> On Tue, Dec 29, 2009 at 10:11 AM, Serge E. Hallyn <[email protected]> wrote:
> > Eric, let me specifically point out a 'disable setuid-root'
> > problem on linux: root still owns most of the system even when
> > it's not privileged. ?So does "disable setuid-root" mean
> > we don't allow exec of setuid-root binaries at all, or that
> > we don't setuid to root, or that we just don't raise privileges
> > for setuid-root?
>
> I, for one, think it would be best to handle it exactly like the
> nosuid mount option - that is, pretend the file doesn't have any
> setuid bits set. There's no reason to deny execution; if the process
> would otherwise be able to execute it, it can also copy the file to
> make a non-suid version and execute that instead. And some programs
> can operate with reduced function without setuid. For example, screen
> comes to mind; it needs root to share screen sessions between multiple
> users, but can operate for a single user just fine without root, and
> indeed the latter is usually the default configuration.
That's fine with me, seems safe for a fully unprivileged program to
use, and would make sense to do through one of the securebits set
with prctl(PR_SET_SECUREBITS).
In addition, I assume we would also refuse to honor file capabilities?
-serge
On Tue, Dec 29, 2009 at 11:39 AM, Serge E. Hallyn <[email protected]> wrote:
> Quoting Bryan Donlan ([email protected]):
>> On Tue, Dec 29, 2009 at 10:11 AM, Serge E. Hallyn <[email protected]> wrote:
>> > Eric, let me specifically point out a 'disable setuid-root'
>> > problem on linux: root still owns most of the system even when
>> > it's not privileged. ?So does "disable setuid-root" mean
>> > we don't allow exec of setuid-root binaries at all, or that
>> > we don't setuid to root, or that we just don't raise privileges
>> > for setuid-root?
>>
>> I, for one, think it would be best to handle it exactly like the
>> nosuid mount option - that is, pretend the file doesn't have any
>> setuid bits set. There's no reason to deny execution; if the process
>> would otherwise be able to execute it, it can also copy the file to
>> make a non-suid version and execute that instead. And some programs
>> can operate with reduced function without setuid. For example, screen
>> comes to mind; it needs root to share screen sessions between multiple
>> users, but can operate for a single user just fine without root, and
>> indeed the latter is usually the default configuration.
>
> That's fine with me, seems safe for a fully unprivileged program to
> use, and would make sense to do through one of the securebits set
> with prctl(PR_SET_SECUREBITS).
>
> In addition, I assume we would also refuse to honor file capabilities?
Yes - essentially a one-time switch saying "never allow me to gain
capabilities again".
"Serge E. Hallyn" <[email protected]> writes:
>
> I have two comments on the idea:
>
> 1. We don't want to complicate the current capabilities
> concepts and API, so if we do something like this,
> we should make sure not to try to store these
> unprivileged capabilities with the current privilege
> capabilities.
I was afraid there might be a complication like that.
Then the user interface side of what I am proposing
needs some more thought.
> In my last email last night I detailed a way to use regular
> capabilities to make the prctl(PR_SET_NETWORK, PR_DROP_NET)
> safer.
Yes. I missed that earlier my apologies.
>> I can see one of two possible reasons you are avoiding the
>> suggestion to disable setuid root.
>> - You have a use for setuid root executables in your contained
>> environment. If you do what is that use?
>
> I don't think Michael was avoiding that. Rather, we haven't quite
> spelled out what it means to disable setuid root, and we haven't
> (to my satisfaction) detailed how setuid root would undo the
> prctl(PR_SET_NETWORK, PR_DROP_NET) - i.e. is it only on a
> privilege-granting setuid-root, or all setuids?
Michael finds suid-root granting network access incompatible
with what he is trying to achieve. The practical example is
network denied applications may communicate with the outside
world by calling ping.
> Eric, let me specifically point out a 'disable setuid-root'
> problem on linux: root still owns most of the system even when
> it's not privileged. So does "disable setuid-root" mean
> we don't allow exec of setuid-root binaries at all, or that
> we don't setuid to root, or that we just don't raise privileges
> for setuid-root?
The semantics I am suggesting under the title "disable suid exec" are
to flag a process such that, that process and any future children may
not increase their kernel enforced privileges. In practice this means
attempts to exec any suid binaries will fail. Likewise attempting to
exec a binary flagged with in the filesystem to gain capabilities will
also fail.
This would appear to require denying of ptracing applications
with other/more privileges, failing attempts to raise the
capabilities on one of the processes, and I think failing
all setuid/setgid calls.
In my conception this is a useful subset of unshare(USERNS) that can
be easily implemented now.
>> - Disabling suid root executables is an indirect path to your
>> goal.
>>
>> The problem with the disable_network semantics you want
>> is that they allow you to perform a denial of service attack
>> on privileged users. An unprivileged DOS attack is unsuitable
>> for a general purpose feature in a general purpose kernel.
>
> Though to be honest I'm still unconvinced that the disablenetwork
> is dangerous. I think long-term a more general solution like what
> I outlined above might be good, but short-term a sysctl that
> turns on or off the ability to drop network would suffice imo.
I have seen the following arguments put forth.
- Certain kinds of logging are broken from suid executables.
- Certain questionable but existing user space authentication
policies will be broken.
That is enough for me to strongly suspect someone with a more
devious mind than myself could find something worse. I know
it took me over a year to figure out how someone could exploit
unshare(NETNS).
The goal is to find something that unprivileged applications can use
safely, and can be available by default in distro kernels.
A syscall that removes the ability to exec suid executables appears to
meet that goal, as well as be the necessary prerequisite for enabling
other forms of isolation without causing security problems.
Eric
Bryan Donlan <[email protected]> writes:
> On Tue, Dec 29, 2009 at 11:39 AM, Serge E. Hallyn <[email protected]> wrote:
>> Quoting Bryan Donlan ([email protected]):
>>> On Tue, Dec 29, 2009 at 10:11 AM, Serge E. Hallyn <[email protected]> wrote:
>>> > Eric, let me specifically point out a 'disable setuid-root'
>>> > problem on linux: root still owns most of the system even when
>>> > it's not privileged. ?So does "disable setuid-root" mean
>>> > we don't allow exec of setuid-root binaries at all, or that
>>> > we don't setuid to root, or that we just don't raise privileges
>>> > for setuid-root?
>>>
>>> I, for one, think it would be best to handle it exactly like the
>>> nosuid mount option - that is, pretend the file doesn't have any
>>> setuid bits set. There's no reason to deny execution; if the process
>>> would otherwise be able to execute it, it can also copy the file to
>>> make a non-suid version and execute that instead. And some programs
>>> can operate with reduced function without setuid. For example, screen
>>> comes to mind; it needs root to share screen sessions between multiple
>>> users, but can operate for a single user just fine without root, and
>>> indeed the latter is usually the default configuration.
>>
>> That's fine with me, seems safe for a fully unprivileged program to
>> use, and would make sense to do through one of the securebits set
>> with prctl(PR_SET_SECUREBITS).
>>
>> In addition, I assume we would also refuse to honor file capabilities?
>
> Yes - essentially a one-time switch saying "never allow me to gain
> capabilities again".
That is what I was thinking. Does setresuid case problems? Assuming
the application that drop permissions could have successfully
called setresuid?
Ignoring the bits instead of honoring them when execing an executable
makes sense as that is the existing precedent.
If it works prctl appears to be a fine interface.
Eric
On Tue, Dec 29, 2009 at 1:36 PM, Eric W. Biederman
<[email protected]> wrote:
> Bryan Donlan <[email protected]> writes:
>
>> On Tue, Dec 29, 2009 at 11:39 AM, Serge E. Hallyn <[email protected]> wrote:
>>> Quoting Bryan Donlan ([email protected]):
>>>> On Tue, Dec 29, 2009 at 10:11 AM, Serge E. Hallyn <[email protected]> wrote:
>>>> > Eric, let me specifically point out a 'disable setuid-root'
>>>> > problem on linux: root still owns most of the system even when
>>>> > it's not privileged. ?So does "disable setuid-root" mean
>>>> > we don't allow exec of setuid-root binaries at all, or that
>>>> > we don't setuid to root, or that we just don't raise privileges
>>>> > for setuid-root?
>>>>
>>>> I, for one, think it would be best to handle it exactly like the
>>>> nosuid mount option - that is, pretend the file doesn't have any
>>>> setuid bits set. There's no reason to deny execution; if the process
>>>> would otherwise be able to execute it, it can also copy the file to
>>>> make a non-suid version and execute that instead. And some programs
>>>> can operate with reduced function without setuid. For example, screen
>>>> comes to mind; it needs root to share screen sessions between multiple
>>>> users, but can operate for a single user just fine without root, and
>>>> indeed the latter is usually the default configuration.
>>>
>>> That's fine with me, seems safe for a fully unprivileged program to
>>> use, and would make sense to do through one of the securebits set
>>> with prctl(PR_SET_SECUREBITS).
>>>
>>> In addition, I assume we would also refuse to honor file capabilities?
>>
>> Yes - essentially a one-time switch saying "never allow me to gain
>> capabilities again".
>
> That is what I was thinking. ?Does setresuid case problems? ?Assuming
> the application that drop permissions could have successfully
> called setresuid?
It's probably reasonable to require that real == effective == saved ==
fs UID (and same for GID); anything else brings up sticky issues of
"which UID is a higher capability?"
If a process does this call, it's effectively saying that the only way
it's going to be accessing resources beyond its current UID and
capabilities is by talking to another process over a (unix domain)
socket.
Bryan Donlan <[email protected]> writes:
> I, for one, think it would be best to handle it exactly like the
> nosuid mount option - that is, pretend the file doesn't have any
> setuid bits set. There's no reason to deny execution; if the process
> would otherwise be able to execute it, it can also copy the file to
> make a non-suid version and execute that instead.
Execute != read. The executable file may contain secrets which must not
be available to the user running the setuid program. If you fail the
setuid, the user will be able to ptrace() and then the secret is
revealed.
It's amazing how many security holes appear from what seems like a very
simple request.
/Benny
Benny Amorsen <[email protected]> writes:
> Bryan Donlan <[email protected]> writes:
>
>> I, for one, think it would be best to handle it exactly like the
>> nosuid mount option - that is, pretend the file doesn't have any
>> setuid bits set. There's no reason to deny execution; if the process
>> would otherwise be able to execute it, it can also copy the file to
>> make a non-suid version and execute that instead.
>
> Execute != read. The executable file may contain secrets which must not
> be available to the user running the setuid program. If you fail the
> setuid, the user will be able to ptrace() and then the secret is
> revealed.
>
> It's amazing how many security holes appear from what seems like a very
> simple request.
Do we have a security hole in nosuid mount option?
Can someone write a patch to fix it?
Eric
On Tue, Dec 29, 2009 at 3:40 PM, Eric W. Biederman
<[email protected]> wrote:
> Benny Amorsen <[email protected]> writes:
>
>> Bryan Donlan <[email protected]> writes:
>>
>>> I, for one, think it would be best to handle it exactly like the
>>> nosuid mount option - that is, pretend the file doesn't have any
>>> setuid bits set. There's no reason to deny execution; if the process
>>> would otherwise be able to execute it, it can also copy the file to
>>> make a non-suid version and execute that instead.
>>
>> Execute != read. The executable file may contain secrets which must not
>> be available to the user running the setuid program. If you fail the
>> setuid, the user will be able to ptrace() and then the secret is
>> revealed.
>>
>> It's amazing how many security holes appear from what seems like a very
>> simple request.
>
> Do we have a security hole in nosuid mount option?
Looks like it:
$ /tmp/m/sudo
sudo: must be setuid root
$ ls -l /tmp/m/sudo
-rwsr-x--x 1 root root 123448 2009-06-22 12:14 /tmp/m/sudo
Bryan Donlan <[email protected]> writes:
> It's probably reasonable to require that real == effective == saved ==
> fs UID (and same for GID); anything else brings up sticky issues of
> "which UID is a higher capability?"
> If a process does this call, it's effectively saying that the only way
> it's going to be accessing resources beyond its current UID and
> capabilities is by talking to another process over a (unix domain)
> socket.
Makes sense. Especially for the initial implementation,
and it keeps the code size small.
Eric
> > Execute != read. The executable file may contain secrets which must not
> > be available to the user running the setuid program. If you fail the
> > setuid, the user will be able to ptrace() and then the secret is
> > revealed.
> >
> > It's amazing how many security holes appear from what seems like a very
> > simple request.
>
> Do we have a security hole in nosuid mount option?
> Can someone write a patch to fix it?
If a setuid app can read a key when its erroneously not set setuid then
the user can read it too.
Anything you can do with ptrace you can do yourself !
2009/12/29 Alan Cox <[email protected]>:
>> > Execute != read. The executable file may contain secrets which must not
>> > be available to the user running the setuid program. If you fail the
>> > setuid, the user will be able to ptrace() and then the secret is
>> > revealed.
>> >
>> > It's amazing how many security holes appear from what seems like a very
>> > simple request.
>>
>> Do we have a security hole in nosuid mount option?
>> Can someone write a patch to fix it?
>
> If a setuid app can read a key when its erroneously not set setuid then
> the user can read it too.
>
> Anything you can do with ptrace you can do yourself !
The security hole is that secrets in a setuid application with
other-exec but no other-read permission can be read when the
filesystem is mounted nosuid. Normally the user would be unable to
ptrace the program, and unable to read the executable, so the secret
would not be divulged; when nosuid is set, the user is now able to
ptrace the program - ie, they gain abilities from nosuid.
Whether this is a severe issue is debatable, of course; it's unlikely
that the administrator will create a setuid program with weird
permissions and then go and mount the fs it's on with nosuid. However
with the proposed 'drop suiding abilities' API, this becomes a bigger
issue, since if we reuse the nosuid semantics, any user can trigger
it, without needing to get root to mount things nosuid.
That said, I do tend to agree that relying on the _presence_ of a suid
mode to protect your secrets is probably a bad idea...
Quoting Bryan Donlan ([email protected]):
> On Tue, Dec 29, 2009 at 1:36 PM, Eric W. Biederman
> <[email protected]> wrote:
> > Bryan Donlan <[email protected]> writes:
> >
> >> On Tue, Dec 29, 2009 at 11:39 AM, Serge E. Hallyn <[email protected]> wrote:
> >>> Quoting Bryan Donlan ([email protected]):
> >>>> On Tue, Dec 29, 2009 at 10:11 AM, Serge E. Hallyn <[email protected]> wrote:
> >>>> > Eric, let me specifically point out a 'disable setuid-root'
> >>>> > problem on linux: root still owns most of the system even when
> >>>> > it's not privileged. ?So does "disable setuid-root" mean
> >>>> > we don't allow exec of setuid-root binaries at all, or that
> >>>> > we don't setuid to root, or that we just don't raise privileges
> >>>> > for setuid-root?
> >>>>
> >>>> I, for one, think it would be best to handle it exactly like the
> >>>> nosuid mount option - that is, pretend the file doesn't have any
> >>>> setuid bits set. There's no reason to deny execution; if the process
> >>>> would otherwise be able to execute it, it can also copy the file to
> >>>> make a non-suid version and execute that instead. And some programs
> >>>> can operate with reduced function without setuid. For example, screen
> >>>> comes to mind; it needs root to share screen sessions between multiple
> >>>> users, but can operate for a single user just fine without root, and
> >>>> indeed the latter is usually the default configuration.
> >>>
> >>> That's fine with me, seems safe for a fully unprivileged program to
> >>> use, and would make sense to do through one of the securebits set
> >>> with prctl(PR_SET_SECUREBITS).
> >>>
> >>> In addition, I assume we would also refuse to honor file capabilities?
> >>
> >> Yes - essentially a one-time switch saying "never allow me to gain
> >> capabilities again".
> >
> > That is what I was thinking. ?Does setresuid case problems? ?Assuming
> > the application that drop permissions could have successfully
> > called setresuid?
>
> It's probably reasonable to require that real == effective == saved ==
> fs UID (and same for GID); anything else brings up sticky issues of
> "which UID is a higher capability?"
I think i disagree. A uid is just a uid (or should be). One day we may
have a way for a factotum-style daemon to grant the ability to an unpriv
task to setuid without CAP_SETUID. I think slingling uids and gids
around that you already have access to should be fine.
> If a process does this call, it's effectively saying that the only way
> it's going to be accessing resources beyond its current UID and
> capabilities is by talking to another process over a (unix domain)
> socket.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Alan Cox <[email protected]> writes:
>> > Execute != read. The executable file may contain secrets which must not
>> > be available to the user running the setuid program. If you fail the
>> > setuid, the user will be able to ptrace() and then the secret is
>> > revealed.
>> >
>> > It's amazing how many security holes appear from what seems like a very
>> > simple request.
>>
>> Do we have a security hole in nosuid mount option?
>> Can someone write a patch to fix it?
>
> If a setuid app can read a key when its erroneously not set setuid then
> the user can read it too.
>
> Anything you can do with ptrace you can do yourself !
Now that I think about it this is really something completely separate
from setuid. This is about being able to read the text segment with
ptrace when you on have execute permissions on the file.
I just skimmed through fs/exec.c and we set the undumpable process
flag in that case so ptrace should not work in that case.
So short of a bug in the implementation we have no security hole.
Eric
> The security hole is that secrets in a setuid application with
> other-exec but no other-read permission can be read when the
> filesystem is mounted nosuid.
Erm no
We enforce the following anyway to prevent execution being permitted to
make file copies. Most Unixen do although its historical value is
primarily to prevent people "stealing valuable proprietary intellectual
software assets".
} else if (file_permission(bprm->file, MAY_READ) ||
bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)
{
set_dumpable(current->mm, suid_dumpable);
}
There does appear to be a small race in modern versions of that code
which wants swatting.
On Tue, 29 Dec 2009 15:27:22 CST, "Serge E. Hallyn" said:
> I think i disagree. A uid is just a uid (or should be). One day we may
> have a way for a factotum-style daemon to grant the ability to an unpriv
> task to setuid without CAP_SETUID. I think slingling uids and gids
> around that you already have access to should be fine.
Yes, but not doing the clear and obvious simple thing now for a "one day
we may have" consideration seems a poor engineering tradeoff.
Yes, slinging uids and gids around *would* be nice. But first we need a clear
plan for making /usr/bin/newgrp a shell builtin - once that happens, *then*
we can re-address this code. ;)
Quoting [email protected] ([email protected]):
> On Tue, 29 Dec 2009 15:27:22 CST, "Serge E. Hallyn" said:
> > I think i disagree. A uid is just a uid (or should be). One day we may
> > have a way for a factotum-style daemon to grant the ability to an unpriv
> > task to setuid without CAP_SETUID. I think slingling uids and gids
> > around that you already have access to should be fine.
>
> Yes, but not doing the clear and obvious simple thing now for a "one day
> we may have" consideration seems a poor engineering tradeoff.
>
> Yes, slinging uids and gids around *would* be nice. But first we need a clear
> plan for making /usr/bin/newgrp a shell builtin - once that happens, *then*
> we can re-address this code. ;)
Absolutely agreed with the principle, but conflicted on the application.
I know earlier in the thread I said uid 0 even when unprivileged is
actually privileged merely by owning most of the system files. But
in fact I think it helps to think more clearly when we separately
consider the cases of (a) changing uid, and (b) enhancing privilege.
That's why I was recommending implementation through securebits - what
we're basically saying is the task should never gain privilege. And
effectively, since it won't have CAP_SETUID (unless it has and keeps it
in pI) it wont' be able to change uids. But if we right off the bat
confuse changing uids with gaining privilege, I'm afraid we might end
up making some poor decisions.
Still, I won't say no to a check to refuse dropping the ability to
setuid to ensure that ruid=euid=suid and pP=pE=pI=empty. It may
come back to bite us, but like I say I'm conflicted - willing to
go either way.
-serge
Quoting Eric W. Biederman ([email protected]):
> Alan Cox <[email protected]> writes:
>
> >> > Execute != read. The executable file may contain secrets which must not
> >> > be available to the user running the setuid program. If you fail the
> >> > setuid, the user will be able to ptrace() and then the secret is
> >> > revealed.
> >> >
> >> > It's amazing how many security holes appear from what seems like a very
> >> > simple request.
> >>
> >> Do we have a security hole in nosuid mount option?
> >> Can someone write a patch to fix it?
> >
> > If a setuid app can read a key when its erroneously not set setuid then
> > the user can read it too.
> >
> > Anything you can do with ptrace you can do yourself !
>
> Now that I think about it this is really something completely separate
> from setuid. This is about being able to read the text segment with
> ptrace when you on have execute permissions on the file.
>
> I just skimmed through fs/exec.c and we set the undumpable process
> flag in that case so ptrace should not work in that case.
And in fact you can't do a new ptrace_attach, but if you're already
tracing the task when it execs the unreadable-but-executable file,
then the ptrace can continue.
Just looking at the code, it appears 2.2 was the same way (though I
could be missing where it used to enforce that).
So, is that intended? What exactly would we do about it if not?
Just refuse exec of a unreadable-but-executable file if we're
being traced?
> So short of a bug in the implementation we have no security hole.
>
> Eric
"Serge E. Hallyn" <[email protected]> writes:
> Quoting Eric W. Biederman ([email protected]):
>> Alan Cox <[email protected]> writes:
>>
>> >> > Execute != read. The executable file may contain secrets which must not
>> >> > be available to the user running the setuid program. If you fail the
>> >> > setuid, the user will be able to ptrace() and then the secret is
>> >> > revealed.
>> >> >
>> >> > It's amazing how many security holes appear from what seems like a very
>> >> > simple request.
>> >>
>> >> Do we have a security hole in nosuid mount option?
>> >> Can someone write a patch to fix it?
>> >
>> > If a setuid app can read a key when its erroneously not set setuid then
>> > the user can read it too.
>> >
>> > Anything you can do with ptrace you can do yourself !
>>
>> Now that I think about it this is really something completely separate
>> from setuid. This is about being able to read the text segment with
>> ptrace when you on have execute permissions on the file.
>>
>> I just skimmed through fs/exec.c and we set the undumpable process
>> flag in that case so ptrace should not work in that case.
>
> And in fact you can't do a new ptrace_attach, but if you're already
> tracing the task when it execs the unreadable-but-executable file,
> then the ptrace can continue.
>
> Just looking at the code, it appears 2.2 was the same way (though I
> could be missing where it used to enforce that).
>
> So, is that intended? What exactly would we do about it if not?
> Just refuse exec of a unreadable-but-executable file if we're
> being traced?
In common cap we drop the new capabilities if we are being ptraced.
Look for brm->unsafe.
Eric
If we can know that a process will never raise it's priveleges we can
enable a lot of features that otherwise would be unsafe, because they
could break assumptions of existing suid executables.
To allow this to be used as a sand boxing feature also disable
ptracing other executables without this new restriction.
For the moment I have used a per thread flag because we are out of per
process flags.
To ensure all descendants get this flag I rely on the default copying
of procss structures.
The disabling of suid executables is exactly the same as MNT_NOSUID.
This should be what we have been talking about in for disabling of
suid exec. I choose not to use securebits as that interface requires
privilege and assumes capabilities. This implementation is more basic
than capabilities and only adds additional sanity checks when
linux capabilities are not present.
I attempt to ensure there are no mixed priveleges present, when we
perform the disable so I don't need to handle or think about
interactions with setreuid or capabilities in this code.
Signed-off-by: Eric W. Biederman <[email protected]>
---
arch/x86/include/asm/thread_info.h | 2 ++
fs/exec.c | 3 ++-
include/linux/prctl.h | 2 ++
kernel/ptrace.c | 4 ++++
kernel/sys.c | 16 ++++++++++++++++
security/commoncap.c | 15 +++++++++++++++
6 files changed, 41 insertions(+), 1 deletions(-)
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 375c917..e716203 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -82,6 +82,7 @@ struct thread_info {
#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
+#define TIF_NOSUID 9 /* suid exec permanently disabled */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
#define TIF_NOTSC 16 /* TSC is not accessible in userland */
@@ -107,6 +108,7 @@ struct thread_info {
#define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_NOSUID (1 << TIF_NOSUID)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
#define _TIF_NOTSC (1 << TIF_NOTSC)
diff --git a/fs/exec.c b/fs/exec.c
index 632b02e..e6c9bc5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1132,7 +1132,8 @@ int prepare_binprm(struct linux_binprm *bprm)
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();
- if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+ if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
+ !test_tsk_thread_flag(current, TIF_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index a3baeb2..acb3516 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -102,4 +102,6 @@
#define PR_MCE_KILL_GET 34
+#define PR_SET_NOSUID 35
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 23bd09c..4b2643c 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
+ if (test_tsk_thread_flag(current, TIF_NOSUID) &&
+ !test_tsk_thread_flag(current, TIF_NOSUID))
+ return -EPERM;
+
return security_ptrace_access_check(task, mode);
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 26a6b73..1d1902a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1578,6 +1578,22 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
error = PR_MCE_KILL_DEFAULT;
break;
+ case PR_SET_NOSUID:
+ {
+ const struct cred *cred = current->cred;
+ error = -EINVAL;
+ if ( (cred->uid != cred->suid) ||
+ (cred->uid != cred->euid) ||
+ (cred->uid != cred->fsuid) ||
+ (cred->gid != cred->sgid) ||
+ (cred->gid != cred->egid) ||
+ (cred->gid != cred->fsgid) ||
+ (atomic_read(¤t->signal->count) != 1))
+ break;
+ error = 0;
+ set_tsk_thread_flag(current, TIF_NOSUID);
+ break;
+ }
default:
error = -EINVAL;
break;
diff --git a/security/commoncap.c b/security/commoncap.c
index f800fdb..8abd3dc 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -392,6 +392,9 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
return 0;
+ if (test_tsk_thread_flag(current, TIF_NOSUID))
+ return 0;
+
dentry = dget(bprm->file->f_dentry);
rc = get_vfs_caps_from_disk(dentry, &vcaps);
@@ -869,6 +872,18 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
goto changed;
+ case PR_SET_NOSUID:
+ {
+ const struct cred *cred = current->cred;
+ error = -EINVAL;
+ // Perform the capabilities checks
+ if (!cap_isclear(cred->cap_permitted) ||
+ !cap_isclear(cred->cap_effective))
+ goto error;
+ // Have the default perform the rest of the work.
+ error = -ENOSYS;
+ goto error;
+ }
default:
/* No functionality available - continue with default */
error = -ENOSYS;
--
1.6.5.2.143.g8cc62
Quoting Eric W. Biederman ([email protected]):
> "Serge E. Hallyn" <[email protected]> writes:
>
> > Quoting Eric W. Biederman ([email protected]):
> >> Alan Cox <[email protected]> writes:
> >>
> >> >> > Execute != read. The executable file may contain secrets which must not
> >> >> > be available to the user running the setuid program. If you fail the
> >> >> > setuid, the user will be able to ptrace() and then the secret is
> >> >> > revealed.
> >> >> >
> >> >> > It's amazing how many security holes appear from what seems like a very
> >> >> > simple request.
> >> >>
> >> >> Do we have a security hole in nosuid mount option?
> >> >> Can someone write a patch to fix it?
> >> >
> >> > If a setuid app can read a key when its erroneously not set setuid then
> >> > the user can read it too.
> >> >
> >> > Anything you can do with ptrace you can do yourself !
> >>
> >> Now that I think about it this is really something completely separate
> >> from setuid. This is about being able to read the text segment with
> >> ptrace when you on have execute permissions on the file.
> >>
> >> I just skimmed through fs/exec.c and we set the undumpable process
> >> flag in that case so ptrace should not work in that case.
> >
> > And in fact you can't do a new ptrace_attach, but if you're already
> > tracing the task when it execs the unreadable-but-executable file,
> > then the ptrace can continue.
> >
> > Just looking at the code, it appears 2.2 was the same way (though I
> > could be missing where it used to enforce that).
> >
> > So, is that intended? What exactly would we do about it if not?
> > Just refuse exec of a unreadable-but-executable file if we're
> > being traced?
>
> In common cap we drop the new capabilities if we are being ptraced.
> Look for brm->unsafe.
Yes - that isn't the issue. The issue is with a file to which
we have execute permission but not read. If user hallyn has two
terminals open, and terminal one does ./foo then terminal two
cannot do strace -f -p `pidof foo`. But user hallyn can do
strace -f -p ./foo and succeed.
So we refuse ptrace_attach to an existing process with dumpable
turned off, but a pre-existing ptrace attach isn't affected by
executing a file which causes dumpable to be unset.
It goes back to finding a way to figure out what is inside the
file when the installer obviously thought we shouldn't be able
to read the file.
Do we care? <shrug>
-serge
On Tue, Dec 29, 2009 at 10:35 PM, Eric W. Biederman
<[email protected]> wrote:
>
> If we can know that a process will never raise it's priveleges we can
> enable a lot of features that otherwise would be unsafe, because they
> could break assumptions of existing suid executables.
>
> To allow this to be used as a sand boxing feature also disable
> ptracing other executables without this new restriction.
>
> For the moment I have used a per thread flag because we are out of per
> process flags.
>
> To ensure all descendants get this flag I rely on the default copying
> of procss structures.
>
> The disabling of suid executables is exactly the same as MNT_NOSUID.
>
> This should be what we have been talking about in for disabling of
> suid exec. ?I choose not to use securebits as that interface requires
> privilege and assumes capabilities. ?This implementation is more basic
> than capabilities and only adds additional sanity checks when
> linux capabilities are not present.
>
> I attempt to ensure there are no mixed priveleges present, when we
> perform the disable so I don't need to handle or think about
> interactions with setreuid or capabilities in this code.
Is this sufficient for other security models such as selinux or
TOMOYO? Can processes in these models gain privileges through means
not restricted here?
Also, perhaps there should be a corresponding GET prctl?
"Serge E. Hallyn" <[email protected]> writes:
>> In common cap we drop the new capabilities if we are being ptraced.
>> Look for brm->unsafe.
>
> Yes - that isn't the issue.
Right. Sorry. I saw that we set unsafe and totally
missed that we don't act on it in that case.
> It goes back to finding a way to figure out what is inside the
> file when the installer obviously thought we shouldn't be able
> to read the file.
>
> Do we care? <shrug>
<shrug>
I expect two lines of testing bprm->unsafe and failing
at the right point would solve that.
Eric
Bryan Donlan <[email protected]> writes:
> Is this sufficient for other security models such as selinux or
> TOMOYO? Can processes in these models gain privileges through means
> not restricted here?
The LSM is primarily about returning -EPERM more often.
Except for the prctl and the capability hooks I am not aware
of anywhere a LSM can increase a processes capabilities.
> Also, perhaps there should be a corresponding GET prctl?
Probably for the final version.
Eric
On Tue, Dec 29, 2009 at 11:33 PM, Eric W. Biederman
<[email protected]> wrote:
> Bryan Donlan <[email protected]> writes:
>
>> Is this sufficient for other security models such as selinux or
>> TOMOYO? Can processes in these models gain privileges through means
>> not restricted here?
>
> The LSM is primarily about returning -EPERM more often.
> Except for the prctl and the capability hooks I am not aware
> of anywhere a LSM can increase a processes capabilities.
I'm more concerned about a case where a privilege that the LSM
currently denies is lifted by execing some executable - this is still
an increase in privilege, even though the LSM only adds additional
restrictions. That is:
1) Initial state: LSM denies access to /somefile (although normal
POSIX permissions would permit access)
2) Disable capability-gaining
3) Disable network access with proposed API
4) Exec some application, which is labeled in a way that permits
access to /somefile
5) Application fails to access the network, then does something to /somefile
I'm not entirely sure if step 4) can happen in any of the currently
existing LSMs - if it's not possible to gain privileges in them via a
suid-like mechanism, this isn't a problem, but it's something that
needs to be checked for.
Eric W. Biederman wrote:
>The problem with the disable_network semantics you want
>is that they allow you to perform a denial of service attack
>on privileged users. An unprivileged DOS attack is unsuitable
>for a general purpose feature in a general purpose kernel.
I'm not persuaded yet.
When you talk about DOS, let's be a bit more precise. disablenetwork
gives a way to deny setuid programs access to the network. It's not a
general-purpose DOS; it's denying access to the network only. And the
network is fundamentally unreliable. No security-critical mechanism
should be relying upon the availability of the network.
There are already a number of ways to deny service to the network.
Let me list a few:
* Limit the number of open file descriptors using rlimit,
open lots of file descriptors, and exec a setuid program.
* Flood the local network link.
* DOS the DNS servers (likely causing most connections to fail).
If there is a setuid-root program that fails catastrophically when the
network is unavailable, you've already got a serious problem -- and that
is true whether or not we introduce the disablenetwork service.
So while I certainly can't rule out the possibility that disablenetwork
might introduce minor issues, I think there are fundamental reasons to
be skeptical that disablenetwork will introduce serious new security
problems.
> Pavel Machek wrote:
> >>index 26a6b73..b48f021 100644
> >>--- a/kernel/sys.c
> >>+++ b/kernel/sys.c
> >>@@ -35,6 +35,7 @@
> >> #include <linux/cpu.h>
> >> #include <linux/ptrace.h>
> >> #include <linux/fs_struct.h>
> >>+#include <linux/prctl_network.h>
> >>
> >> #include <linux/compat.h>
> >> #include <linux/syscalls.h>
> >
> >Something seems to be wrong with whitespace here. Damaged patch?
>
> Nope; kernel/sys.c has a newline there:
>
> http://repo.or.cz/w/linux-2.6.git/blob/HEAD:/kernel/sys.c#l36
>
> Shall I remove it?
notice two spaces before include. something was definitely wrong there.
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Bryan Donlan <[email protected]> writes:
> On Tue, Dec 29, 2009 at 11:33 PM, Eric W. Biederman
> <[email protected]> wrote:
>> Bryan Donlan <[email protected]> writes:
>>
>>> Is this sufficient for other security models such as selinux or
>>> TOMOYO? Can processes in these models gain privileges through means
>>> not restricted here?
>>
>> The LSM is primarily about returning -EPERM more often.
>> Except for the prctl and the capability hooks I am not aware
>> of anywhere a LSM can increase a processes capabilities.
>
> I'm more concerned about a case where a privilege that the LSM
> currently denies is lifted by execing some executable - this is still
> an increase in privilege, even though the LSM only adds additional
> restrictions. That is:
>
> 1) Initial state: LSM denies access to /somefile (although normal
> POSIX permissions would permit access)
> 2) Disable capability-gaining
> 3) Disable network access with proposed API
> 4) Exec some application, which is labeled in a way that permits
> access to /somefile
> 5) Application fails to access the network, then does something to /somefile
>
> I'm not entirely sure if step 4) can happen in any of the currently
> existing LSMs - if it's not possible to gain privileges in them via a
> suid-like mechanism, this isn't a problem, but it's something that
> needs to be checked for.
A reasonable concern. When the glitches get worked out of this patch
I intend to allow much more dangerous things like unprivileged unsharing
of all of the namespaces, and unprivileged mounts.
It appears I missed a place where MNT_NOSUID was handled in selinux.
So I will be adding a bprm->nosuid field so I don't have to duplicate
the MNT_NOSUID check everywhere it is used.
I don't understand TOMOYO I think it is file based access control,
which suggests there is not a suid like mechanism.
Smack and selinux are label based. Selinux at least can switch labels
on exec, but it handles NOSUID already.
Looking a little farther if I assume that lsm implementations that
implement the set_creds hook need attention. Only selinux has
an interesting set_creds implementation and it handles nosuid already.
So I think we are ok.
Eric
If we can know that a process will never raise
it's priveleges we can enable a lot of features
that otherwise would be unsafe, because they
could break assumptions of existing suid executables.
To allow this to be used as a sand boxing feature
also disable ptracing other executables without
this new restriction.
For the moment I have used a per thread flag because
we are out of per process flags.
To ensure all descendants get this flag I rely on
the default copying of procss structures.
Added bprm->nosuid to make remove the need to add
duplicate error prone checks. This ensures that
the disabling of suid executables is exactly the
same as MNT_NOSUID.
Signed-off-by: Eric W. Biederman <[email protected]>
---
arch/x86/include/asm/thread_info.h | 2 ++
fs/exec.c | 6 ++++--
include/linux/binfmts.h | 1 +
include/linux/prctl.h | 2 ++
kernel/ptrace.c | 4 ++++
kernel/sys.c | 16 ++++++++++++++++
security/commoncap.c | 14 +++++++++++++-
security/selinux/hooks.c | 2 +-
8 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 375c917..e716203 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -82,6 +82,7 @@ struct thread_info {
#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
+#define TIF_NOSUID 9 /* suid exec permanently disabled */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
#define TIF_NOTSC 16 /* TSC is not accessible in userland */
@@ -107,6 +108,7 @@ struct thread_info {
#define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_NOSUID (1 << TIF_NOSUID)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
#define _TIF_NOTSC (1 << TIF_NOTSC)
diff --git a/fs/exec.c b/fs/exec.c
index 632b02e..5cba5ac 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1131,8 +1131,10 @@ int prepare_binprm(struct linux_binprm *bprm)
/* clear any previous set[ug]id data from a previous binary */
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();
-
- if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+ bprm->nosuid =
+ (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
+ test_tsk_thread_flag(current, TIF_NOSUID);
+ if (bprm->nosuid) {
/* Set-uid? */
if (mode & S_ISUID) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index cd4349b..c3b5a30 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -44,6 +44,7 @@ struct linux_binprm{
#ifdef __alpha__
unsigned int taso:1;
#endif
+ unsigned int nosuid:1; /* True if suid bits are ignored */
unsigned int recursion_depth;
struct file * file;
struct cred *cred; /* new credentials */
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index a3baeb2..acb3516 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -102,4 +102,6 @@
#define PR_MCE_KILL_GET 34
+#define PR_SET_NOSUID 35
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 23bd09c..b91040c 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
+ if (test_tsk_thread_flag(current, TIF_NOSUID) &&
+ !test_tsk_thread_flag(task, TIF_NOSUID))
+ return -EPERM;
+
return security_ptrace_access_check(task, mode);
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 26a6b73..1d1902a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1578,6 +1578,22 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
error = PR_MCE_KILL_DEFAULT;
break;
+ case PR_SET_NOSUID:
+ {
+ const struct cred *cred = current->cred;
+ error = -EINVAL;
+ if ( (cred->uid != cred->suid) ||
+ (cred->uid != cred->euid) ||
+ (cred->uid != cred->fsuid) ||
+ (cred->gid != cred->sgid) ||
+ (cred->gid != cred->egid) ||
+ (cred->gid != cred->fsgid) ||
+ (atomic_read(¤t->signal->count) != 1))
+ break;
+ error = 0;
+ set_tsk_thread_flag(current, TIF_NOSUID);
+ break;
+ }
default:
error = -EINVAL;
break;
diff --git a/security/commoncap.c b/security/commoncap.c
index f800fdb..28ab286 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
if (!file_caps_enabled)
return 0;
- if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
+ if (bprm->nosuid)
return 0;
dentry = dget(bprm->file->f_dentry);
@@ -869,6 +869,18 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
goto changed;
+ case PR_SET_NOSUID:
+ {
+ const struct cred *cred = current->cred;
+ error = -EINVAL;
+ /* Perform the capabilities checks */
+ if (!cap_isclear(cred->cap_permitted) ||
+ !cap_isclear(cred->cap_effective))
+ goto error;
+ /* Have the default perform the rest of the work. */
+ error = -ENOSYS;
+ goto error;
+ }
default:
/* No functionality available - continue with default */
error = -ENOSYS;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7a374c2..d14cd24 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
COMMON_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path = bprm->file->f_path;
- if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
+ if (bprm->nosid)
new_tsec->sid = old_tsec->sid;
if (new_tsec->sid == old_tsec->sid) {
--
1.6.5.2.143.g8cc62
Eric,
I'm not clear why capabilities need to be manipulated by this feature
(the pure capability support already has a feature for disabling
privilege and blocking unsafe, or insufficient privilege, execution).
Perhaps I'm just unclear what features can be more safely enabled with
this in effect - that is, your description suggests that this is why
you are doing this, but leaves it unclear what they are. Could you
take a few moments to enumerate some of them?
Thanks
Andrew
On Wed, Dec 30, 2009 at 4:49 AM, Eric W. Biederman
<[email protected]> wrote:
>
> If we can know that a process will never raise
> it's priveleges we can enable a lot of features
> that otherwise would be unsafe, because they
> could break assumptions of existing suid executables.
>
> To allow this to be used as a sand boxing feature
> also disable ptracing other executables without
> this new restriction.
>
> For the moment I have used a per thread flag because
> we are out of per process flags.
>
> To ensure all descendants get this flag I rely on
> the default copying of procss structures.
>
> Added bprm->nosuid to make remove the need to add
> duplicate error prone checks. ?This ensures that
> the disabling of suid executables is exactly the
> same as MNT_NOSUID.
>
> Signed-off-by: Eric W. Biederman <[email protected]>
> ---
> ?arch/x86/include/asm/thread_info.h | ? ?2 ++
> ?fs/exec.c ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ?6 ++++--
> ?include/linux/binfmts.h ? ? ? ? ? ?| ? ?1 +
> ?include/linux/prctl.h ? ? ? ? ? ? ?| ? ?2 ++
> ?kernel/ptrace.c ? ? ? ? ? ? ? ? ? ?| ? ?4 ++++
> ?kernel/sys.c ? ? ? ? ? ? ? ? ? ? ? | ? 16 ++++++++++++++++
> ?security/commoncap.c ? ? ? ? ? ? ? | ? 14 +++++++++++++-
> ?security/selinux/hooks.c ? ? ? ? ? | ? ?2 +-
> ?8 files changed, 43 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
> index 375c917..e716203 100644
> --- a/arch/x86/include/asm/thread_info.h
> +++ b/arch/x86/include/asm/thread_info.h
> @@ -82,6 +82,7 @@ struct thread_info {
> ?#define TIF_SYSCALL_EMU ? ? ? ? ? ? ? ?6 ? ? ? /* syscall emulation active */
> ?#define TIF_SYSCALL_AUDIT ? ? ?7 ? ? ? /* syscall auditing active */
> ?#define TIF_SECCOMP ? ? ? ? ? ?8 ? ? ? /* secure computing */
> +#define TIF_NOSUID ? ? ? ? ? ? 9 ? ? ? /* suid exec permanently disabled */
> ?#define TIF_MCE_NOTIFY ? ? ? ? 10 ? ? ?/* notify userspace of an MCE */
> ?#define TIF_USER_RETURN_NOTIFY 11 ? ? ?/* notify kernel of userspace return */
> ?#define TIF_NOTSC ? ? ? ? ? ? ?16 ? ? ?/* TSC is not accessible in userland */
> @@ -107,6 +108,7 @@ struct thread_info {
> ?#define _TIF_SYSCALL_EMU ? ? ? (1 << TIF_SYSCALL_EMU)
> ?#define _TIF_SYSCALL_AUDIT ? ? (1 << TIF_SYSCALL_AUDIT)
> ?#define _TIF_SECCOMP ? ? ? ? ? (1 << TIF_SECCOMP)
> +#define _TIF_NOSUID ? ? ? ? ? ?(1 << TIF_NOSUID)
> ?#define _TIF_MCE_NOTIFY ? ? ? ? ? ? ? ?(1 << TIF_MCE_NOTIFY)
> ?#define _TIF_USER_RETURN_NOTIFY ? ? ? ?(1 << TIF_USER_RETURN_NOTIFY)
> ?#define _TIF_NOTSC ? ? ? ? ? ? (1 << TIF_NOTSC)
> diff --git a/fs/exec.c b/fs/exec.c
> index 632b02e..5cba5ac 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1131,8 +1131,10 @@ int prepare_binprm(struct linux_binprm *bprm)
> ? ? ? ?/* clear any previous set[ug]id data from a previous binary */
> ? ? ? ?bprm->cred->euid = current_euid();
> ? ? ? ?bprm->cred->egid = current_egid();
> -
> - ? ? ? if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
> + ? ? ? bprm->nosuid =
> + ? ? ? ? ? ? ? (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
> + ? ? ? ? ? ? ? test_tsk_thread_flag(current, TIF_NOSUID);
> + ? ? ? if (bprm->nosuid) {
> ? ? ? ? ? ? ? ?/* Set-uid? */
> ? ? ? ? ? ? ? ?if (mode & S_ISUID) {
> ? ? ? ? ? ? ? ? ? ? ? ?bprm->per_clear |= PER_CLEAR_ON_SETID;
> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
> index cd4349b..c3b5a30 100644
> --- a/include/linux/binfmts.h
> +++ b/include/linux/binfmts.h
> @@ -44,6 +44,7 @@ struct linux_binprm{
> ?#ifdef __alpha__
> ? ? ? ?unsigned int taso:1;
> ?#endif
> + ? ? ? unsigned int nosuid:1; ?/* True if suid bits are ignored */
> ? ? ? ?unsigned int recursion_depth;
> ? ? ? ?struct file * file;
> ? ? ? ?struct cred *cred; ? ? ?/* new credentials */
> diff --git a/include/linux/prctl.h b/include/linux/prctl.h
> index a3baeb2..acb3516 100644
> --- a/include/linux/prctl.h
> +++ b/include/linux/prctl.h
> @@ -102,4 +102,6 @@
>
> ?#define PR_MCE_KILL_GET 34
>
> +#define PR_SET_NOSUID ?35
> +
> ?#endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/ptrace.c b/kernel/ptrace.c
> index 23bd09c..b91040c 100644
> --- a/kernel/ptrace.c
> +++ b/kernel/ptrace.c
> @@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
> ? ? ? ?if (!dumpable && !capable(CAP_SYS_PTRACE))
> ? ? ? ? ? ? ? ?return -EPERM;
>
> + ? ? ? if (test_tsk_thread_flag(current, TIF_NOSUID) &&
> + ? ? ? ? ? !test_tsk_thread_flag(task, TIF_NOSUID))
> + ? ? ? ? ? ? ? return -EPERM;
> +
> ? ? ? ?return security_ptrace_access_check(task, mode);
> ?}
>
> diff --git a/kernel/sys.c b/kernel/sys.c
> index 26a6b73..1d1902a 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -1578,6 +1578,22 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> ? ? ? ? ? ? ? ? ? ? ? ?else
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?error = PR_MCE_KILL_DEFAULT;
> ? ? ? ? ? ? ? ? ? ? ? ?break;
> + ? ? ? ? ? ? ? case PR_SET_NOSUID:
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? ? ? ? const struct cred *cred = current->cred;
> + ? ? ? ? ? ? ? ? ? ? ? error = -EINVAL;
> + ? ? ? ? ? ? ? ? ? ? ? if ( ? ?(cred->uid != cred->suid) ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (cred->uid != cred->euid) ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (cred->uid != cred->fsuid) ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (cred->gid != cred->sgid) ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (cred->gid != cred->egid) ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (cred->gid != cred->fsgid) ||
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (atomic_read(¤t->signal->count) != 1))
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? ? ? ? ? error = 0;
> + ? ? ? ? ? ? ? ? ? ? ? set_tsk_thread_flag(current, TIF_NOSUID);
> + ? ? ? ? ? ? ? ? ? ? ? break;
> + ? ? ? ? ? ? ? }
> ? ? ? ? ? ? ? ?default:
> ? ? ? ? ? ? ? ? ? ? ? ?error = -EINVAL;
> ? ? ? ? ? ? ? ? ? ? ? ?break;
> diff --git a/security/commoncap.c b/security/commoncap.c
> index f800fdb..28ab286 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
> ? ? ? ?if (!file_caps_enabled)
> ? ? ? ? ? ? ? ?return 0;
>
> - ? ? ? if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
> + ? ? ? if (bprm->nosuid)
> ? ? ? ? ? ? ? ?return 0;
>
> ? ? ? ?dentry = dget(bprm->file->f_dentry);
> @@ -869,6 +869,18 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> ? ? ? ? ? ? ? ? ? ? ? ?new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
> ? ? ? ? ? ? ? ?goto changed;
>
> + ? ? ? case PR_SET_NOSUID:
> + ? ? ? {
> + ? ? ? ? ? ? ? const struct cred *cred = current->cred;
> + ? ? ? ? ? ? ? error = -EINVAL;
> + ? ? ? ? ? ? ? /* Perform the capabilities checks */
> + ? ? ? ? ? ? ? if (!cap_isclear(cred->cap_permitted) ||
> + ? ? ? ? ? ? ? ? ? !cap_isclear(cred->cap_effective))
> + ? ? ? ? ? ? ? ? ? ? ? goto error;
> + ? ? ? ? ? ? ? /* Have the default perform the rest of the work. */
> + ? ? ? ? ? ? ? error = -ENOSYS;
> + ? ? ? ? ? ? ? goto error;
> + ? ? ? }
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?/* No functionality available - continue with default */
> ? ? ? ? ? ? ? ?error = -ENOSYS;
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 7a374c2..d14cd24 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
> ? ? ? ?COMMON_AUDIT_DATA_INIT(&ad, FS);
> ? ? ? ?ad.u.fs.path = bprm->file->f_path;
>
> - ? ? ? if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
> + ? ? ? if (bprm->nosid)
> ? ? ? ? ? ? ? ?new_tsec->sid = old_tsec->sid;
>
> ? ? ? ?if (new_tsec->sid == old_tsec->sid) {
> --
> 1.6.5.2.143.g8cc62
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
On Wed, 30 Dec 2009 07:24:11 GMT, David Wagner said:
> So while I certainly can't rule out the possibility that disablenetwork
> might introduce minor issues, I think there are fundamental reasons to
> be skeptical that disablenetwork will introduce serious new security
> problems.
I have to agree with David here - although there's many failure modes if
a security-relevant program wants to talk to the network, they're all already
prone to stuffage by an attacker.
Biggest danger is probably programs that rashly assume that 127.0.0.1 is
reachable. Seen a lot of *that* in my day (no, don't ask how I found out ;)
Quoting Eric W. Biederman ([email protected]):
> "Serge E. Hallyn" <[email protected]> writes:
>
> >> In common cap we drop the new capabilities if we are being ptraced.
> >> Look for brm->unsafe.
> >
> > Yes - that isn't the issue.
>
> Right. Sorry. I saw that we set unsafe and totally
> missed that we don't act on it in that case.
>
> > It goes back to finding a way to figure out what is inside the
> > file when the installer obviously thought we shouldn't be able
> > to read the file.
> >
> > Do we care? <shrug>
>
> <shrug>
>
> I expect two lines of testing bprm->unsafe and failing
> at the right point would solve that.
But what is the right response? Prevent excecution? Stop the
tracer? Enter some one-shot mode where the whole exec appears
as one step, but tracing continues if execution continues on a
dumpable file?
-serge
Quoting Eric W. Biederman ([email protected]):
>
> If we can know that a process will never raise
> it's priveleges we can enable a lot of features
> that otherwise would be unsafe, because they
> could break assumptions of existing suid executables.
>
> To allow this to be used as a sand boxing feature
> also disable ptracing other executables without
> this new restriction.
>
> For the moment I have used a per thread flag because
> we are out of per process flags.
>
> To ensure all descendants get this flag I rely on
> the default copying of procss structures.
>
> Added bprm->nosuid to make remove the need to add
> duplicate error prone checks. This ensures that
> the disabling of suid executables is exactly the
> same as MNT_NOSUID.
>
> Signed-off-by: Eric W. Biederman <[email protected]>
> ---
> arch/x86/include/asm/thread_info.h | 2 ++
> fs/exec.c | 6 ++++--
> include/linux/binfmts.h | 1 +
> include/linux/prctl.h | 2 ++
> kernel/ptrace.c | 4 ++++
> kernel/sys.c | 16 ++++++++++++++++
> security/commoncap.c | 14 +++++++++++++-
> security/selinux/hooks.c | 2 +-
> 8 files changed, 43 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
> index 375c917..e716203 100644
> --- a/arch/x86/include/asm/thread_info.h
> +++ b/arch/x86/include/asm/thread_info.h
> @@ -82,6 +82,7 @@ struct thread_info {
> #define TIF_SYSCALL_EMU 6 /* syscall emulation active */
> #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
> #define TIF_SECCOMP 8 /* secure computing */
> +#define TIF_NOSUID 9 /* suid exec permanently disabled */
> #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
> #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
> #define TIF_NOTSC 16 /* TSC is not accessible in userland */
> @@ -107,6 +108,7 @@ struct thread_info {
> #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
> #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
> #define _TIF_SECCOMP (1 << TIF_SECCOMP)
> +#define _TIF_NOSUID (1 << TIF_NOSUID)
> #define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
> #define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
> #define _TIF_NOTSC (1 << TIF_NOTSC)
> diff --git a/fs/exec.c b/fs/exec.c
> index 632b02e..5cba5ac 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1131,8 +1131,10 @@ int prepare_binprm(struct linux_binprm *bprm)
> /* clear any previous set[ug]id data from a previous binary */
> bprm->cred->euid = current_euid();
> bprm->cred->egid = current_egid();
> -
> - if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
> + bprm->nosuid =
> + (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
> + test_tsk_thread_flag(current, TIF_NOSUID);
> + if (bprm->nosuid) {
> /* Set-uid? */
> if (mode & S_ISUID) {
> bprm->per_clear |= PER_CLEAR_ON_SETID;
> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
> index cd4349b..c3b5a30 100644
> --- a/include/linux/binfmts.h
> +++ b/include/linux/binfmts.h
> @@ -44,6 +44,7 @@ struct linux_binprm{
> #ifdef __alpha__
> unsigned int taso:1;
> #endif
> + unsigned int nosuid:1; /* True if suid bits are ignored */
> unsigned int recursion_depth;
> struct file * file;
> struct cred *cred; /* new credentials */
> diff --git a/include/linux/prctl.h b/include/linux/prctl.h
> index a3baeb2..acb3516 100644
> --- a/include/linux/prctl.h
> +++ b/include/linux/prctl.h
> @@ -102,4 +102,6 @@
>
> #define PR_MCE_KILL_GET 34
>
> +#define PR_SET_NOSUID 35
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/ptrace.c b/kernel/ptrace.c
> index 23bd09c..b91040c 100644
> --- a/kernel/ptrace.c
> +++ b/kernel/ptrace.c
> @@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
> if (!dumpable && !capable(CAP_SYS_PTRACE))
> return -EPERM;
>
> + if (test_tsk_thread_flag(current, TIF_NOSUID) &&
> + !test_tsk_thread_flag(task, TIF_NOSUID))
> + return -EPERM;
> +
> return security_ptrace_access_check(task, mode);
> }
>
> diff --git a/kernel/sys.c b/kernel/sys.c
> index 26a6b73..1d1902a 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -1578,6 +1578,22 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> else
> error = PR_MCE_KILL_DEFAULT;
> break;
> + case PR_SET_NOSUID:
> + {
> + const struct cred *cred = current->cred;
> + error = -EINVAL;
> + if ( (cred->uid != cred->suid) ||
> + (cred->uid != cred->euid) ||
> + (cred->uid != cred->fsuid) ||
> + (cred->gid != cred->sgid) ||
> + (cred->gid != cred->egid) ||
> + (cred->gid != cred->fsgid) ||
> + (atomic_read(¤t->signal->count) != 1))
> + break;
> + error = 0;
> + set_tsk_thread_flag(current, TIF_NOSUID);
> + break;
> + }
> default:
> error = -EINVAL;
> break;
> diff --git a/security/commoncap.c b/security/commoncap.c
> index f800fdb..28ab286 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
> if (!file_caps_enabled)
> return 0;
>
> - if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
> + if (bprm->nosuid)
> return 0;
>
> dentry = dget(bprm->file->f_dentry);
> @@ -869,6 +869,18 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
> goto changed;
>
> + case PR_SET_NOSUID:
> + {
> + const struct cred *cred = current->cred;
> + error = -EINVAL;
Should this be -EPERM? not sure...
> + /* Perform the capabilities checks */
> + if (!cap_isclear(cred->cap_permitted) ||
> + !cap_isclear(cred->cap_effective))
No need to check cap_effective, as no bits can be there which are not
in cap_permitted.
To be honest, I don't think there is much reason to not have this
check done in the main sys_prctl(0 - capabilities themselves are not
optional in the kernel, while cap_task_prctl() is. So you are setting
us up to have cases where say an apparmor user can call this with uid
0 and/or active capabilities.
> + goto error;
> + /* Have the default perform the rest of the work. */
> + error = -ENOSYS;
> + goto error;
> + }
> default:
> /* No functionality available - continue with default */
> error = -ENOSYS;
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 7a374c2..d14cd24 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
> COMMON_AUDIT_DATA_INIT(&ad, FS);
> ad.u.fs.path = bprm->file->f_path;
>
> - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
> + if (bprm->nosid)
typo - nosuid?
> new_tsec->sid = old_tsec->sid;
>
> if (new_tsec->sid == old_tsec->sid) {
> --
> 1.6.5.2.143.g8cc62
Thanks, I think this looks good.
-serge
Quoting Andrew G. Morgan ([email protected]):
> Eric,
>
> I'm not clear why capabilities need to be manipulated by this feature
> (the pure capability support already has a feature for disabling
> privilege and blocking unsafe, or insufficient privilege, execution).
Not entirely - this option would also prevent file capabilities from
being honored.
> Perhaps I'm just unclear what features can be more safely enabled with
> this in effect - that is, your description suggests that this is why
> you are doing this, but leaves it unclear what they are. Could you
> take a few moments to enumerate some of them?
There are two desirable features which are at the moment unsafe for
unprivileged users, because it allows them to fool privileged (setuid
or bearing file capabilities) programs. One is to unconditionally
restrict privilege to yourself and all your descendents. The recent
disablenetwork patchset is one example. The other is the ability to
make substantial changes to your environment in a private namespace.
A private namespace can protect already-running privileged program,
but cannot protect privilege-bearing binaries. Unless we prevent
them from bearing privilege. Which is what this patch does.
-serge
Quoting Michael Stone ([email protected]):
> Daniel Bernstein has observed [1] that security-conscious userland processes
> may benefit from the ability to irrevocably remove their ability to create,
> bind, connect to, or send messages except in the case of previously connected
> sockets or AF_UNIX filesystem sockets.
>
> This patch provides
>
> * a new configuration option named CONFIG_SECURITY_DISABLENETWORK,
> * a new prctl option-pair (PR_SET_NETWORK, PR_GET_NETWORK),
> * a new prctl(PR_SET_NETWORK) flag named PR_NETWORK_OFF, and
> * a new task_struct flags field named "network"
>
> Signed-off-by: Michael Stone <[email protected]>
> ---
> include/linux/prctl.h | 7 +++++
> include/linux/prctl_network.h | 7 +++++
> include/linux/sched.h | 4 +++
> kernel/sys.c | 53 +++++++++++++++++++++++++++++++++++++++++
> security/Kconfig | 11 ++++++++
> 5 files changed, 82 insertions(+), 0 deletions(-)
> create mode 100644 include/linux/prctl_network.h
>
> diff --git a/include/linux/prctl.h b/include/linux/prctl.h
> index a3baeb2..4eb4110 100644
> --- a/include/linux/prctl.h
> +++ b/include/linux/prctl.h
> @@ -102,4 +102,11 @@
>
> #define PR_MCE_KILL_GET 34
>
> +/* 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
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/include/linux/prctl_network.h b/include/linux/prctl_network.h
> new file mode 100644
> index 0000000..d18f8cb
> --- /dev/null
> +++ b/include/linux/prctl_network.h
> @@ -0,0 +1,7 @@
> +#ifndef _LINUX_PRCTL_NETWORK_H
> +#define _LINUX_PRCTL_NETWORK_H
> +
> +extern long prctl_get_network(unsigned long*);
> +extern long prctl_set_network(unsigned long*);
> +
> +#endif /* _LINUX_PRCTL_NETWORK_H */
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index f2f842d..6fcaef8 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1403,6 +1403,10 @@ struct task_struct {
> #endif
> seccomp_t seccomp;
>
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + unsigned long network;
> +#endif
> +
> /* Thread group tracking */
> u32 parent_exec_id;
> u32 self_exec_id;
> diff --git a/kernel/sys.c b/kernel/sys.c
> index 26a6b73..b48f021 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -35,6 +35,7 @@
> #include <linux/cpu.h>
> #include <linux/ptrace.h>
> #include <linux/fs_struct.h>
> +#include <linux/prctl_network.h>
>
> #include <linux/compat.h>
> #include <linux/syscalls.h>
> @@ -1578,6 +1579,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> else
> error = PR_MCE_KILL_DEFAULT;
> break;
> + case PR_SET_NETWORK:
> + error = prctl_set_network((unsigned long*)arg2);
> + break;
> + case PR_GET_NETWORK:
> + error = prctl_get_network((unsigned long*)arg2);
> + break;
> default:
> error = -EINVAL;
> break;
> @@ -1585,6 +1592,52 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> return error;
> }
>
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> +
> +long prctl_get_network(unsigned long* user)
> +{
> + return put_user(current->network, user);
> +}
> +
> +long prctl_set_network(unsigned long* user)
> +{
> + unsigned long network_flags;
> + long ret;
> +
> + ret = -EFAULT;
> + if (copy_from_user(&network_flags, user, sizeof(network_flags)))
> + goto out;
Do you expect to pass more than 32 bits through this interface at
some point? If not, how about avoiding the copy, and just passing
a long into prctl_set_network(), and having prctl_get_network
return 0 or a positive value indicating the active bits?
So
long prctl_get_network(void)
{
return current->network;
}
long prctl_set_network(unsigned long network_flags)
{
if (network_flags & ~PR_NETWORK_ALL_FLAGS)
return -EINVAL;
if (current->network & ~network_flags)
return -EPERM;
current->network = network_flags;
return 0;
}
> + ret = -EINVAL;
> + if (network_flags & ~PR_NETWORK_ALL_FLAGS)
> + goto out;
> +
> + /* only dropping access is permitted */
> + ret = -EPERM;
> + if (current->network & ~network_flags)
whitespace.
> + goto out;
> +
> + current->network = network_flags;
> + ret = 0;
> +
> +out:
> + return ret;
> +}
> +
> +#else
> +
> +long prctl_get_network(unsigned long* user)
> +{
> + return -ENOSYS;
> +}
> +
> +long prctl_set_network(unsigned long* user)
> +{
> + return -ENOSYS;
> +}
> +
> +#endif /* ! CONFIG_SECURITY_DISABLENETWORK */
> +
> SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
> struct getcpu_cache __user *, unused)
> {
> diff --git a/security/Kconfig b/security/Kconfig
> index 226b955..afd7f76 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -137,6 +137,17 @@ config LSM_MMAP_MIN_ADDR
> this low address space will need the permission specific to the
> systems running LSM.
>
> +config SECURITY_DISABLENETWORK
> + bool "Socket and networking discretionary access control"
> + depends on SECURITY_NETWORK
> + help
> + This enables processes to drop networking privileges via
> + prctl(PR_SET_NETWORK, PR_NETWORK_OFF).
> +
> + See Documentation/disablenetwork.txt for more information.
> +
> + If you are unsure how to answer this question, answer N.
> +
> source security/selinux/Kconfig
> source security/smack/Kconfig
> source security/tomoyo/Kconfig
> --
> 1.6.6.rc2
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Michael Stone ([email protected]):
> Implement security_* hooks for socket_create, socket_bind, socket_connect,
> socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
> process with networking restrictions. Exempt AF_UNIX sockets.
>
> Signed-off-by: Michael Stone <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
> ---
> include/linux/disablenetwork.h | 22 +++++++++++
> security/Makefile | 1 +
> security/disablenetwork.c | 73 ++++++++++++++++++++++++++++++++++++++
> security/security.c | 76 +++++++++++++++++++++++++++++++++++++---
> 4 files changed, 167 insertions(+), 5 deletions(-)
> create mode 100644 include/linux/disablenetwork.h
> create mode 100644 security/disablenetwork.c
>
> diff --git a/include/linux/disablenetwork.h b/include/linux/disablenetwork.h
> new file mode 100644
> index 0000000..8a7bcc2
> --- /dev/null
> +++ b/include/linux/disablenetwork.h
> @@ -0,0 +1,22 @@
> +#ifndef __LINUX_DISABLENETWORK_H
> +#define __LINUX_DISABLENETWORK_H
> +
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> +
> +int disablenetwork_security_socket_create(int family, int type,
> + int protocol, int kern);
Bleh, I think disablenetwork_socket_create() is long enough :)
> +int disablenetwork_security_socket_bind(struct socket *sock,
> + struct sockaddr *address,
> + int addrlen);
> +int disablenetwork_security_socket_connect(struct socket *sock,
> + struct sockaddr *address,
> + int addrlen);
> +int disablenetwork_security_socket_sendmsg(struct socket *sock,
> + struct msghdr *msg,
> + int size);
> +int disablenetwork_security_ptrace_access_check(struct task_struct *child,
> + unsigned int mode);
> +
> +#endif /* CONFIG_SECURITY_DISABLENETWORK */
> +
> +#endif /* ! __LINUX_DISABLENETWORK_H */
> diff --git a/security/Makefile b/security/Makefile
> index da20a19..2f23b60 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
> obj-$(CONFIG_AUDIT) += lsm_audit.o
> obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
> obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
> +obj-$(CONFIG_SECURITY_DISABLENETWORK) += disablenetwork.o
>
> # Object integrity file lists
> subdir-$(CONFIG_IMA) += integrity/ima
> diff --git a/security/disablenetwork.c b/security/disablenetwork.c
> new file mode 100644
> index 0000000..f45ddfc
> --- /dev/null
> +++ b/security/disablenetwork.c
> @@ -0,0 +1,73 @@
> +/*
> + * disablenetwork security hooks.
> + *
> + * Copyright (C) 2008-2009 Michael Stone <[email protected]>
> + *
> + * Implements the disablenetwork discretionary access control logic underlying
> + * the prctl(PRCTL_SET_NETWORK, PR_NETWORK_OFF) interface.
> + *
> + * See Documentation/disablenetwork.txt for more information.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation, version 2 of the
> + * License.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/sched.h>
> +#include <net/sock.h>
> +#include <linux/socket.h>
> +#include <linux/disablenetwork.h>
> +
> +static inline int maybe_allow(void)
> +{
> + if (current->network)
> + return -EPERM;
> + return 0;
> +}
> +
> +int disablenetwork_security_socket_create(int family, int type,
> + int protocol, int kern)
> +{
> + if (family == AF_UNIX)
> + return 0;
> + return maybe_allow();
> +}
> +
> +int disablenetwork_security_socket_bind(struct socket * sock,
> + struct sockaddr * address,
> + int addrlen)
> +{
> + if (address->sa_family == AF_UNIX)
> + return 0;
> + return maybe_allow();
> +}
> +
> +int disablenetwork_security_socket_connect(struct socket * sock,
> + struct sockaddr * address,
> + int addrlen)
> +{
> + if (address->sa_family == AF_UNIX)
> + return 0;
> + return maybe_allow();
> +}
> +
> +int disablenetwork_security_socket_sendmsg(struct socket * sock,
> + struct msghdr * msg, int size)
> +{
> + if (sock->sk->sk_family != PF_UNIX &&
> + current->network &&
> + (msg->msg_name != NULL || msg->msg_namelen != 0))
> + return -EPERM;
> + return 0;
> +}
> +
> +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)
> + return -EPERM;
> + return 0;
> +}
> diff --git a/security/security.c b/security/security.c
> index 24e060b..40ac615 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -17,6 +17,7 @@
> #include <linux/kernel.h>
> #include <linux/security.h>
> #include <linux/ima.h>
> +#include <linux/disablenetwork.h>
>
> /* Boot-time LSM user choice */
> static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
> @@ -130,7 +131,20 @@ int register_security(struct security_operations *ops)
>
> int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
> {
> - return security_ops->ptrace_access_check(child, mode);
> + int ret = 0;
> +
> + ret = security_ops->ptrace_access_check(child, mode);
> + if (ret)
> + goto out;
> +
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + ret = disablenetwork_security_ptrace_access_check(child, mode);
> + if (ret)
> + goto out;
> +#endif
> +
> +out:
> + return ret;
> }
>
> int security_ptrace_traceme(struct task_struct *parent)
> @@ -1054,7 +1068,20 @@ EXPORT_SYMBOL(security_unix_may_send);
>
> int security_socket_create(int family, int type, int protocol, int kern)
> {
> - return security_ops->socket_create(family, type, protocol, kern);
> + int ret = 0;
> +
> + ret = security_ops->socket_create(family, type, protocol, kern);
> + if (ret)
> + goto out;
> +
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + ret = disablenetwork_security_socket_create(family, type, protocol, kern);
> + if (ret)
> + goto out;
> +#endif
> +
> +out:
> + return ret;
> }
>
> int security_socket_post_create(struct socket *sock, int family,
> @@ -1066,12 +1093,38 @@ int security_socket_post_create(struct socket *sock, int family,
>
> int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
> {
> - return security_ops->socket_bind(sock, address, addrlen);
> + int ret = 0;
> +
> + ret = security_ops->socket_bind(sock, address, addrlen);
> + if (ret)
> + goto out;
> +
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + ret = disablenetwork_security_socket_bind(sock, address, addrlen);
> + if (ret)
> + goto out;
> +#endif
> +
> +out:
> + return ret;
> }
>
> int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
> {
> - return security_ops->socket_connect(sock, address, addrlen);
> + int ret = 0;
> +
> + ret = security_ops->socket_connect(sock, address, addrlen);
> + if (ret)
> + goto out;
> +
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + ret = disablenetwork_security_socket_connect(sock, address, addrlen);
> + if (ret)
> + goto out;
> +#endif
> +
> +out:
> + return ret;
> }
>
> int security_socket_listen(struct socket *sock, int backlog)
> @@ -1086,7 +1139,20 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
>
> int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
> {
> - return security_ops->socket_sendmsg(sock, msg, size);
> + int ret = 0;
> +
> + ret = security_ops->socket_sendmsg(sock, msg, size);
> + if (ret)
> + goto out;
> +
> +#ifdef CONFIG_SECURITY_DISABLENETWORK
> + ret = disablenetwork_security_socket_sendmsg(sock, msg, size);
> + if (ret)
> + goto out;
> +#endif
> +
> +out:
> + return ret;
> }
>
> int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
> --
> 1.6.6.rc2
"Serge E. Hallyn" <[email protected]> writes:
> Quoting Andrew G. Morgan ([email protected]):
>> Eric,
>>
>> I'm not clear why capabilities need to be manipulated by this feature
>> (the pure capability support already has a feature for disabling
>> privilege and blocking unsafe, or insufficient privilege, execution).
>
> Not entirely - this option would also prevent file capabilities from
> being honored.
All my patch does is verify the caller doesn't have privilege.
>> Perhaps I'm just unclear what features can be more safely enabled with
>> this in effect - that is, your description suggests that this is why
>> you are doing this, but leaves it unclear what they are. Could you
>> take a few moments to enumerate some of them?
>
> There are two desirable features which are at the moment unsafe for
> unprivileged users, because it allows them to fool privileged (setuid
> or bearing file capabilities) programs. One is to unconditionally
> restrict privilege to yourself and all your descendents. The recent
> disablenetwork patchset is one example. The other is the ability to
> make substantial changes to your environment in a private namespace.
> A private namespace can protect already-running privileged program,
> but cannot protect privilege-bearing binaries. Unless we prevent
> them from bearing privilege. Which is what this patch does.
Effectively by ensuring privileges can not be raised this removes
the set of circumstances that lead to the sendmail capabilities bug.
So any kernel feature that requires capabilities only because not
doing so would break backwards compatibility with suid applications.
This includes namespace manipulation, like plan 9.
This includes unsharing pid and network and sysvipc namespaces.
There are probably other useful but currently root only features
that this will allow to be used by unprivileged processes, that
I am not aware of.
In addition to the fact that knowing privileges can not be escalated
by a process is a good feature all by itself. Run this in a chroot
and the programs will never be able to gain root access even if
there are suid binaries available for them to execute.
Eric
Quoting Eric W. Biederman ([email protected]):
> "Serge E. Hallyn" <[email protected]> writes:
>
> > Quoting Andrew G. Morgan ([email protected]):
> >> Eric,
> >>
> >> I'm not clear why capabilities need to be manipulated by this feature
> >> (the pure capability support already has a feature for disabling
> >> privilege and blocking unsafe, or insufficient privilege, execution).
> >
> > Not entirely - this option would also prevent file capabilities from
> > being honored.
>
> All my patch does is verify the caller doesn't have privilege.
No, you shortcut security/commoncap.c:get_file_caps() if (bprm->nosuid),
which is set if test_tsk_thread_flag(current, TIF_NOSUID) at exec.
So if we're in this new no-suid mode, then file capabilities are not
honored.
Which is the right thing to do.
> >> Perhaps I'm just unclear what features can be more safely enabled with
> >> this in effect - that is, your description suggests that this is why
> >> you are doing this, but leaves it unclear what they are. Could you
> >> take a few moments to enumerate some of them?
> >
> > There are two desirable features which are at the moment unsafe for
> > unprivileged users, because it allows them to fool privileged (setuid
> > or bearing file capabilities) programs. One is to unconditionally
> > restrict privilege to yourself and all your descendents. The recent
> > disablenetwork patchset is one example. The other is the ability to
> > make substantial changes to your environment in a private namespace.
> > A private namespace can protect already-running privileged program,
> > but cannot protect privilege-bearing binaries. Unless we prevent
> > them from bearing privilege. Which is what this patch does.
>
> Effectively by ensuring privileges can not be raised this removes
> the set of circumstances that lead to the sendmail capabilities bug.
>
> So any kernel feature that requires capabilities only because not
> doing so would break backwards compatibility with suid applications.
> This includes namespace manipulation, like plan 9.
> This includes unsharing pid and network and sysvipc namespaces.
>
> There are probably other useful but currently root only features
> that this will allow to be used by unprivileged processes, that
> I am not aware of.
>
> In addition to the fact that knowing privileges can not be escalated
> by a process is a good feature all by itself. Run this in a chroot
> and the programs will never be able to gain root access even if
> there are suid binaries available for them to execute.
>
> Eric
"Serge E. Hallyn" <[email protected]> writes:
>> @@ -869,6 +869,18 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
>> new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
>> goto changed;
>>
>> + case PR_SET_NOSUID:
>> + {
>> + const struct cred *cred = current->cred;
>> + error = -EINVAL;
>
> Should this be -EPERM? not sure...
I intended -EINVAL to say it is simply a set of initial conditions
that are not supported today. But could be supported if someone
does the audit, and found there are no security issues.
>> + /* Perform the capabilities checks */
>> + if (!cap_isclear(cred->cap_permitted) ||
>> + !cap_isclear(cred->cap_effective))
>
> No need to check cap_effective, as no bits can be there which are not
> in cap_permitted.
>
> To be honest, I don't think there is much reason to not have this
> check done in the main sys_prctl(0 - capabilities themselves are not
> optional in the kernel, while cap_task_prctl() is. So you are setting
> us up to have cases where say an apparmor user can call this with uid
> 0 and/or active capabilities.
Sounds fine to me. I had noticed all of the capabilities checks were
off in their own file, so I had tried to maintain that. But you are
right we can't remove capabilities so splitting the code like this only
obfuscates it.
>> @@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
>> COMMON_AUDIT_DATA_INIT(&ad, FS);
>> ad.u.fs.path = bprm->file->f_path;
>>
>> - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
>> + if (bprm->nosid)
>
> typo - nosuid?
Yep.
Eric
"Serge E. Hallyn" <[email protected]> writes:
> Quoting Eric W. Biederman ([email protected]):
>> "Serge E. Hallyn" <[email protected]> writes:
>>
>> >> In common cap we drop the new capabilities if we are being ptraced.
>> >> Look for brm->unsafe.
>> >
>> > Yes - that isn't the issue.
>>
>> Right. Sorry. I saw that we set unsafe and totally
>> missed that we don't act on it in that case.
>>
>> > It goes back to finding a way to figure out what is inside the
>> > file when the installer obviously thought we shouldn't be able
>> > to read the file.
>> >
>> > Do we care? <shrug>
>>
>> <shrug>
>>
>> I expect two lines of testing bprm->unsafe and failing
>> at the right point would solve that.
>
> But what is the right response? Prevent excecution? Stop the
> tracer? Enter some one-shot mode where the whole exec appears
> as one step, but tracing continues if execution continues on a
> dumpable file?
The whole exec should already appear as one step.
The right response is to either fail the exec or disable
the tracer. Since the other case drops privs. I expect
failing the exec is the simplest and most consistent thing
we can do.
Eric
If we can know that a process will never raise
it's priveleges we can enable a lot of features
without privilege (such as unsharing namespaces
and unprivileged mounts) that otherwise would be unsafe,
because they could break assumptions of existing
suid executables.
To allow this to be used as a sand boxing feature
also disable ptracing other executables without
this new restriction.
For the moment I have used a per thread flag because
we are out of per process flags.
To ensure all descendants get this flag I rely on
the default copying of procss structures.
Added bprm->nosuid to make remove the need to add
duplicate error prone checks. This ensures that
the disabling of suid executables is exactly the
same as MNT_NOSUID.
Signed-off-by: Eric W. Biederman <[email protected]>
---
arch/x86/include/asm/thread_info.h | 2 ++
fs/exec.c | 6 ++++--
include/linux/binfmts.h | 1 +
include/linux/prctl.h | 3 +++
kernel/ptrace.c | 4 ++++
kernel/sys.c | 21 +++++++++++++++++++++
security/commoncap.c | 3 +--
security/selinux/hooks.c | 2 +-
8 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 375c917..e716203 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -82,6 +82,7 @@ struct thread_info {
#define TIF_SYSCALL_EMU 6 /* syscall emulation active */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
+#define TIF_NOSUID 9 /* suid exec permanently disabled */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
#define TIF_NOTSC 16 /* TSC is not accessible in userland */
@@ -107,6 +108,7 @@ struct thread_info {
#define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_NOSUID (1 << TIF_NOSUID)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
#define _TIF_NOTSC (1 << TIF_NOTSC)
diff --git a/fs/exec.c b/fs/exec.c
index 632b02e..5cba5ac 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1131,8 +1131,10 @@ int prepare_binprm(struct linux_binprm *bprm)
/* clear any previous set[ug]id data from a previous binary */
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();
-
- if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+ bprm->nosuid =
+ (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
+ test_tsk_thread_flag(current, TIF_NOSUID);
+ if (bprm->nosuid) {
/* Set-uid? */
if (mode & S_ISUID) {
bprm->per_clear |= PER_CLEAR_ON_SETID;
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index cd4349b..c3b5a30 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -44,6 +44,7 @@ struct linux_binprm{
#ifdef __alpha__
unsigned int taso:1;
#endif
+ unsigned int nosuid:1; /* True if suid bits are ignored */
unsigned int recursion_depth;
struct file * file;
struct cred *cred; /* new credentials */
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index a3baeb2..8adc517 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -102,4 +102,7 @@
#define PR_MCE_KILL_GET 34
+#define PR_SET_NOSUID 35
+#define PR_GET_NOSUID 36
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 23bd09c..b91040c 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
+ if (test_tsk_thread_flag(current, TIF_NOSUID) &&
+ !test_tsk_thread_flag(task, TIF_NOSUID))
+ return -EPERM;
+
return security_ptrace_access_check(task, mode);
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 26a6b73..8731f2a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1578,6 +1578,27 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
else
error = PR_MCE_KILL_DEFAULT;
break;
+ case PR_SET_NOSUID:
+ {
+ const struct cred *cred = current->cred;
+ error = -EINVAL;
+ /* Don't support cases that could be unsafe */
+ if ( (cred->uid != cred->suid) ||
+ (cred->uid != cred->euid) ||
+ (cred->uid != cred->fsuid) ||
+ (cred->gid != cred->sgid) ||
+ (cred->gid != cred->egid) ||
+ (cred->gid != cred->fsgid) ||
+ !cap_isclear(cred->cap_permitted) ||
+ (atomic_read(¤t->signal->count) != 1))
+ break;
+ error = 0;
+ set_tsk_thread_flag(current, TIF_NOSUID);
+ break;
+ }
+ case PR_GET_NOSUID:
+ error = !!test_tsk_thread_flag(current, TIF_NOSUID);
+ break;
default:
error = -EINVAL;
break;
diff --git a/security/commoncap.c b/security/commoncap.c
index f800fdb..34500e3 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
if (!file_caps_enabled)
return 0;
- if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
+ if (bprm->nosuid)
return 0;
dentry = dget(bprm->file->f_dentry);
@@ -868,7 +868,6 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
else
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
goto changed;
-
default:
/* No functionality available - continue with default */
error = -ENOSYS;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7a374c2..bd77a2b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
COMMON_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path = bprm->file->f_path;
- if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
+ if (bprm->nosuid)
new_tsec->sid = old_tsec->sid;
if (new_tsec->sid == old_tsec->sid) {
--
1.6.5.2.143.g8cc62
> Added bprm->nosuid to make remove the need to add
> duplicate error prone checks. This ensures that
> the disabling of suid executables is exactly the
> same as MNT_NOSUID.
Another fine example of why we have security hooks so that we don't get a
kernel full of other "random security idea of the day" hacks.
Alan
Alan Cox <[email protected]> writes:
>> Added bprm->nosuid to make remove the need to add
>> duplicate error prone checks. This ensures that
>> the disabling of suid executables is exactly the
>> same as MNT_NOSUID.
>
> Another fine example of why we have security hooks so that we don't get a
> kernel full of other "random security idea of the day" hacks.
Well it comes from plan 9. Except there they just simply did not
implement suid. What causes you to think dropping the ability
to execute suid executables is a random security idea of the day?
Eric
On Wed, 30 Dec 2009 13:36:57 -0800
[email protected] (Eric W. Biederman) wrote:
> Alan Cox <[email protected]> writes:
>
> >> Added bprm->nosuid to make remove the need to add
> >> duplicate error prone checks. This ensures that
> >> the disabling of suid executables is exactly the
> >> same as MNT_NOSUID.
> >
> > Another fine example of why we have security hooks so that we don't get a
> > kernel full of other "random security idea of the day" hacks.
>
> Well it comes from plan 9. Except there they just simply did not
> implement suid. What causes you to think dropping the ability
> to execute suid executables is a random security idea of the day?
Well to be fair its random regurgitated security idea of every year or
two.
More to the point - we have security_* hooks so this kind of continuous
security proposal turdstream can stay out of the main part of the kernel.
Cleaning up the mechanism by which NOSUID is handled in kernel seems a
good idea. Adding wacky new prctls and gunk for it doesn't, and belongs
in whatever security model you are using via the security hooks.
On Wed, Dec 30, 2009 at 6:00 PM, Alan Cox <[email protected]> wrote:
> On Wed, 30 Dec 2009 13:36:57 -0800
> [email protected] (Eric W. Biederman) wrote:
>
>> Alan Cox <[email protected]> writes:
>>
>> >> Added bprm->nosuid to make remove the need to add
>> >> duplicate error prone checks. ?This ensures that
>> >> the disabling of suid executables is exactly the
>> >> same as MNT_NOSUID.
>> >
>> > Another fine example of why we have security hooks so that we don't get a
>> > kernel full of other "random security idea of the day" hacks.
>>
>> Well it comes from plan 9. ?Except there they just simply did not
>> implement suid. ?What causes you to think dropping the ability
>> to execute suid executables is a random security idea of the day?
>
> Well to be fair its random regurgitated security idea of every year or
> two.
>
> More to the point - we have security_* hooks so this kind of continuous
> security proposal turdstream can stay out of the main part of the kernel.
>
> Cleaning up the mechanism by which NOSUID is handled in kernel seems a
> good idea. Adding wacky new prctls and gunk for it doesn't, and belongs
> in whatever security model you are using via the security hooks.
I see this as being a security-model agnostic API - the reason being,
the application is specifying a policy for itself that has meaning in
all existing security models, and which does not require administrator
intervention to configure. Rather than reimplementing this for each
security model, it's far better to do it just once. Moreover, by
having a single, common API, the application can state the general
policy "I will never need to gain priviliges over exec" without
needing to know what LSM is in use.
The future goal of this API is to allow us to relax restrictions on
creating new namespaces, chrooting, and otherwise altering the task's
environment in ways that may confuse privileged applications. Since
security hooks are all about making the existing security restrictions
_stricter_, it's not easy to later relax these using the security hook
model. And once we put in the general requirement that "this task
shall never gain privilege", it should be safe to relax these
restrictions for _all_ security models.
In short, this is something which is meaningful for all existing LSMs
and should be implemented in a central point, it will make things
easier for the namespace folks, and since it will lead to relaxing
restrictions later, it doesn't make sense to put it in a LSM as they
stand now.
Alan Cox <[email protected]> writes:
> On Wed, 30 Dec 2009 13:36:57 -0800
> [email protected] (Eric W. Biederman) wrote:
>
>> Alan Cox <[email protected]> writes:
>>
>> >> Added bprm->nosuid to make remove the need to add
>> >> duplicate error prone checks. This ensures that
>> >> the disabling of suid executables is exactly the
>> >> same as MNT_NOSUID.
>> >
>> > Another fine example of why we have security hooks so that we don't get a
>> > kernel full of other "random security idea of the day" hacks.
>>
>> Well it comes from plan 9. Except there they just simply did not
>> implement suid. What causes you to think dropping the ability
>> to execute suid executables is a random security idea of the day?
>
> Well to be fair its random regurgitated security idea of every year or
> two.
>
> More to the point - we have security_* hooks so this kind of continuous
> security proposal turdstream can stay out of the main part of the kernel.
>
> Cleaning up the mechanism by which NOSUID is handled in kernel seems a
> good idea. Adding wacky new prctls and gunk for it doesn't, and belongs
> in whatever security model you are using via the security hooks.
I am more than happy to make this a proper system call, instead of a
prctl. The way this code is evolving that seems to be the clean way
to handle this. No point in hiding the functionality away in a corner
in shame.
In my book SUID applications are the root of all evil. They are
exploitable if you twist their environment in a way they have not
hardened themselves against, and simply supporting them prevents a lot
of good features from being used by ordinary applications.
To get SUID out of my way I have to do something. A disable SUID
from this process and it's children is a simple and direct way there.
My other path is much more complicated.
As this also has security related uses it seems even better as a feature.
Eric
Alan Cox <[email protected]> writes:
> Well to be fair its random regurgitated security idea of every year or
> two.
true, last year the same kind of discussion occurs with the 'personal
firewall' aka a network MAC.
http://marc.info/?t=123247387500003&r=3&w=2
http://marc.info/?t=123187029200001&r=2&w=2
> More to the point - we have security_* hooks so this kind of continuous
> security proposal turdstream can stay out of the main part of the kernel.
indeed, LSM framework was design to be the abstraction tool. the 3
design rules were :
0. truly generic, where using a different security model is merely a
matter of loading a different kernel module;
1. conceptually simple, minimally invasive, and efficient; and
2. able to support the existing POSIX.1e capabilities logic as an
optional security module.
so, 'minimally invasive' is keyword. what's why I don't understand the
purpose of this kind of patch, even if I see the goal to achieve:
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
- return security_ops->socket_connect(sock, address, addrlen);
+ int ret = 0;
+
+ ret = security_ops->socket_connect(sock, address, addrlen);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_SECURITY_DISABLENETWORK
+ ret = disablenetwork_security_socket_connect(sock, address, addrlen);
+ if (ret)
+ goto out;
+#endif
+
+out:
+ return ret;
}
This really seems to be a kind of stacking, but it's not. So are we
going to move LSM framework to support stacking, or are we respecting
the rules of LSM framework (respecting the abstract hooks) ?
This change makes LSM framework no more generic at all.
On Thu, Dec 31, 2009 at 11:00 PM, Samir Bellabes <[email protected]> wrote:
> Alan Cox <[email protected]> writes:
>
>> Well to be fair its random regurgitated security idea of every year or
>> two.
>
> true, last year the same kind of discussion occurs with the 'personal
> firewall' aka a network MAC.
> http://marc.info/?t=123247387500003&r=3&w=2
> http://marc.info/?t=123187029200001&r=2&w=2
Lets step back for a moment. What is the common issue with both.
The issue is simple. "How to I generically tell the secuirty system
want particular restrictions."
There is no generic LSM API for application or users to talk to the
LSM and say I want the following restricted. Of course the
restrictions have to be tighter than what the profiles already say.
To control the LSM the applications are expected to know what the LSM.
This has caused items like chrome major issues.
Also by providing a generic LSM API there would be a base set of
requirements for a LSM to provide to meet the requirements of the
generic interfaces.
Basically until a generic interface to talk to LSM module is provided
these requests are going to keep coming. Maybe assign secuirty ops
string values that applications can say disable the following secuirty
operations from me.
Application does not need to be informed what is disabled from it.
Peter Dolding
Quoting Eric W. Biederman ([email protected]):
>
> If we can know that a process will never raise
> it's priveleges we can enable a lot of features
> without privilege (such as unsharing namespaces
> and unprivileged mounts) that otherwise would be unsafe,
> because they could break assumptions of existing
> suid executables.
>
> To allow this to be used as a sand boxing feature
> also disable ptracing other executables without
> this new restriction.
>
> For the moment I have used a per thread flag because
> we are out of per process flags.
>
> To ensure all descendants get this flag I rely on
> the default copying of procss structures.
>
> Added bprm->nosuid to make remove the need to add
> duplicate error prone checks. This ensures that
> the disabling of suid executables is exactly the
> same as MNT_NOSUID.
>
> Signed-off-by: Eric W. Biederman <[email protected]>
> ---
> arch/x86/include/asm/thread_info.h | 2 ++
> fs/exec.c | 6 ++++--
> include/linux/binfmts.h | 1 +
> include/linux/prctl.h | 3 +++
> kernel/ptrace.c | 4 ++++
> kernel/sys.c | 21 +++++++++++++++++++++
> security/commoncap.c | 3 +--
> security/selinux/hooks.c | 2 +-
> 8 files changed, 37 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
> index 375c917..e716203 100644
> --- a/arch/x86/include/asm/thread_info.h
> +++ b/arch/x86/include/asm/thread_info.h
> @@ -82,6 +82,7 @@ struct thread_info {
> #define TIF_SYSCALL_EMU 6 /* syscall emulation active */
> #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
> #define TIF_SECCOMP 8 /* secure computing */
> +#define TIF_NOSUID 9 /* suid exec permanently disabled */
> #define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
> #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
> #define TIF_NOTSC 16 /* TSC is not accessible in userland */
> @@ -107,6 +108,7 @@ struct thread_info {
> #define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
> #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
> #define _TIF_SECCOMP (1 << TIF_SECCOMP)
> +#define _TIF_NOSUID (1 << TIF_NOSUID)
> #define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
> #define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
> #define _TIF_NOTSC (1 << TIF_NOTSC)
> diff --git a/fs/exec.c b/fs/exec.c
> index 632b02e..5cba5ac 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1131,8 +1131,10 @@ int prepare_binprm(struct linux_binprm *bprm)
> /* clear any previous set[ug]id data from a previous binary */
> bprm->cred->euid = current_euid();
> bprm->cred->egid = current_egid();
> -
> - if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
> + bprm->nosuid =
> + (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
> + test_tsk_thread_flag(current, TIF_NOSUID);
> + if (bprm->nosuid) {
> /* Set-uid? */
> if (mode & S_ISUID) {
> bprm->per_clear |= PER_CLEAR_ON_SETID;
> diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
> index cd4349b..c3b5a30 100644
> --- a/include/linux/binfmts.h
> +++ b/include/linux/binfmts.h
> @@ -44,6 +44,7 @@ struct linux_binprm{
> #ifdef __alpha__
> unsigned int taso:1;
> #endif
> + unsigned int nosuid:1; /* True if suid bits are ignored */
> unsigned int recursion_depth;
> struct file * file;
> struct cred *cred; /* new credentials */
> diff --git a/include/linux/prctl.h b/include/linux/prctl.h
> index a3baeb2..8adc517 100644
> --- a/include/linux/prctl.h
> +++ b/include/linux/prctl.h
> @@ -102,4 +102,7 @@
>
> #define PR_MCE_KILL_GET 34
>
> +#define PR_SET_NOSUID 35
> +#define PR_GET_NOSUID 36
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/ptrace.c b/kernel/ptrace.c
> index 23bd09c..b91040c 100644
> --- a/kernel/ptrace.c
> +++ b/kernel/ptrace.c
> @@ -152,6 +152,10 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
> if (!dumpable && !capable(CAP_SYS_PTRACE))
> return -EPERM;
>
> + if (test_tsk_thread_flag(current, TIF_NOSUID) &&
> + !test_tsk_thread_flag(task, TIF_NOSUID))
> + return -EPERM;
> +
> return security_ptrace_access_check(task, mode);
> }
>
> diff --git a/kernel/sys.c b/kernel/sys.c
> index 26a6b73..8731f2a 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -1578,6 +1578,27 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
> else
> error = PR_MCE_KILL_DEFAULT;
> break;
> + case PR_SET_NOSUID:
> + {
> + const struct cred *cred = current->cred;
> + error = -EINVAL;
> + /* Don't support cases that could be unsafe */
> + if ( (cred->uid != cred->suid) ||
> + (cred->uid != cred->euid) ||
> + (cred->uid != cred->fsuid) ||
> + (cred->gid != cred->sgid) ||
> + (cred->gid != cred->egid) ||
> + (cred->gid != cred->fsgid) ||
> + !cap_isclear(cred->cap_permitted) ||
> + (atomic_read(¤t->signal->count) != 1))
> + break;
> + error = 0;
> + set_tsk_thread_flag(current, TIF_NOSUID);
> + break;
> + }
> + case PR_GET_NOSUID:
> + error = !!test_tsk_thread_flag(current, TIF_NOSUID);
> + break;
> default:
> error = -EINVAL;
> break;
> diff --git a/security/commoncap.c b/security/commoncap.c
> index f800fdb..34500e3 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
> if (!file_caps_enabled)
> return 0;
>
> - if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
> + if (bprm->nosuid)
> return 0;
I'm sorry, this may actually not be sufficient.
Could you try the following test on a kernel with this patch? :
1. become root
2. do prctl(PR_SET_NOSUID);
3. run bash, and examine your capabilities in /proc/self/status
I think the code in security/commoncap.c:457-458 will re-raise your
capabilities.
>
> dentry = dget(bprm->file->f_dentry);
> @@ -868,7 +868,6 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> else
> new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
> goto changed;
> -
> default:
> /* No functionality available - continue with default */
> error = -ENOSYS;
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 7a374c2..bd77a2b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2147,7 +2147,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
> COMMON_AUDIT_DATA_INIT(&ad, FS);
> ad.u.fs.path = bprm->file->f_path;
>
> - if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
> + if (bprm->nosuid)
> new_tsec->sid = old_tsec->sid;
>
> if (new_tsec->sid == old_tsec->sid) {
> --
> 1.6.5.2.143.g8cc62
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
"Serge E. Hallyn" <[email protected]> writes:
>> diff --git a/security/commoncap.c b/security/commoncap.c
>> index f800fdb..34500e3 100644
>> --- a/security/commoncap.c
>> +++ b/security/commoncap.c
>> @@ -389,7 +389,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
>> if (!file_caps_enabled)
>> return 0;
>>
>> - if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
>> + if (bprm->nosuid)
>> return 0;
>
> I'm sorry, this may actually not be sufficient.
>
> Could you try the following test on a kernel with this patch? :
>
> 1. become root
> 2. do prctl(PR_SET_NOSUID);
> 3. run bash, and examine your capabilities in /proc/self/status
>
> I think the code in security/commoncap.c:457-458 will re-raise your
> capabilities.
Right. That is a legitimate issue.
I almost guard against it with my test against with my start condition test
of cap_isclear(cred->cap_permitted).
Which causes this to fail for root in most situations. I will add a
test for the securebits, and deny this to root unless the securebits
are such that root cannot gain privilege.
Thanks for catching this. I figured I might need a uid == 0 exclusion.
Where the test was split when I wrote it I wasn't certain where to put it.
Eric
> Lets step back for a moment. What is the common issue with both.
>
> The issue is simple. "How to I generically tell the secuirty system
> want particular restrictions."
You don't. It's not "the security system", its a whole collection of
completely different models of security and differing tools.
> There is no generic LSM API for application or users to talk to the
> LSM and say I want the following restricted.
That's a meaningless observation I think because security doesn't work
that way. Removing specific features from a specific piece of code
generally isn't a security feature - its only meaningful in the context
of a more general policy and that policy expression isn't generic.
> To control the LSM the applications are expected to know what the LSM.
> This has caused items like chrome major issues.
..
> Application does not need to be informed what is disabled from it.
So why does it cause chrome problems ?
There are multiple security models because nobody can agree on what they
should look like, just like multiple desktops. Each of them is based on a
totally different conceptual model so the idea of a single interface to
them is a bit meaningless.
Alan
> I see this as being a security-model agnostic API - the reason being,
Thats what everyone else says about their security model too
> the application is specifying a policy for itself that has meaning in
> all existing security models, and which does not require administrator
> intervention to configure. Rather than reimplementing this for each
> security model, it's far better to do it just once. Moreover, by
> having a single, common API, the application can state the general
> policy "I will never need to gain priviliges over exec" without
> needing to know what LSM is in use.
So it can sit in the security hooks and stack.
> The future goal of this API is to allow us to relax restrictions on
> creating new namespaces, chrooting, and otherwise altering the task's
> environment in ways that may confuse privileged applications. Since
All of which are security policy, general purpose and frequently part of
the main LSM module loaded - in other words it's nothing of the sort when
it comes to being separate. Its just another magic interface hook, and as
I think the history of capability stuff in kernel shows it doesn't work
that way.
> security hooks are all about making the existing security restrictions
> _stricter_, it's not easy to later relax these using the security hook
> model. And once we put in the general requirement that "this task
> shall never gain privilege", it should be safe to relax these
> restrictions for _all_ security models.
In which case the hooks can be tweaked. It's an interface it can be
tuned - and has been - eg for Tomoyo.
> In short, this is something which is meaningful for all existing LSMs
But is it - and if its combined with 500 other similar hooks and a set of
system policies can you even work out the result ?
> restrictions later, it doesn't make sense to put it in a LSM as they
> stand now.
And it certainly doesn't make sense to add this and the several hundred
other variants of this "can't open sockets, can't mount, can't this,
can't that ...." stuff continually being suggested by randomly extending
other unrelated interfaces.
Look up the sendmail security archive and you'll even find examples where
enforcing extra security on setuid *caused* security problems to show up
that were basically impossible to hit otherwise.
We have a security system, with a set of interfaces for attaching
security models, please stop trying to go round the back of the kernel
design because you can't be bothered to do the required work to do the
job right and would rather add more unmaintainable crap all over the
place.
Yes it might mean the hooks need tweaking, yes it probably means the
people who want these need to do some trivial stacking work, but if as
many people are actually really interested as are having random 'lets add
a button to disable reading serial ports on wednesday' ideas there should
be no shortage of people to do the job right.
Alan
Alan Cox wrote:
>Look up the sendmail security archive and you'll even find examples where
>enforcing extra security on setuid *caused* security problems to show up
>that were basically impossible to hit otherwise.
Yes, we know: people have mentioned the sendmail bug multiple times
in this thread. That's exactly the hazard that this proposed patch
was intended to help address. That's exactly the hazard that all
this discussion has been focused on.
This patch is not a security model. It may facilitate other
security models, hopefully, but it's not intended as a security
model in itself.
>We have a security system, with a set of interfaces for attaching
>security models, please stop trying to go round the back of the kernel
>design because you can't be bothered to do the required work to do the
>job right and would rather add more unmaintainable crap all over the
>place.
Got a constructive suggestion for a better way to implement this?
My impression is that all thread participants have been happy to
listen to constructive suggestions about alternative ways to achieve
the goals, from people who have payed attention to the discussion and
taken the time to understand the points that havee been raised so far.
Quoting Alan Cox ([email protected]):
> > I see this as being a security-model agnostic API - the reason being,
>
> Thats what everyone else says about their security model too
LOL
> > the application is specifying a policy for itself that has meaning in
> > all existing security models, and which does not require administrator
> > intervention to configure. Rather than reimplementing this for each
> > security model, it's far better to do it just once. Moreover, by
> > having a single, common API, the application can state the general
> > policy "I will never need to gain priviliges over exec" without
> > needing to know what LSM is in use.
>
> So it can sit in the security hooks and stack.
>
> > The future goal of this API is to allow us to relax restrictions on
> > creating new namespaces, chrooting, and otherwise altering the task's
> > environment in ways that may confuse privileged applications. Since
>
> All of which are security policy, general purpose and frequently part of
> the main LSM module loaded - in other words it's nothing of the sort when
> it comes to being separate. Its just another magic interface hook, and as
> I think the history of capability stuff in kernel shows it doesn't work
> that way.
>
> > security hooks are all about making the existing security restrictions
> > _stricter_, it's not easy to later relax these using the security hook
> > model. And once we put in the general requirement that "this task
> > shall never gain privilege", it should be safe to relax these
> > restrictions for _all_ security models.
>
> In which case the hooks can be tweaked. It's an interface it can be
> tuned - and has been - eg for Tomoyo.
>
> > In short, this is something which is meaningful for all existing LSMs
>
> But is it - and if its combined with 500 other similar hooks and a set of
> system policies can you even work out the result ?
>
> > restrictions later, it doesn't make sense to put it in a LSM as they
> > stand now.
>
> And it certainly doesn't make sense to add this and the several hundred
> other variants of this "can't open sockets, can't mount, can't this,
> can't that ...." stuff continually being suggested by randomly extending
> other unrelated interfaces.
>
> Look up the sendmail security archive and you'll even find examples where
> enforcing extra security on setuid *caused* security problems to show up
> that were basically impossible to hit otherwise.
That's exactly what we're trying to avoid :) But I'm personally not
against making this an LSM. As you say:
> We have a security system, with a set of interfaces for attaching
> security models, please stop trying to go round the back of the kernel
> design because you can't be bothered to do the required work to do the
> job right and would rather add more unmaintainable crap all over the
> place.
>
> Yes it might mean the hooks need tweaking, yes it probably means the
Yes, and in particular, we'll need to do something about data
->security annotations, since, if we make this an LSM, then we can't
use a per-thread flag.
This feature is used during exec and ptrace, not on hot-paths, so
dereferencing task->security would be fine. But finding a way to
multiplex task->security so it can be used by Eric's nosuid lsm,
Michael's disablenetwork LSM, and SELinux/smack/apparmor, that
will likely take months, and, history shows, may never happen.
> people who want these need to do some trivial stacking work, but if as
> many people are actually really interested as are having random 'lets add
> a button to disable reading serial ports on wednesday' ideas there should
> be no shortage of people to do the job right.
Eric, the thing is, once an API goes upstream, we can't change it,
but in contrast we can change how task->security is used at any time.
So I'd suggest just adding
#ifdef CONFIG_SECURITY_NOSUID
short nosuid;
#endif
or something like it next to the
#ifdef CONFIG_SECURITY
void *security;
#endif
in struct cred and doing that for a first go. You could
share that field with Michael's disablenetwork, or not if you
prefer - either way, it keeps you and SELinux out of each other's
ways.
-serge
Alan Cox wrote:
>Removing specific features from a specific piece of code
>generally isn't a security feature -
You lost me there. The ability of a specific piece of code to voluntarily
relinquish privileges can be a big benefit to security. It enables
privilege-separated software architectures, which are a powerful way to
reduce risk. That's the motivation for the disablenetwork proposal that
has stimulated all this discussion. I hope this is obvious? Does it
need elaboration?
Why not implement this as another securebit? So far as I can see the
whole thing can be implemented in the capability LSM.
What is less clear to me is whether per-process 'disabling of setuid
bits on files' should force mandatory disabling of file capabilities.
It seems as if disabling the transition of one luser to another luser
through a setuid executable is something distinct from privilege
escalation.
Since there is already independent support for disabling file
capabilities (the privilege escalation part), I see these two
mechanisms as separable.
Cheers
Andrew
On Thu, Dec 31, 2009 at 9:52 AM, Serge E. Hallyn <[email protected]> wrote:
> Quoting Alan Cox ([email protected]):
>> > I see this as being a security-model agnostic API - the reason being,
>>
>> Thats what everyone else says about their security model too
>
> LOL
>
>> > the application is specifying a policy for itself that has meaning in
>> > all existing security models, and which does not require administrator
>> > intervention to configure. Rather than reimplementing this for each
>> > security model, it's far better to do it just once. Moreover, by
>> > having a single, common API, the application can state the general
>> > policy "I will never need to gain priviliges over exec" without
>> > needing to know what LSM is in use.
>>
>> So it can sit in the security hooks and stack.
>>
>> > The future goal of this API is to allow us to relax restrictions on
>> > creating new namespaces, chrooting, and otherwise altering the task's
>> > environment in ways that may confuse privileged applications. Since
>>
>> All of which are security policy, general purpose and frequently part of
>> the main LSM module loaded - in other words it's nothing of the sort when
>> it comes to being separate. Its just another magic interface hook, and as
>> I think the history of capability stuff in kernel shows it doesn't work
>> that way.
>>
>> > security hooks are all about making the existing security restrictions
>> > _stricter_, it's not easy to later relax these using the security hook
>> > model. And once we put in the general requirement that "this task
>> > shall never gain privilege", it should be safe to relax these
>> > restrictions for _all_ security models.
>>
>> In which case the hooks can be tweaked. It's an interface it can be
>> tuned ?- and has been - eg for Tomoyo.
>>
>> > In short, this is something which is meaningful for all existing LSMs
>>
>> But is it - and if its combined with 500 other similar hooks and a set of
>> system policies can you even work out the result ?
>>
>> > restrictions later, it doesn't make sense to put it in a LSM as they
>> > stand now.
>>
>> And it certainly doesn't make sense to add this and the several hundred
>> other variants of this "can't open sockets, can't mount, can't this,
>> can't that ...." stuff continually being suggested by randomly extending
>> other unrelated interfaces.
>>
>> Look up the sendmail security archive and you'll even find examples where
>> enforcing extra security on setuid *caused* security problems to show up
>> that were basically impossible to hit otherwise.
>
> That's exactly what we're trying to avoid :) ?But I'm personally not
> against making this an LSM. ?As you say:
>
>> We have a security system, with a set of interfaces for attaching
>> security models, please stop trying to go round the back of the kernel
>> design because you can't be bothered to do the required work to do the
>> job right and would rather add more unmaintainable crap all over the
>> place.
>>
>> Yes it might mean the hooks need tweaking, yes it probably means the
>
> Yes, and in particular, we'll need to do something about data
> ->security annotations, since, if we make this an LSM, then we can't
> use a per-thread flag.
>
> This feature is used during exec and ptrace, not on hot-paths, so
> dereferencing task->security would be fine. ?But finding a way to
> multiplex task->security so it can be used by Eric's nosuid lsm,
> Michael's disablenetwork LSM, and SELinux/smack/apparmor, that
> will likely take months, and, history shows, may never happen.
>
>> people who want these need to do some trivial stacking work, but if as
>> many people are actually really interested as are having random 'lets add
>> a button to disable reading serial ports on wednesday' ideas there should
>> be no shortage of people to do the job right.
>
> Eric, the thing is, once an API goes upstream, we can't change it,
> but in contrast we can change how task->security is used at any time.
> So I'd suggest just adding
>
> #ifdef CONFIG_SECURITY_NOSUID
> ? ? ? ?short nosuid;
> #endif
>
> or something like it next to the
>
> #ifdef CONFIG_SECURITY
> ? ? ? ?void *security;
> #endif
>
> in struct cred and doing that for a first go. ?You could
> share that field with Michael's disablenetwork, or not if you
> prefer - either way, it keeps you and SELinux out of each other's
> ways.
>
> -serge
>
"Andrew G. Morgan" <[email protected]> writes:
> Why not implement this as another securebit? So far as I can see the
> whole thing can be implemented in the capability LSM.
>
> What is less clear to me is whether per-process 'disabling of setuid
> bits on files' should force mandatory disabling of file capabilities.
> It seems as if disabling the transition of one luser to another luser
> through a setuid executable is something distinct from privilege
> escalation.
>
> Since there is already independent support for disabling file
> capabilities (the privilege escalation part), I see these two
> mechanisms as separable.
The goal is to disable privilege escalation.
The anatomy of the sendmail capabilities bug as I understand it was:
- unprivileged process took action to prevent gaining a capability.
- exec'd suid sendmail.
- sendmail took action as root because it could not become someone else.
I would like to trivially stop that entire class of exploit by making
execing a suid ( or equivalent ) executable impossible.
Once that hole is closed we can enable things like chroot without
privilege.
If there is a way to express this with capabilities today I would be
more than happy to.
Eric
"Andrew G. Morgan" <[email protected]> writes:
> Since there is already independent support for disabling file
> capabilities (the privilege escalation part), I see these two
> mechanisms as separable.
I guess there is something that resembles support for disabling
privilege escalation. The problem is that it requires privilege to
use it.
I have no problem with expressing this in a fine grained manner internally
to the kernel but the user space interface needs to be atomic so that
we can enable this all without privilege.
Further I may be off but I think the implementation would be more
challenging than what I have already posted. That doesn't mean it
won't be more useful long term.
Eric
Quoting Eric W. Biederman ([email protected]):
> "Andrew G. Morgan" <[email protected]> writes:
>
> > Since there is already independent support for disabling file
> > capabilities (the privilege escalation part), I see these two
> > mechanisms as separable.
>
> I guess there is something that resembles support for disabling
> privilege escalation. The problem is that it requires privilege to
> use it.
>
> I have no problem with expressing this in a fine grained manner internally
> to the kernel but the user space interface needs to be atomic so that
> we can enable this all without privilege.
>
> Further I may be off but I think the implementation would be more
> challenging than what I have already posted. That doesn't mean it
> won't be more useful long term.
>
> Eric
Right, what we can currently do with capabilities is:
1. drop capabilities from the bounding set. This is
privileged because it is fine-grained, and can trick
capability-unaware privileged programs.
2. drop CAP_SETUID from pP, pI, and the bounding set,
to prevent any future setuids. Privileged for the
same reason as 1.
3. set SECURE_NOROOT and SECURE_NOSUIDFIXUP, so that
uid 0 won't automatically get privileges.
It doesn't provide a way for stopping setuid on setuid binaries, though,
and as we've previously noted, while we'd *like* to say that uids and
privileges can be treated separately, in reality the unprivileged
root user still owns most of the system. So we should also provide the
per-task nosuid bit, meaning do not change uid for a setuid binary. This
could be treated as another securebit,
SECURE_NOSUID
So if the capabilities module supports a special
prctl(PR_SET_NOSUID)
which at the same time completely empties pP, pE, pI, and
the bounding set, and sets the SECURE_NOSUID securebit, that
should be safe for an unprivileged user. (There is no need
for SECURE_NOROOT and SECURE_NOSUIDFIXUP in that case obviously).
Or, it could set SECURE_NOSUID|SECURE_NOROOT|SECURE_NOSUID_FIXUP
(and the corresponding _LOCKED bits).
-serge
On Fri, Jan 1, 2010 at 3:06 AM, Alan Cox <[email protected]> wrote:
>> Lets step back for a moment. ?What is the common issue with both.
>>
>> The issue is simple. ?"How to I generically tell the secuirty system
>> want particular restrictions."
>
> You don't. It's not "the security system", its a whole collection of
> completely different models of security and differing tools.
>
>> There is no generic LSM API for application or users to talk to the
>> LSM and say I want the following restricted.
>
> That's a meaningless observation I think because security doesn't work
> that way. Removing specific features from a specific piece of code
> generally isn't a security feature - its only meaningful in the context
> of a more general policy and that policy expression isn't generic.
>
Sandboxing it has meaning. The LSM section of the Linux secuirty
system is out of reach of applications to talk to generically. They
can use capabilities they can use DAC they can even talk generically
to the firewall.
>> To control the LSM the applications are expected to know what the LSM.
>> ?This has caused items like chrome major issues.
>
> ..
>
>> Application does not need to be informed what is disabled from it.
>
> So why does it cause chrome problems ?
>
>
They were trying to create a sandbox inside there applications.
> There are multiple security models because nobody can agree on what they
> should look like, just like multiple desktops. Each of them is based on a
> totally different conceptual model so the idea of a single interface to
> them is a bit meaningless.
>
Bad argument flawed one and in breach of LSM API basic idea.
All the secuirty modules are using generic hooks. All these patches
are duplications of generic hooks because applications and users
cannot control the generic hooks. All your answer is use the LSM
because it already has the hook there. Problem is they cannot
generically. So LSM is failing to make LSM generic enough for all
requirements.
The interface I am talking about does not give a rats about 90 percent
of the secuirty module. So if they want completely different
conceptual ideas there go for it.
Generic is the following.
Means for applications or users to say I don't want to use any off
the following locations that LSM has hooks. Everything in the
generic has to exist as LSM hooks.
Now a generic LSM interface for applications and users the LSM is free
to use the application and users provided data how they choose this
include disregarding just like file capabilities can be disabled.
API call is one way. Section in the ELF file is another ie elf
having text data secuirty. The section design has to be LSM generic
as well. Lets say a LSM does not have a profile for an application it
sees that application comes with a secuirty section so is able to pick
this up and use this as a rough profile.
The generic is having nothing todo with role based secuirty controls
or inheritance of permissions to be correct the LSM is free to apply
those limitations over the top.
In some cases an application declaring in advance what features they
need could protect end users from data lose from LSM termination.
Reason the application did not start in the first place. The biggest
headache with setting up non standard LSM correctly is that
applications have no way of declaring a list of what they need and
don't need in a LSM generic way.
Everything in the generic interfaces for users and applications would
relate directly to the raw generic LSM hooks not to the security model
being applied past that. This is not crossing into LSM turf.
I don't want to be inside the LSM turf when coding inside an
application and need to sandbox just need to tell the LSM that from
here on must be restricted. Preferable in a way that is LSM generic.
I don't want as a application design to having to create rules for
every LSM in existance with verations for each distributions idea of
role base secuirty and the like.
Be truthful LSM hooks are a lot finer than capabilities and can cut a
lot more things off from applications.
Exactly what secuirty advantage is served by applications not being
able to talk to the LSM module in a generic way?
None that I know of. If there is some please tell me. But I can
think of plenty that can be served by applications being able to talk
to and provide generic information.
1) Simpler LSM configuration this is one of the biggest bug bears of LSM.
2) Less data loss from LSM configured wrong ie application being able
to provide list of what it needs so admin does not restrict it too
much. It might take months it use a feature that causes the LSM to
terminate an application.
3) Sandboxing inside applications that works fairly simply for
application developers.
4) Windows managers and the like able to provide users with options
like networking on particular applications disabled on user demard in
a generic way. Things that cannot always rewritten into policy.
Some applications users will want to run different ways depending on
what they are doing. Like you might want to run a download manager
with networking disabled even that you are online because you are on a
voip call and you don't want it starting up downloading stuff.
5) Anti-virus/Anti-malware being able to apply restrictions to items
detected as suspect even if user decided to keep on running it in a
generic way.
6) Option to reduce how much in LSM secuirty configuration data has to
be LSM unique. If lets say LSMs would use a secuirty section in the
elf data as part of there application config. Any alteration in the
generic data would apply to all the LSM support it at once. Less
duplication of data is better. Lower the duplication less risk of
maintainer errors when updating LSM secuirty information.
Of course providing all this not one removes the need for role based
secuirty and the like over the top its in the role based secuiryt and
the like where LSM want to fight. Let them lets just not cripple
users secuirty control while in use just because those guys cannot get
to a common design. Yes applying what I say might cause a higher
level inside LSM's to become generic. This would be LSM completing it
goals of being generic. It exists to encourage generic methods in the
LSM modules.
Peter Dolding
> > Added bprm->nosuid to make remove the need to add
> > duplicate error prone checks. This ensures that
> > the disabling of suid executables is exactly the
> > same as MNT_NOSUID.
>
> Another fine example of why we have security hooks so that we don't get a
> kernel full of other "random security idea of the day" hacks.
well... new unshare functionality depends on this. if unshare is
important enough, this may not be lsm.
(and disablenetwork *should* depend on this)
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[email protected] (David Wagner) writes:
> Eric W. Biederman wrote:
>>The problem with the disable_network semantics you want
>>is that they allow you to perform a denial of service attack
>>on privileged users. An unprivileged DOS attack is unsuitable
>>for a general purpose feature in a general purpose kernel.
>
> I'm not persuaded yet.
I won't try hard to persuade you if you drop me off the cc list.
> When you talk about DOS, let's be a bit more precise. disablenetwork
> gives a way to deny setuid programs access to the network. It's not a
> general-purpose DOS; it's denying access to the network only. And the
> network is fundamentally unreliable. No security-critical mechanism
> should be relying upon the availability of the network.
The audit daemon should not rely on netlink?
> So while I certainly can't rule out the possibility that disablenetwork
> might introduce minor issues, I think there are fundamental reasons to
> be skeptical that disablenetwork will introduce serious new security
> problems.
For me the case is simple. I have seen several plausible sounding
scenarios that get most of the way there. I know I am stupid when
it comes to security and that people exploiting problems are going
to be looking harder than I will. Therefore I think there is
a reasonable chance this will introduce a security hole for someone.
Eric
> Quoting Michael Stone ([email protected]):
> > Implement security_* hooks for socket_create, socket_bind, socket_connect,
> > socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
> > process with networking restrictions. Exempt AF_UNIX sockets.
> >
> > Signed-off-by: Michael Stone <[email protected]>
>
> Acked-by: Serge Hallyn <[email protected]>
For the record: NAK, as it introduces security holes.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> - unprivileged process took action to prevent gaining a capability.
> - exec'd suid sendmail.
> - sendmail took action as root because it could not become someone else.
Which is a classic bug and replicated historically in cpu time, quota and
other similar "remove rights and then .." attacks.
> I would like to trivially stop that entire class of exploit by making
> execing a suid ( or equivalent ) executable impossible.
Fine the LSM modules can already build such policies or you can add a new
LSM for it - it doesn't need whacky one off extensions to prctl.
Of course you could also have an LSM which undoes restrictions on suid
apps instead. Thats an equally valid model, just don't load both at once
and don't assume you have the one true model.
On Thu, 31 Dec 2009 17:55:27 +0000 (UTC)
[email protected] (David Wagner) wrote:
> Alan Cox wrote:
> >Removing specific features from a specific piece of code
> >generally isn't a security feature -
>
> You lost me there. The ability of a specific piece of code to voluntarily
> relinquish privileges can be a big benefit to security.
Can be - but its historically been an endless source of bugs and flaws
because the code being run after you take the rights away is being run in
an environment it didn't expect and wasn't tested in.
>From inanities like setting the file size limit to 0 and running passwd
blanking the password file (SGI Irix) to closing file handle 0 or setting
cpu quotas to make a forked daemon process die unexpectedly the list is
endless.
Alan
> > - unprivileged process took action to prevent gaining a capability.
> > - exec'd suid sendmail.
> > - sendmail took action as root because it could not become someone else.
>
> Which is a classic bug and replicated historically in cpu time, quota and
> other similar "remove rights and then .." attacks.
Yes, so from now on, when we add new "cpu cache misses quota", we
should require prctl(I_SHOULD_NOT_BE_ABLE_TO_LAUNCH_SETUID) for
unpriviledged users, first.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> dereferencing task->security would be fine. But finding a way to
> multiplex task->security so it can be used by Eric's nosuid lsm,
> Michael's disablenetwork LSM, and SELinux/smack/apparmor, that
> will likely take months, and, history shows, may never happen.
You assume firstly that it matters. If it doesn't matter and people don't
want to mix SELinux etc with weird little hacks then the problem doesn't
really arise anyway. If people do want to stack them then yes they'll
have to do the work. Diddums, thats how it works, and filling the kernel
with crap shortcuts just makes a bigger mess longer term and leaves a
huge mess to sort out.
There are lots of trivial ways to implement a fast lookup per security
context. The only real problem is figuring out how much space is needed
and that's fairly trivial to do providing you don't try and be clever and
reclaim slots unloading modules
You just need void * security and an offset allocated per security module
as its registered. We've even got library code to hand those out nicely
alloc and free them (leaving holes on unload and refilling on reload)
Then it all comes out as
lsm_context = (struct my_lsm_context *)(task->security + lsm->offset)
whoopee 1 clock.
You pay a cost at LSM load time (which is extremely rare) to update all
the tasks and introduce them to the LSM but you need to do that anyway to
initialise your LSM state for each task.
If people were serious about doing the work right rather than just trying
to dump their pet neat idea into the kernel with no care about the cost
I'd expect to see patches for sharing ->security, LSM stacking first.
They are not hard technically.
There are real issues about what it *means* to stack LSM modules
semantically but thats a problem for the admin not the kernel so it's not
a "hard" problem programming wise.
> Eric, the thing is, once an API goes upstream, we can't change it,
> but in contrast we can change how task->security is used at any time.
> So I'd suggest just adding
>
> #ifdef CONFIG_SECURITY_NOSUID
> short nosuid;
> #endif
Should be a bitflag - then you can also fix some of the locking questions
- the current code really doesn't consider locking issues at all - which
needs fixing.
> or something like it next to the
>
> #ifdef CONFIG_SECURITY
> void *security;
> #endif
And 148 other #defines later it'll be a joyous mess.
Its always easier short term to pee in the pond than install a toilet -
it's just not a good long term plan.
Hi!
> > it is really only required for binaries setuid to someone else, but
> > that would be too ugly. (Plus, as someone said, ping is great for
> > leaking data out.)
>
> No, this is not sufficient; one needs only to find a setuid process
> that can be convinced to run a program with the original (pre-suid)
Ok.
> Or one can target a non-root setuid program that may have security
> holes - how about nethack?
Well, security holes are bad idea, who'd know?
> That said, I do feel this is a separate issue. The process should
> first drop its ability to suid; then it can freely apply additional
> restrictions without there being any risk of breaking setuid
> applications.
ACK.
> In short, how does this sound:
> * Add an API to allow processes to permanently revoke their own
> ability to gain privileges from setuid-exec
> * Add this disablenetwork facility, conditional on dropping
> setuid-exec abilities
>
> This also paves the way for:
> * Allow processes that have dropped said suid ability to freely create
> new namespaces (and chroot)
Works for me.
> Which, combined with doing whatever audits are necessary to allow
> cross-network-namespace uses of unix domain sockets, actually
> eliminates the need for the disablenetwork API. :)
Cool ;-).
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi!
> I think that Pavel's point, at its strongest and most general, could be
> rephrased as:
>
> "Adding *any* interesting isolation facility to the kernel breaks
> backwards
> compatibility for *some* program [in a way that violates security
> goals]."
Yep.
> So far, I've seen the following suggestions:
>
> a) setuid restores pre-isolation semantics
>
> - Doesn't work for me because it violates the security guarantee of
> the
> isolation primitive
d) when any new isolation feature requires removing ability to
exec(anything setuid) first.
> b) setuid is an escape-hatch
>
> - Probably the cleanest in the long-run
>
> - Doesn't, by itself, suffice for Pavel since it violates backwards
> compatibility
>
> c) signal to the kernel through a privileged mechanism that
> backwards-incompatible isolation may or may not be used
>
> - No problems seen so far.
> I would be happy with (c), assuming we can agree on an appropriate
> signalling
> mechanism and default.
>
> So far, two defaults have been proposed:
>
> default-deny incompatible isolation (Pavel)
> So far, several signalling mechanisms have been proposed:
>
> 1) enabling a kernel config option implies default-permit
>
> - My favorite; apparently insufficient for Pavel?
>
> 2) default-deny; disablesuid grants disablenetwork
>
> - "disablesuid" is my name for the idea of dropping the privilege of
> exec'ing setuid binaries
>
> - Suggested by Pavel and supported by several others.
> - I think it has the same backwards-compatibility problem as
> disablenetwork: disablesuid is an isolation primitive.
Which is ok, use can already arbitrarily break *his own* apps, eg. by
using ptrace. Only with setuid in place it becomes security problem.
> 4) default-deny; setting a sysctl implies permit
>
> - Suggested by Serge; works fine for me
...
> I am happiest with (1) and, if (1) isn't good enough, with (4).
>
> Pavel, what do you think of (4)?
It is still bad idea: (2) is better solution.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
(Please use group reply, so that cc lists are preserved).
> Pavel writes:
> > Policy may well be "If the network works, noone can
> > log in locally, because administration is normally done over
> > network. If the network fails, larger set of people is allowed in,
> > because something clearly went wrong and we want anyone going around
> > to fix it."
>
> Michael Stone writes:
> > Have you actually seen this security policy in real life?
>
> Pavel responds:
> > Actually, I've seen a *lot* of similar [..] policies.
>
> OK, so to translate: it sounds like the answer is No, you
> haven't seen this policy in real life.
>
> More to the point, the real question is whether this policy
> is embedded in code anywhere such that Michael's mechanism would
> introduce a new security hole, and if so, whether the cost of
> that would outweigh the benefit of his mechanism. I think the
Actually, no, this is not the (only) question. Kernel tries to be
backwards-compatible.
> answer is, No, no one even has a plausible story for how this
> policy might appear in some legacy executable that would then
> be newly subvertible due to Michael Stone's policy. First off,
It is Michael's responsibility to prove that no legacy executable is
affected, and they clearly are.
(Another example would be DoS; imagine sendmail forking into
background from setuid program. It maybe even does that. Run that with
network disabled and you have DoSed mail system on the server.)
> I think what Michael is trying to do has the potential to be very
> valuable and should be supported, and this is not a convincing
> argument against it.
People already proposed systems (disablenetwork needs disablesuid)
that have all the advantages, and no security-related
back-compatibility problems
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Sat, Jan 2, 2010 at 8:39 AM, Alan Cox <[email protected]> wrote:
>> Sure. Not that it would be hard to do so. And have a careful look
>> at the recent discussions on checkpoint/restart.
>
> Indeed the LSM "no removal of restrictions" is simply a policy decision
> that came about early on - no reason to assume it is a right policy
> decision if it can be shown otherwise.
>
>> Application developers want systems that work the way the man pages
>> say they work. They do not want additional or conditional restrictions.
>
> I disagree somewhat. They want them to work they way they did when they
> tested it and the way they believe it works. Most of them never read the
> manual or the standards documents. Take a look at the whining when stat()
> size data stopped happening by chance to reflect bytes queued in a pipe.
>
>> How many commercial applications start their installation instructions
>> with "disable SELinux"? (Hint: lots)
>
> And I am sure it time the sequence is going to go "Why did your business
> web site get taken out for four weeks" / "We disabled SELinux as the app
> said" / "Sue the app vendor"
>
> If you tell someone to disable the safety systems on a crane you get
> prosecuted.
>
>
The disable SELinux is the same problem I pointed to.
"There is no generic LSM API for application or users to talk to the
LSM and say I want the following restricted."
I should expand that to say "There is no generic way for applications
to say I want the following restricted and I need the following to
operate."
SELinux is far more complex that want application developers need to know about.
To an application developers.
1) Mandatory access controls that relate to what the application need
to do is of interest.
2) mandatory integrity controls that relate to what the application
needs protected of interest.
Notice something here User related stuff like role-based access
control not really of interest. The user related stuff could be
configured different between modules and distributions. User based
configurations own to the administrator of the network not application
developers.
Application developers need generic interfaces so they can code.
Administrators need replaceable modules so if one secuirty framework
gets breached or they need different user controls they can swap it.
Meeting both requirements is possible. Will make Administrators and
Distributions job simpler because it will not longer be guessing
blind.
Current problem we have here is that what should be application
developers and what should be administrators of the network are mixing
up in one big mother of a mess.
The simple problem here is that SELinux along with Smack and others
because its too complex with too many variables making its config
files too hard for applications makers to release ones that work.
Remember safety systems can kill just as much save. In this case we
as a kernel could be prosecuted for a too complex interface to
secuirty system when a simpler could be done to achieve the same level
of secuirty. There have been cases where companys who have put too
complex of secuirty on devices have been sued and lost. Due to the
fact it too so long to start up a machine to move weight off a person
that they died from crushing.
Currently Application Developers are being crushed under too large of
problem so they are responding with the only valid path remove the
defective secuirty.
Basically the One size fits all is the problem. We currently have a
shoe that fits no one well. We need 2 shoes one for the application
developer(Generic LSM interface for applications) one for the
administrators(Very much the current LSM system cleaned up) that fits
over the same socks(Linux) no problems.
Please don't over look Alan Cox that items like Selinux are spreading
arms out in stuff like postgresql and X11. These interfaces really
should have been generic interfaces or the same crap of duplication
you are fighting against in kernel is going to happen every where else
in Userspace.
The compete user-space application side interfaces for LSM has been
baddy neglected. It seams to be the idea that Applications have no
right to talk to LSM becuase that way everything will be more secure.
LSM with application control can run finer secuirty than LSM without
application control. Reason application know what it is doing in
each thread so can tell LSM to disable what is not need in that thread
so reducing attack points to get access where the LSM without
application control has to provide an access rights over the complete
applications.
Basically current model is defective secuirty. So we have complex
hard to use secuirty that does not work as good as what it could. No
wonder application developers are disabling it. We should be more
serious about addressing the problem.
Peter Dolding
> >Can be - but its historically been an endless source of bugs and flaws
> >because the code being run after you take the rights away is being run in
> >an environment it didn't expect and wasn't tested in.
>
> Are you just *shrugging* at the goals underlying these efforts?
> The goals of enabling privilege separation and sandboxing seem like
> highly laudable goals to me. I don't understand why anyone would
> be opposed to efforts to achieve those goals.
I am just pointing out the dangers of continuing to blindly pursue that
model without thinking about the bigger picture. Something Unix security
has taught people is that the model of removing rights isn't the right
one if applied simplistically.
A good example is how fd 0/1/2 is handled these days. The kernel or C
library in the Linux case puts a setuid process into a sensible context
rather than just saying "oh you removed the access to this fd, thats
cool"
If you are going to add more and more "take away the right to" type
features it's more and more important that an application can be run in
the context it expects. That is running a setuid application should
throw off various random restrictions automatically so that it gets the
expected context, without cpu limit surprises, memory restrictions etc.
That in turn reads on the rest of your policy because you have to think
very hard what kind of escape hatch you might be creating.
> Privilege-separation is a powerful software architecture technique.
> It's been used in openssh, qmail, vsftpd, and other highly regarded
> security-critical applications. (When a software designer uses privilege
> separation, he *intends* for his code to be run in a low-privilege
> environment. That's not a source of bugs.)
Internally yes - its when stuff gets run from the outside it gets harder.
> How many examples have there been? I can think of one of any significance
> (sendmail). In any case, I would classify these flaws as inherently
> relatively low-severity, because they can only be exploited by local
> users.
The number of file handle based attacks has been quite large if not very
public. There have been lots of quota based attacks, some CPU limit based
attacks, hangup bases attacks and more. Classics like SGI passwd for
example.
If you are really bored take a look how many setuid apps directly or
indirectly call a memory allocator (usually indirectly via C lib
functions) and don't check the result. Now play with the memory limits
> Perhaps I'm reading you wrong, but I seem to sense an attitude where you
> consider privilege separation and sandboxing to be relatively unimportant,
> and where you consider the risk of local attacks on setuid programs to
> be unavoidable and of paramount importance. I'm surprised to get this
> impression, because that seems narrow and counter-productive to me.
I care about both. Working on building a mass market OS doesn't give you
the privilege of saying "Oh but persohnally I don't give a **** about
XYZ"
Alan
Eric W. Biederman wrote:
> Alan Cox <[email protected]> writes:
>
>
>>> - unprivileged process took action to prevent gaining a capability.
>>> - exec'd suid sendmail.
>>> - sendmail took action as root because it could not become someone else.
>>>
>> Which is a classic bug and replicated historically in cpu time, quota and
>> other similar "remove rights and then .." attacks.
>>
>
> Exactly. The problem that most limits the evolution of the unix
> userspace API for ordinary processes. I want a per process disable so
> I can use advanced features of the API without being root (or a subset
> of root).
>
And why don't you look into using the security model provided to
accomplish your goals rather than decrying the precise semantics?
Look at what you just said. You want to provide a mechanism that
does what the capabilities mechanism does, but you don't want it
to be the capabilities mechanism because what the capabilities
mechanism does is bad.
>>> I would like to trivially stop that entire class of exploit by making
>>> execing a suid ( or equivalent ) executable impossible.
>>>
The setuid mechanism is not an exploit. It is a component of the
security policy. If you take it out you must introduce an alternative
of equal or greater power.
>> Fine the LSM modules can already build such policies or you can add a new
>> LSM for it - it doesn't need whacky one off extensions to prctl.
>>
>
> No it needs a proper system call. no_suid_for_me_and_my_children().
> Spelled nosuid to keep from breaking peoples fingers.
>
This is a misguided notion. It assumes that the behavior of all
applications that might be execed are known in advance. If that
is the case, it's pretty silly to use a restriction like this.
>> Of course you could also have an LSM which undoes restrictions on suid
>> apps instead. Thats an equally valid model, just don't load both at once
>> and don't assume you have the one true model.
>>
>
> Alan what are you talking about? LSMs are not allowed to remove
> restrictions.
>
Sure. Not that it would be hard to do so. And have a careful look
at the recent discussions on checkpoint/restart.
> You are quite right that my initial patch is a bit hacky, I am doing
> my development in the open, proving that the concept can be sanely
> implemented with very little code, and getting feedback from people
> who know the area of code better than I do. I know development in the
> open and not having everything perfect and committed to before you
> submit a patch is a strange concept on linux-kernel, but I am trying
> it out.
>
> My target audience here are application developers. Not professional
> system administrators, not distribution maintainers, and certainly
> not professional security trolls.
>
Application developers have historically been intolerant of systems
that change their security policy on the fly. No, let me say
what I really mean. They hate them with a flaming passion. Sometimes
the system requirements make it necessary, but please don't think
the application developers will thank you for it.
Application developers want systems that work the way the man pages
say they work. They do not want additional or conditional restrictions.
How many commercial applications start their installation instructions
with "disable SELinux"? (Hint: lots)
> I am about removing an impediment from the unix API for those
> applications that don't need it so they can use features that would
> otherwise be reserved to root and only root, because those features
> can be used to addle suid applications.
>
> I am sick and fed up with the conversations that go:
> - I want to do X.
> - X has been implemented.
> - Sorry I can't use X as implemented because you have to be root to
> use X.
>
Exasperated sigh. Privileged operations are privileged for a reason,
not always a good reason mind you, but a reason nonetheless. If
your application developers want to do things that require privilege
you need to teach them how to write privileged programs safely. We've
been working on exotic variations of system controls for decades
and in the end your programmers have to write decent code because
we haven't yet come up with a way to make all the things that people
want their programs to do safe.
> In this case X was the network namespace, which for non-root
> users happens to act just like the proposed disable_network.
>
> Putting something in an LSM versus anywhere else in the kernel still
> pollutes the pool and we still have to maintain it forever. So my
> preference is for something small, trivial, that people can easily
> audit.
>
> I am not satisfied with my patch to disable suid yet, but it does
> look simple and in the right ballpark. It certainly needs better
> integration with securebits and the like.
>
> So Alan would you please give some constructive criticism about:
> - Why this is a bad idea.
>
It is a bad idea because the setuid mechanism is a core component
of the Linux base security policy and changing this makes many
security cognizant applications function in ways they are not intended
to and may result in unintended and undesired information flows.
> - How to implement this so it is available to application developers
> in general.
>
If what your application developers want to do requires privilege
today you need to upgrade your developers to the point where they
can be trusted to write privileged programs.
> As I see and I may be wrong the LSM and the security modules that
> exist today are useless unless you control the entire machine the
> kernel runs on. Which applications short of Oracle do not.
>
Duh? We're talking system level security, are we not?
> Personally I think I am on the sent of a good general feature that
> makes sense, is useful in a lot of situations, is useful to a lot of
> different people, and is useful in a lot of different ways.
>
> Anything we merge into the mainstream kernel we have to maintain
> forever, LSM or core feature. I think this is a good backwards
> compatible feature that removes impediments to forward compatibility.
>
I think that this is a well meant but ill conceived feature. I think
that if you could get in your wayback machine and talk Ken and Dennis
out of implementing setuid and into doing something else instead you
might have a large number of fans, even among "security trools".
The feature has good attributes and bad, but it is essential to
application developers the world over that is be consistent.
> Eric
>
>
>
Alan Cox <[email protected]> writes:
>> - unprivileged process took action to prevent gaining a capability.
>> - exec'd suid sendmail.
>> - sendmail took action as root because it could not become someone else.
>
> Which is a classic bug and replicated historically in cpu time, quota and
> other similar "remove rights and then .." attacks.
Exactly. The problem that most limits the evolution of the unix
userspace API for ordinary processes. I want a per process disable so
I can use advanced features of the API without being root (or a subset
of root).
>> I would like to trivially stop that entire class of exploit by making
>> execing a suid ( or equivalent ) executable impossible.
>
> Fine the LSM modules can already build such policies or you can add a new
> LSM for it - it doesn't need whacky one off extensions to prctl.
No it needs a proper system call. no_suid_for_me_and_my_children().
Spelled nosuid to keep from breaking peoples fingers.
> Of course you could also have an LSM which undoes restrictions on suid
> apps instead. Thats an equally valid model, just don't load both at once
> and don't assume you have the one true model.
Alan what are you talking about? LSMs are not allowed to remove
restrictions.
You are quite right that my initial patch is a bit hacky, I am doing
my development in the open, proving that the concept can be sanely
implemented with very little code, and getting feedback from people
who know the area of code better than I do. I know development in the
open and not having everything perfect and committed to before you
submit a patch is a strange concept on linux-kernel, but I am trying
it out.
My target audience here are application developers. Not professional
system administrators, not distribution maintainers, and certainly
not professional security trolls.
I am about removing an impediment from the unix API for those
applications that don't need it so they can use features that would
otherwise be reserved to root and only root, because those features
can be used to addle suid applications.
I am sick and fed up with the conversations that go:
- I want to do X.
- X has been implemented.
- Sorry I can't use X as implemented because you have to be root to
use X.
In this case X was the network namespace, which for non-root
users happens to act just like the proposed disable_network.
Putting something in an LSM versus anywhere else in the kernel still
pollutes the pool and we still have to maintain it forever. So my
preference is for something small, trivial, that people can easily
audit.
I am not satisfied with my patch to disable suid yet, but it does
look simple and in the right ballpark. It certainly needs better
integration with securebits and the like.
So Alan would you please give some constructive criticism about:
- Why this is a bad idea.
- How to implement this so it is available to application developers
in general.
As I see and I may be wrong the LSM and the security modules that
exist today are useless unless you control the entire machine the
kernel runs on. Which applications short of Oracle do not.
Personally I think I am on the sent of a good general feature that
makes sense, is useful in a lot of situations, is useful to a lot of
different people, and is useful in a lot of different ways.
Anything we merge into the mainstream kernel we have to maintain
forever, LSM or core feature. I think this is a good backwards
compatible feature that removes impediments to forward compatibility.
Eric
2009/12/31 Eric W. Biederman <[email protected]>:
> "Andrew G. Morgan" <[email protected]> writes:
>
>> Since there is already independent support for disabling file
>> capabilities (the privilege escalation part), I see these two
>> mechanisms as separable.
>
> I guess there is something that resembles support for disabling
> privilege escalation. ?The problem is that it requires privilege to
> use it.
Just to be clear, this does not prevent luser1 -> luser2 transitions
(even though it does strip root of its privilege), but here is a
concrete worked example of what support is in the current kernel.
That is, here is a program that cripples privilege in a process tree.
Other than setting it up one time, you don't need to become root (or
visit a *uid=0) to execute it, and because capabilities are not
naively inherited nothing about the privilege of the limiter
executable can leak through the execve().
Setup (see below for source code, and
http://ols.fedoraproject.org/OLS/Reprints-2008/hallyn-reprint.pdf for
an explanation of how it all works):
luser> cc -o limiter limiter.c -lcap
luser> sudo /usr/sbin/setcap cap_setpcap=p ./limiter
Use:
luser> ./limiter /bin/bash
[feeling powerless]
luser> ...try something privileged... or look at /proc/self/status etc.
luser> exit
luser> back in parent shell
//---- cut here 8< ----- [this is limiter.c]
/* Quick demo of blocking privilege */
#include <stdio.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <stdlib.h>
int main(int argc, char *argv[], char *envp[])
{
if (argc < 2) {
fprintf(stderr, "usage: %s <execv args>\n", argv[0]);
exit(1);
}
cap_t needed = cap_from_text("cap_setpcap=ep");
if (cap_set_proc(needed) != 0) {
perror("cap_set_proc failed");
exit(1);
}
int cap = 0;
int set;
while ((set = prctl(PR_CAPBSET_READ, cap)) >= 0) {
if (set && prctl(PR_CAPBSET_DROP, cap)) {
fprintf(stderr, "failed to drop bset capability: %s\n",
cap_to_name(cap));
exit(1);
}
cap++;
}
if (prctl(PR_SET_SECUREBITS, 0x2e /* magic combination */)) {
perror("unable lock secure-bits");
exit(1);
}
fprintf(stderr, "[feeling powerless]\n");
execve(argv[1], argv + 1, envp);
fprintf(stderr, "[execve(\"%s\",...) failed - try something else.]\n",
argv[1]);
exit(1);
}
//---- cut here 8< -----
> I have no problem with expressing this in a fine grained manner internally
> to the kernel but the user space interface needs to be atomic so that
> we can enable this all without privilege.
I'm not clear on the need for this specific detail.
> Further I may be off but I think the implementation would be more
> challenging than what I have already posted. ?That doesn't mean it
> won't be more useful long term.
[Not sure I followed this bit.]
I can see a desire to block luser -> luser transitions being a good
thing, but not because it has anything to do with privilege.
Cheers [and happy New Year!]
Andrew
>
> Eric
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
Alan Cox wrote:
>[email protected] (David Wagner) wrote:
>> You lost me there. The ability of a specific piece of code to voluntarily
>> relinquish privileges can be a big benefit to security.
>
>Can be - but its historically been an endless source of bugs and flaws
>because the code being run after you take the rights away is being run in
>an environment it didn't expect and wasn't tested in.
Are you just *shrugging* at the goals underlying these efforts?
The goals of enabling privilege separation and sandboxing seem like
highly laudable goals to me. I don't understand why anyone would
be opposed to efforts to achieve those goals.
Privilege-separation is a powerful software architecture technique.
It's been used in openssh, qmail, vsftpd, and other highly regarded
security-critical applications. (When a software designer uses privilege
separation, he *intends* for his code to be run in a low-privilege
environment. That's not a source of bugs.)
Sandboxing is a powerful security tool. It's been used for many
purposes. (When we invent a sandboxing tool, the whole purpose is
to run the sandboxed code to run in a low-privilege environment.)
There is indeed one undesired source of bugs sometimes introduced by
privilege-separation and sandboxing tools, and that is an increased
potential for attacks against setuid programs by local users. But calling
this "an endless source of bugs and flaws" seems over the top to me.
How many examples have there been? I can think of one of any significance
(sendmail). In any case, I would classify these flaws as inherently
relatively low-severity, because they can only be exploited by local
users.
I'm far more concerned about attacks by remote attackers. I don't
let untrusted people have accounts on my system. So I really am not
that concerned about ways that a local user might try to attack
setuid root programs. But I am quite concerned about remote exploits.
And privilege separation and sandboxing are two of the best techniques
we have available to defend against remote exploits.
To do that, application developers need better mechanisms to enable
them to voluntarily and irrevocably relinquish privilege. That seems
like a worthwhile goal, and something that ought to be attainable without
introducing much risk of opening up new ways of attacking setuid programs.
(Indeed, there have been a number of proposals for how to achieve that
here on linux-kernel in the past few days.) So why are you pushing back
against that goal? Why are you so critical even of reasonable attempts
to provide a way to achieve the benefits without enabling those kinds
of attacks on setuid programs? What am I missing?
Perhaps I'm reading you wrong, but I seem to sense an attitude where you
consider privilege separation and sandboxing to be relatively unimportant,
and where you consider the risk of local attacks on setuid programs to
be unavoidable and of paramount importance. I'm surprised to get this
impression, because that seems narrow and counter-productive to me.
> Sure. Not that it would be hard to do so. And have a careful look
> at the recent discussions on checkpoint/restart.
Indeed the LSM "no removal of restrictions" is simply a policy decision
that came about early on - no reason to assume it is a right policy
decision if it can be shown otherwise.
> Application developers want systems that work the way the man pages
> say they work. They do not want additional or conditional restrictions.
I disagree somewhat. They want them to work they way they did when they
tested it and the way they believe it works. Most of them never read the
manual or the standards documents. Take a look at the whining when stat()
size data stopped happening by chance to reflect bytes queued in a pipe.
> How many commercial applications start their installation instructions
> with "disable SELinux"? (Hint: lots)
And I am sure it time the sequence is going to go "Why did your business
web site get taken out for four weeks" / "We disabled SELinux as the app
said" / "Sue the app vendor"
If you tell someone to disable the safety systems on a crane you get
prosecuted.
> > I am sick and fed up with the conversations that go:
> > - I want to do X.
> > - X has been implemented.
> > - Sorry I can't use X as implemented because you have to be root to
> > use X.
> >
> Exasperated sigh. Privileged operations are privileged for a reason,
> not always a good reason mind you, but a reason nonetheless. If
> your application developers want to do things that require privilege
> you need to teach them how to write privileged programs safely. We've
> been working on exotic variations of system controls for decades
> and in the end your programmers have to write decent code because
> we haven't yet come up with a way to make all the things that people
> want their programs to do safe.
A useful question here would be to ask what it means to containerise
security. At the moment you can do this with virtual machines and while
its a nasty managability/security trade off the choice is there for the
most part and you can point at things like the amazon cloud as working
examples. We don't really have the notion of what setuidness means within
a container or how you can create a container which has its own internal
setuid, security model, LSM and 'superuser' but can't mess anything else
up, only for a virtual machine.
[I'll note Hurd tried to explore this area in part because Hurd was
designed around a model that history proved bogus - a big computer being
equitably shared with all the power possible but without messing up other
users]
Alan
Alan Cox wrote:
>> Sure. Not that it would be hard to do so. And have a careful look
>> at the recent discussions on checkpoint/restart.
>>
>
> Indeed the LSM "no removal of restrictions" is simply a policy decision
> that came about early on - no reason to assume it is a right policy
> decision if it can be shown otherwise.
>
>
>> Application developers want systems that work the way the man pages
>> say they work. They do not want additional or conditional restrictions.
>>
>
> I disagree somewhat. They want them to work they way they did when they
> tested it and the way they believe it works. Most of them never read the
> manual or the standards documents. Take a look at the whining when stat()
> size data stopped happening by chance to reflect bytes queued in a pipe.
>
Yeah, the good ones do at least try to consider both the documented
and traditional behaviors.
>
>> How many commercial applications start their installation instructions
>> with "disable SELinux"? (Hint: lots)
>>
>
> And I am sure it time the sequence is going to go "Why did your business
> web site get taken out for four weeks" / "We disabled SELinux as the app
> said" / "Sue the app vendor"
>
You have to demonstrate that SELinux would be prevented the outage.
Not so easy.
> If you tell someone to disable the safety systems on a crane you get
> prosecuted.
>
If you survive. The difference is the obvious physical harm.
>>> I am sick and fed up with the conversations that go:
>>> - I want to do X.
>>> - X has been implemented.
>>> - Sorry I can't use X as implemented because you have to be root to
>>> use X.
>>>
>>>
>> Exasperated sigh. Privileged operations are privileged for a reason,
>> not always a good reason mind you, but a reason nonetheless. If
>> your application developers want to do things that require privilege
>> you need to teach them how to write privileged programs safely. We've
>> been working on exotic variations of system controls for decades
>> and in the end your programmers have to write decent code because
>> we haven't yet come up with a way to make all the things that people
>> want their programs to do safe.
>>
>
> A useful question here would be to ask what it means to containerise
> security. At the moment you can do this with virtual machines and while
> its a nasty managability/security trade off the choice is there for the
> most part and you can point at things like the amazon cloud as working
> examples. We don't really have the notion of what setuidness means within
> a container or how you can create a container which has its own internal
> setuid, security model, LSM and 'superuser' but can't mess anything else
> up, only for a virtual machine.
>
I've said it many times. Separation is easy, sharing is hard. Isolated
machines, dedicated machines, virtual machines, containers, Mandatory
Access Control, and Discretionary Access Control and all means for
separation. Each has mechanisms to allow controlled sharing. The setuid
mechanism is primarily a DAC mechanism to allow Fred to give Barney
access to resources that Fred has access to that Barney does not.
Overloading the user ID with the root privilege model offered advantages
in the days of computers with 64k of RAM, and we have that legacy to
deal with. This tends to obfuscate the value of setuid for DAC.
> [I'll note Hurd tried to explore this area in part because Hurd was
> designed around a model that history proved bogus - a big computer being
> equitably shared with all the power possible but without messing up other
> users]
>
> Alan
>
Eric W. Biederman wrote:
>[email protected] (David Wagner) writes:
>> When you talk about DOS, let's be a bit more precise. disablenetwork
>> gives a way to deny setuid programs access to the network. It's not a
>> general-purpose DOS; it's denying access to the network only. And the
>> network is fundamentally unreliable. No security-critical mechanism
>> should be relying upon the availability of the network.
>
>The audit daemon should not rely on netlink?
auditd is not a setuid-root program. It is launched at boot time.
(If that's what you're referring to.)
I'm personally not very worried about attacks on a setuid-root program
that leave it unable to log messages to the audit log. I personally
find it hard to get very concerned about that scenario. And if there
is a setuid-root program where it is absolutely vital that the log
messages get through, then the setuid-root program probably ought to
be checking return values and acknowledgements anyway, regardless of
whether disablenetwork is in place or not.
>For me the case is simple. I have seen several plausible sounding
>scenarios that get most of the way there. I know I am stupid when
>it comes to security and that people exploiting problems are going
>to be looking harder than I will. Therefore I think there is
>a reasonable chance this will introduce a security hole for someone.
OK. I'm not opposed to introducing some way to disable setuid
execution, to give folks a greater comfort level. I still am not
convinced it's necessary (I personally suspect it to be unnecessary),
but if it is the necessary political compromise to enable the Linux
kernel to better support privilege separation and sandboxing,
so be it. Whatever it takes to get that support in place is
worthwhile. So, thank you for working out how to implement such
a mechanism!
On Sun, Jan 3, 2010 at 6:47 AM, Casey Schaufler <[email protected]> wrote:
> Peter Dolding wrote:
>> ...
>
> If you are using SELinux application developers need to know
> what the policy of the system they are using is or they need
> to know that any operation may fail for reasons mysterious to
> the developer and that the programs needs to be coded accordingly.
Again how can application developers do this releasing on many
different distrobutions in a cost effective way.
Yes application developer can code to cope with operations may fail
for mysterious. But again you over look the poor end user who the
application just failed to work right for. The Application maker
gets rightly or wrong tared and feathered for applications failing to
perform tasks.
>
>> To an application developers.
>> 1) Mandatory access controls that relate to what the application need
>> to do is of interest.
>> 2) mandatory integrity controls that relate to what the application
>> needs protected of interest.
>>
>
> Right. And with SELinux there is no way for an application to
> determine from readily available information whether an action
> is appropriate. This is not a failing of the LSM, it is a well
> known and often discussed characteristic of SELinux.
>
It is a failing of LSM. Where is the framework providing such a
feature to applications in a LSM neutral way. Since such a framework
does not exist there is no pressure on LSM's to support it. Of course
SELinux could go on disregarding the hooks but then more applications
developers would be recommending other LSM frameworks that support
them.
Ie if SELinux wants to keep market share they would be force to lift game.
This is the problem you are not seeing you have 4 different sets of
people LSM's have to interact with.
1) LSM developers. The current framework is good for them.
2) Application Developers. Current framework completely suxs there
is nothing in it for them to make there live easy.
3) Administrators. Ok can be made do most of what they want but is
insane to add applications to a LSM that don't have a preexisting
profile. Or you end up running items like Apparmor that really don't
secure the application correctly to avoid. Basically it suxs for
these guys as well. Since its either waste hours or do there job
poorly.
4) The poor end user having application magically fail due to secuirty
system configuration being wrong. Suxs for these people as well.
Earlier here you went into upper level policy information like
passwords and the like.
I am not talking upper level policy. I am talking low level part of
the policy engine give to the application developers. Will make their
life more tolerable. Applications may have there own policy engine
inside ie good examples mysql and postgresql they have there own
security engines inside. So if they want to do upper level policy
they can by there own engine. They just need access to the settings
of raw LSM hooks somehow to enforce it. Basically we are not talking
normal LSM module policies here. Application developers have no
reason to have any interest in LSM normal policies they are not a
usable tool to them. Instead LSM normal polices are just a pain in
the but that cause applications to fail on there users in strange and
unpredictable ways.
I am not talking about applications controling application to
application policy here other than direct execution. Like accessing
system wide password data that is application to application policy.
That is not normally the worry of Application developers. Application
developers would just list they need access to particular applications
to operate like getent to look up global user information.
Other thing is provide application developers a way of providing a
list of LSM monitored points that it needs to pass to operate
completely. Like required files, network access, root rights and so
on this is what I would call Application secuirty data.
Administrator can use this Application secuirty data to confirm if or
if not the LSM will allow application to operate correctly. So the
poor end user does not have application fail to perform a task they
need. Also having a list of everything the application needs to
operate could be used to access the secuirty risk of an application
even before it is first run. Useful for when Administrator has to
pick between two different applications todo task.
Application secuirty data could also be processed by LSM to produce
basic profiles that work.
Now of course I know this kind of data is going to go against your
grain Casey Schaufler because it will not be simple. Everything the
LSM hooks could control that the application is planing to come into
contact with would be listed.
Its one of the largest things that makes SELinux policies unworkable.
But that is lack of clean seperation between user and application
data. Complexity is required here so no more than what application
needs is granted. Application developers don't have a issue with
complexity if they can do it once for everything.
Capabilities have improved secuirty because application developers can
control them in a dependable way. Now I don't think the idea of
allowing Capabilities to control every single LSM hook directly would
go down well. For configurable items like if or if not access to a
particular file is allowed Capabilities cannot do it. API limitation
not flexible enough.
Serious question. If we attempted to make a generic application mac
enforcement engine. Number 1 is it possible? Number two how many
hooks would be required into the engine to allow same flexablity as
current day LSM modules has?
I think it would be possible. And I don't think there would be many
hooks required.
1) File access hook to handle the different ways LSM store file access.
2) Notifcation hook to inform LSM of a event it flaged.
3) Execute Hook to setup engines processing.
Engine could take care of auto termination of applications and the
like. A single engine that can handle all hooks would basically
follow the model of iptables. It can be configured any way LSM
choose.
LSM goal is to be generic. Part of that goal should be to make LSM's
more generic reducing down the differences between LSM modules.
>>
>> The simple problem here is that SELinux along with Smack and others
>> because its too complex with too many variables making its config
>> files too hard for applications makers to release ones that work.
>>
>
> You are inappropriately painting SELinux and Smack with the same brush.
> Addressing this complexity was a design goal of Smack and while the
> addition of any MAC scheme will require additional attention by the
> application developer at least it is possible to do so with Smack.
> SELinux embraces the "ignorant application" fallacy, assuming that the
> policy takes care of everything so that the application doesn't have
> to do anything. This never worked in the bad old days of Unix based
> MLS systems, and as you point out, it still does not work today.
I should have written that point better. Application developers have
to build for all systems. They have to build configurations for the
multitude of SELinux systems out there that are incompatible then
system might be running Smack or other LSM so then they have to build
configuration files for them. So it ends up too complex more files
they have to maintain bigger risk of sink errors between the files.
>
>> Remember safety systems can kill just as much save. ?In this case we
>> as a kernel could be prosecuted for a too complex interface to
>> secuirty system when a simpler could be done to achieve the same level
>> of secuirty. ?There have been cases where companys who have put too
>> complex of secuirty on devices have been sued and lost. ?Due to the
>> fact it too so long to start up a machine to move weight off a person
>> that they died from crushing.
>>
>
> Amen brother. Simple good. Sophisticated bad.
Too simple is bad as well. Its key to make sure complexity is
manageable. Sophisticated and Simple are not against each other.
Something can be extremely simple to use but performing extremely
Sophisticated operations. The key thing to make a Sophisticated
Simple is breaking design into manageable parts.
Past you have just taken make design simpler cut out the Sophisticated
parts so making a weaker system.
A embroidery machine is insanely Sophisticated. The hardware side is
hidden from users. Mechanics working on the machine worry about that
part. The designer worries about the designs stitches and the like
while not worrying about the hardware. The operate of the machine
just make sure they feed the matterial for the embroidery in and press
the right button for the right design.
Now lets say we took that same Sophisticated machine and made creating
the design and the hardware side 1. Straight away a machine that was
perfectly simple for a designer to put in a new pattern becomes
insanely complex. They were split in 2 for a good reason.
Is there any good reason to keep application and user related secuirty
data in the same file or even the same format. There is no good
reason if it just making a Sophisticated problem more complex than it
should be.
Note Mechanices and designers work in 2 completely different formats
in embroidery machines and they get along perfectly.
A generic format the designer produces when in-loading into machine
its converted to the machines internal format. Even printing is the
same with PDF. Every printing press design is different but you can
send the same documents to them all. Makes life simpler. We need
the same for application secuirty data.
Please don't think Sophisticated equals complex for user any more. I
can keep on providing examples after examples that its wrong.
Sophisticated to create yes. But should not equal complex to use.
>
>> Currently Application Developers are being crushed under too large of
>> problem so they are responding with the only valid path remove the
>> defective secuirty.
>>
>> Basically the One size fits all is the problem. ?We currently have a
>> shoe that fits no one well. ? We need 2 shoes one for the application
>> developer(Generic LSM interface for applications) one for the
>> administrators(Very much the current LSM system cleaned up) that fits
>> over the same socks(Linux) no problems.
>>
>
> Yes. One size fits all is bad. No, generic interfaces to disparate
> mechanisms are not good. I hate to say this, but you can't have what
> you're requesting. It does not make sense.
Generic interfaces covering what will always been the same is good.
It prevents unrequired duplication.
>
>> Please don't over look Alan Cox that items like Selinux are spreading
>> arms out in stuff like postgresql and X11. ?These interfaces really
>> should have been generic interfaces or the same crap of duplication
>> you are fighting against in kernel is going to happen every where else
>> in Userspace.
>>
>
> It's already started. Sorry.
So adding on a framework for generic controls of LSM does go hand in
hand with this. Other wise threads that should have been lowed in
privilege are not.
>
>> The compete user-space application side interfaces for LSM has been
>> baddy neglected. ?It seams to be the idea that Applications have no
>> right to talk to LSM becuase that way everything will be more secure.
>> ?LSM with application control can run finer secuirty than LSM without
>> application control. ? Reason application know what it is doing in
>> each thread so can tell LSM to disable what is not need in that thread
>> so reducing attack points to get access where the LSM without
>> application control has to provide an access rights over the complete
>> applications.
>>
>> Basically current model is defective secuirty. ? So we have complex
>> hard to use secuirty that does not work as good as what it could. ?No
>> wonder application developers are disabling it. ? We should be more
>> serious about addressing the problem.
>>
>
> If you want to get away from complexity you can start by eschewing
> SELinux. SELinux is designed to encompass absolutely everything and
> hence must be too complex. Look elsewhere and look carefully before
> you blame the underlying mechanisms.
>
You don't get it I am not just talking about SELinux. I am talking
about the complete LSM model from the application builder point of
view. There is no central data store for application stuff.
Application and user control policies are different. Current LSM
model shoves both into the same area. So making it extremely hard to
sort out what was a admin alteration to allow user to do something and
what is required by application. This is a very big design problem.
Peter Dolding
Alan Cox wrote:
> I am just pointing out the dangers of continuing to blindly pursue that
> model without thinking about the bigger picture.
But people have been thinking about the bigger picture.
Indeed, that's the motivation for the patch proposed here.
I don't know why you think people have ignored the bigger picture.
On Fri, 1 Jan 2010, Pavel Machek wrote:
> > Quoting Michael Stone ([email protected]):
> > > Implement security_* hooks for socket_create, socket_bind, socket_connect,
> > > socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
> > > process with networking restrictions. Exempt AF_UNIX sockets.
> > >
> > > Signed-off-by: Michael Stone <[email protected]>
> >
> > Acked-by: Serge Hallyn <[email protected]>
>
> For the record: NAK, as it introduces security holes.
Please elaborate.
--
James Morris
<[email protected]>
On Mon 2010-01-11 08:11:55, James Morris wrote:
> On Fri, 1 Jan 2010, Pavel Machek wrote:
>
> > > Quoting Michael Stone ([email protected]):
> > > > Implement security_* hooks for socket_create, socket_bind, socket_connect,
> > > > socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
> > > > process with networking restrictions. Exempt AF_UNIX sockets.
> > > >
> > > > Signed-off-by: Michael Stone <[email protected]>
> > >
> > > Acked-by: Serge Hallyn <[email protected]>
> >
> > For the record: NAK, as it introduces security holes.
>
> Please elaborate.
See the mailthread.
Allows user to disable suid program's access to network. That bypasses
audit, and will cause system-wide DoS if suid program decides to go
daemon.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Sun, 10 Jan 2010, Pavel Machek wrote:
> > > For the record: NAK, as it introduces security holes.
> >
> > Please elaborate.
>
> See the mailthread.
Yep, wading through several weeks of it..
>
> Allows user to disable suid program's access to network. That bypasses
> audit, and will cause system-wide DoS if suid program decides to go
> daemon.
Ok.
--
James Morris
<[email protected]>
On Fri, 1 Jan 2010, Pavel Machek wrote:
> > > Quoting Michael Stone ([email protected]):
> > > > Implement security_* hooks for socket_create, socket_bind, socket_connect,
> > > > socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
> > > > process with networking restrictions. Exempt AF_UNIX sockets.
> > > >
> > > > Signed-off-by: Michael Stone <[email protected]>
> > >
> > > Acked-by: Serge Hallyn <[email protected]>
> >
> > For the record: NAK, as it introduces security holes.
>
> Please elaborate.
Pavel's position is that disablenetwork is likely to permit some attacker
somewhere to deny network access to some setuid app some day in a way that
violates some security policy.
He has mentioned specific concern over scenarios like:
Alice configures PAM auth to 'fail open' by checking login credentials
against a restrictive LDAP server and, if the server is unavailable, against
a very permissive files database.
Alice updates her kernel to a version with disablenetwork.
Mallory calls disablenetwork, calls su -, and vanquishes all.
My position is that better isolation facilities like disablenetwork will
prevent far more grievous security faults than they (theoretically) cause.
What is your perspective on the matter?
Regards,
Michael
On Sun 2010-01-10 16:54:09, Michael Stone wrote:
> On Fri, 1 Jan 2010, Pavel Machek wrote:
>
> >> > Quoting Michael Stone ([email protected]):
> >> > > Implement security_* hooks for socket_create, socket_bind, socket_connect,
> >> > > socket_sendmsg, and ptrace_access_check which return -EPERM when called from a
> >> > > process with networking restrictions. Exempt AF_UNIX sockets.
> >> > > > > > Signed-off-by: Michael Stone <[email protected]>
> >> > > > Acked-by: Serge Hallyn <[email protected]>
> >> > For the record: NAK, as it introduces security holes.
> >
> >Please elaborate.
>
> Pavel's position is that disablenetwork is likely to permit some attacker
> somewhere to deny network access to some setuid app some day in a way that
> violates some security policy.
>
> He has mentioned specific concern over scenarios like:
Make that scenario 1.
> Alice configures PAM auth to 'fail open' by checking login credentials
> against a restrictive LDAP server and, if the server is unavailable, against
> a very permissive files database.
Scenario 2:
Mallory calls disablenetwork, calls sendmail as the first user after
boot; sendmail can't deliver anything (its network is disabled), but
starts forking and taking requests for other users, DoSing the mail
delivery.
Scenario 3:
Mallory calls disablenetwork, then keeps hammering on su, knowing that
su can no longer send data to audit subsystem and so he will not get caught.
> My position is that better isolation facilities like disablenetwork will
> prevent far more grievous security faults than they (theoretically) cause.
You can trivialy make disablenetwork disable setuid exec, too. That
will introduce better isolation facilities, but not introduce any new
security problems.
For some reason, you don't want to do the obviously right thing.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Sun, Jan 10, 2010 at 16:54, Michael Stone <[email protected]> wrote:
> On Fri, 1 Jan 2010, Pavel Machek wrote:
>> > > For the record: NAK, as it introduces security holes.
>>
>> Please elaborate.
>
> Pavel's position is that disablenetwork is likely to permit some attacker
> somewhere to deny network access to some setuid app some day in a way that
> violates some security policy.
>
> He has mentioned specific concern over scenarios like:
>
> Alice configures PAM auth to 'fail open' by checking login credentials
> against a restrictive LDAP server and, if the server is unavailable,
> against
> a very permissive files database.
>
> Alice updates her kernel to a version with disablenetwork.
>
> Mallory calls disablenetwork, calls su -, and vanquishes all.
No, there is a *MUCH* bigger security issue here. There are existing
PAM modules which lazily fork background processes to handle
authentication, authorization, logging, etc. Now assume that one of
those PAM modules is hooked from /etc/pam.d/su.
(1) Mallory runs "disablenetwork su -"
(2) The PAM module lazily starts its background daemon with a
10-minute idle timeout.
(3) The daemon has network disabled, and so it is completely nonfunctional.
(4) The daemon automatically denies all logins because it cannot
communicate with the login server
(5) Alice tries to run "su -" from her regular terminal.
(6) Alice's "su" process communicates with the running daemon and
fails because "the network is down".
All of that software is perfectly reasonably designed... the daemon is
even fail-secure in the event that the network really is inaccessible.
Unfortunately it lets Mallory easily DoS every superuser login on the
system without generating a single audit log. The only process that
knows what he did is the one that cannot communicate with the remote
audit daemon.
Moreover, that DoS would continue until the 10-minute idle timeout
actually expired. As Alice keeps trying to log in, it will keep
automatically extending the daemon's lifetime.
Now, you can try to claim "Nobody has it configured like that" or
"None of the standard Linux PAM modules do that"... but that does not
resolve the problem. A sysadmin and part-time programmer (not knowing
about a little-documented "disablenetwork" feature) could very easily
write software like that and assume that it is secure.
The #1 rule for setuid binaries is that you DO NOT INHERIT ANYTHING.
Any kernel feature or setuid program which violates that rule is just
going to cause big security holes. Security models must be either
obviously correct or mathematically provable (or both)... and this is
neither.
Cheers,
Kyle Moffett
Pavel Machek wrote:
> You can trivialy make disablenetwork disable setuid exec, too. That
> will introduce better isolation facilities, but not introduce any new
> security problems.
>
> For some reason, you don't want to do the obviously right thing.
I don't want to do it because it's not "obviously right" to me: I *have* setuid
programs that I want to be able to raise privileges when network-disabled.
I *don't have* any setuid programs that will be harmed by disablenetwork.
Examples of software that I want to be able to gain privileges normally include:
rainbow, which requires privilege in order to add new accounts to the system
and in order to call setuid() but which does not require networking
privileges.
qmail-queue, which uses setuid to deliver mail that it reads from fd 0 to
local users
and other old favorites like mount, fusermount, X, and, presumably, any audio
software that wants to go realtime.
Kind regards,
Michael
On Sun, 10 Jan 2010, Michael Stone wrote:
>
> Pavel's position is that disablenetwork is likely to permit some attacker
> somewhere to deny network access to some setuid app some day in a way that
> violates some security policy.
>
> He has mentioned specific concern over scenarios like:
>
> Alice configures PAM auth to 'fail open' by checking login credentials
> against a restrictive LDAP server and, if the server is unavailable, against
> a very permissive files database.
>
> Alice updates her kernel to a version with disablenetwork.
>
> Mallory calls disablenetwork, calls su -, and vanquishes all.
>
> My position is that better isolation facilities like disablenetwork will
> prevent far more grievous security faults than they (theoretically) cause.
>
> What is your perspective on the matter?
Unexpected failure modes for privileged apps using security interfaces has
already proven to be a problem (e.g. the sendmail capabilities bug), so it
seems prudent to try and mitigate that as well. I don't think we need to
look at this as an either-or situation -- it seems we can do both, and get
something useful in its own right from the mitigation.
--
James Morris
<[email protected]>
Paraphrasing Kyle:
> Suppose there exist PAM modules which lazily fork background processes. Now
> assume that one of those PAM modules is hooked from /etc/pam.d/su, that the
> module fails closed when the network is unavailable, and that Mallory wins
> the race to start the daemon. Boom.
I'm not disagreeing that there are configurations of programs, written for
kernels without disablenetwork, which cease to be correct on kernels that
provide it. However, all this says to me is that people who need to use those
configurations probably shouldn't use disablenetwork. (Or that we haven't found
exactly the right semantics for disablenetwork yet.)
Let's keep working on it.
Michael
On Sun, Jan 10, 2010 at 6:08 PM, Michael Stone <[email protected]> wrote:
> Paraphrasing Kyle:
>
>> Suppose there exist PAM modules which lazily fork background processes.
>> Now
>> assume that one of those PAM modules is hooked from /etc/pam.d/su, that
>> the
>> module fails closed when the network is unavailable, and that Mallory wins
>> the race to start the daemon. Boom.
>
> I'm not disagreeing that there are configurations of programs, written for
> kernels without disablenetwork, which cease to be correct on kernels that
> provide it. However, all this says to me is that people who need to use
> those
> configurations probably shouldn't use disablenetwork. (Or that we haven't
> found
> exactly the right semantics for disablenetwork yet.)
With the semantics given, the choice for using disablenetwork is given
to the unprivileged process, not to the administrator or privileged
process, so people using these configurations have no choice - the
malicious local user can just use it anyway.
I still think requiring a drop of suid abilities would be best - if
the suid process wants to run in a no-network environment it can still
disablenetwork itself.
Michael Stone wrote:
> Examples of software that I want to be able to gain privileges normally include:
>
> rainbow, which requires privilege in order to add new accounts to the system
> and in order to call setuid() but which does not require networking
> privileges.
If the system is not using local files (i.e. /etc/passwd and /etc/shadow),
the process who wants to add new accounts to the system might need network
access (e.g. to LDAP server), doesn't it?
Michael Stone wrote:
>Pavel's position is that disablenetwork is likely to permit some attacker
>somewhere to deny network access to some setuid app some day in a way that
>violates some security policy.
>
>He has mentioned specific concern over scenarios like:
>
> Alice configures PAM auth to 'fail open' by checking login credentials
> against a restrictive LDAP server and, if the server is unavailable, against
> a very permissive files database.
>
> Alice updates her kernel to a version with disablenetwork.
>
> Mallory calls disablenetwork, calls su -, and vanquishes all.
>
>My position is that better isolation facilities like disablenetwork will
>prevent far more grievous security faults than they (theoretically) cause.
>
>What is your perspective on the matter?
I agree with you. As I've mentioned before, I think it's an unconvincing
objection. If Alice sets such a poorly thought-out security policy,
then there are probably many other ways to attack the system, even if
you don't introduce disablenetwork. (Example atttack #1: Use rlimit
to set the number of file descriptors that can be opened very low, then
call su -. Example attack #2: DOS the LDAP server, and then call su -.
There are probably many more.)
But it's also true that it's possible to achieve many of the benefits
of disablenetwork in a way that avoids introducing the potential risks
that Pavel is concerned about. If that's the political compromise
that it takes to get disablenetwork into the kernel, that's still a
step forward. It'd be better than what we have today.
Pavel Machek wrote:
>Scenario 2:
>
>Mallory calls disablenetwork, calls sendmail as the first user after
>boot; sendmail can't deliver anything (its network is disabled), but
>starts forking and taking requests for other users, DoSing the mail
>delivery.
On my system, sendmail is started by trusted boot scripts before
a "Mallory" would have a chance to do that, so the premise does not
apply. I cannot guarantee this is the case on every system, but I'm
not familiar with any important exceptions.
>Scenario 3:
>
>Mallory calls disablenetwork, then keeps hammering on su, knowing that
>su can no longer send data to audit subsystem and so he will not get caught.
And then what? I don't see how this gets Mallory very far.
She can keep hammering on su and keep getting denied access to
root, and it's not going to help her much.
(Note: If root's password is guessable, then there's a fair chance you're
screwed even without disablenetwork. If root has a guessable password,
then Mallory can keep trying until she guesses right, then when she
gets it right, go and retroactively edit the logs to eliminate the
log entries if necessary -- if those log entries are ever looked at,
which is often dubious. It's very difficult to build a secure system
if the root password is guessable. So in my opinion, the root password
must be unguessable if you want to have a secure system, and we should
analyze disablenetwork under the assumption that sysadmins have done so.
And if the system administrators do choose an unguessable password,
then your Scenario 3 doesn't seem to help Mallory.)
The impact here seems pretty minor.
>You can trivialy make disablenetwork disable setuid exec, too. That
>will introduce better isolation facilities, but not introduce any new
>security problems.
Yup, this is probably the compromise that must be made, for political
reasons, to get this into the kernel.
But I just want to document that it's not clear to me that this decision
is well justified on technical grounds.
Kyle Moffett wrote:
>No, there is a *MUCH* bigger security issue here. There are existing
>PAM modules which lazily fork background processes to handle
>authentication, authorization, logging, etc. Now assume that one of
>those PAM modules is hooked from /etc/pam.d/su.
>
>(1) Mallory runs "disablenetwork su -"
>(2) The PAM module lazily starts its background daemon with a
>10-minute idle timeout.
>(3) The daemon has network disabled, and so it is completely nonfunctional.
>(4) The daemon automatically denies all logins because it cannot
>communicate with the login server
>(5) Alice tries to run "su -" from her regular terminal.
>(6) Alice's "su" process communicates with the running daemon and
>fails because "the network is down".
>
>All of that software is perfectly reasonably designed... the daemon is
>even fail-secure in the event that the network really is inaccessible.
> Unfortunately it lets Mallory easily DoS every superuser login on the
>system without generating a single audit log. The only process that
>knows what he did is the one that cannot communicate with the remote
>audit daemon.
It's just a DOS. There are a gazillion and one ways to DOS a typical
Linux system, especially if the attacker has an account on the system.
One alternative way: Mallory can mount such a DOS simply by flooding
the network. That's not rocket science.
Another alternative way that might work (I don't know): What happens if
Mallory uses rlimit (RLIMIT_NOFILE) to set the maximum number of open
file descriptors very low, then runs "su -"? Do we get the same DOS
outcome you listed above? I'd guess yes, unless because these resource
limits are inherited across fork and exec.
I think stopping DOS is just really hard. I'm not convinced this
is increasing the power of real-life attackers to any significant
extent.
>Now, you can try to claim "Nobody has it configured like that" or
>"None of the standard Linux PAM modules do that"... but that does not
>resolve the problem. A sysadmin and part-time programmer (not knowing
>about a little-documented "disablenetwork" feature) could very easily
>write software like that and assume that it is secure.
I don't know. I'm not really persuaded by your invocation of a
hypothetical sysadmin who writes their own setuid programs. Writing
setuid programs (or programs invoked by setuid programs) securely is
really hard. In all honesty, if your average "sysadmin and part-time
programmer" tries to roll their own setuid program for this kind of
thing, there's a fair chance that it will have a security hole --
and that's probably true whether or not you enable disablenetwork.
Introducing disablenetwork may increase the chances of insecurity in
setuid programs written by non-experts somewhat, but I bet it's only a
small increment compared to the overall risk.
>The #1 rule for setuid binaries is that you DO NOT INHERIT ANYTHING.
>Any kernel feature or setuid program which violates that rule is just
>going to cause big security holes. Security models must be either
>obviously correct or mathematically provable (or both)... and this is
>neither.
Yeah, but we can also argue the other way from first principles too: If
you're writing a setuid program that *assumes* the network is reliable,
and fails insecurely if a packet doesn't get through, then you're
probably doing something wrong. Networks are fundamentally unreliable.
Security-critical software shouldn't be written in a way that fails
unsafely if the network is unavailable.
Tetsuo Handa wrote:
>Michael Stone wrote:
>> Examples of software that I want to be able to gain privileges normally include:
>>
>> rainbow, which requires privilege in order to add new accounts to the system
>> and in order to call setuid() but which does not require networking
>> privileges.
>
> If the system is not using local files (i.e. /etc/passwd and /etc/shadow),
> the process who wants to add new accounts to the system might need network
> access (e.g. to LDAP server), doesn't it?
General purpose account manipulation tools might need network access but
rainbow handles all its account manipulations via state stored in
/var/spool/rainbow/2. This state is made available to the rest of the system
via libnss_rainbow.
Michael
Tetsuo Handa wrote:
> Michael Stone wrote:
>
>> Examples of software that I want to be able to gain privileges normally include:
>>
>> rainbow, which requires privilege in order to add new accounts to the system
>> and in order to call setuid() but which does not require networking
>> privileges.
>>
>
> If the system is not using local files (i.e. /etc/passwd and /etc/shadow),
> the process who wants to add new accounts to the system might need network
> access (e.g. to LDAP server), doesn't it?
>
>
It's much worse than that. A user that has been network disabled
who tries using ls may find that it goes looking for the network
on each name lookup and has to wait for a timeout for each. Yet
another example of why Real Users hate security features with
such passion. Then, if there are local file entries that differ
from the "official" network account values when the library
functions finally fall back on the local values you get the wrong
names for file owners. Now we've made ls slow and untrustworthy
in the name of security.
Bryan Donlan wrote:
> On Sun, Jan 10, 2010 at 6:08 PM, Michael Stone <[email protected]> wrote:
>
>> Paraphrasing Kyle:
>>
>>
>>> Suppose there exist PAM modules which lazily fork background processes.
>>> Now
>>> assume that one of those PAM modules is hooked from /etc/pam.d/su, that
>>> the
>>> module fails closed when the network is unavailable, and that Mallory wins
>>> the race to start the daemon. Boom.
>>>
>> I'm not disagreeing that there are configurations of programs, written for
>> kernels without disablenetwork, which cease to be correct on kernels that
>> provide it. However, all this says to me is that people who need to use
>> those
>> configurations probably shouldn't use disablenetwork. (Or that we haven't
>> found
>> exactly the right semantics for disablenetwork yet.)
>>
>
> With the semantics given, the choice for using disablenetwork is given
> to the unprivileged process, not to the administrator or privileged
> process, so people using these configurations have no choice - the
> malicious local user can just use it anyway.
>
> I still think requiring a drop of suid abilities would be best - if
> the suid process wants to run in a no-network environment it can still
> disablenetwork itself.
>
>
Stop. If you can count on the program to use the mechanisms you've
described correctly you can count on it to use exec, socket, and
bind correctly. You're only trading one set of behaviors for another.
On Sun, Jan 10, 2010 at 8:50 PM, Casey Schaufler <[email protected]> wrote:
> Bryan Donlan wrote:
>> On Sun, Jan 10, 2010 at 6:08 PM, Michael Stone <[email protected]> wrote:
>>
>>> Paraphrasing Kyle:
>>>
>>>
>>>> Suppose there exist PAM modules which lazily fork background processes.
>>>> Now
>>>> assume that one of those PAM modules is hooked from /etc/pam.d/su, that
>>>> the
>>>> module fails closed when the network is unavailable, and that Mallory wins
>>>> the race to start the daemon. Boom.
>>>>
>>> I'm not disagreeing that there are configurations of programs, written for
>>> kernels without disablenetwork, which cease to be correct on kernels that
>>> provide it. However, all this says to me is that people who need to use
>>> those
>>> configurations probably shouldn't use disablenetwork. (Or that we haven't
>>> found
>>> exactly the right semantics for disablenetwork yet.)
>>>
>>
>> With the semantics given, the choice for using disablenetwork is given
>> to the unprivileged process, not to the administrator or privileged
>> process, so people using these configurations have no choice - the
>> malicious local user can just use it anyway.
>>
>> I still think requiring a drop of suid abilities would be best - if
>> the suid process wants to run in a no-network environment it can still
>> disablenetwork itself.
>>
>>
>
> Stop. If you can count on the program to use the mechanisms you've
> described correctly you can count on it to use exec, socket, and
> bind correctly. You're only trading one set of behaviors for another.
I don't think there's any argument that a program designed with
disablenetwork in mind will have no problems with disablenetwork
existing. The only concern is when a malicious (or ill-conceived)
program disables network access, then invokes a naive setuid program.
What I meant by the above is is, by my reading Michael suggests that
systems where there are setuid programs that grossly misbehave without
network access should simply not use disablenetwork; however my point
is that there is no such choice available to the administrator. In the
proposed APIs, disablenetwork is always available, and any untrusted
user can push it on all setuid programs in the system.
There were also suggestions of setuid programs that might themselves
want to drop network access; but one can simply have said setuid
program drop network access after it's executed, rather than relying
on the (untrusted anyway!) invoker to do so. So there's no need to
have it set by the caller, and indeed this may be undesirable because
the suid program will need to drop it again _anyway_ since it can't
assume the caller really did drop it. And of course, since this suid
program is asking for its network access to be disabled, it is
presumably prepared to deal with the consequences.
Finally, if there is a need for an untrusted program to invoke a
set-uid program, this can always be emulated by making a request over
a unix domain socket. Since presumably the program that used the
disablenetwork facility is designed around said disablenetwork
facility, it's not much of a burden to expect it use such a facility
in the unlikely case that there's a program that can't be trusted to
use the network, but does need to make some privileged operations.
In short:
* If network access is restored over suid, then we can leak data over
ping or any number of other routes, so that's right out.
* If network access is denied over suid, there are concerns of denial
of service in certain configurations.
* If suid is denied entirely, we have no denial of service or
information leak concerns via the suid mechanism (since the mechanism
is completely unusable). And if we really do need to execute something
at an elevated privilege, we can ask a helper daemon to do it on our
behalf.
Hi!
> * If network access is restored over suid, then we can leak data over
> ping or any number of other routes, so that's right out.
ACK.
> * If network access is denied over suid, there are concerns of denial
> of service in certain configurations.
So that should be right out, too.
> * If suid is denied entirely, we have no denial of service or
> information leak concerns via the suid mechanism (since the mechanism
> is completely unusable). And if we really do need to execute something
> at an elevated privilege, we can ask a helper daemon to do it on our
> behalf.
Yes please. This is the obvious solution.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Hi!
> >You can trivialy make disablenetwork disable setuid exec, too. That
> >will introduce better isolation facilities, but not introduce any new
> >security problems.
> >
> >For some reason, you don't want to do the obviously right thing.
>
> I don't want to do it because it's not "obviously right" to me: I *have*
> setuid
> programs that I want to be able to raise privileges when network-disabled.
> I *don't have* any setuid programs that will be harmed by disablenetwork.
Well, I do not have any desire to use disablenetwork, but I do not
want my users to use it and DoS sendmail.
> Examples of software that I want to be able to gain privileges normally
> include:
You'll have to make sure those are not accessed from the
disablenetworked parts, I'd say. Pre-existing unix domain socket
should be the way to go.
> rainbow, which requires privilege in order to add new accounts to the
> system
> and in order to call setuid() but which does not require networking
> privileges.
>
> qmail-queue, which uses setuid to deliver mail that it reads from fd 0 to
> local users
>
> and other old favorites like mount, fusermount, X, and, presumably, any
> audio
> software that wants to go realtime.
mount certainly wants network access for NFS.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Mon, Jan 11, 2010 at 01:29:43AM +0000, David Wagner wrote:
> Pavel Machek wrote:
> >Scenario 2:
> >
> >Mallory calls disablenetwork, calls sendmail as the first user after
> >boot; sendmail can't deliver anything (its network is disabled), but
> >starts forking and taking requests for other users, DoSing the mail
> >delivery.
>
> On my system, sendmail is started by trusted boot scripts before
> a "Mallory" would have a chance to do that, so the premise does not
> apply. I cannot guarantee this is the case on every system, but I'm
> not familiar with any important exceptions.
>
> >Scenario 3:
> >
> >Mallory calls disablenetwork, then keeps hammering on su, knowing that
> >su can no longer send data to audit subsystem and so he will not get caught.
>
> And then what? I don't see how this gets Mallory very far.
> She can keep hammering on su and keep getting denied access to
> root, and it's not going to help her much.
I wondered about that too. But IIRC the stated scenario was that there
was a PAM module involved that spawned a daemon on-demand that communicated
over the network. And if Mallory's invocation of su caused that daemon to
be spawned then it would be inherit disablenetwork. And that would affect
subsequent authentication through that module.
Furthermore the scenario had su access being logged over the network,
so Mallory's maliciousness would not be logged.
> (Note: If root's password is guessable, then there's a fair chance you're
> screwed even without disablenetwork. If root has a guessable password,
> then Mallory can keep trying until she guesses right, then when she
> gets it right, go and retroactively edit the logs to eliminate the
> log entries if necessary -- if those log entries are ever looked at,
> which is often dubious. It's very difficult to build a secure system
> if the root password is guessable. So in my opinion, the root password
> must be unguessable if you want to have a secure system, and we should
> analyze disablenetwork under the assumption that sysadmins have done so.
> And if the system administrators do choose an unguessable password,
> then your Scenario 3 doesn't seem to help Mallory.)
>
> The impact here seems pretty minor.
I don't think guessable passwords were part of the scenario.
> >You can trivialy make disablenetwork disable setuid exec, too. That
> >will introduce better isolation facilities, but not introduce any new
> >security problems.
>
> Yup, this is probably the compromise that must be made, for political
> reasons, to get this into the kernel.
>
> But I just want to document that it's not clear to me that this decision
> is well justified on technical grounds.
Quoting Michael Stone ([email protected]):
> Tetsuo Handa wrote:
>
> >Michael Stone wrote:
> >>Examples of software that I want to be able to gain privileges normally include:
> >>
> >> rainbow, which requires privilege in order to add new accounts to the system
> >> and in order to call setuid() but which does not require networking
> >> privileges.
> >
> >If the system is not using local files (i.e. /etc/passwd and /etc/shadow),
> >the process who wants to add new accounts to the system might need network
> >access (e.g. to LDAP server), doesn't it?
>
> General purpose account manipulation tools might need network access but
> rainbow handles all its account manipulations via state stored in
> /var/spool/rainbow/2. This state is made available to the rest of the system
> via libnss_rainbow.
>
> Michael
Michael, I'm sorry, I should go back and search the thread for the
answer, but don't have time right now - do you really need
disablenetwork to be available to unprivileged users? Or is it ok
to require CAP_SETPCAP (same thing required for dropping privs from
bounding set)? Surely rainbow could be started either with that
capability, or even from a smaller, easier-to-audit wrapper that
has the capability, calls disablenetwork, then launches rainbow?
-serge
On Sun, 10 Jan 2010 22:58:48 +0100, Pavel Machek said:
> Scenario 2:
>
> Mallory calls disablenetwork, calls sendmail as the first user after
> boot; sendmail can't deliver anything (its network is disabled), but
> starts forking and taking requests for other users, DoSing the mail
> delivery.
You need to be root to start sendmail as a daemon. If Mallory is getting
a root shell before your /etc/rc.d scripts have started sendmail, you
have bigger problems.
> Scenario 3:
>
> Mallory calls disablenetwork, then keeps hammering on su, knowing that
> su can no longer send data to audit subsystem and so he will not get caught.
I assume you mean syslog, not audit. And it still won't work.
% strace /usr/bin/logger test message
...
socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 1
connect(1, {sa_family=AF_FILE, path="/dev/log"}, 110) = 0
sendto(1, "<13>Jan 11 21:49:25 logger: test"..., 40, MSG_NOSIGNAL, NULL, 0) = 40
close(1) = 0
su's complaint will get written to /dev/log which isn't interfered with
by the disablenetwork patch - and then syslogd will forward over the net
if configured to do so.
On Sun, 10 Jan 2010 17:46:49 PST, Casey Schaufler said:
> It's much worse than that. A user that has been network disabled
> who tries using ls may find that it goes looking for the network
> on each name lookup and has to wait for a timeout for each.
Ya know Casey - I learned back in 1986 or so that if you set up a SunOS 3.2
cluster using Yellow Pages, professors who managed to unplug the AUI cable
on the back of their Sun 3/50 would notice things blowing chunks. I have to
admit that 24 years ago I told them "Well don't do that then", and I have
to say the same thing for anybody running a login shell network-disabled.
Now, a more subtle point is that a *program* may call getuserbyname() or
getuserbyuid() and be surprised when it times out - but that's a
different issue than a network-deprived user calling /bin/ls.
> Then, if there are local file entries that differ
> from the "official" network account values when the library
> functions finally fall back on the local values you get the wrong
> names for file owners.
The sysadmin who set that up already had the bullet in the chamber and
the gun pointed at their feet. This is another "we knew better a quarter
century ago" issue - SunOS allowed '+:' at the end of /etc/passwd to merge
in the YP database, and Sun actively discouraged the sort of "local userid
overlaps the YP userid space" misconfiguration you mention.
[email protected] wrote:
> On Sun, 10 Jan 2010 17:46:49 PST, Casey Schaufler said:
>
>> It's much worse than that. A user that has been network disabled
>> who tries using ls may find that it goes looking for the network
>> on each name lookup and has to wait for a timeout for each.
>>
>
> Ya know Casey - I learned back in 1986 or so that if you set up a SunOS 3.2
> cluster using Yellow Pages, professors who managed to unplug the AUI cable
> on the back of their Sun 3/50 would notice things blowing chunks. I have to
> admit that 24 years ago I told them "Well don't do that then", and I have
> to say the same thing for anybody running a login shell network-disabled.
>
> Now, a more subtle point is that a *program* may call getuserbyname() or
> getuserbyuid() and be surprised when it times out - but that's a
> different issue than a network-deprived user calling /bin/ls.
>
I was working at Sun when YP was introduced and was probably the
first person who had to explain what would happen if the network
got disconnected to "security experts". They weren't real happy
then, and shouldn't be happier now. If anything, today's computer
users are less well adapted to dealing with applications that
behave differently when the network is unexpectedly absent because
both the user and the programmer assume that the network will be
there because it always is. They would never set up a situation
where the network would be missing and the programs they use/write
are unlikely to handle the situation. Lazy kids.
>> Then, if there are local file entries that differ
>> from the "official" network account values when the library
>> functions finally fall back on the local values you get the wrong
>> names for file owners.
>>
>
> The sysadmin who set that up already had the bullet in the chamber and
> the gun pointed at their feet. This is another "we knew better a quarter
> century ago" issue - SunOS allowed '+:' at the end of /etc/passwd to merge
> in the YP database, and Sun actively discouraged the sort of "local userid
> overlaps the YP userid space" misconfiguration you mention.
>
>
Sysadmins are so busy fixing Sanborn-Oxley compliance issues (funded)
that they are perfectly happy to put loaded guns in their pants as far
as (unfunded) "real" security is concerned. Sure we knew better. We
knew how to do lots of things back then that the Linux community is
relearning today. Knowing better isn't going to help the current
generation, as wisdom (like you and I have) can only be passed along
by experience and exposure to the wise. I like secure systems myself,
but I certainly understand why so many people don't.
Serge Hallyn wrote:
> Michael, I'm sorry, I should go back and search the thread for the
> answer, but don't have time right now - do you really need
> disablenetwork to be available to unprivileged users?
Rainbow can only drop the networking privileges when we know at app launch time
(e.g. based on a manifest or from the human operator) that privileges can be
dropped. Unfortunately, most of the really interesting uses of disablenetwork
happen *after* rainbow has dropped privilege and handed control the app.
Therefore, having an API which can be used by at least some low-privilege
processes is important to me.
> is it ok to require CAP_SETPCAP (same thing required for dropping privs from
> bounding set)?
Let me try to restate your idea:
We can make disablenetwork safer by permitting its use only where explicitly
permitted by some previously privileged ancestor. The securebits facility
described in
http://lwn.net/Articles/280279/
may be a good framework in which to implement this control.
Did I understand correctly? If so, then yes, this approach seems like it would
work for me.
Regards, and thanks very much for your help,
Michael
> On Sun, 10 Jan 2010 22:58:48 +0100, Pavel Machek said:
>
> > Scenario 2:
> >
> > Mallory calls disablenetwork, calls sendmail as the first user after
> > boot; sendmail can't deliver anything (its network is disabled), but
> > starts forking and taking requests for other users, DoSing the mail
> > delivery.
>
> You need to be root to start sendmail as a daemon.
Well, maybe, but mailer system where first user starts is as a daemon
makes sense... same for authentication system, etc. And it was okay
before disablenetwork come.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
On Tue, 12 Jan 2010 08:59:27 +0100, Pavel Machek said:
> Well, maybe, but mailer system where first user starts is as a daemon
> makes sense...
Does it? How do you get port 25 open for listening if the first user isn't
root? Most *actual* schemes to "launch at first use" that require privs for
something have used inetd or similar - that program exists for a *reason*.
Quoting Michael Stone ([email protected]):
> Serge Hallyn wrote:
> >Michael, I'm sorry, I should go back and search the thread for the
> >answer, but don't have time right now - do you really need
> >disablenetwork to be available to unprivileged users?
>
> Rainbow can only drop the networking privileges when we know at app launch time
> (e.g. based on a manifest or from the human operator) that privileges can be
> dropped. Unfortunately, most of the really interesting uses of disablenetwork
> happen *after* rainbow has dropped privilege and handed control the app.
> Therefore, having an API which can be used by at least some low-privilege
> processes is important to me.
>
> >is it ok to require CAP_SETPCAP (same thing required for dropping privs from
> >bounding set)?
>
> Let me try to restate your idea:
>
> We can make disablenetwork safer by permitting its use only where explicitly
> permitted by some previously privileged ancestor. The securebits facility
> described in
>
> http://lwn.net/Articles/280279/
>
> may be a good framework in which to implement this control.
>
> Did I understand correctly? If so, then yes, this approach seems like it would
> work for me.
That is a little more than I was saying this time though I think I
suggested it earlier.
But really I don't think anyone would care to separate a system into
some processes allowed to do unprivileged disablenetwork and other
processes not allowed to, so a (root-owned mode 644) sysctl seems just
as useful.
> Regards, and thanks very much for your help,
>
> Michael
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Serge E. Hallyn wrote:
>Michael, I'm sorry, I should go back and search the thread for the
>answer, but don't have time right now - do you really need
>disablenetwork to be available to unprivileged users?
I don't know about Michael's specific case, but answering more
broadly, Yes. There are important use cases for disablenetwork for
unprivileged users. Basically, it facilitates privilege separation,
which is hard to do today. A privilege-separated software architecture
is useful for a broad variety of programs that talk to the network --
some/many of which are unprivileged. For instance, the very original
post on this topic referred to a proposal by Dan Bernstein, where Dan
points out that (for instance) it would make be useful if we could start
a separate process for decompression (or image file transformation),
running that separate process with no privileges (including no network
access) to reduce the impact of vulnerabilities in that code. Think
of, say, a browser that needs to convert a .jpg to a bitmap; that
would be an example of an unprivileged program that could benefit
from the disablenetwork feature, because it could spawn a separate
process to do the image conversion.
> On Tue, 12 Jan 2010 08:59:27 +0100, Pavel Machek said:
>
> > Well, maybe, but mailer system where first user starts is as a daemon
> > makes sense...
>
> Does it? How do you get port 25 open for listening if the first user isn't
> root? Most *actual* schemes to "launch at first use" that require privs for
> something have used inetd or similar - that program exists for a
> *reason*.
Remember sendmail is setuid root... so it already has the permissions.
Except that proposed disablenetwork would take network connectivity
even from setuid apps.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
> Quoting Michael Stone ([email protected]):
> > Serge Hallyn wrote:
> > >Michael, I'm sorry, I should go back and search the thread for the
> > >answer, but don't have time right now - do you really need
> > >disablenetwork to be available to unprivileged users?
> >
> > Rainbow can only drop the networking privileges when we know at app launch time
> > (e.g. based on a manifest or from the human operator) that privileges can be
> > dropped. Unfortunately, most of the really interesting uses of disablenetwork
> > happen *after* rainbow has dropped privilege and handed control the app.
> > Therefore, having an API which can be used by at least some low-privilege
> > processes is important to me.
> >
> > >is it ok to require CAP_SETPCAP (same thing required for dropping privs from
> > >bounding set)?
> >
> > Let me try to restate your idea:
> >
> > We can make disablenetwork safer by permitting its use only where explicitly
> > permitted by some previously privileged ancestor. The securebits facility
> > described in
> >
> > http://lwn.net/Articles/280279/
> >
> > may be a good framework in which to implement this control.
> >
> > Did I understand correctly? If so, then yes, this approach seems like it would
> > work for me.
>
> That is a little more than I was saying this time though I think I
> suggested it earlier.
>
> But really I don't think anyone would care to separate a system into
> some processes allowed to do unprivileged disablenetwork and other
> processes not allowed to, so a (root-owned mode 644) sysctl seems just
> as useful.
Global solution like that is always wrong. (And we have better
solution available.)
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Pavel Machek wrote:
>> On Tue, 12 Jan 2010 08:59:27 +0100, Pavel Machek said:
>> > Well, maybe, but mailer system where first user starts is as a daemon
>> > makes sense...
>>
>> Does it? How do you get port 25 open for listening if the first user isn't
>> root? Most *actual* schemes to "launch at first use" that require privs for
>> something have used inetd or similar - that program exists for a
>> *reason*.
>
>Remember sendmail is setuid root... so it already has the permissions.
sendmail hasn't been setuid root on my system for (what feels like)
a long time; rather, it is setgid to a special group.
$ ls -l /usr/sbin/sendmail.sendmail
-rwxr-sr-x 1 root smmsp 841528 2008-03-29 05:27 /usr/sbin/sendmail.sendmail*
Please fix your email settings.
On Tue 2010-01-12 18:30:56, David Wagner wrote:
> Serge E. Hallyn wrote:
> >Michael, I'm sorry, I should go back and search the thread for the
> >answer, but don't have time right now - do you really need
> >disablenetwork to be available to unprivileged users?
>
> I don't know about Michael's specific case, but answering more
> broadly, Yes. There are important use cases for disablenetwork for
> unprivileged users. Basically, it facilitates privilege separation,
> which is hard to do today. A privilege-separated software architecture
> is useful for a broad variety of programs that talk to the network --
> some/many of which are unprivileged. For instance, the very original
> post on this topic referred to a proposal by Dan Bernstein, where Dan
> points out that (for instance) it would make be useful if we could start
> a separate process for decompression (or image file transformation),
> running that separate process with no privileges (including no network
> access) to reduce the impact of vulnerabilities in that code. Think
> of, say, a browser that needs to convert a .jpg to a bitmap; that
> would be an example of an unprivileged program that could benefit
> from the disablenetwork feature, because it could spawn a separate
> process to do the image conversion.
That's still ok; but is there need for unpriviledged helper executing
setuid probgrams? I don't think so...
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Quoting Pavel Machek ([email protected]):
> > Quoting Michael Stone ([email protected]):
> > > Serge Hallyn wrote:
> > > >Michael, I'm sorry, I should go back and search the thread for the
> > > >answer, but don't have time right now - do you really need
> > > >disablenetwork to be available to unprivileged users?
> > >
> > > Rainbow can only drop the networking privileges when we know at app launch time
> > > (e.g. based on a manifest or from the human operator) that privileges can be
> > > dropped. Unfortunately, most of the really interesting uses of disablenetwork
> > > happen *after* rainbow has dropped privilege and handed control the app.
> > > Therefore, having an API which can be used by at least some low-privilege
> > > processes is important to me.
> > >
> > > >is it ok to require CAP_SETPCAP (same thing required for dropping privs from
> > > >bounding set)?
> > >
> > > Let me try to restate your idea:
> > >
> > > We can make disablenetwork safer by permitting its use only where explicitly
> > > permitted by some previously privileged ancestor. The securebits facility
> > > described in
> > >
> > > http://lwn.net/Articles/280279/
> > >
> > > may be a good framework in which to implement this control.
> > >
> > > Did I understand correctly? If so, then yes, this approach seems like it would
> > > work for me.
> >
> > That is a little more than I was saying this time though I think I
> > suggested it earlier.
> >
> > But really I don't think anyone would care to separate a system into
> > some processes allowed to do unprivileged disablenetwork and other
> > processes not allowed to, so a (root-owned mode 644) sysctl seems just
> > as useful.
>
> Global solution like that is always wrong. (And we have better
> solution available.)
All right, so Michael suggested securebits, I personally feel prctl would
be more appropriate, but in any case the suggestion then is:
foo_enable_disablenet() is either prctl(PR_ALLOW_DISABLENET) or
prctl(PR_SET_SECUREBITS, (1 << PR_ALLOW_DISABLENET) | (1 << PR_ALLOW_DISABLENET_LOCK))
and it requires privilege (CAP_NET_ADMIN presumably) to make this call.
prctl(PR_SET_DISABLENETWORK), or whatever Michael was using, does not
require privilege, but requires that foo_enable_disablenet() have been
previously called by a privileged app.
-serge
> Quoting Pavel Machek ([email protected]):
> > > Quoting Michael Stone ([email protected]):
> > > > Serge Hallyn wrote:
> > > > >Michael, I'm sorry, I should go back and search the thread for the
> > > > >answer, but don't have time right now - do you really need
> > > > >disablenetwork to be available to unprivileged users?
> > > >
> > > > Rainbow can only drop the networking privileges when we know at app launch time
> > > > (e.g. based on a manifest or from the human operator) that privileges can be
> > > > dropped. Unfortunately, most of the really interesting uses of disablenetwork
> > > > happen *after* rainbow has dropped privilege and handed control the app.
> > > > Therefore, having an API which can be used by at least some low-privilege
> > > > processes is important to me.
> > > >
> > > > >is it ok to require CAP_SETPCAP (same thing required for dropping privs from
> > > > >bounding set)?
> > > >
> > > > Let me try to restate your idea:
> > > >
> > > > We can make disablenetwork safer by permitting its use only where explicitly
> > > > permitted by some previously privileged ancestor. The securebits facility
> > > > described in
> > > >
> > > > http://lwn.net/Articles/280279/
> > > >
> > > > may be a good framework in which to implement this control.
> > > >
> > > > Did I understand correctly? If so, then yes, this approach seems like it would
> > > > work for me.
> > >
> > > That is a little more than I was saying this time though I think I
> > > suggested it earlier.
> > >
> > > But really I don't think anyone would care to separate a system into
> > > some processes allowed to do unprivileged disablenetwork and other
> > > processes not allowed to, so a (root-owned mode 644) sysctl seems just
> > > as useful.
> >
> > Global solution like that is always wrong. (And we have better
> > solution available.)
>
> All right, so Michael suggested securebits, I personally feel prctl would
> be more appropriate.
I'm happy with either approach so I'll prepare patches based on Serge's
suggestion first.
Regards,
Michael
Quoting Michael Stone ([email protected]):
> >Quoting Pavel Machek ([email protected]):
> >> > Quoting Michael Stone ([email protected]):
> >> > > Serge Hallyn wrote:
> >> > > >Michael, I'm sorry, I should go back and search the thread for the
> >> > > >answer, but don't have time right now - do you really need
> >> > > >disablenetwork to be available to unprivileged users?
> >> > > > > > Rainbow can only drop the networking privileges when
> >we know at app launch time
> >> > > (e.g. based on a manifest or from the human operator) that privileges can be
> >> > > dropped. Unfortunately, most of the really interesting uses of disablenetwork
> >> > > happen *after* rainbow has dropped privilege and handed control the app.
> >> > > Therefore, having an API which can be used by at least some low-privilege
> >> > > processes is important to me.
> >> > > > > > >is it ok to require CAP_SETPCAP (same thing required
> >for dropping privs from
> >> > > >bounding set)?
> >> > > > > > Let me try to restate your idea:
> >> > > > > > We can make disablenetwork safer by permitting its
> >use only where explicitly
> >> > > permitted by some previously privileged ancestor. The securebits facility
> >> > > described in
> >> > > > > > http://lwn.net/Articles/280279/
> >> > > > > > may be a good framework in which to implement this
> >control.
> >> > > > > > Did I understand correctly? If so, then yes, this
> >approach seems like it would
> >> > > work for me.
> >> > > > That is a little more than I was saying this time though I
> >think I
> >> > suggested it earlier.
> >> > > > But really I don't think anyone would care to separate a
> >system into
> >> > some processes allowed to do unprivileged disablenetwork and other
> >> > processes not allowed to, so a (root-owned mode 644) sysctl seems just
> >> > as useful.
> >> > Global solution like that is always wrong. (And we have better
> >> solution available.)
> >
> >All right, so Michael suggested securebits, I personally feel prctl would
> >be more appropriate.
>
> I'm happy with either approach so I'll prepare patches based on Serge's
> suggestion first.
Ah - but I worry that if you do that Alan or others will object. Where do
you plan to store the disablenet_allowed bit? You can use security_prctl()
to keep the code out of sys_prctl(), but you still have the question of
whether you add a bit to the task struct, use task->security and not stack
with selinux, use a thread flag, or try to enable stacking of task->security.
To me securebits are all about capability hacks, but their name is more
generic than that :), so maybe they are appropriate after all. Andrew Morgan,
would you object to using securebits to store the fact that a privileged
process has said "from now on an unprivileged process may call disablenetwork"?
-serge
Quoting Michael Stone ([email protected]):
> Quoting Michael Stone ([email protected]):
>
> >Ah - but I worry that if you do that Alan or others will object. Where do
> >you plan to store the disablenet_allowed bit?
>
> If using prctl directly, I would store the bit in the task->network bitfield
> introduced by the earlier patches.
>
> >You can use security_prctl() to keep the code out of sys_prctl().
>
> I don't understand this suggestion; can you clarify? (Also, for what it's
> worth: I intended to put the check for CAP_SETPCAP in prctl_set_network().)
>
> >but you still have the question of whether you add a bit to the task struct,
> >use task->security and not stack with selinux, use a thread flag, or try to
> >enable stacking of task->security.
>
> For this revision of the patch, I will use the same approach as the previous
> patches (conditionally compiled task->network).
>
> Michael
>
> P.S. - Patches to follow tonight or tomorrow.
Cool I'll just wait for the patches :)
thanks,
-serge
On Fri, Jan 15, 2010 at 12:13 AM, Michael Stone <[email protected]> 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 <[email protected]>
> ---
> ?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
>
On Fri, Jan 15, 2010 at 03:10, Michael Stone <[email protected]> wrote:
> As promised, here are patches implementing and documenting a CAP_SETPCAP-gated
> "enable" bit along with a couple of other tweaks discussed earlier in the
> thread. For ease of development and review, the following four patches
> extend the disablenetwork (v4) patch series rather than replacing it.
To be honest, I'm still not convinced that this is the right way to
approach your problem. I think you would be much better off with
something analogous to the stripped-down SELinux policy I sent in an
earlier email (150 lines, give or take). By using the appropriate
SELinux hooks you can obtain the *exact* same enforcement, but without
adding any code to the kernel.
I have some time this week to split out my SELinux policy build
machinery; I will pull out a standalone set of files to build the
policy and do some extra testing on one of my bog-standard Debian
boxes and then send it all out again.
Cheers,
Kyle Moffett
On Thu, 14 Jan 2010 10:22:51 +0100, Pavel Machek said:
> > On Tue, 12 Jan 2010 08:59:27 +0100, Pavel Machek said:
> >
> > > Well, maybe, but mailer system where first user starts is as a daemon
> > > makes sense...
> >
> > Does it? How do you get port 25 open for listening if the first user isn't
> > root? Most *actual* schemes to "launch at first use" that require privs fo
r
> > something have used inetd or similar - that program exists for a
> > *reason*.
>
> Remember sendmail is setuid root... so it already has the permissions.
Actually, the sendmail setuid bit was removed quite some time ago:
8.12.0/8.12.0 2001/09/08
*NOTICE*: The default installation of sendmail does not use
set-user-ID root anymore. You need to create a new user and
a new group before installing sendmail (both called smmsp by
default). The installation process tries to install
/etc/mail/submit.cf and creates /var/spool/clientmqueue by
default. Please see sendmail/SECURITY for details.
Wow. 2001. And people *still* think it's setuid. ;)
(Interestingly enough, the capabilities bug came *later*:
8.12.1/8.12.1 2001/10/01
SECURITY: Check whether dropping group privileges actually succeeded
to avoid possible compromises of the mail system by
supplying bogus data. Add configuration options for
different set*gid() calls to reset saved gid. Problem
found by Michal Zalewski.
and was mostly an issue because the same problem existed in pre-8.12 sendmails
that were still setuid and hadn't upgraded yet...
On Mon, Jan 18, 2010 at 4:54 AM, <[email protected]> wrote:
> (Interestingly enough, the capabilities bug came *later*:
>
> 8.12.1/8.12.1 ? 2001/10/01
> ? ? ? ?SECURITY: Check whether dropping group privileges actually succeeded
> ? ? ? ? ? ? ? ?to avoid possible compromises of the mail system by
> ? ? ? ? ? ? ? ?supplying bogus data. ?Add configuration options for
> ? ? ? ? ? ? ? ?different set*gid() calls to reset saved gid. ?Problem
> ? ? ? ? ? ? ? ?found by Michal Zalewski.
>
> and was mostly an issue because the same problem existed in pre-8.12 sendmails
> that were still setuid and hadn't upgraded yet...
>
>
I think the above was 'a' sendmail bug. 'The' capabilities bug came before that:
http://userweb.kernel.org/~morgan/sendmail-capabilities-war-story.html
Cheers
Andrew
As promised, here are patches implementing and documenting a CAP_SETPCAP-gated
"enable" bit along with a couple of other tweaks discussed earlier in the
thread. For ease of development and review, the following four patches extend
the disablenetwork (v4) patch series rather than replacing it.
Enjoy,
Michael
When network_flags is passed by pointer to memory shared among several tasks,
one of those tasks could change the pointed-to value after it was checked by
security_prctl() and before it was used by prctl_set_network().
Also, since no cleanup is needed in prctl_set_network(), simplify its
return-value conventions.
Signed-off-by: Michael Stone <[email protected]>
---
include/linux/prctl_network.h | 2 +-
kernel/sys.c | 24 ++++++------------------
2 files changed, 7 insertions(+), 19 deletions(-)
diff --git a/include/linux/prctl_network.h b/include/linux/prctl_network.h
index d18f8cb..2c03292 100644
--- a/include/linux/prctl_network.h
+++ b/include/linux/prctl_network.h
@@ -2,6 +2,6 @@
#define _LINUX_PRCTL_NETWORK_H
extern long prctl_get_network(unsigned long*);
-extern long prctl_set_network(unsigned long*);
+extern long prctl_set_network(unsigned long);
#endif /* _LINUX_PRCTL_NETWORK_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index b48f021..1fadf10 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1580,7 +1580,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
error = PR_MCE_KILL_DEFAULT;
break;
case PR_SET_NETWORK:
- error = prctl_set_network((unsigned long*)arg2);
+ error = prctl_set_network(arg2);
break;
case PR_GET_NETWORK:
error = prctl_get_network((unsigned long*)arg2);
@@ -1599,29 +1599,17 @@ long prctl_get_network(unsigned long* user)
return put_user(current->network, user);
}
-long prctl_set_network(unsigned long* user)
+long prctl_set_network(unsigned long network_flags)
{
- unsigned long network_flags;
- long ret;
-
- ret = -EFAULT;
- if (copy_from_user(&network_flags, user, sizeof(network_flags)))
- goto out;
-
- ret = -EINVAL;
if (network_flags & ~PR_NETWORK_ALL_FLAGS)
- goto out;
+ return -EINVAL;
/* only dropping access is permitted */
- ret = -EPERM;
- if (current->network & ~network_flags)
- goto out;
+ if (current->network & ~network_flags)
+ return -EPERM;
current->network = network_flags;
- ret = 0;
-
-out:
- return ret;
+ return 0;
}
#else
--
1.6.6.rc2
The idea is that calls like
sendto(fd, buffer, len, 0, NULL, 0);
send(fd, buffer, len, 0)
write(fd, buffer, len)
are all to be permitted but that calls like
sendto(fd, buffer, len, 0, (struct sockadr *) &addr, sizeof(addr));
are to be rejected when the current task's network is disabled on the grounds
that the former calls must use previously connected sockets but that the latter
socket need not have been previously connected.
Signed-off-by: Michael Stone <[email protected]>
---
security/disablenetwork.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/security/disablenetwork.c b/security/disablenetwork.c
index f45ddfc..27b88d7 100644
--- a/security/disablenetwork.c
+++ b/security/disablenetwork.c
@@ -56,11 +56,10 @@ int disablenetwork_security_socket_connect(struct socket * sock,
int disablenetwork_security_socket_sendmsg(struct socket * sock,
struct msghdr * msg, int size)
{
- if (sock->sk->sk_family != PF_UNIX &&
- current->network &&
- (msg->msg_name != NULL || msg->msg_namelen != 0))
- return -EPERM;
- return 0;
+ /* 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();
}
int disablenetwork_security_ptrace_access_check(struct task_struct *child,
--
1.6.6.rc2
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 <[email protected]>
---
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))
+ 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
Signed-off-by: Michael Stone <[email protected]>
---
Documentation/disablenetwork.txt | 43 ++++++++++++++++++++++++++++---------
1 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/Documentation/disablenetwork.txt b/Documentation/disablenetwork.txt
index c885502..5d376e6 100644
--- a/Documentation/disablenetwork.txt
+++ b/Documentation/disablenetwork.txt
@@ -30,11 +30,19 @@ Implementation
The initial userland interface for accessing the disablenetwork functionality
is provided through the prctl() framework via a new pair of options named
-PR_{GET,SET}_NETWORK and a new flag named PR_NETWORK_OFF.
+PR_{GET,SET}_NETWORK and a pair of flags named PR_NETWORK_ENABLE_DN and
+PR_NETWORK_OFF.
The PR_{GET,SET}_NETWORK options access and modify a new (conditionally
compiled) task_struct flags field named "network".
+prctl(PR_SET_NETWORK) takes its argument by value rather than by address to
+avoid a time-of-check-to-time-of-use race between security_prctl() and
+prctl_set_network().
+
+However, prctl(PR_GET_NETWORK) returns the value of the "network" field via a
+pointer argument so that its return code can represent errors like ENOSYS.
+
Finally, the pre-existing
security_socket_create(),
@@ -58,22 +66,35 @@ Writes which attempt to clear bits in current->network return -EPERM.
The default value for current->network is named PR_NETWORK_ON and is defined
to be 0.
-Presently, only one flag is defined: PR_NETWORK_OFF.
-
+Presently, two flags are defined: PR_NETWORK_ENABLE_DN and PR_NETWORK_OFF.
More flags may be defined in the future if they become needed.
Attempts to set undefined flags result in -EINVAL.
-When PR_NETWORK_OFF is set, the disablenetwork security hooks for socket(),
-bind(), connect(), sendmsg(), and ptrace() will return -EPERM or 0.
+CAP_SETPCAP is required in order to set PR_NETWORK_ENABLE_DN. We believe that
+this restriction will protect privileged legacy system configurations from
+unprivileged misuse of disablenetwork. (Thanks to Pavel Machek and Serge Hallyn
+for analyzing the problem and for suggesting this compromise approach.)
+
+We say that "disablenetwork is active" when both PR_NETWORK_ENABLE_DN and
+PR_NETWORK_OFF are set. Otherwise, we say that it is "inactive".
+
+When the disablenetwork is inactive, the disablenetwork_* security hooks for
+socket(), bind(), connect(), sendmsg(), and ptrace() will return 0.
+
+When disablenetwork is active -EPERM or 0 as follows:
+
+The hooks will return 0 when disablenetwork is active for the current process
+and when an exception applies: i.e. when the current process is
-Exceptions are made for
+ * manipulating an AF_UNIX socket or,
+ * calling sendmsg() on a previously connected socket (i.e. one with
+ msg.msg_name == NULL && msg.msg_namelen == 0) or
+ * calling ptrace() on a target process in which disablenetwork is also
+ active.
- * processes manipulating an AF_UNIX socket or,
- * processes calling sendmsg() on a previously connected socket
- (i.e. one with msg.msg_name == NULL && msg.msg_namelen == 0) or
- * processes calling ptrace() on a target process which shares every
- networking restriction flag set in current->network.
+When disablenetwork is active in non-exceptional circumstances, the hooks will
+return -EPERM.
References
----------
--
1.6.6.rc2