From: t_jeang Date: Tue, 6 Jan 2009 12:05:54 +0000 (+0000) Subject: * Fri Jun 20 2008 Anton Arapov [2.6.18-92.1.6.el5] X-Git-Tag: kernel-2.6.18-92.el5-fixes.patch X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=020c1ce3d58a149b91d3bacc6e74b82563db8219;p=xenclient%2Fkernel.git * Fri Jun 20 2008 Anton Arapov [2.6.18-92.1.6.el5] - [x86] sanity checking for read_tsc on i386 (Brian Maly ) [447686 443435] * Mon Jun 16 2008 Anton Arapov [2.6.18-92.1.5.el5] - [x86_64] copy_user doesn't zero tail bytes on page fault (Vitaly Mayatskikh) [451275 451276] {CVE-2008-2729} * Mon Jun 09 2008 Anton Arapov [2.6.18-92.1.4.el5] - Revert: [misc] ttyS1 loses interrupt and stops transmitting (Simon McGrath ) [443071 440121] * Fri Jun 06 2008 Anton Arapov [2.6.18-92.1.3.el5] - [x86_64] fix possible data leaks in copy_from_user() routine (Anton Arapov ) [433944 433945] {CVE-2008-0598} * Thu Jun 05 2008 Anton Arapov [2.6.18-92.1.2.el5] - [misc] ttyS1 loses interrupt and stops transmitting (Simon McGrath ) [443071 440121] - [net] DCCP sanity check feature length (Anton Arapov ) [447395 447396] {CVE-2008-2358} - [misc] fix possible buffer overflow in ASN.1 parsing routine (Anton Arapov ) [444464 444465] {CVE-2008-1673} * Thu May 22 2008 Anton Arapov [2.6.18-92.1.1.el5] - [xen] netfront: send fake arp when link gets carrier (Herbert Xu ) [447684 441716] - [net] fix xfrm reverse flow lookup for icmp6 (Neil Horman ) [447688 446250] - [net] negotiate all algorithms when id bit mask zero (Neil Horman ) [447685 442820] - [net] 32/64 bit compat MCAST_ sock options support (Neil Horman ) [447687 444582] - [misc] add CPU hotplug support for relay functions (Kei Tokunaga ) [447522 441523] --- diff --git a/Makefile b/Makefile index cb93e10b..c3703062 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 18 -EXTRAVERSION = -92.el5 +EXTRAVERSION = -92.1.6.el5 RHEL_MAJOR = 5 RHEL_MINOR = 2 NAME=Avast! A bilge rat! diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index 650b7462..16dbae74 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -325,14 +325,27 @@ core_initcall(cpufreq_tsc); static unsigned long current_tsc_khz = 0; static int tsc_update_callback(void); +static struct clocksource clocksource_tsc; +/* + * We compare the TSC to the cycle_last value in the clocksource + * structure to avoid a nasty time-warp issue. This can be observed in + * a very small window right after one CPU updated cycle_last under + * xtime lock and the other CPU reads a TSC value which is smaller + * than the cycle_last reference value due to a TSC which is slighty + * behind. This delta is nowhere else observable, but in that case it + * results in a forward time jump in the range of hours due to the + * unsigned delta calculation of the time keeping core code, which is + * necessary to support wrapping clocksources like pm timer. + */ static cycle_t read_tsc(void) { cycle_t ret; rdtscll(ret); - return ret; + return ret >= clocksource_tsc.cycle_last ? + ret : clocksource_tsc.cycle_last; } static struct clocksource clocksource_tsc = { diff --git a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user.S index 962f3a69..15815d01 100644 --- a/arch/x86_64/lib/copy_user.S +++ b/arch/x86_64/lib/copy_user.S @@ -213,18 +213,18 @@ ENTRY(copy_user_generic) .quad .Ls2,.Ls2e .quad .Ls3,.Ls3e .quad .Ls4,.Ls4e - .quad .Ld1,.Ls1e - .quad .Ld2,.Ls2e - .quad .Ld3,.Ls3e - .quad .Ld4,.Ls4e + .quad .Ld1,.Ld1e + .quad .Ld2,.Ld2e + .quad .Ld3,.Ld3e + .quad .Ld4,.Ld4e .quad .Ls5,.Ls5e .quad .Ls6,.Ls6e .quad .Ls7,.Ls7e .quad .Ls8,.Ls8e - .quad .Ld5,.Ls5e - .quad .Ld6,.Ls6e - .quad .Ld7,.Ls7e - .quad .Ld8,.Ls8e + .quad .Ld5,.Ld5e + .quad .Ld6,.Ld6e + .quad .Ld7,.Ld7e + .quad .Ld8,.Ld8e .quad .Ls9,.Le_quad .quad .Ld9,.Le_quad .quad .Ls10,.Le_byte @@ -236,18 +236,44 @@ ENTRY(copy_user_generic) .quad .Le5,.Le_zero .previous + /* Don't forget to store registers, which were loaded before fault. + Otherwise we will have up to 24 bytes of garbage and possible + security leak */ +.Ls8e: addl $8,%eax + movq %r9,6*8(%rdi) +.Ls7e: addl $8,%eax + movq %r8,5*8(%rdi) +.Ls6e: addl $8,%eax + movq %r11,4*8(%rdi) +.Ls5e: addl $32,%eax + jmp .Ls1e + +.Ls4e: addl $8,%eax + movq %r9,2*8(%rdi) +.Ls3e: addl $8,%eax + movq %r8,1*8(%rdi) +.Ls2e: addl $8,%eax + movq %r11,(%rdi) +.Ls1e: addq %rax,%rdi + shlq $6,%rdx + addq %rbx,%rdx + subq %rax,%rdx + andl $63,%ecx + addq %rcx,%rdx + jmp .Lzero_rest + /* compute 64-offset for main loop. 8 bytes accuracy with error on the pessimistic side. this is gross. it would be better to fix the interface. */ /* eax: zero, ebx: 64 */ -.Ls1e: addl $8,%eax -.Ls2e: addl $8,%eax -.Ls3e: addl $8,%eax -.Ls4e: addl $8,%eax -.Ls5e: addl $8,%eax -.Ls6e: addl $8,%eax -.Ls7e: addl $8,%eax -.Ls8e: addl $8,%eax +.Ld1e: addl $8,%eax +.Ld2e: addl $8,%eax +.Ld3e: addl $8,%eax +.Ld4e: addl $8,%eax +.Ld5e: addl $8,%eax +.Ld6e: addl $8,%eax +.Ld7e: addl $8,%eax +.Ld8e: addl $8,%eax addq %rbx,%rdi /* +64 */ subq %rax,%rdi /* correct destination with computed offset */ @@ -299,22 +325,32 @@ ENDPROC(copy_user_generic) */ copy_user_generic_c: CFI_STARTPROC + xorq %rax,%rax movl %edx,%ecx shrl $3,%ecx - andl $7,%edx -1: rep + andl $7,%edx +.Lc1: rep movsq movl %edx,%ecx -2: rep +.Lc2: rep movsb -4: movl %ecx,%eax ret -3: lea (%rdx,%rcx,8),%rax + +.Lc1e: movq %rcx,%rsi +.Lc3: rep + stosq +.Lc2e: movl %edx,%ecx +.Lc4: rep + stosb +.Lc3e: leaq (%rdx,%rsi,8),%rax ret CFI_ENDPROC END(copy_user_generic_c) .section __ex_table,"a" - .quad 1b,3b - .quad 2b,4b + .align 8 + .quad .Lc1,.Lc1e + .quad .Lc2,.Lc2e + .quad .Lc3,.Lc3e + .quad .Lc4,.Lc3e .previous diff --git a/buildconfigs/Rules.mk b/buildconfigs/Rules.mk index 941f939e..879cb142 100644 --- a/buildconfigs/Rules.mk +++ b/buildconfigs/Rules.mk @@ -2,7 +2,7 @@ XEN_TARGET_ARCH = x86_32 XEN_TARGET_X86_PAE ?= y LINUX_SERIES = 2.6 -LINUX_VER = 2.6.18-92.el5 +LINUX_VER = 2.6.18-92.1.6.el5 EXTRAVERSION ?= xen diff --git a/configs/kernel-2.6.18-i686-PAE.config b/configs/kernel-2.6.18-i686-PAE.config index 102abd29..e119cdcd 100644 --- a/configs/kernel-2.6.18-i686-PAE.config +++ b/configs/kernel-2.6.18-i686-PAE.config @@ -2,7 +2,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18-prep -# Thu May 22 07:09:53 2008 +# Tue Jul 1 11:03:51 2008 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y diff --git a/configs/kernel-2.6.18-i686-debug.config b/configs/kernel-2.6.18-i686-debug.config index d023ad39..a8c5d219 100644 --- a/configs/kernel-2.6.18-i686-debug.config +++ b/configs/kernel-2.6.18-i686-debug.config @@ -2,7 +2,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18-prep -# Thu May 22 07:09:53 2008 +# Tue Jul 1 11:03:51 2008 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y diff --git a/configs/kernel-2.6.18-i686-xen.config b/configs/kernel-2.6.18-i686-xen.config index e5eac62b..e6de9e82 100644 --- a/configs/kernel-2.6.18-i686-xen.config +++ b/configs/kernel-2.6.18-i686-xen.config @@ -2,7 +2,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18-prep -# Thu May 22 07:09:53 2008 +# Tue Jul 1 11:03:51 2008 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y diff --git a/configs/kernel-2.6.18-i686.config b/configs/kernel-2.6.18-i686.config index 34329fa9..065bed08 100644 --- a/configs/kernel-2.6.18-i686.config +++ b/configs/kernel-2.6.18-i686.config @@ -2,7 +2,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.18-prep -# Thu May 22 07:09:54 2008 +# Tue Jul 1 11:03:51 2008 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 2a01f3ef..9fbbae86 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -182,6 +182,11 @@ asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) } } } + + /* don't trust len bigger than ctx buffer */ + if (*len > ctx->end - ctx->pointer) + return 0; + return 1; } diff --git a/include/linux/relay.h b/include/linux/relay.h index 24accb48..05bf63be 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h @@ -64,6 +64,12 @@ struct rchan void *private_data; /* for user-defined data */ size_t last_toobig; /* tried to log event > subbuf size */ struct rchan_buf *buf[NR_CPUS]; /* per-cpu channel buffers */ +#ifndef __GENKSYMS__ + int is_global; /* One global buffer ? */ + struct list_head list; /* for channel list */ + struct dentry *parent; /* parent dentry passed to open */ + char base_filename[NAME_MAX]; /* saved base filename */ +#endif }; /* diff --git a/include/net/compat.h b/include/net/compat.h index 9859b602..5e7f58f7 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -39,4 +39,10 @@ extern int put_cmsg_compat(struct msghdr*, int, int, int, void *); extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int); +extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int, + int (*)(struct sock *, int, int, char __user *, int)); +extern int compat_mc_getsockopt(struct sock *, int, int, char __user *, + int __user *, int (*)(struct sock *, int, int, char __user *, + int __user *)); + #endif /* NET_COMPAT_H */ diff --git a/kernel/relay.c b/kernel/relay.c index 0ad4ec35..d82d6da7 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -1,12 +1,14 @@ /* * Public API and common code for kernel->userspace relay file support. * - * See Documentation/filesystems/relayfs.txt for an overview of relayfs. + * See Documentation/filesystems/relay.txt for an overview. * * Copyright (C) 2002-2005 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp * Copyright (C) 1999-2005 - Karim Yaghmour (karim@opersys.com) * * Moved to kernel/relay.c by Paul Mundt, 2006. + * November 2006 - CPU hotplug support by Mathieu Desnoyers + * (mathieu.desnoyers@polymtl.ca) * * This file is released under the GPL. */ @@ -18,6 +20,11 @@ #include #include #include +#include + +/* list of open channels, for cpu hotplug */ +static DEFINE_MUTEX(relay_channels_mutex); +static LIST_HEAD(relay_channels); /* * close() vm_op implementation for relay file mapping. @@ -188,6 +195,7 @@ void relay_destroy_buf(struct rchan_buf *buf) __free_page(buf->page_array[i]); kfree(buf->page_array); } + chan->buf[buf->cpu] = NULL; kfree(buf->padding); kfree(buf); kref_put(&chan->kref, relay_destroy_channel); @@ -361,51 +369,70 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init) void relay_reset(struct rchan *chan) { unsigned int i; - struct rchan_buf *prev = NULL; if (!chan) return; - for (i = 0; i < NR_CPUS; i++) { - if (!chan->buf[i] || chan->buf[i] == prev) - break; - __relay_reset(chan->buf[i], 0); - prev = chan->buf[i]; + if (chan->is_global && chan->buf[0]) { + __relay_reset(chan->buf[0], 0); + return; } + + mutex_lock(&relay_channels_mutex); + for_each_online_cpu(i) + if (chan->buf[i]) + __relay_reset(chan->buf[i], 0); + mutex_unlock(&relay_channels_mutex); } EXPORT_SYMBOL_GPL(relay_reset); -/** +/* * relay_open_buf - create a new relay channel buffer * - * Internal - used by relay_open(). + * used by relay_open() and CPU hotplug. */ -static struct rchan_buf *relay_open_buf(struct rchan *chan, - const char *filename, - struct dentry *parent, - int *is_global) +static struct rchan_buf *relay_open_buf(struct rchan *chan, unsigned int cpu) { - struct rchan_buf *buf; + struct rchan_buf *buf = NULL; struct dentry *dentry; + char *tmpname; - if (*is_global) + if (chan->is_global) return chan->buf[0]; + tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); + if (!tmpname) + goto end; + snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu); + buf = relay_create_buf(chan); if (!buf) - return NULL; + goto free_name; + + buf->cpu = cpu; + __relay_reset(buf, 1); /* Create file in fs */ - dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR, - buf, is_global); - if (!dentry) { - relay_destroy_buf(buf); - return NULL; - } + dentry = chan->cb->create_buf_file(tmpname, chan->parent, S_IRUSR, + buf, &chan->is_global); + if (!dentry) + goto free_buf; buf->dentry = dentry; - __relay_reset(buf, 1); + if(chan->is_global) { + chan->buf[0] = buf; + buf->cpu = 0; + } + + goto free_name; + +free_buf: + relay_destroy_buf(buf); + buf = NULL; +free_name: + kfree(tmpname); +end: return buf; } @@ -446,6 +473,47 @@ static inline void setup_callbacks(struct rchan *chan, chan->cb = cb; } +/** + * + * relay_hotcpu_callback - CPU hotplug callback + * @nb: notifier block + * @action: hotplug action to take + * @hcpu: CPU number + * + * Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD) + */ +static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb, + unsigned long action, + void *hcpu) +{ + unsigned int hotcpu = (unsigned long)hcpu; + struct rchan *chan; + + switch(action) { + case CPU_UP_PREPARE: + mutex_lock(&relay_channels_mutex); + list_for_each_entry(chan, &relay_channels, list) { + if (chan->buf[hotcpu]) + continue; + chan->buf[hotcpu] = relay_open_buf(chan, hotcpu); + if(!chan->buf[hotcpu]) { + printk(KERN_ERR + "relay_hotcpu_callback: cpu %d buffer " + "creation failed\n", hotcpu); + mutex_unlock(&relay_channels_mutex); + return NOTIFY_BAD; + } + } + mutex_unlock(&relay_channels_mutex); + break; + case CPU_DEAD: + /* No need to flush the cpu : will be flushed upon + * final relay_flush() call. */ + break; + } + return NOTIFY_OK; +} + /** * relay_open - create a new relay channel * @base_filename: base name of files to create @@ -469,9 +537,6 @@ struct rchan *relay_open(const char *base_filename, { unsigned int i; struct rchan *chan; - char *tmpname; - int is_global = 0; - if (!base_filename) return NULL; @@ -486,38 +551,31 @@ struct rchan *relay_open(const char *base_filename, chan->n_subbufs = n_subbufs; chan->subbuf_size = subbuf_size; chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs); + chan->parent = parent; + strlcpy(chan->base_filename, base_filename, NAME_MAX); setup_callbacks(chan, cb); kref_init(&chan->kref); - tmpname = kmalloc(NAME_MAX + 1, GFP_KERNEL); - if (!tmpname) - goto free_chan; - + mutex_lock(&relay_channels_mutex); for_each_online_cpu(i) { - sprintf(tmpname, "%s%d", base_filename, i); - chan->buf[i] = relay_open_buf(chan, tmpname, parent, - &is_global); + chan->buf[i] = relay_open_buf(chan, i); if (!chan->buf[i]) goto free_bufs; - - chan->buf[i]->cpu = i; } + list_add(&chan->list, &relay_channels); + mutex_unlock(&relay_channels_mutex); - kfree(tmpname); return chan; free_bufs: - for (i = 0; i < NR_CPUS; i++) { + for_each_online_cpu(i) { if (!chan->buf[i]) break; relay_close_buf(chan->buf[i]); - if (is_global) - break; } - kfree(tmpname); -free_chan: kref_put(&chan->kref, relay_destroy_channel); + mutex_unlock(&relay_channels_mutex); return NULL; } EXPORT_SYMBOL_GPL(relay_open); @@ -617,24 +675,26 @@ EXPORT_SYMBOL_GPL(relay_subbufs_consumed); void relay_close(struct rchan *chan) { unsigned int i; - struct rchan_buf *prev = NULL; if (!chan) return; - for (i = 0; i < NR_CPUS; i++) { - if (!chan->buf[i] || chan->buf[i] == prev) - break; - relay_close_buf(chan->buf[i]); - prev = chan->buf[i]; - } + mutex_lock(&relay_channels_mutex); + if (chan->is_global && chan->buf[0]) + relay_close_buf(chan->buf[0]); + else + for_each_possible_cpu(i) + if (chan->buf[i]) + relay_close_buf(chan->buf[i]); if (chan->last_toobig) printk(KERN_WARNING "relay: one or more items not logged " "[item size (%Zd) > sub-buffer size (%Zd)]\n", chan->last_toobig, chan->subbuf_size); + list_del(&chan->list); kref_put(&chan->kref, relay_destroy_channel); + mutex_unlock(&relay_channels_mutex); } EXPORT_SYMBOL_GPL(relay_close); @@ -647,17 +707,20 @@ EXPORT_SYMBOL_GPL(relay_close); void relay_flush(struct rchan *chan) { unsigned int i; - struct rchan_buf *prev = NULL; if (!chan) return; - for (i = 0; i < NR_CPUS; i++) { - if (!chan->buf[i] || chan->buf[i] == prev) - break; - relay_switch_subbuf(chan->buf[i], 0); - prev = chan->buf[i]; + if (chan->is_global && chan->buf[0]) { + relay_switch_subbuf(chan->buf[0], 0); + return; } + + mutex_lock(&relay_channels_mutex); + for_each_possible_cpu(i) + if (chan->buf[i]) + relay_switch_subbuf(chan->buf[i], 0); + mutex_unlock(&relay_channels_mutex); } EXPORT_SYMBOL_GPL(relay_flush); @@ -1018,3 +1081,12 @@ struct file_operations relay_file_operations = { .sendfile = relay_file_sendfile, }; EXPORT_SYMBOL_GPL(relay_file_operations); + +static __init int relay_init(void) +{ + + hotcpu_notifier(relay_hotcpu_callback, 0); + return 0; +} + +module_init(relay_init); diff --git a/kernel/timer.c b/kernel/timer.c index 35a40dc3..567eea3d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1050,6 +1050,7 @@ static int change_clocksource(void) u64 nsec; new = clocksource_get_next(); if (clock != new) { + new->cycle_last = 0; now = clocksource_read(new); nsec = __get_nsec_offset(); timespec_add_ns(&xtime, nsec); @@ -1117,6 +1118,7 @@ static int timekeeping_resume(struct sys_device *dev) write_seqlock_irqsave(&xtime_lock, flags); /* restart the last cycle value */ + clock->cycle_last = 0; clock->cycle_last = clocksource_read(clock); clock->error = 0; timekeeping_suspended = 0; diff --git a/net/compat.c b/net/compat.c index d5d69fa1..86d3ebcc 100644 --- a/net/compat.c +++ b/net/compat.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include @@ -589,6 +591,203 @@ asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, } return err; } + +struct compat_group_req { + __u32 gr_interface; + struct __kernel_sockaddr_storage gr_group + __attribute__ ((aligned(4))); +} __attribute__ ((packed)); + +struct compat_group_source_req { + __u32 gsr_interface; + struct __kernel_sockaddr_storage gsr_group + __attribute__ ((aligned(4))); + struct __kernel_sockaddr_storage gsr_source + __attribute__ ((aligned(4))); +} __attribute__ ((packed)); + +struct compat_group_filter { + __u32 gf_interface; + struct __kernel_sockaddr_storage gf_group + __attribute__ ((aligned(4))); + __u32 gf_fmode; + __u32 gf_numsrc; + struct __kernel_sockaddr_storage gf_slist[1] + __attribute__ ((aligned(4))); +} __attribute__ ((packed)); + +#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \ + sizeof(struct __kernel_sockaddr_storage)) + + +int compat_mc_setsockopt(struct sock *sock, int level, int optname, + char __user *optval, int optlen, + int (*setsockopt)(struct sock *,int,int,char __user *,int)) +{ + char __user *koptval = optval; + int koptlen = optlen; + + switch (optname) { + case MCAST_JOIN_GROUP: + case MCAST_LEAVE_GROUP: + { + struct compat_group_req __user *gr32 = (void *)optval; + struct group_req __user *kgr = + compat_alloc_user_space(sizeof(struct group_req)); + u32 interface; + + if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) || + !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) || + __get_user(interface, &gr32->gr_interface) || + __put_user(interface, &kgr->gr_interface) || + copy_in_user(&kgr->gr_group, &gr32->gr_group, + sizeof(kgr->gr_group))) + return -EFAULT; + koptval = (char __user *)kgr; + koptlen = sizeof(struct group_req); + break; + } + case MCAST_JOIN_SOURCE_GROUP: + case MCAST_LEAVE_SOURCE_GROUP: + case MCAST_BLOCK_SOURCE: + case MCAST_UNBLOCK_SOURCE: + { + struct compat_group_source_req __user *gsr32 = (void *)optval; + struct group_source_req __user *kgsr = compat_alloc_user_space( + sizeof(struct group_source_req)); + u32 interface; + + if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) || + !access_ok(VERIFY_WRITE, kgsr, + sizeof(struct group_source_req)) || + __get_user(interface, &gsr32->gsr_interface) || + __put_user(interface, &kgsr->gsr_interface) || + copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group, + sizeof(kgsr->gsr_group)) || + copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source, + sizeof(kgsr->gsr_source))) + return -EFAULT; + koptval = (char __user *)kgsr; + koptlen = sizeof(struct group_source_req); + break; + } + case MCAST_MSFILTER: + { + struct compat_group_filter __user *gf32 = (void *)optval; + struct group_filter __user *kgf; + u32 interface, fmode, numsrc; + + if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || + __get_user(interface, &gf32->gf_interface) || + __get_user(fmode, &gf32->gf_fmode) || + __get_user(numsrc, &gf32->gf_numsrc)) + return -EFAULT; + koptlen = optlen + sizeof(struct group_filter) - + sizeof(struct compat_group_filter); + if (koptlen < GROUP_FILTER_SIZE(numsrc)) + return -EINVAL; + kgf = compat_alloc_user_space(koptlen); + if (!access_ok(VERIFY_WRITE, kgf, koptlen) || + __put_user(interface, &kgf->gf_interface) || + __put_user(fmode, &kgf->gf_fmode) || + __put_user(numsrc, &kgf->gf_numsrc) || + copy_in_user(&kgf->gf_group, &gf32->gf_group, + sizeof(kgf->gf_group)) || + (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist, + numsrc * sizeof(kgf->gf_slist[0])))) + return -EFAULT; + koptval = (char __user *)kgf; + break; + } + + default: + break; + } + return setsockopt(sock, level, optname, koptval, koptlen); +} + +EXPORT_SYMBOL(compat_mc_setsockopt); + +int compat_mc_getsockopt(struct sock *sock, int level, int optname, + char __user *optval, int __user *optlen, + int (*getsockopt)(struct sock *,int,int,char __user *,int __user *)) +{ + struct compat_group_filter __user *gf32 = (void *)optval; + struct group_filter __user *kgf; + int __user *koptlen; + u32 interface, fmode, numsrc; + int klen, ulen, err; + + if (optname != MCAST_MSFILTER) + return getsockopt(sock, level, optname, optval, optlen); + + koptlen = compat_alloc_user_space(sizeof(*koptlen)); + if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) || + __get_user(ulen, optlen)) + return -EFAULT; + + /* adjust len for pad */ + klen = ulen + sizeof(*kgf) - sizeof(*gf32); + + if (klen < GROUP_FILTER_SIZE(0)) + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) || + __put_user(klen, koptlen)) + return -EFAULT; + + /* have to allow space for previous compat_alloc_user_space, too */ + kgf = compat_alloc_user_space(klen+sizeof(*optlen)); + + if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || + __get_user(interface, &gf32->gf_interface) || + __get_user(fmode, &gf32->gf_fmode) || + __get_user(numsrc, &gf32->gf_numsrc) || + __put_user(interface, &kgf->gf_interface) || + __put_user(fmode, &kgf->gf_fmode) || + __put_user(numsrc, &kgf->gf_numsrc) || + copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group))) + return -EFAULT; + + err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen); + if (err) + return err; + + if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) || + __get_user(klen, koptlen)) + return -EFAULT; + + ulen = klen - (sizeof(*kgf)-sizeof(*gf32)); + + if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) || + __put_user(ulen, optlen)) + return -EFAULT; + + if (!access_ok(VERIFY_READ, kgf, klen) || + !access_ok(VERIFY_WRITE, gf32, ulen) || + __get_user(interface, &kgf->gf_interface) || + __get_user(fmode, &kgf->gf_fmode) || + __get_user(numsrc, &kgf->gf_numsrc) || + __put_user(interface, &gf32->gf_interface) || + __put_user(fmode, &gf32->gf_fmode) || + __put_user(numsrc, &gf32->gf_numsrc)) + return -EFAULT; + if (numsrc) { + int copylen; + + klen -= GROUP_FILTER_SIZE(0); + copylen = numsrc * sizeof(gf32->gf_slist[0]); + if (copylen > klen) + copylen = klen; + if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen)) + return -EFAULT; + } + return err; +} + +EXPORT_SYMBOL(compat_mc_getsockopt); + + /* Argument list sizes for compat_sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), diff --git a/net/dccp/feat.c b/net/dccp/feat.c index a1b0682e..aceb1db8 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -25,6 +25,11 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); + if (len > 3) { + if (net_ratelimit()) + printk("%s: invalid length %d\n", __func__, len); + return -EINVAL; + } /* XXX sanity check feat change request */ /* check if that feature is already being negotiated */ diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 4173a2a4..a1078274 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -37,6 +37,9 @@ #include #include #include +#ifndef __GENKSYMS__ +#include +#endif #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include #endif @@ -921,6 +924,10 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, if (level != SOL_IP) return -ENOPROTOOPT; + if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) + return compat_mc_setsockopt(sk, level, optname, optval, optlen, + ip_setsockopt); + err = do_ip_setsockopt(sk, level, optname, optval, optlen); #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ @@ -1188,7 +1195,14 @@ int ip_getsockopt(struct sock *sk, int level, int compat_ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - int err = do_ip_getsockopt(sk, level, optname, optval, optlen); + int err; + + if (optname == MCAST_MSFILTER) + return compat_mc_getsockopt(sk, level, optname, optval, optlen, + ip_getsockopt); + + err = do_ip_getsockopt(sk, level, optname, optval, optlen); + #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 18b7fbdc..6fc60ca7 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -235,6 +235,11 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx, } } } + + /* don't trust len bigger than ctx buffer */ + if (*len > ctx->end - ctx->pointer) + return 0; + return 1; } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index bfad9b8f..388eb7dc 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -413,10 +413,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, xfrm6_decode_session_reverse(skb, &fl2); - if (ip6_dst_lookup(sk, &dst2, &fl)) + if (ip6_dst_lookup(sk, &dst2, &fl2)) goto out; - err = xfrm_nlookup(&dst2, &fl, sk, XFRM_LOOKUP_ICMP); + err = xfrm_nlookup(&dst2, &fl2, sk, XFRM_LOOKUP_ICMP); if (err == -ENOENT || err == -ENOSYS) { err = -ENOENT; if (!dst) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 13580ff0..2ea8e6b5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -52,6 +52,9 @@ #include #include #include +#ifndef __GENKSYMS__ +#include +#endif #include @@ -769,6 +772,10 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, if (level != SOL_IPV6) return -ENOPROTOOPT; + if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) + return compat_mc_setsockopt(sk, level, optname, optval, optlen, + ipv6_setsockopt); + err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ @@ -1057,6 +1064,10 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, if (level != SOL_IPV6) return -ENOPROTOOPT; + if (optname == MCAST_MSFILTER) + return compat_mc_getsockopt(sk, level, optname, optval, optlen, + ipv6_getsockopt); + err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); #ifdef CONFIG_NETFILTER /* we need to exclude all possible EINVALs except default case */ diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index be3b3015..c03eb1b6 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1107,13 +1107,16 @@ static inline int xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short family) { + /* If all masks are ~0, then we allow all algorithms. */ + int allalgs = !~(tmpl->aalgos & tmpl->ealgos & tmpl->calgos); + if (xfrm_state_kern(x)) return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, family); return x->id.proto == tmpl->id.proto && (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && (x->props.reqid == tmpl->reqid || !tmpl->reqid) && x->props.mode == tmpl->mode && - (tmpl->aalgos & (1<props.aalgo)) && + (allalgs || (tmpl->aalgos & (1<props.aalgo))) && !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family)); }