lkml.org 
[lkml]   [2006]   [Aug]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patches in this message
/
Date
From
Subject[PATCH x7] misc fixes from 2.4.33-ow1
Willy and all,

Attached are 7 small changes from 2.4.33-ow1, as separate patches. I do
not feel that these warrant separate messages.

linux-2.4.33-ow1-BAD_ADDR.diff

This one is a one-liner, in binfmt_elf.c:

-#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)
+#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)

I feel that it is more logical to have BAD_ADDR() defined in this way:
indeed, the first kernel-space address is unusable for userspace. I
don't think this change affects anything, and we had it in -ow for a
couple of years.

linux-2.4.33-ow1-create_elf_tables.diff
linux-2.4.33-ow1-elf_core_dump.diff

These two are pieces from my more elaborate version of the coredump
vulnerability fix:

http://www.isec.pl/vulnerabilities/isec-0023-coredump.txt

The first one does for env_end the same thing that the minimal fix did
for arg_end, and the second one makes things more correct for 64-bit
archs. Neither fixes any known security problem, although I would not
be surprised if there's a yet unexplored attack vector that uses env_end.
This has been in -ow for over a year.

linux-2.4.33-ow1-load_elf_library.diff

This rejects ELF libraries with elf_ex.e_phnum == 0 earlier in the code.
Without this change, such libraries would be rejected anyway - after a
kmalloc() and a kernel_read(), both of zero bytes. This has been in -ow
for almost two years.

linux-2.4.33-ow1-mremap-arch-sanity.diff

This makes 32-bit emulation mmap/mremap calls on 64-bit archs refuse to
accept/return addresses beyond the 32-bit user address space. This is
about correctness, not security. Andrea Arcangeli did not like these,
commenting on them like: "supeflous, reject, must BUG if something", to
which I replied:

I don't see how these architecture-specific checks are superfluous.
The non-arch-specific code has only checked against TASK_SIZE, not
against the lower limit present with 32-bit syscall emulation on
64-bit archs. Yes, with other checks in the arch-specific code, my
added checks are pretty much limited to just the special case of
addr == end, but such addr's are invalid under 32-bit syscall
emulation and should not be accepted/returned by syscalls.

BUG() would be wrong, it would introduce a DoS.

(That discussion occurred in December, 2003; I kept the changes in -ow
since then.)

linux-2.4.33-ow1-proc_file_read.diff

This is hardening of proc_file_read() similar to what was recently done
in 2.6 in response to the vulnerability discovery. While 2.4 kernels
were not vulnerable due to differences in the lseek implementation, I
prefer to harden the reads as well. This change is new with 2.4.33-ow1.

linux-2.4.33-ow1-proc-nosuid-noexec-nodev.diff

This attempts to make procfs MS_NOSUID | MS_NOEXEC | MS_NODEV by
default, in response to another recently discovered 2.6-specific
vulnerability (so for 2.4 this is just proactive hardening). Most of
the changes in this patch were in -ow patches for years (in order to
enable the uid= and gid= mount options to work). Only the specific
"s->s_flags |= ..." line is a recent addition, and this one has not yet
been tested to actually make a difference.

Thanks,

Alexander
diff -urpPX nopatch linux-2.4.33/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.33/fs/binfmt_elf.c Sat Aug 12 08:48:39 2006
+++ linux/fs/binfmt_elf.c Sat Aug 12 08:51:47 2006
@@ -73,5 +76,5 @@
};

-#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)
+#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)

static int set_brk(unsigned long start, unsigned long end)diff -urpPX nopatch linux-2.4.33/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.33/fs/binfmt_elf.c Sat Aug 12 08:48:39 2006
+++ linux/fs/binfmt_elf.c Sat Aug 12 08:51:47 2006
@@ -232,6 +244,7 @@ create_elf_tables(char *p, int argc, int
}
__put_user(NULL, argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+ current->mm->env_end = (unsigned long) p;
while (envc-->0) {
__put_user((elf_caddr_t)(unsigned long)p,envp++);
len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);diff -urpPX nopatch linux-2.4.33/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.33/fs/binfmt_elf.c Sat Aug 12 08:48:39 2006
+++ linux/fs/binfmt_elf.c Sat Aug 12 08:51:47 2006
@@ -1166,9 +1206,12 @@ static int elf_core_dump(long signr, str
{
unsigned int i, len;

- len = current->mm->arg_end - current->mm->arg_start;
- if (len >= ELF_PRARGSZ)
- len = ELF_PRARGSZ-1;
+ if (current->mm->arg_end > current->mm->arg_start) {
+ len = current->mm->arg_end - current->mm->arg_start;
+ if (len >= ELF_PRARGSZ)
+ len = ELF_PRARGSZ-1;
+ } else
+ len = 0;
copy_from_user(&psinfo.pr_psargs,
(const char *)current->mm->arg_start, len);
for(i = 0; i < len; i++)diff -urpPX nopatch linux-2.4.33/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.33/fs/binfmt_elf.c Sat Aug 12 08:48:39 2006
+++ linux/fs/binfmt_elf.c Sat Aug 12 08:51:47 2006
@@ -945,8 +983,9 @@ static int load_elf_library(struct file
goto out;

/* First of all, some simple consistency checks */
- if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap)
+ if (elf_ex.e_type != ET_EXEC ||
+ elf_ex.e_phnum < 1 || elf_ex.e_phnum > 2 ||
+ !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap)
goto out;

/* Now read in all of the header information */diff -urpPX nopatch linux-2.4.33/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- linux-2.4.33/arch/alpha/kernel/osf_sys.c Fri Jun 13 18:51:29 2003
+++ linux/arch/alpha/kernel/osf_sys.c Sat Aug 12 08:51:47 2006
@@ -1346,6 +1346,8 @@ arch_get_unmapped_area(struct file *filp

if (len > limit)
return -ENOMEM;
+ if (addr >= limit)
+ return -ENOMEM;

/* First, see if the given suggestion fits.

diff -urpPX nopatch linux-2.4.33/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- linux-2.4.33/arch/sparc/kernel/sys_sparc.c Mon Aug 25 15:44:40 2003
+++ linux/arch/sparc/kernel/sys_sparc.c Sat Aug 12 08:51:47 2006
@@ -52,6 +52,8 @@ unsigned long arch_get_unmapped_area(str
/* See asm-sparc/uaccess.h */
if (len > TASK_SIZE - PAGE_SIZE)
return -ENOMEM;
+ if (addr >= TASK_SIZE - PAGE_SIZE)
+ return -ENOMEM;
if (ARCH_SUN4C_SUN4 && len > 0x20000000)
return -ENOMEM;
if (!addr)
diff -urpPX nopatch linux-2.4.33/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- linux-2.4.33/arch/sparc64/kernel/sys_sparc.c Mon Aug 25 15:44:40 2003
+++ linux/arch/sparc64/kernel/sys_sparc.c Sat Aug 12 08:51:47 2006
@@ -63,6 +63,8 @@ unsigned long arch_get_unmapped_area(str
task_size = 0xf0000000UL;
if (len > task_size || len > -PAGE_OFFSET)
return -ENOMEM;
+ if (addr >= task_size)
+ return -ENOMEM;
if (!addr)
addr = TASK_UNMAPPED_BASE;

diff -urpPX nopatch linux-2.4.33/arch/x86_64/kernel/sys_x86_64.c linux/arch/x86_64/kernel/sys_x86_64.c
--- linux-2.4.33/arch/x86_64/kernel/sys_x86_64.c Fri Nov 28 21:26:19 2003
+++ linux/arch/x86_64/kernel/sys_x86_64.c Sat Aug 12 08:51:47 2006
@@ -94,6 +94,8 @@ unsigned long arch_get_unmapped_area(str
if (len > end)
return -ENOMEM;
addr = PAGE_ALIGN(addr);
+ if (addr >= end)
+ return -ENOMEM;

for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
/* At this point: (!vma || addr < vma->vm_end). */diff -urpPX nopatch linux-2.4.33/fs/proc/generic.c linux/fs/proc/generic.c
--- linux-2.4.33/fs/proc/generic.c Wed Jan 19 17:10:11 2005
+++ linux/fs/proc/generic.c Sun Aug 13 20:59:16 2006
@@ -62,11 +62,17 @@ proc_file_read(struct file * file, char
if (!(page = (char*) __get_free_page(GFP_KERNEL)))
return -ENOMEM;

+ if (pos < 0 || pos >= MAX_NON_LFS)
+ eof = 1;
+ else if (nbytes > MAX_NON_LFS - pos)
+ nbytes = MAX_NON_LFS - pos;
+
while ((nbytes > 0) && !eof)
{
- count = MIN(PROC_BLOCK_SIZE, nbytes);
- if ((unsigned)pos > INT_MAX)
+ /* This is redundant, but better safe than sorry */
+ if (pos < 0 || pos >= MAX_NON_LFS)
break;
+ count = MIN(PROC_BLOCK_SIZE, nbytes);

start = NULL;
if (dp->get_info) {diff -urpPX nopatch linux-2.4.33/fs/proc/generic.c linux/fs/proc/generic.c
--- linux-2.4.33/fs/proc/generic.c Wed Jan 19 17:10:11 2005
+++ linux/fs/proc/generic.c Sun Aug 13 20:59:16 2006
@@ -396,7 +402,9 @@ static int proc_register(struct proc_dir
static void proc_kill_inodes(struct proc_dir_entry *de)
{
struct list_head *p;
- struct super_block *sb = proc_mnt->mnt_sb;
+ struct super_block *sb = proc_super;
+
+ if (!sb) return;

/*
* Actually it's a partial revoke().
diff -urpPX nopatch linux-2.4.33/fs/proc/inode.c linux/fs/proc/inode.c
--- linux-2.4.33/fs/proc/inode.c Fri Nov 28 21:26:21 2003
+++ linux/fs/proc/inode.c Wed Aug 16 04:54:57 2006
@@ -73,8 +74,6 @@ static void proc_delete_inode(struct ino
}
}

-struct vfsmount *proc_mnt;
-
static void proc_read_inode(struct inode * inode)
{
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -176,12 +179,15 @@ out_fail:
goto out;
}

+struct super_block *proc_super = NULL;
+
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
struct inode * root_inode;
struct task_struct *p;

+ s->s_flags |= MS_NOSUID | MS_NOEXEC | MS_NODEV;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = PROC_SUPER_MAGIC;
@@ -201,6 +207,10 @@ struct super_block *proc_read_super(stru
if (!s->s_root)
goto out_no_root;
parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
+ if (!proc_super) {
+ s->s_count++;
+ proc_super = s;
+ }
return s;

out_no_root:
diff -urpPX nopatch linux-2.4.33/fs/proc/root.c linux/fs/proc/root.c
--- linux-2.4.33/fs/proc/root.c Wed Nov 17 14:54:21 2004
+++ linux/fs/proc/root.c Sat Aug 12 08:51:47 2006
@@ -30,12 +31,6 @@ void __init proc_root_init(void)
int err = register_filesystem(&proc_fs_type);
if (err)
return;
- proc_mnt = kern_mount(&proc_fs_type);
- err = PTR_ERR(proc_mnt);
- if (IS_ERR(proc_mnt)) {
- unregister_filesystem(&proc_fs_type);
- return;
- }
proc_misc_init();
proc_net = proc_mkdir("net", 0);
proc_net_stat = proc_mkdir("net/stat", NULL);
diff -urpPX nopatch linux-2.4.33/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- linux-2.4.33/include/linux/proc_fs.h Sat Aug 12 08:48:39 2006
+++ linux/include/linux/proc_fs.h Sat Aug 12 08:51:47 2006
@@ -96,7 +96,7 @@ extern struct proc_dir_entry *create_pro
struct proc_dir_entry *parent);
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);

-extern struct vfsmount *proc_mnt;
+extern struct super_block *proc_super;
extern struct super_block *proc_read_super(struct super_block *,void *,int);
extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
\
 
 \ /
  Last update: 2006-08-20 04:11    [W:0.063 / U:0.120 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site