My spin on Pavels patch

Y2K (y2k@y2ker.com)
Tue, 20 Apr 1999 16:46:23 -0700 (PDT)


I only changed the parts that Pavel altered very sparingly.
I did however change some parts so that privledges can work for non-root
users too.
Also I am hashing around a few ideas on a per-process securebits in
addition to the global securebits. That way one can set more
backwards-broken on a per-process basis.
Anyway criticism wanted most desperately.

diff -ur linux-orig/fs/binfmt_elf.c linux-cap/fs/binfmt_elf.c
--- linux-orig/fs/binfmt_elf.c Tue Oct 27 10:23:40 1998
+++ linux-cap/fs/binfmt_elf.c Tue Apr 20 15:26:15 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,44 @@
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 *) &note,
+ 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;
+
+ 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) {
+ printk( "signature = %x, version = %x, header @ %x\n", note.cap.signature, note.cap.version, elf_ppnt->p_offset );
+ 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) ) {
+ /* We only honour random uid changes for root */
+ /* or guys with CAP_SETUID */
+ 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 );
+ /* bprm->securebits |= note.cap.securebits; */
+
+ 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 -ur linux-orig/fs/exec.c linux-cap/fs/exec.c
--- linux-orig/fs/exec.c Mon Jan 18 13:47:38 1999
+++ linux-cap/fs/exec.c Tue Apr 20 15:09:27 1999
@@ -580,6 +580,7 @@

bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
+ /* bprm->securebits = current->securebits | securebits */
id_change = cap_raised = 0;

/* Set-uid? */
@@ -602,28 +603,38 @@
}

/* We don't have VFS support for capabilities yet */
- cap_clear(bprm->cap_inheritable);
+ /* if we did we'd do something like this pseudo */
+ /* if (HAD_VFS_CAPS_AVAIL) {
+ * USE_VFS_CAPS
+ * else {
+ * USE_DEFAULTS_AS_BELOW
+ * }
+ */
+
+ /* these are some useful defaults */
+ cap_t(bprm->cap_inheritable)=cap_t(current->cap_permitted);
cap_clear(bprm->cap_permitted);
- cap_clear(bprm->cap_effective);
+ 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)
+ 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 +679,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
@@ -679,7 +691,8 @@
{
int new_permitted = cap_t(bprm->cap_permitted) |
(cap_t(bprm->cap_inheritable) &
- cap_t(current->cap_inheritable));
+ cap_t(current->cap_inheritable) &
+ cap_t(current->cap_permitted) );

/* For init, we want to retain the capabilities set
* in the init_task struct. Thus we skip the usual
@@ -694,6 +707,7 @@

current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ /* current->securebits=bprm->securebits | securebits */
if (current->euid != current->uid || current->egid != current->gid ||
!cap_issubset(new_permitted, current->cap_permitted))
current->dumpable = 0;
diff -ur linux-orig/include/linux/elf.h linux-cap/include/linux/elf.h
--- linux-orig/include/linux/elf.h Tue Jan 26 15:21:22 1999
+++ linux-cap/include/linux/elf.h Tue Apr 20 14:13:01 1999
@@ -496,6 +496,41 @@
Elf32_Word n_type; /* Content type */
} Elf64_Nhdr;

+/* Capabilities support
+ */
+struct elf_capabilities {
+ Elf32_Word signature;
+ 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;
+ /* hopefully some day we can have per process issecure() */
+ Elf32_Word effective;
+ Elf32_Word effective1;
+ Elf32_Word effective2;
+ Elf32_Word effective3;
+ Elf32_Word permitted;
+ Elf32_Word permitted1;
+ Elf32_Word permitted2;
+ Elf32_Word permitted3;
+ Elf32_Word inheritable;
+ Elf32_Word inheritable1;
+ Elf32_Word inheritable2;
+ Elf32_Word inheritable3;
+ Elf32_Word known;
+ Elf32_Word known1;
+ Elf32_Word known2;
+ Elf32_Word known3;
+};
+
+struct elf_capabilities_note {
+ Elf32_Nhdr notehdr;
+ __u32 note_signature; /* == "CAPS" */
+ struct elf_capabilities cap;
+};
+
#if ELF_CLASS == ELFCLASS32

extern Elf32_Dyn _DYNAMIC [];
diff -ur linux-orig/include/linux/securebits.h linux-cap/include/linux/securebits.h
--- linux-orig/include/linux/securebits.h Wed Apr 1 16:26:34 1998
+++ linux-cap/include/linux/securebits.h Tue Apr 20 14:19:12 1999
@@ -22,9 +22,16 @@
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. */
-
+#if 1
#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 )
+/* there is currently no perprocess securebits defined */
+/* would have do some thing like current->securebits=securebits when exec */
+#endif

#endif /* !_LINUX_SECUREBITS_H */

-
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/