In particular logic says I could change the masking to just setting the allowed
capabilities to CAP_SYS_EXEC because no other capabilites are not masked out
and without CAP_SYS_EXEC you never get to that code. The same logic does not
apply to capabilities that cut other things normally allowed (CAP_SYS_SOCKET
could make it harder to transfer rootkits to a cracked host; it would also have
"marketing value" as an internet nanny solution).
Duncan (-:
--- linux/fs/exec.c.dist Wed Aug 12 04:46:08 1998
+++ linux/fs/exec.c Wed Aug 12 20:32:34 1998
@@ -569,6 +569,7 @@
int mode;
int retval,id_change,cap_raised;
struct inode * inode = bprm->dentry->d_inode;
+ static const kernel_cap_t normal_caps={ CAP_KEEP_SET };
mode = inode->i_mode;
if (!S_ISREG(mode)) /* must be regular file */
@@ -609,9 +610,12 @@
}
/* We don't have VFS support for capabilities yet */
- cap_clear(bprm->cap_inheritable);
- cap_clear(bprm->cap_permitted);
- cap_clear(bprm->cap_effective);
+ bprm->cap_inheritable=current->cap_inheritable;
+ bprm->cap_permitted=current->cap_permitted;
+ bprm->cap_effective=current->cap_effective;
+ cap_mask(bprm->cap_inheritable, normal_caps);
+ cap_mask(bprm->cap_permitted, normal_caps);
+ cap_mask(bprm->cap_effective, normal_caps);
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise the
@@ -810,6 +814,13 @@
struct dentry * dentry;
int retval;
int i;
+
+ /* Nobody without CAP_SYS_EXEC can exec anything */
+ if (!capable(CAP_SYS_EXEC))
+ {
+ printk(KERN_INFO " exec denied for pid %d\n", current->pid);
+ return -EPERM;
+ }
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
--- linux/kernel/sys.c.dist Wed Aug 12 04:56:54 1998
+++ linux/kernel/sys.c Wed Aug 12 20:33:16 1998
@@ -335,18 +335,28 @@
* fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
* never happen.
*
- * -astor
+ * -astor
+ *
+ * keep is the set of capabilties preserved. This is fixed as CAP_KEEP_SET
+ * normally just CAP_SYS_EXEC() (the exec() system call). The idea is that
+ * daemons that do not need this capability should drop it so standard
+ * shellcode anywhere fails.
+ *
+ * Duncan (-:
+ *
*/
extern inline void cap_emulate_setxuid(int old_ruid, int old_euid,
int old_suid)
{
+ static const kernel_cap_t keep={ CAP_KEEP_SET };
+
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
(current->uid != 0 && current->euid != 0 && current->suid != 0)) {
- cap_clear(current->cap_permitted);
- cap_clear(current->cap_effective);
+ cap_mask(current->cap_permitted, keep);
+ cap_mask(current->cap_effective, keep);
}
if (old_euid == 0 && current->euid != 0) {
- cap_clear(current->cap_effective);
+ cap_mask(current->cap_effective, keep);
}
if (old_euid != 0 && current->euid == 0) {
current->cap_effective = current->cap_permitted;
--- linux/include/linux/capability.h.dist Wed Aug 12 04:23:32 1998
+++ linux/include/linux/capability.h Wed Aug 12 05:14:37 1998
@@ -254,6 +254,10 @@
#define CAP_SYS_TTY_CONFIG 26
+/* Allow use of exec(). Anti-shellcode measure */
+
+#define CAP_SYS_EXEC 27
+
#ifdef __KERNEL__
/*
@@ -266,6 +270,7 @@
#define CAP_INIT_INH_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) }
#define CAP_TO_MASK(x) (1 << (x))
+#define CAP_KEEP_SET (CAP_TO_MASK(CAP_SYS_EXEC))
#define cap_raise(c, flag) ((c).cap |= CAP_TO_MASK(flag))
#define cap_lower(c, flag) ((c).cap &= ~CAP_TO_MASK(flag))
#define cap_raised(c, flag) ((c).cap & CAP_TO_MASK(flag))
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html