Home
Reading
Searching
Subscribe
Sponsors
Statistics
Posting
Contact
Spam
Lists
Links
About
Hosting
Filtering
Features Download
Marketing
Archives
FAQ
Blog
 
Gmane
From: Andrew G. Morgan <morgan <at> kernel.org>
Subject: [RFC PATCH] Add secure bit to prevent set[ug]id executables from exec()ing.
Newsgroups: gmane.linux.kernel.lsm
Date: Sunday 3rd January 2010 19:26:36 UTC (over 7 years ago)
Capabilities are an alternative privilege implementation to the traditional
UN*X model of an all powerful superuser ('root'). Per-process secure-bits
exist to turn off the default privilege for the superuser, but they do not
do anything about the fact that, in a typical system, most of the important
system files are owned by root (and other system users). So, while it is
possible to protect the kernel from root with secure-bits, it has been
harder to protect the system from a rogue setuid-root program.

This patch adds a new per-process secure-bit (bit 6) with a corresponding
lock-bit (bit 7) to deny exec()ution of any setuid program that would
modify the euid/egid of the invoking user.

Here is a fully worked example of how to use this new feature:

// --8<----- cut here [this is limiter.c]
/*
 * Quick demo of blocking privilege (without accompanying kernel patch
 * change the 0xef to 0x2f below, which will not attempt to disable
 * setuid executables).
 */

#include 
#include 
#include 
#include 

int main(int argc, char *argv[], char *envp[])
{
    if (argc < 2) {
	fprintf(stderr, "usage: %s \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, 0xef /* 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);
}
// ---- >8-- [end of limiter.c]

To compile this use libcap2 which can be found here:

http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/

Compilation:

admin> cc -o limiter limiter.c -lcap
admin> sudo /usr/sbin/setcap cap_setpcap=p ./limiter

Use:

luser> ./limiter /bin/bash
[feeling powerless]
luser> ...try something privileged, like 'su' should get not permitted.
luser> ...look at /proc/self/status etc.
luser> ...or try capsh --print
luser> exit
luser> ...back in parent shell

Signed-off-by: Andrew G. Morgan 
---
 include/linux/securebits.h |   15 ++++++++++++++-
 security/commoncap.c       |   13 ++++++++++++-
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 3340617..c931442 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -46,9 +46,22 @@
 #define SECBIT_KEEP_CAPS	(issecure_mask(SECURE_KEEP_CAPS))
 #define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED))
 
+/*
+ * When set, any setuid program that would otherwise cause e[ug]id of
+ * an exec()d application to differ from the current [ug]id of the
+ * exec()ing process, prevent the exec() from succeeding - return with
+ * -EPERM.
+ */
+#define SECURE_NO_SETUID_EXEC		6
+#define SECURE_NO_SETUID_EXECLOCKED	7  /* make bit-6 immutable */
+
+#define SECBIT_NO_SETUID_EXEC	(issecure_mask(SECURE_NO_SETUID_EXEC))
+#define SECBIT_NO_SETUID_LOCKED
(issecure_mask(SECURE_NO_SETUID_EXEC_LOCKED))
+
 #define SECURE_ALL_BITS		(issecure_mask(SECURE_NOROOT) | \
 				 issecure_mask(SECURE_NO_SETUID_FIXUP) | \
-				 issecure_mask(SECURE_KEEP_CAPS))
+				 issecure_mask(SECURE_KEEP_CAPS) | \
+				 issecure_mask(SECURE_NO_SETUID_EXEC))
 #define SECURE_ALL_LOCKS	(SECURE_ALL_BITS << 1)
 
 #endif /* !_LINUX_SECUREBITS_H */
diff --git a/security/commoncap.c b/security/commoncap.c
index f800fdb..3386f09 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -432,6 +432,10 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
 	bool effective;
 	int ret;
 
+	if (issecure(SECURE_NO_SETUID_EXEC) &&
+	    ((new->euid != old->uid) || (new->egid != old->gid)))
+		return -EPERM;   /* refuse to honor set[ug]id transitions */
+
 	effective = false;
 	ret = get_file_caps(bprm, &effective);
 	if (ret < 0)
@@ -569,7 +573,7 @@ int cap_inode_setxattr(struct dentry *dentry, const
char *name,
 	}
 
 	if (!strncmp(name, XATTR_SECURITY_PREFIX,
-		     sizeof(XATTR_SECURITY_PREFIX) - 1)  &&
+		     sizeof(XATTR_SECURITY_PREFIX) - 1) &&
 	    !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	return 0;
@@ -825,6 +829,13 @@ int cap_task_prctl(int option, unsigned long arg2,
unsigned long arg3,
 	 * will ensure that the current process and all of its
 	 * children will be locked into a pure
 	 * capability-based-privilege environment.
+	 *
+	 * In addition, some DAC policies include permitting users to
+	 * create setuid applications that permit third-party users
+	 * access to their resources. We provide a secure-bit to
+	 * prevent the execution of such applications by a
+	 * third-party. This bit with the corresponding LOCKED bit is:
+	 * issecure_mask(SECURE_NO_SETUID_EXEC).
 	 */
 	case PR_SET_SECUREBITS:
 		error = -EPERM;
-- 
1.6.2.5

--
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
 
CD: 4ms