Messages in this thread Patch in this message | | | Date | Wed, 21 Oct 1998 13:41:51 +1300 | From | Chris Wedgwood <> | Subject | PATCH: pre-2.1.126-2 core dump as root and O_NOFOLLOW (was "Linux 2.1.125 doesn't dump core on SIGSEGV") |
| |
On Wed, Oct 21, 1998 at 01:26:32AM +0100, David Woodhouse wrote:
> It would appear so - the only operations we're affecting are those with > O_NOFOLLOW set, and those currently total zero, as we've only just defined it. > > Second version (i386 only for now)... > > --- linux/fs/namei.c.nofollow Wed Oct 21 00:30:39 1998 > +++ linux/fs/namei.c Wed Oct 21 01:15:13 1998 > @@ -564,7 +564,8 @@ > * is the same scheme used by, for example, Solaris 2.5.1. --KAB > */ > dentry = lookup_dentry(pathname, NULL, > - (flag & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL)); > + (flag & (O_CREAT|O_EXCL)) != (O_CREAT|O_EXCL) > + && !(flag & O_NOFOLLOW));
[...]
What are thes patches against? pre-2.1.126-2 looks a little different.
Here are my patches (against pre-2.1.126-2), which should work for all architectures (untested).
Summary of changes
- Alexander Kjeldaas <astor@guardian.no> `core dump as root' fix
- Added O_NOFOLLOW semantics to VFS, disallow open on O_FOLLOW and symlink (bad idea?)
- core dump no uses O_NOFOLLOW
- don't dump on multiple linked files
In truth, mose of this is untested properly, but `works for me'.
-cw diff -ur linux/fs/binfmt_elf.c /usr/src/linux-2.1.x/fs/binfmt_elf.c --- linux/fs/binfmt_elf.c Wed Oct 21 13:24:56 1998 +++ /usr/src/linux-2.1.x/fs/binfmt_elf.c Wed Oct 21 13:16:29 1998 @@ -1118,12 +1118,16 @@ #else corefile[4] = '\0'; #endif - dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600); + dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); if (IS_ERR(dentry)) { dentry = NULL; goto end_coredump; } inode = dentry->d_inode; + + if(inode->i_nlink > 1) + goto end_coredump; /* multiple links - don't dump */ + if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) diff -ur linux/fs/exec.c /usr/src/linux-2.1.x/fs/exec.c --- linux/fs/exec.c Wed Oct 21 13:24:22 1998 +++ /usr/src/linux-2.1.x/fs/exec.c Tue Oct 20 13:13:43 1998 @@ -702,17 +702,17 @@ 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)); + /* For init, we want to retain the capabilities set * in the init_task struct. Thus we skip the usual * capability rules */ if (current->pid != 1) { - int new_permitted = bprm->cap_permitted.cap | - (bprm->cap_inheritable.cap & - current->cap_inheritable.cap); - - current->cap_permitted.cap = new_permitted; - current->cap_effective.cap = new_permitted & - bprm->cap_effective.cap; + cap_t(current->cap_permitted) = new_permitted; + cap_t(current->cap_effective) = new_permitted & + cap_t(bprm->cap_effective); } /* AUD: Audit candidate if current->cap_effective is set */ @@ -720,7 +720,7 @@ current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; if (current->euid != current->uid || current->egid != current->gid || - !cap_isclear(current->cap_permitted)) + !cap_issubset(new_permitted, current->cap_permitted)) current->dumpable = 0; } diff -ur linux/fs/namei.c /usr/src/linux-2.1.x/fs/namei.c --- linux/fs/namei.c Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/fs/namei.c Wed Oct 21 13:00:14 1998 @@ -544,8 +544,23 @@ */ #define no_follow(f) (((f) & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) #define opendir(f) ((f) & O_DIRECTORY) -#define lookup_flags(f) \ - (no_follow(f) ? 0 : opendir(f) ? (LOOKUP_FOLLOW | LOOKUP_DIRECTORY) : LOOKUP_FOLLOW) + + +/* my brain didn't grok the macro initially... -cw */ + +static inline int mk_lkupflags(int f) +{ + if((f) & O_NOFOLLOW) + return 0; + + if(no_follow(f)) + return 0; + + if(opendir(f)) + return LOOKUP_FOLLOW | LOOKUP_DIRECTORY; + + return LOOKUP_FOLLOW; +} /* * open_namei() @@ -569,10 +584,15 @@ mode &= S_IALLUGO & ~current->fs->umask; mode |= S_IFREG; - dentry = lookup_dentry(pathname, NULL, lookup_flags(flag)); + dentry = lookup_dentry(pathname,NULL,mk_lkupflags(flag)); if (IS_ERR(dentry)) return dentry; + if(dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)){ + error = -EACCES; + goto exit; + } + acc_mode = ACC_MODE(flag); if (flag & O_CREAT) { struct dentry *dir; diff -ur linux/fs/proc/array.c /usr/src/linux-2.1.x/fs/proc/array.c --- linux/fs/proc/array.c Wed Oct 21 13:25:11 1998 +++ /usr/src/linux-2.1.x/fs/proc/array.c Tue Oct 20 13:13:44 1998 @@ -799,9 +799,9 @@ return buffer + sprintf(buffer, "CapInh:\t%016x\n" "CapPrm:\t%016x\n" "CapEff:\t%016x\n", - p->cap_inheritable.cap, - p->cap_permitted.cap, - p->cap_effective.cap); + cap_t(p->cap_inheritable), + cap_t(p->cap_permitted), + cap_t(p->cap_effective)); } diff -ur linux/include/asm-alpha/fcntl.h /usr/src/linux-2.1.x/include/asm-alpha/fcntl.h --- linux/include/asm-alpha/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-alpha/fcntl.h Wed Oct 21 13:30:55 1998 @@ -19,6 +19,7 @@ #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECT 040000 /* direct disk access - should check with OSF/1 */ #define O_DIRECTORY 0100000 /* must be a directory */ +#define O_NOFOLLOW 0200000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/asm-arm/fcntl.h /usr/src/linux-2.1.x/include/asm-arm/fcntl.h --- linux/include/asm-arm/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-arm/fcntl.h Wed Oct 21 13:31:07 1998 @@ -17,6 +17,7 @@ #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 080000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/asm-i386/fcntl.h /usr/src/linux-2.1.x/include/asm-i386/fcntl.h --- linux/include/asm-i386/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-i386/fcntl.h Wed Oct 21 12:16:39 1998 @@ -19,6 +19,7 @@ #define O_DIRECT 040000 /* direct disk access hint - currently ignored */ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ +#define O_NOFOLLOW 0400000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/asm-m68k/fcntl.h /usr/src/linux-2.1.x/include/asm-m68k/fcntl.h --- linux/include/asm-m68k/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-m68k/fcntl.h Wed Oct 21 13:31:17 1998 @@ -17,6 +17,7 @@ #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 080000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/asm-mips/fcntl.h /usr/src/linux-2.1.x/include/asm-mips/fcntl.h --- linux/include/asm-mips/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-mips/fcntl.h Wed Oct 21 13:31:26 1998 @@ -16,6 +16,7 @@ #define O_NOCTTY 0x0800 /* not fcntl */ #define FASYNC 0x1000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 0x2000 /* must be a directory */ +#define O_NOFOLLOW 0x4000 /* don't follow links */ #define O_NDELAY O_NONBLOCK diff -ur linux/include/asm-ppc/fcntl.h /usr/src/linux-2.1.x/include/asm-ppc/fcntl.h --- linux/include/asm-ppc/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-ppc/fcntl.h Wed Oct 21 13:32:06 1998 @@ -17,6 +17,7 @@ #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 080000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/asm-sparc/fcntl.h /usr/src/linux-2.1.x/include/asm-sparc/fcntl.h --- linux/include/asm-sparc/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-sparc/fcntl.h Wed Oct 21 13:32:14 1998 @@ -18,6 +18,7 @@ #define O_NDELAY (0x0004 | O_NONBLOCK) #define O_NOCTTY 0x8000 /* not fcntl */ #define O_DIRECTORY 0x10000 /* must be a directory */ +#define O_NOFOLLOW 0x20000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/asm-sparc64/fcntl.h /usr/src/linux-2.1.x/include/asm-sparc64/fcntl.h --- linux/include/asm-sparc64/fcntl.h Wed Oct 21 13:26:56 1998 +++ /usr/src/linux-2.1.x/include/asm-sparc64/fcntl.h Wed Oct 21 13:32:31 1998 @@ -18,6 +18,7 @@ #define O_NONBLOCK 0x4000 #define O_NOCTTY 0x8000 /* not fcntl */ #define O_DIRECTORY 0x10000 /* must be a directory */ +#define O_NOFOLLOW 0x20000 /* don't follow links */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ diff -ur linux/include/linux/capability.h /usr/src/linux-2.1.x/include/linux/capability.h --- linux/include/linux/capability.h Wed Oct 21 13:22:09 1998 +++ /usr/src/linux-2.1.x/include/linux/capability.h Wed Oct 21 12:16:44 1998 @@ -38,9 +38,19 @@ #ifdef __KERNEL__ +/* #define STRICT_CAP_T_TYPECHECKS */ + +#ifdef STRICT_CAP_T_TYPECHECKS + typedef struct kernel_cap_struct { __u32 cap; } kernel_cap_t; + +#else + +typedef __u32 kernel_cap_t; + +#endif #define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) @@ -259,51 +269,63 @@ /* * Internal kernel functions only */ + +#ifdef STRICT_CAP_T_TYPECHECKS + +#define to_cap_t(x) { x } +#define cap_t(x) (x).cap + +#else + +#define to_cap_t(x) (x) +#define cap_t(x) (x) + +#endif -#define CAP_EMPTY_SET { 0 } -#define CAP_FULL_SET { ~0 } -#define CAP_INIT_EFF_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } -#define CAP_INIT_INH_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } +#define CAP_EMPTY_SET to_cap_t(0) +#define CAP_FULL_SET to_cap_t(~0) +#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) +#define CAP_INIT_INH_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) #define CAP_TO_MASK(x) (1 << (x)) -#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)) +#define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag)) +#define cap_lower(c, flag) (cap_t(c) &= ~CAP_TO_MASK(flag)) +#define cap_raised(c, flag) (cap_t(c) & CAP_TO_MASK(flag)) static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b) { kernel_cap_t dest; - dest.cap = a.cap | b.cap; + cap_t(dest) = cap_t(a) | cap_t(b); return dest; } static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b) { kernel_cap_t dest; - dest.cap = a.cap & b.cap; + cap_t(dest) = cap_t(a) & cap_t(b); return dest; } static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop) { kernel_cap_t dest; - dest.cap = a.cap & ~drop.cap; + cap_t(dest) = cap_t(a) & ~cap_t(drop); return dest; } static inline kernel_cap_t cap_invert(kernel_cap_t c) { kernel_cap_t dest; - dest.cap = ~c.cap; + cap_t(dest) = ~cap_t(c); return dest; } -#define cap_isclear(c) (!(c).cap) -#define cap_issubset(a,set) (!((a).cap & ~(set).cap)) +#define cap_isclear(c) (!cap_t(c)) +#define cap_issubset(a,set) (!(cap_t(a) & ~cap_t(set))) -#define cap_clear(c) do { (c).cap = 0; } while(0) -#define cap_set_full(c) do { (c).cap = ~0; } while(0) -#define cap_mask(c,mask) do { (c).cap &= (mask).cap; } while(0) +#define cap_clear(c) do { cap_t(c) = 0; } while(0) +#define cap_set_full(c) do { cap_t(c) = ~0; } while(0) +#define cap_mask(c,mask) do { cap_t(c) &= cap_t(mask); } while(0) #define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK) diff -ur linux/kernel/capability.c /usr/src/linux-2.1.x/kernel/capability.c --- linux/kernel/capability.c Wed Oct 21 13:24:10 1998 +++ /usr/src/linux-2.1.x/kernel/capability.c Tue Oct 20 13:13:44 1998 @@ -61,9 +61,9 @@ } if (!error) { - data.permitted = target->cap_permitted.cap; - data.inheritable = target->cap_inheritable.cap; - data.effective = target->cap_effective.cap; + data.permitted = cap_t(target->cap_permitted); + data.inheritable = cap_t(target->cap_inheritable); + data.effective = cap_t(target->cap_effective); } if (target != current) diff -ur linux/kernel/sys.c /usr/src/linux-2.1.x/kernel/sys.c --- linux/kernel/sys.c Wed Oct 21 13:23:57 1998 +++ /usr/src/linux-2.1.x/kernel/sys.c Tue Oct 20 13:13:44 1998 @@ -586,11 +586,11 @@ if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (old_fsuid == 0 && current->fsuid != 0) { - current->cap_effective.cap &= ~CAP_FS_MASK; + cap_t(current->cap_effective) &= ~CAP_FS_MASK; } if (old_fsuid != 0 && current->fsuid == 0) { - current->cap_effective.cap |= - (current->cap_permitted.cap & CAP_FS_MASK); + cap_t(current->cap_effective) |= + (cap_t(current->cap_permitted) & CAP_FS_MASK); } } | |