From 04c91a30f078eb1559325c84dec803d231929d83 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:24:54 -0500 Subject: [PATCH] Linux 2.2.27-rc2 o CAN-2005-0001: fixed expand_stack() SMP race (Redhat) o CAN-2004-0883, CAN-2004-0949: smbfs: fixed client (Stefan Esser) overflow. There are two bugs in the handling of SMB responses that result in remote kernel overflows. Due to the nature of the bugs both seem to be very hard to exploit (in the sense of remote code execution or local privilege escalation) but are trivial remote kernel crashes. o rose_rt_ioctl: lack of bounds checking (Coverity) o sdla_xfer: lack of bounds checking (Coverity) o coda: bounds checking for tainted scalars (Coverity) o sendmsg compat wrapper fixes for 64bit compat mode (Olaf Kirch) --- ChangeLog-2.2.27 | 46 +++++++++++++++++++++---------- MAINTAINERS | 6 ++-- Makefile | 2 +- arch/sparc64/kernel/sys_sparc32.c | 11 ++++---- fs/coda/upcall.c | 41 ++++++++++++++++----------- fs/smbfs/proc.c | 10 ++++--- fs/smbfs/sock.c | 19 +++++++++++-- include/linux/coda.h | 4 +-- include/linux/mm.h | 4 +++ net/rose/rose_route.c | 3 ++ 10 files changed, 97 insertions(+), 49 deletions(-) diff --git a/ChangeLog-2.2.27 b/ChangeLog-2.2.27 index 300d417aeb16..271a73228665 100644 --- a/ChangeLog-2.2.27 +++ b/ChangeLog-2.2.27 @@ -21,28 +21,44 @@ You may find more informations about it at http://www.wolk-project.de/ +2.2.27-rc2 +---------- +o CAN-2005-0001: fixed expand_stack() SMP race (Redhat) +o CAN-2004-0883, CAN-2004-0949: smbfs: fixed client (Stefan Esser) + overflow. There are two bugs in the handling of SMB + responses that result in remote kernel overflows. Due + to the nature of the bugs both seem to be very hard + to exploit (in the sense of remote code execution or + local privilege escalation) but are trivial remote + kernel crashes. +o rose_rt_ioctl: lack of bounds checking (Coverity) +o sdla_xfer: lack of bounds checking (Coverity) +o coda: bounds checking for tainted scalars (Coverity) +o sendmsg compat wrapper fixes for 64bit compat mode (Olaf Kirch) + + + 2.2.27-rc1 ---------- o CAN-2004-0497: fixed missing DAC check on sys_chown (Thomas Biege) -o CAN-2004-1016: fixed a buffer overflow vulnerability (Paul Starzetz) - in the "__scm_send" function which handles the sending - of UDP network packets. A wrong validity check of the - cmsghdr structure allowed a local attacker to modify - kernel memory, thus causing an endless loop (DoS) or - possibly even root privilege escalation. -o CAN-2004-1333: fixed integer overflow in the vc_resize (Georgi Guninski) - function allows local users to cause a denial of - service (kernel crash) via a short new screen value, - which leads to a buffer overflow. Make sure VC - resizing fits in s16. -o If the user makes ip_cmsg_send call ip_options_get (Georgi Guninski) - multiple times, we leak kmalloced IP options data. -o fixed moxa serial bound checking issue (Alan Cox) +o CAN-2004-1016: fixed a buffer overflow vulnerability (Paul Starzetz) + in the "__scm_send" function which handles the sending + of UDP network packets. A wrong validity check of the + cmsghdr structure allowed a local attacker to modify + kernel memory, thus causing an endless loop (DoS) or + possibly even root privilege escalation. +o CAN-2004-1333: fixed integer overflow in the vc_resize (Georgi Guninski) + function allows local users to cause a denial of + service (kernel crash) via a short new screen value, + which leads to a buffer overflow. Make sure VC + resizing fits in s16. +o If the user makes ip_cmsg_send call ip_options_get (Georgi Guninski) + multiple times, we leak kmalloced IP options data. +o fixed moxa serial bound checking issue (Alan Cox) o menu cleanups (me) - 2.2.27-pre2 ----------- o A more correct fix to last mremap (2) bug (Dan Yefimov/Solar Designer) diff --git a/MAINTAINERS b/MAINTAINERS index 9a0c79ace067..b200257e3ec7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -880,10 +880,8 @@ S: Maintained SMB FILESYSTEM P: Urban Widmark -M: urban@svenskatest.se -W: http://samba.org/ -L: samba@samba.org -S: Maintained +M: Urban.Widmark@enlight.net +S: Odd Fixes SMP: (except SPARC) P: Linus Torvalds diff --git a/Makefile b/Makefile index c70ccd72e782..2fc2f302b635 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 27 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index ec4562abef84..9b054f4ed429 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -2183,6 +2183,11 @@ struct cmsghdr32 { (struct cmsghdr32 *)(ctl) : \ (struct cmsghdr32 *)NULL) #define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) +#define CMSG32_OK(ucmlen, ucmsg, mhdr) \ + ((ucmlen) >= sizeof(struct cmsghdr32) && \ + (ucmlen) <= (unsigned long) \ + ((mhdr)->msg_controllen - \ + ((char *)(ucmsg) - (char *)(mhdr)->msg_control))) __inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, struct cmsghdr32 *__cmsg, int __cmsg_len) @@ -2309,11 +2314,7 @@ static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg, return -EFAULT; /* Catch bogons. */ - if(CMSG32_ALIGN(ucmlen) < - CMSG32_ALIGN(sizeof(struct cmsghdr32))) - return -EINVAL; - if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) - + ucmlen) > kmsg->msg_controllen) + if (!CMSG32_OK(ucmlen, ucmsg, kmsg)) return -EINVAL; tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index ede97aec9f19..f2f0db11ddd6 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -517,6 +517,11 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, goto exit; } + if (data->vi.out_size > VC_MAXDATASIZE) { + error = EINVAL; + goto exit; + } + inp->coda_ioctl.VFid = *fid; /* the cmd field was mutated by increasing its size field to @@ -544,26 +549,30 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, error, coda_f2s(fid)); goto exit; } - - /* Copy out the OUT buffer. */ + + if (outsize < (int)outp->coda_ioctl.data + outp->coda_ioctl.len) { + CDEBUG(D_FILE, "reply size %d < reply len %ld\n", outsize, + (int)outp->coda_ioctl.data + outp->coda_ioctl.len); + error = EINVAL; + goto exit; + } + if (outp->coda_ioctl.len > data->vi.out_size) { - CDEBUG(D_FILE, "return len %d <= request len %d\n", - outp->coda_ioctl.len, - data->vi.out_size); + CDEBUG(D_FILE, "return len %d > request len %d\n", + outp->coda_ioctl.len, data->vi.out_size); error = EINVAL; - } else { - error = verify_area(VERIFY_WRITE, data->vi.out, - data->vi.out_size); - if ( error ) goto exit; - - if (copy_to_user(data->vi.out, - (char *)outp + (int)outp->coda_ioctl.data, - data->vi.out_size)) { - error = EINVAL; - goto exit; - } + goto exit; } + /* Copy out the OUT buffer. */ + error = verify_area(VERIFY_WRITE, data->vi.out, outp->coda_ioctl.len); + if ( error ) goto exit; + + if (copy_to_user(data->vi.out, + (char *)outp + (int)outp->coda_ioctl.data, + outp->coda_ioctl.len)) { + error = EINVAL; + } exit: CODA_FREE(inp, insize); return error; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 235cda0af37d..f156b93caeae 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -1108,10 +1108,12 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data) data_len = WVAL(buf, 1); /* we can NOT simply trust the data_len given by the server ... */ - if (data_len > server->packet_size - (buf+3 - server->packet)) { - printk(KERN_ERR "smb_proc_read: invalid data length!! " - "%d > %d - (%p - %p)\n", - data_len, server->packet_size, buf+3, server->packet); + if (data_len > count || + (buf+3 - server->packet) + data_len > server->packet_size) { + printk(KERN_ERR "smb_proc_read: invalid data length/offset!! " + "%d > %d || (%p - %p) + %d > %d\n", + data_len, count, + buf+3, server->packet, data_len, server->packet_size); result = -EIO; goto out; } diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index 566990a2cf09..07e4585c55d6 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -510,9 +510,12 @@ smb_receive_trans2(struct smb_sb_info *server, VERBOSE("fast track, parm=%u %u %u, data=%u %u %u\n", parm_disp, parm_offset, parm_count, data_disp, data_offset, data_count); - *parm = base + parm_offset; + if (*parm - inbuf + parm_tot > server->packet_size) + goto out_bad_parm; *data = base + data_offset; + if (*data - inbuf + data_tot > server->packet_size) + goto out_bad_data; goto success; } @@ -534,6 +537,8 @@ smb_receive_trans2(struct smb_sb_info *server, rcv_buf = smb_vmalloc(buf_len); if (!rcv_buf) goto out_no_mem; + memset(rcv_buf, 0, buf_len); + *parm = rcv_buf; *data = rcv_buf + total_p; } else if (data_tot > total_d || parm_tot > total_p) @@ -541,8 +546,12 @@ smb_receive_trans2(struct smb_sb_info *server, if (parm_disp + parm_count > total_p) goto out_bad_parm; + if (parm_offset + parm_count > server->packet_size) + goto out_bad_parm; if (data_disp + data_count > total_d) goto out_bad_data; + if (data_offset + data_count > server->packet_size) + goto out_bad_data; memcpy(*parm + parm_disp, base + parm_offset, parm_count); memcpy(*data + data_disp, base + data_offset, data_count); @@ -553,8 +562,11 @@ smb_receive_trans2(struct smb_sb_info *server, * Check whether we've received all of the data. Note that * we use the packet totals -- total lengths might shrink! */ - if (data_len >= data_tot && parm_len >= parm_tot) + if (data_len >= data_tot && parm_len >= parm_tot) { + data_len = data_tot; + parm_len = parm_tot; break; + } } /* @@ -568,6 +580,9 @@ smb_receive_trans2(struct smb_sb_info *server, server->packet = rcv_buf; rcv_buf = inbuf; } else { + if (parm_len + data_len > buf_len) + goto out_data_grew; + PARANOIA("copying data, old size=%d, new size=%u\n", server->packet_size, buf_len); memcpy(inbuf, rcv_buf, parm_len + data_len); diff --git a/include/linux/coda.h b/include/linux/coda.h index 8cb3ff46b25b..4c5a24d8c44d 100644 --- a/include/linux/coda.h +++ b/include/linux/coda.h @@ -774,8 +774,8 @@ union coda_downcalls { #define PIOCPARM_MASK 0x0000ffff struct ViceIoctl { caddr_t in, out; /* Data to be transferred in, or out */ - short in_size; /* Size of input buffer <= 2K */ - short out_size; /* Maximum size of output buffer, <= 2K */ + u_short in_size; /* Size of input buffer <= 2K */ + u_short out_size; /* Maximum size of output buffer, <= 2K */ }; struct PioctlData { diff --git a/include/linux/mm.h b/include/linux/mm.h index ad89e46aa2f0..403706b1c590 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -354,6 +354,10 @@ static inline int expand_stack(struct vm_area_struct * vma, unsigned long addres unsigned long grow; address &= PAGE_MASK; + + if (vma->vm_start <= address) + return 0; + grow = vma->vm_start - address; if ((vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) || diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 1fad6b7cc926..23c731cda4bc 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -629,6 +629,9 @@ int rose_rt_ioctl(unsigned int cmd, void *arg) if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; + if (rose_route.ndigis > 8) /* No more than 8 digipeats */ + return -EINVAL; + return rose_add_node(&rose_route, dev); case SIOCDELRT: -- 2.39.5