[PATCH x7] misc fixes from 2.4.33-ow1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 *);
 

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux