diff -urP linux/Documentation/Configure.help linux-cap/Documentation/Configure.help
--- linux/Documentation/Configure.help Wed Apr 21 00:15:55 1999
+++ linux-cap/Documentation/Configure.help Thu Apr 22 22:07:37 1999
@@ -1572,6 +1572,39 @@
you have use for it; the module is called binfmt_misc.o. If you
don't know what to answer at this point, say Y.
+Securebits no root !
+CONFIG_SECUREBITS_NOROOT
+ This is experimental tweak that will effect SECUREBITS_DEFAULT
+ 0 is insecure but not fixed
+ 1 is secure but not fixed
+ 2 is insecure and fixed
+ 3 is secure and fixed
+ Your userland probably doesn't understand capabilities well enough yet!
+ A secure setting will most likely cause your whole system to become unusable!
+ If you don't know what to answer at this point, say 2!
+
+Securebits no setuid fixup !
+CONFIG_SECUREBITS_NO_SETUID_FIXUP
+ This is experimental tweak that will effect SECUREBITS_DEFAULT
+ 0 is insecure but not fixed
+ 1 is secure but not fixed
+ 2 is insecure and fixed
+ 3 is secure and fixed
+ Your userland probably doesn't understand capabilities well enough yet!
+ A secure setting will most likely cause your whole system to become unusable!
+ If you don't know what to answer at this point, say 2!
+
+Securebits pure capabilites !
+CONFIG_SECUREBITS_PURE_CAP
+ This is experimental tweak that will effect SECUREBITS_DEFAULT
+ 0 is insecure but not fixed
+ 1 is secure but not fixed
+ 2 is insecure and fixed
+ 3 is secure and fixed
+ Your userland probably doesn't understand capabilities well enough yet!
+ A secure setting will most likely cause your whole system to become unusable!
+ If you don't know what to answer at this point, say 2!
+
Solaris binary emulation
CONFIG_SOLARIS_EMUL
This is experimental code which will enable you to run (many)
diff -urP linux/arch/i386/config.in linux-cap/arch/i386/config.in
--- linux/arch/i386/config.in Mon Feb 1 12:03:20 1999
+++ linux-cap/arch/i386/config.in Thu Apr 22 22:08:40 1999
@@ -112,6 +112,12 @@
bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ int 'Securebits NOROOT 0,1,2,3' CONFIG_SECUREBITS_NOROOT 2
+ int 'Securebits NO_SETUID_FIXUP 0,1,2,3' CONFIG_SECUREBITS_NO_SETUID_FIXUP 2
+ int 'Securebits PURE_CAP 0,1,2,3' CONFIG_SECUREBITS_PURE_CAP 2
+fi
+
endmenu
source drivers/pnp/Config.in
diff -urP linux/cap.ldo linux-cap/cap.ldo
--- linux/cap.ldo Wed Dec 31 16:00:00 1969
+++ linux-cap/cap.ldo Mon Apr 26 10:10:37 1999
@@ -0,0 +1,27 @@
+/* sample fake cap ldo thingy */
+/* ld -i -T cap.lds cap.ldo */
+
+SECTIONS {
+ .caps (NOLOAD) : {
+LONG(4); /* name size */
+LONG(64); /* content size */
+LONG(7); /* content type */
+BYTE(67); /* C */
+BYTE(65); /* A */
+BYTE(80); /* P */
+BYTE(83); /* S */
+/* CAPS is name of note */
+LONG(0xca5ab1e); /* yet another signature */
+LONG(0); /* version */
+LONG(0); /* flags */
+LONG(1); /* xuid */
+LONG(0); /* securebits */
+LONG(-1); /* effective fE */
+LONG(0); /* permitted fP */
+LONG(-1); /* inheritable fI */
+LONG(0); /* required fR */
+LONG(0); /* known fK -- another source of version info? */
+LONG(0); /* disinherite fD aka fM */
+LONG(0); /* padding */
+ } :pcaps
+}
diff -urP linux/cap.lds linux-cap/cap.lds
--- linux/cap.lds Wed Dec 31 16:00:00 1969
+++ linux-cap/cap.lds Mon Apr 26 08:19:29 1999
@@ -0,0 +1,10 @@
+/* cap.lds cap ld script */
+/* ld -i -T cap.lds foo.ldo */
+
+OUTPUT(cap.o)
+PHDRS {
+pcaps PT_NOTE /* PHDRS */ ;
+}
+SECTIONS {
+ .caps (NOLOAD) : { *(.caps) } : pcaps
+}
diff -urP linux/fs/attr.c linux-cap/fs/attr.c
--- linux/fs/attr.c Fri Nov 13 10:07:26 1998
+++ linux-cap/fs/attr.c Wed Apr 21 20:10:36 1999
@@ -37,6 +37,9 @@
if (ia_valid & ATTR_MODE) {
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
goto error;
+ /* Also check the setuid bit! */
+ if ( (inode->i_uid==0) && !capable(CAP_SETPCAP) )
+ attr->ia_mode &= ~S_ISUID;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid) && !capable(CAP_FSETID))
@@ -74,6 +77,8 @@
inode->i_mode = attr->ia_mode;
if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
inode->i_mode &= ~S_ISGID;
+ if ( (inode->i_uid==0) && !capable(CAP_SETPCAP) )
+ attr->ia_mode &= ~S_ISUID;
}
mark_inode_dirty(inode);
}
diff -urP linux/fs/binfmt_elf.c linux-cap/fs/binfmt_elf.c
--- linux/fs/binfmt_elf.c Wed Apr 21 00:15:27 1999
+++ linux-cap/fs/binfmt_elf.c Mon Apr 26 10:16:18 1999
@@ -425,8 +425,11 @@
retval = -ENOEXEC;
/* First of all, some simple consistency checks */
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
+ if (elf_ex.e_ident[0] != 0x7f)
+ goto out;
+
+ if (strncmp(&elf_ex.e_ident[1], "ELF", 3) &&
+ strncmp(&elf_ex.e_ident[1], "FLE", 3))
goto out;
if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN)
@@ -473,6 +476,59 @@
end_data = 0;
for (i = 0; i < elf_ex.e_phnum; i++) {
+ if (elf_ppnt->p_type == PT_NOTE) {
+ struct elf_capabilities_note note;
+
+ printk( "Before: " );
+ retval = read_exec(bprm->dentry, elf_ppnt->p_offset,
+ (void *) ¬e,
+ sizeof (struct elf_capabilities_note), 1);
+ if (retval<0)
+ goto out_free_ph;
+
+ printk( "(s) " );
+
+ if (note.note_signature != be32_to_cpu(0x43415053)) /* "CAPS" */
+ continue;
+ if (note.notehdr.n_type!=NT_ELF_CAP)
+ continue;
+
+ printk( "uid = %d, effective = %x, permitted = %x, inheritable = %x\n", bprm->e_uid, bprm->cap_effective, bprm->cap_permitted, bprm->cap_inheritable );
+
+ retval = -ENOEXEC;
+ if (note.cap.signature!=0xca5ab1e || note.cap.version) {
+ printk( "signature = %x, version = %x, header @ %x\n", note.cap.signature, note.cap.version, elf_ppnt->p_offset );
+ goto out_free_ph;
+ }
+ if (!cap_issubset(note.cap.required,bprm->cap_inheritable) ) {
+ retval=-EPERM;
+ goto out_free_ph;
+ }
+ if (note.cap.flags & ECF_MAKE_EUID_UID) /* You may want to loose owner's uid */
+ bprm->e_uid = current->uid;
+ if (!bprm->e_uid&&
+ (capable(CAP_SETUID)||
+ cap_raised(bprm->permitted,CAP_SETUID)) ) {
+ /* We only honour random uid changes for root */
+ /* maybe we should care about CAP_SETUID here */
+ /* what is your opinion? */
+ if (note.cap.flags & ECF_MAKE_EUID_XUID)
+ bprm->e_uid = note.cap.xuid;
+ }
+ cap_mask( bprm->cap_effective, note.cap.effective );
+ cap_mask( bprm->cap_permitted, note.cap.permitted );
+ cap_mask( bprm->cap_inheritable, note.cap.inheritable );
+ if (note.cap.securebits&&capable(CAP_LINUX_SECUREBITS) )
+ SECUREBITS_SET(bprm->securebits,
+ note.cap.securebits);
+ else if (note.cap.securebits) {
+ retval=-EPERM;
+ goto out_free_ph;
+ }
+
+ printk( "Now: uid = %d, effective = %x, permitted = %x, inheritable = %x\n", bprm->e_uid, bprm->cap_effective, bprm->cap_permitted, bprm->cap_inheritable );
+
+ }
if (elf_ppnt->p_type == PT_INTERP) {
retval = -EINVAL;
if (elf_interpreter)
diff -urP linux/fs/exec.c linux-cap/fs/exec.c
--- linux/fs/exec.c Mon Jan 18 13:47:38 1999
+++ linux-cap/fs/exec.c Sun Apr 25 19:41:04 1999
@@ -580,6 +580,7 @@
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
+ bprm->securebits = securebits | current->securebits;
id_change = cap_raised = 0;
/* Set-uid? */
@@ -602,28 +603,46 @@
}
/* We don't have VFS support for capabilities yet */
- cap_clear(bprm->cap_inheritable);
- cap_clear(bprm->cap_permitted);
- cap_clear(bprm->cap_effective);
+ /* if we did we'd do something like this pseudo */
+ /* if (HAD_VFS_CAPS_AVAIL) {
+ * USE_VFS_CAPS
+ * else {
+ * USE_DEFAULTS_AS_BELOW
+ * }
+ */
+ if (issecure(SECURE_PURE_CAP) ) {
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+ }
+ else {
+ /* these are some useful defaults */
+ cap_t(bprm->cap_inheritable)=cap_t(current->cap_permitted);
+ cap_clear(bprm->cap_permitted);
+ cap_set_full(bprm->cap_effective);
+ }
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise the
- * effective and inherited bitmasks of the executable file
+ * effective and permitted bitmasks of suid-root executable files
* (translation: we set the executable "capability dumb" and
- * set the allowed set to maximum). We don't set any forced
- * bits.
+ * set the allowed set to maximum).
*
- * If only the real uid is 0, we only raise the inheritable
- * bitmask of the executable file (translation: we set the
- * allowed set to maximum and the application to "capability
- * smart").
+ * if root executes a non-root-suid file he will not raise
+ * any special privledges. He will however have his effective
+ * set cleared out for backwards compatibility.
*/
- if (!issecure(SECURE_NOROOT)) {
- if (bprm->e_uid == 0 || current->uid == 0)
- cap_set_full(bprm->cap_inheritable);
- if (bprm->e_uid == 0)
+ /* HELP: FIXME: should the below be SECURE_NO_SETUID_FIXUP ? */
+ /* if (!issecure(SECURE_NO_SETUID_FIXUP)&&(mode&S_ISUID) ) { */
+ if (!issecure(SECURE_NOROOT)&&(mode&S_ISUID) ) {
+ if (inode->i_uid==0) {
+ cap_set_full(bprm->cap_permitted);
cap_set_full(bprm->cap_effective);
+ }
+ else if (current->uid==0) {
+ cap_clear(bprm->cap_effective);
+ }
}
/* Only if pP' is _not_ a subset of pP, do we consider there
@@ -668,7 +687,8 @@
* The formula used for evolving capabilities is:
*
* pI' = pI
- * (***) pP' = fP | (fI & pI)
+ * (***) pP' = fP | (fI & pI & pP)
+ * used to be pP' = fP | (fI & pI )
* pE' = pP' & fE [NB. fE is 0 or ~0]
*
* I=Inheritable, P=Permitted, E=Effective // p=process, f=file
@@ -677,9 +697,13 @@
void compute_creds(struct linux_binprm *bprm)
{
- int new_permitted = cap_t(bprm->cap_permitted) |
- (cap_t(bprm->cap_inheritable) &
- cap_t(current->cap_inheritable));
+ int new_permitted = cap_t(bprm->cap_inheritable) &
+ cap_t(current->cap_inheritable);
+
+ if (!issecure(SECURE_CAP_PURE))
+ cap_intersect(new_permitted,current->cap_permitted);
+
+ cap_combine(new_permitted,cap_t(bprm->cap_permitted) );
/* For init, we want to retain the capabilities set
* in the init_task struct. Thus we skip the usual
@@ -694,6 +718,12 @@
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ current->securebits=bprm->securebits | securebits;
+ /* HELP: FIXME: should the below be SECURE_NO_SETUID_FIXUP ? */
+ /* if (issecure(SECURE_NO_SETUID_FIXUP)||current->euid) */
+ if (!issecure(SECURE_CAP_PURE)&&
+ (issecure(SECURE_NOROOT)||current->euid))
+ cap_clear(current->cap_inheritable);
if (current->euid != current->uid || current->egid != current->gid ||
!cap_issubset(new_permitted, current->cap_permitted))
current->dumpable = 0;
diff -urP linux/fs/open.c linux-cap/fs/open.c
--- linux/fs/open.c Wed Apr 21 00:16:09 1999
+++ linux-cap/fs/open.c Wed Apr 21 19:56:36 1999
@@ -295,11 +295,8 @@
current->fsuid = current->uid;
current->fsgid = current->gid;
- /* Clear the capabilities if we switch to a non-root user */
- if (current->uid)
- cap_clear(current->cap_effective);
- else
- current->cap_effective = current->cap_permitted;
+ /* Clear the capabilities */
+ cap_clear(current->cap_effective);
dentry = namei(filename);
res = PTR_ERR(dentry);
diff -urP linux/include/linux/capability.h linux-cap/include/linux/capability.h
--- linux/include/linux/capability.h Mon Feb 22 14:50:24 1999
+++ linux-cap/include/linux/capability.h Thu Apr 22 21:56:55 1999
@@ -264,6 +264,24 @@
#define CAP_SYS_TTY_CONFIG 26
+/* Allow changing of securebits stuff */
+
+#define CAP_LINUX_SECUREBITS 27
+
+/* These following caps can not really exist right now */
+/* for discussion only */
+/* they are greater than 31 */
+
+/* linux will ignore these. used by user-land only */
+
+#define CAP_LINUX_USR_0 96
+#define CAP_LINUX_USR_15 111
+
+/* reserved for new caps that may be made that normaly everyone has */
+#define CAP_LINUX_RESERVE_NORMAL_0 112
+#define CAP_LINUX_RESERVE_NORMAL_15 127
+
+
#ifdef __KERNEL__
/*
diff -urP linux/include/linux/elf.h linux-cap/include/linux/elf.h
--- linux/include/linux/elf.h Tue Jan 26 15:21:22 1999
+++ linux-cap/include/linux/elf.h Mon Apr 26 10:21:21 1999
@@ -476,6 +476,7 @@
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
+#define NT_ELF_CAP 7
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
@@ -495,6 +496,33 @@
Elf32_Word n_descsz; /* Content size */
Elf32_Word n_type; /* Content type */
} Elf64_Nhdr;
+
+/* Capabilities support
+ */
+struct elf_capabilities {
+ Elf32_Word signature; /* 0xca5ab1e */
+ Elf32_Word version;
+/* Currently 0, this is so that you can append on the end painlessly */
+ Elf32_Word flags;
+#define ECF_MAKE_EUID_UID 1
+#define ECF_MAKE_EUID_XUID 2
+ Elf32_Word xuid;
+ Elf32_Word securebits;
+ /* we can have per process issecure(SECURE_foo) */
+ Elf32_Word effective; /* fE */
+ Elf32_Word permitted; /* fP */
+ Elf32_Word inheritable; /* fI */
+ Elf32_Word required; /* fR */
+ Elf32_Word known; /* fK */
+ Elf32_Word disinherite; /* fD aka fM */
+ Elf32_Word pad; /* extra padding, pretty thin right now */
+};
+
+struct elf_capabilities_note {
+ Elf32_Nhdr notehdr;
+ Elf32_Word note_signature; /* CAPS 0x43415053 */
+ struct elf_capabilities cap;
+};
#if ELF_CLASS == ELFCLASS32
diff -urP linux/include/linux/sched.h linux-cap/include/linux/sched.h
--- linux/include/linux/sched.h Wed Apr 21 00:15:50 1999
+++ linux-cap/include/linux/sched.h Wed Apr 21 21:09:51 1999
@@ -285,6 +285,7 @@
int ngroups;
gid_t groups[NGROUPS];
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
+ unsigned securebits;
struct user_struct *user;
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
diff -urP linux/include/linux/securebits.h linux-cap/include/linux/securebits.h
--- linux/include/linux/securebits.h Wed Apr 1 16:26:34 1998
+++ linux-cap/include/linux/securebits.h Thu Apr 22 23:47:43 1999
@@ -1,7 +1,23 @@
#ifndef _LINUX_SECUREBITS_H
#define _LINUX_SECUREBITS_H 1
-#define SECUREBITS_DEFAULT 0x00000000
+#ifndef CONFIG_SECUREBITS_NOROOT
+#define CONFIG_SECUREBITS_NOROOT 0x00000002
+#endif
+
+#ifndef CONFIG_SECUREBITS_NO_SETUID_FIXUP
+#define CONFIG_SECUREBITS_NO_SETUID_FIXUP 0x00000002
+#endif
+
+#ifndef CONFIG_SECUREBITS_PURE_CAP
+#define CONFIG_SECUREBITS_PURE_CAP 0x00000002
+#endif
+
+#define SECUREBITS_DEFAULT ( CONFIG_SECUREBITS_NOROOT | \
+ (CONFIG_SECUREBITS_NO_SETUID_FIXUP << 2) | \
+ (CONFIG_SECUREBITS_PURE_CAP << 4) )
+
+#define SECUREBITS_PER_TASK
extern unsigned securebits;
@@ -18,13 +34,28 @@
privileges. When unset, setuid doesn't change privileges. */
#define SECURE_NO_SETUID_FIXUP 2
+/* When set, kernel can act in "pure draft" cap mode */
+#define SECURE_PURE_CAP 4
+
/* Each securesetting is implemented using two bits. One bit specify
whether the setting is on or off. The other bit specify whether the
setting is fixed or not. A setting which is fixed cannot be changed
from user-level. */
+#ifndef SECUREBITS_PER_TASK
#define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ? \
(1 << (X)) & SECUREBITS_DEFAULT : \
(1 << (X)) & securebits )
+#else
+#define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ? \
+ (1 << (X)) & SECUREBITS_DEFAULT : \
+ (1 << (X)) & current->securebits )
+#endif
+
+#define SECUREBITS_SETA(X,Y,Z) ( X = ( (1<<(Z +1))&SECUREBITS_DEFAULT ? \
+ X : X | ((1<< Z)& Y) ) )
+#define SECUREBITS_SET(X,Y) ( SECUREBITS_SETA((X),(Y),SECURE_NOROOT) , \
+ SECUREBITS_SETA((X),(Y),SECURE_NO_SETUID_FIXUP) , \
+ SECUREBITS_SETA((X),(Y),SECURE_PURE_CAP) )
#endif /* !_LINUX_SECUREBITS_H */
diff -urP linux/kernel/sys.c linux-cap/kernel/sys.c
--- linux/kernel/sys.c Fri Nov 20 11:43:19 1998
+++ linux-cap/kernel/sys.c Wed Apr 21 12:48:11 1999
@@ -318,6 +318,7 @@
*
* 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
* capabilities are set to the permitted capabilities.
+ * The inheritible set is combined with the permitted.
*
* fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
* never happen.
@@ -337,6 +338,7 @@
}
if (old_euid != 0 && current->euid == 0) {
current->cap_effective = current->cap_permitted;
+ cap_combine(current->cap_inheritable,current->cap_permitted);
}
}
-- Warning: When I mention capabilites I mean "soiled" capabilities not "pure draft". Any caps I mention are *derived* from a withdrawn draft posix document.
- 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.tux.org/lkml/