]> xenbits.xensource.com Git - xenclient/kernel.git/commitdiff
* Fri Jun 20 2008 Anton Arapov <aarapov@redhat.com> [2.6.18-92.1.6.el5] kernel-2.6.18-92.el5-fixes.patch
authort_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:05:54 +0000 (12:05 +0000)
committert_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:05:54 +0000 (12:05 +0000)
- [x86] sanity checking for read_tsc on i386 (Brian Maly ) [447686 443435]

* Mon Jun 16 2008 Anton Arapov <aarapov@redhat.com> [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 <aarapov@redhat.com> [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 <aarapov@redhat.com> [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 <aarapov@redhat.com> [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 <aarapov@redhat.com> [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]

20 files changed:
Makefile
arch/i386/kernel/tsc.c
arch/x86_64/lib/copy_user.S
buildconfigs/Rules.mk
configs/kernel-2.6.18-i686-PAE.config
configs/kernel-2.6.18-i686-debug.config
configs/kernel-2.6.18-i686-xen.config
configs/kernel-2.6.18-i686.config
fs/cifs/asn1.c
include/linux/relay.h
include/net/compat.h
kernel/relay.c
kernel/timer.c
net/compat.c
net/dccp/feat.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter/ip_nat_snmp_basic.c
net/ipv6/icmp.c
net/ipv6/ipv6_sockglue.c
net/xfrm/xfrm_policy.c

index cb93e10b27407181c51e5e582178264fb726ad02..c37030623d0563d08149f022f5db7fade9c4cf8e 100644 (file)
--- 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!
index 650b7462a9ff9a555c1a83120cfbae9fb93267f9..16dbae74bdb7b585a7a05d0248f594a49c602f55 100644 (file)
@@ -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 = {
index 962f3a693c5ec6332db8eb1a4875d7a5c48f34d5..15815d01dcc87da5a4caa226265e36f437ea725c 100644 (file)
@@ -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
index 941f939ee8938035a70ca12536d051d6bfeef1ef..879cb142e534fd96e1362f92292d7c836aa372ba 100644 (file)
@@ -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
 
index 102abd298e0de618ecc741f6a2e3e26bd0d72874..e119cdcd5ebc523457bd36a21d824aa01be86de6 100644 (file)
@@ -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
index d023ad39b29a177dc14dd3851fd2e9c80c09069d..a8c5d219a8cff26d50d25facaf078ead0bd816aa 100644 (file)
@@ -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
index e5eac62b953eef1caeaa85f4ea4c6b4c51af5549..e6de9e82f1e9c19dc5be6f5ab5ed03afb7c48184 100644 (file)
@@ -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
index 34329fa9e3e827122f4ec922b72caeb3eb0cae63..065bed08d4b70a9e76d91fcf95e231031e12b1fb 100644 (file)
@@ -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
index 2a01f3ef96a0503332da509b81e4c788f07113c2..9fbbae8646b7e5f42fda564787bdd6feff47d9ab 100644 (file)
@@ -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;
 }
 
index 24accb483849c86415406a33ff685bc927900441..05bf63beb2c0e2dc4f7bd26ebe646faf564b7bbc 100644 (file)
@@ -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
 };
 
 /*
index 9859b60280d5631571cdbebdf611c28c8e283b48..5e7f58f738122adbcb028a52ac1a393015e93252 100644 (file)
@@ -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 */
index 0ad4ec353bf5dce56773841d7c33f0f775b7a2e4..d82d6da774ad12c0c9a16bb6c2109f688f0e131f 100644 (file)
@@ -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.
  */
 #include <linux/relay.h>
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
+#include <linux/cpu.h>
+
+/* 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);
index 35a40dc374f199cb598e81187772ba9f07e5b688..567eea3debe450ba92b558185c087cd668488060 100644 (file)
@@ -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;
index d5d69fa15d07a65a26975797d654813e5f055568..86d3ebccc4697e37492357ff11aa540a5d208561 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <net/scm.h>
 #include <net/sock.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 #include <asm/uaccess.h>
 #include <net/compat.h>
 
@@ -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),
index a1b0682ee77c7f9af2b72dae2afb38f4decd9f97..aceb1db88d19fb92fbdde0ceca92258142406ef9 100644 (file)
@@ -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 */
index 4173a2a424db76f32eefe2fe9061424012226c81..a1078274ce03bb865489510fe0d47ade92ea0869 100644 (file)
@@ -37,6 +37,9 @@
 #include <linux/mroute.h>
 #include <net/route.h>
 #include <net/xfrm.h>
+#ifndef __GENKSYMS__
+#include <net/compat.h>
+#endif
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 #include <net/transp_v6.h>
 #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
index 18b7fbdccb6126684f67478fa6a7ba1580445b23..6fc60ca775f179f2b7c1f2bffee51573d49f3cab 100644 (file)
@@ -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;
 }
 
index bfad9b8fd5fdec1803e6188cdb3dbbf1327790f0..388eb7dcbc473a8485b3e258d3adcd5087137579 100644 (file)
@@ -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)
index 13580ff0e20c11110866456e2b551933bb688599..2ea8e6b5990b72e3e7ca23cc8d85b88221672e20 100644 (file)
@@ -52,6 +52,9 @@
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/xfrm.h>
+#ifndef __GENKSYMS__
+#include <net/compat.h>
+#endif
 
 #include <asm/uaccess.h>
 
@@ -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 */
index be3b3015ac432a0f5c889bbcdc74530969298abc..c03eb1b69f7e2fb02f114c9d35c50feec82e7375 100644 (file)
@@ -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<<x->props.aalgo)) &&
+               (allalgs || (tmpl->aalgos & (1<<x->props.aalgo))) &&
                !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family));
 }