]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.26 2.2.26
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:24:46 +0000 (15:24 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:24:46 +0000 (15:24 -0500)
o   CAN-2004-0077: behave safely in case of do_munmap()   (Solar Designer)
     failures in mremap(2)
o   CAN-2003-0984: /dev/rtc can leak parts of kernel      (Solar Designer)
     memory to unprivileged users (2.4 backport)
o   CAN-2003-0244: hashing exploits in network stack      (David S. Miller)
o   update_atime() performance improvement (2.4 backport) (Solar Designer)
o   ability to swapoff after a device file might          (Solar Designer)
     have been re-created
o   MAINTAINERS correction for Kernel 2.2 and 2.2 fixes   (Marc-Christian Petersen)
o   fixed some typos                                      (Solar Designer,
                                                           Marc-Christian Petersen)

25 files changed:
ChangeLog-2.2.26 [new file with mode: 0644]
MAINTAINERS
Makefile
arch/i386/kernel/traps.c
arch/i386/mm/fault.c
arch/m68k/bvme6000/rtc.c
arch/m68k/mvme16x/rtc.c
drivers/char/rtc.c
drivers/macintosh/rtc.c
drivers/sbus/char/rtc.c
drivers/sgi/char/ds1286.c
drivers/sgi/char/graphics.c
fs/fat/inode.c
fs/inode.c
fs/proc/array.c
fs/proc/proc_tty.c
fs/select.c
include/linux/jhash.h [new file with mode: 0644]
include/linux/sysctl.h
mm/mmap.c
mm/mremap.c
mm/swapfile.c
net/ipv4/af_inet.c
net/ipv4/ip_fragment.c
net/ipv4/route.c

diff --git a/ChangeLog-2.2.26 b/ChangeLog-2.2.26
new file mode 100644 (file)
index 0000000..76e5794
--- /dev/null
@@ -0,0 +1,36 @@
+Kernel 2.2.xx Mainline
+----------------------
+Person:                Marc-Christian Petersen
+EMail:         m.c.p@wolk-project.de
+Mailinglist:   linux-kernel@vger.kernel.org
+Website:       http://www.kernel.org/pub/linux/kernel/people/mcp/
+Status:                Maintained
+Employed by:   Linux-Systeme GmbH, http://www.linux-systeme.de/
+
+
+    Thanks to Alan Cox 8-)
+
+
+-------------------------------------------------------------------------
+If you need a more secured, more stable, even faster, better SMP support,
+IDE LBA48 support, LFS support, IPSec support, HTB support, IPVS support
+etc. enabled kernel with many more features and important fixes, please
+use my 2.2-secure tree.
+You may find more informations about it at http://www.wolk-project.de.
+-------------------------------------------------------------------------
+
+
+
+2.2.26
+------
+o      CAN-2004-0077: behave safely in case of do_munmap()     (Solar Designer)
+         failures in mremap(2)
+o      CAN-2003-0984: /dev/rtc can leak parts of kernel        (Solar Designer)
+         memory to unprivileged users (2.4 backport)
+o      CAN-2003-0244: hashing exploits in network stack        (David S. Miller)
+o      update_atime() performance improvement (2.4 backport)   (Solar Designer)
+o      ability to swapoff after a device file might            (Solar Designer)
+         have been re-created
+o      MAINTAINERS correction for Kernel 2.2 and 2.2 fixes     (me)
+o      fixed some typos                                        (Solar Designer, me)
+
index 1d424926ea228999b741f46ad96e44513d9e11a2..efdf10688628d3d0b78f8393ce9ef1b3ab7ddb8d 100644 (file)
@@ -561,11 +561,11 @@ L:        linux-hams@vger.kernel.org
 S:     Maintained
 
 KERNEL  (2.2.XX TREE)
-P:      Alan Cox
-M:     Alan.Cox@linux.org
-L:      linux-kernel@vger.kernel.org
-W:      http://www.kernel.org/pub/linux/kernel/alan/
-S:      Maintained
+P:     Marc-Christian Petersen
+M:     m.c.p@wolk-project.de
+L:     linux-kernel@vger.kernel.org
+W:     http://www.kernel.org/pub/linux/kernel/people/mcp/
+S:     Maintained
 
 KERNEL AUTOMOUNTER (AUTOFS)
 P:     H. Peter Anvin
@@ -1172,8 +1172,8 @@ W:        http://cvs.conectiva.com.br/drivers/ZFL-watchdog/
 S:     Maintained
 
 LINUX 2.2 FIXES
-P:     Alan Cox
-M:     alan@lxorguk.ukuu.org.uk
+P:     Marc-Christian Petersen
+M:     m.c.p@wolk-project.de
 S:     Maintained
 
 THE REST
index aa42130601a01891814896550141123bf213f299..26007ff6f2a823fc802d660c80dacfc8232f1022 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 25
+SUBLEVEL = 26
 EXTRAVERSION = 
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
index 8f3935e167af6bbe44bfb8432786e4afc7cdc4fa..d1637ca78b67841644ab403bf35cbaf677aad868 100644 (file)
@@ -389,7 +389,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
                        goto clear_TF;
        }
 
-       /* Mast out spurious debug traps due to lazy DR7 setting */
+       /* Mask out spurious debug traps due to lazy DR7 setting */
        if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
                if (!tsk->tss.debugreg[7])
                        goto clear_dr7;
index fd9b1dc4ffeada1b0916d633833a1b2dafb9abe7..fac9e67b1e820aa39924a3f154e257d5b8d13043 100644 (file)
@@ -212,7 +212,7 @@ bad_area:
        /* User mode accesses just cause a SIGSEGV */
        if (error_code & 4) {
                tsk->tss.cr2 = address;
-               tsk->tss.error_code = error_code;
+               tsk->tss.error_code = error_code | (address >= TASK_SIZE);
                tsk->tss.trap_no = 14;
                force_sig(SIGSEGV, tsk);
                return;
index cf05ab9aa71979c929fca4187f25ec54bfb77081..bc68594c0ecf61f5579814fb2312adeff0944d0d 100644 (file)
@@ -53,6 +53,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                /* Ensure clock and real-time-mode-register are accessible */
                msr = rtc->msr & 0xc0;
                rtc->msr = 0x40;
+               memset(&wtime, 0, sizeof(wtime));
                do {
                        wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
                        wtime.tm_min =  BCD2BIN(rtc->bcd_min);
index b9485e54db3d2bfdf248bffcb21c6b34447d102a..bfb2bb1be301f0e8ef5d2a1e7f40c94a8f6af97f 100644 (file)
@@ -51,6 +51,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                cli();
                /* Ensure clock and real-time-mode-register are accessible */
                rtc->ctrl = RTC_READ;
+               memset(&wtime, 0, sizeof(wtime));
                wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
                wtime.tm_min =  BCD2BIN(rtc->bcd_min);
                wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
index fb256a4385cb96d49a99f6b04d52595267074def..4583309bcf1f678f32f19d083228e82cbd0f3de5 100644 (file)
@@ -250,6 +250,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                 * tm_min, and tm_sec values are filled in.
                 */
 
+               memset(&wtime, 0, sizeof(wtime));
                get_rtc_alm_time(&wtime);
                break; 
        }
@@ -293,6 +294,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        }
        case RTC_RD_TIME:       /* Read the time/date from RTC  */
        {
+               memset(&wtime, 0, sizeof(wtime));
                get_rtc_time(&wtime);
                break;
        }
index 4799c2052276ca3ccf312d8c7a72c2b129e34890..8c04f2a76f7f6c779620b5bd6c3a50dd8a880942 100644 (file)
@@ -73,6 +73,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        case RTC_RD_TIME:
                if (ppc_md.get_rtc_time)
                {
+                       memset(&rtc_tm, 0, sizeof(rtc_tm));
                        get_rtc_time(&rtc_tm);
 
                        copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT);
index 930aa3aa34719e862099bae3cc48565d2d354061..e74cc56306fcda2a727001f6f0f7f49f410e34a1 100644 (file)
@@ -83,6 +83,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        switch (cmd)
        {
        case RTCGET:
+               memset(&rtc_tm, 0, sizeof(rtc_tm));
                get_rtc_time(&rtc_tm);
 
                copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT);
index 4e72214c5fdac4bb3bbbbc9a014e5fe9f013e3f3..995423f9c83c7408772e7b37bd34008779e2207c 100644 (file)
@@ -222,6 +222,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
                 * tm_min, and tm_sec values are filled in.
                 */
 
+               memset(&wtime, 0, sizeof(wtime));
                get_rtc_alm_time(&wtime);
                break; 
        }
@@ -264,6 +265,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
        }
        case RTC_RD_TIME:       /* Read the time/date from RTC  */
        {
+               memset(&wtime, 0, sizeof(wtime));
                get_rtc_time(&wtime);
                break;
        }
index c1b2bb04fa64efafc2dd3cf1d8c68e3489b927b9..551404c231a4054ee3521fda2d6fda70e178578a 100644 (file)
@@ -105,7 +105,7 @@ sgi_graphics_ioctl (struct inode *inode, struct file *file, unsigned int cmd, un
 
                if (board >= boards)
                        return -EINVAL;
-               if (max_len < sizeof (struct gfx_getboardinfo_args))
+               if (max_len < (int)sizeof (struct gfx_getboardinfo_args))
                        return -EINVAL;
                if (max_len > cards [board].g_board_info_len)
                        max_len = cards [boards].g_board_info_len;
index ff549587a3f78bd5984d9ed1f4d94729809280b2..165b9929bf76ba091e64aca010209b3becccb937 100644 (file)
@@ -852,7 +852,8 @@ retry:
        i_pos = MSDOS_I(inode)->i_location;
        if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) return;
        if (!(bh = fat_bread(sb, ((unsigned long long) i_pos) >> MSDOS_DPB_BITS))) {
-               printk("dev = %s, ino = %ld\n", kdevname(inode->i_dev), i_pos);
+               printk("dev = %s, ino = %ld\n",
+                       kdevname(inode->i_dev), (long)i_pos);
                fat_fs_panic(sb, "msdos_write_inode: unable to read i-node block");
                return;
        }
index cca2311a1918007d9a59f3fbea4c2a0c2a329b23..1e6b1e4be280b71a1fbb6d99b27605ccda2c6686 100644 (file)
@@ -891,6 +891,7 @@ int fs_may_remount_ro(struct super_block *sb)
 
 void update_atime (struct inode *inode)
 {
+    if ( inode->i_atime == CURRENT_TIME ) return;
     if ( IS_NOATIME (inode) ) return;
     if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
     if ( IS_RDONLY (inode) ) return;
index 52ba9168fe39ec1b9f97f68f7edad94d05d44ff9..5a5c3dda19462892283c3e39fb68327d629c170f 100644 (file)
@@ -457,7 +457,7 @@ static int get_array(struct task_struct *p, unsigned long start, unsigned long e
        int size = 0, result = 0;
        char c;
 
-       if (start >= end)
+       if (!start || start >= end)
                return result;
        for (;;) {
                addr = get_phys_addr(p, start);
@@ -1540,8 +1540,7 @@ static ssize_t array_read(struct file * file, char * buf,
        start = NULL;
        dp = (struct proc_dir_entry *) inode->u.generic_ip;
        
-       if (pid && process_unauthorized(type, pid))
-       {
+       if (pid && process_unauthorized(type, pid)) {
                free_page(page);
                return -EIO;
        }
@@ -1556,6 +1555,10 @@ static ssize_t array_read(struct file * file, char * buf,
                free_page(page);
                return length;
        }
+       if (pid && process_unauthorized(type, pid)) {
+               free_page(page);
+               return -EIO;
+       }
        if (start != NULL) {
                /* We have had block-adjusting processing! */
                copy_to_user(buf, start, length);
index 4a04a043b12120bba23fba2287870d10d7aa3e4c..772c4ff94d4ca63ef29b3bfabb72e6e78ace9335 100644 (file)
@@ -138,7 +138,7 @@ static int tty_ldiscs_read_proc(char *page, char **start, off_t off,
 }
 
 /*
- * Thsi function is called by register_tty_driver() to handle
+ * This function is called by tty_register_driver() to handle
  * registering the driver's /proc handler into /proc/tty/driver/<foo>
  */
 void proc_tty_register_driver(struct tty_driver *driver)
@@ -161,7 +161,7 @@ void proc_tty_register_driver(struct tty_driver *driver)
 }
 
 /*
- * This function is called by unregister_tty_driver()
+ * This function is called by tty_unregister_driver()
  */
 void proc_tty_unregister_driver(struct tty_driver *driver)
 {
index 9000cc0b29819e45307bbf751e89d25f508aebcf..2f590596fdd4226ee43b9c89cd5afd2ab37b584c 100644 (file)
@@ -265,7 +265,7 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
        fd_set_bits fds;
        char *bits;
        long timeout;
-       int ret, size;
+       int ret, size, max_fdset;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
@@ -299,8 +299,11 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
         
        if (n < 0)
                goto out_nofds;
-       if (n > current->files->max_fdset)
-               n = current->files->max_fdset;
+       max_fdset = current->files->max_fdset;
+       if (n > max_fdset)
+               n = max_fdset;
+       if (n > NR_OPEN)
+               n = NR_OPEN;
                
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -412,7 +415,7 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
        lock_kernel();
        /* Do a sanity check on nfds ... */
        err = -EINVAL;
-       if (nfds > current->files->max_fds || nfds > 0x100000)
+       if (nfds > current->files->max_fds || nfds > NR_OPEN)
                goto out;
 
        if (timeout) {
diff --git a/include/linux/jhash.h b/include/linux/jhash.h
new file mode 100644 (file)
index 0000000..83f6af2
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef _LINUX_JHASH_H
+#define _LINUX_JHASH_H
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose.  It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault.  -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<<8); \
+  c -= a; c -= b; c ^= (b>>13); \
+  a -= b; a -= c; a ^= (c>>12);  \
+  b -= c; b -= a; b ^= (a<<16); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>3);  \
+  b -= c; b -= a; b ^= (a<<10); \
+  c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO     0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes.  No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(void *key, u32 length, u32 initval)
+{
+       u32 a, b, c, len;
+       u8 *k = key;
+
+       len = length;
+       a = b = JHASH_GOLDEN_RATIO;
+       c = initval;
+
+       while (len >= 12) {
+               a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+               b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+               c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+               __jhash_mix(a,b,c);
+
+               k += 12;
+               len -= 12;
+       }
+
+       c += length;
+       switch (len) {
+       case 11: c += ((u32)k[10]<<24);
+       case 10: c += ((u32)k[9]<<16);
+       case 9 : c += ((u32)k[8]<<8);
+       case 8 : b += ((u32)k[7]<<24);
+       case 7 : b += ((u32)k[6]<<16);
+       case 6 : b += ((u32)k[5]<<8);
+       case 5 : b += k[4];
+       case 4 : a += ((u32)k[3]<<24);
+       case 3 : a += ((u32)k[2]<<16);
+       case 2 : a += ((u32)k[1]<<8);
+       case 1 : a += k[0];
+       };
+
+       __jhash_mix(a,b,c);
+
+       return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(u32 *k, u32 length, u32 initval)
+{
+       u32 a, b, c, len;
+
+       a = b = JHASH_GOLDEN_RATIO;
+       c = initval;
+       len = length;
+
+       while (len >= 3) {
+               a += k[0];
+               b += k[1];
+               c += k[2];
+               __jhash_mix(a, b, c);
+               k += 3; len -= 3;
+       }
+
+       c += length * 4;
+
+       switch (len) {
+       case 2 : b += k[1];
+       case 1 : a += k[0];
+       };
+
+       __jhash_mix(a,b,c);
+
+       return c;
+}
+
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ *       done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+       a += JHASH_GOLDEN_RATIO;
+       b += JHASH_GOLDEN_RATIO;
+       c += initval;
+
+       __jhash_mix(a, b, c);
+
+       return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+       return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+       return jhash_3words(a, 0, 0, initval);
+}
+
+#endif /* _LINUX_JHASH_H */
index 2ef616ed6ab45ca728c041d14941b48ce277bff4..78681ced22143d27694571480c20b6e582dce80c 100644 (file)
@@ -249,7 +249,8 @@ enum {
        NET_IPV4_ROUTE_ERROR_COST=12,
        NET_IPV4_ROUTE_ERROR_BURST=13,
        NET_IPV4_ROUTE_GC_ELASTICITY=14,
-       NET_IPV4_ROUTE_MTU_EXPIRES=15
+       NET_IPV4_ROUTE_MTU_EXPIRES=15,
+       NET_IPV4_ROUTE_SECRET_INTERVAL=16,
 };
 
 enum
index 66d51fe7599c5123be1e32fbf7ba7e554a4648c3..7cdb7a8d432c51da5c315892cee315dd5ecc5077 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -610,7 +610,7 @@ int do_munmap(unsigned long addr, size_t len)
        struct mm_struct * mm;
        struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;
 
-       if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
+       if ((addr & ~PAGE_MASK) || addr >= TASK_SIZE || len > TASK_SIZE-addr)
                return -EINVAL;
 
        if ((len = PAGE_ALIGN(len)) == 0)
index 206010db848204f8cb3559b338471c287dc74286..9d31c25bbc2b7de7152ece290900a61e8452fe7d 100644 (file)
@@ -90,7 +90,6 @@ static int move_page_tables(struct mm_struct * mm,
        unsigned long offset = len;
 
        flush_cache_range(mm, old_addr, old_addr + len);
-       flush_tlb_range(mm, old_addr, old_addr + len);
 
        /*
         * This is not the clever way to do this, but we're taking the
@@ -102,6 +101,7 @@ static int move_page_tables(struct mm_struct * mm,
                if (move_one_page(mm, old_addr + offset, new_addr + offset))
                        goto oops_we_failed;
        }
+       flush_tlb_range(mm, old_addr, old_addr + len);
        return 0;
 
        /*
@@ -140,6 +140,7 @@ static inline unsigned long move_vma(struct vm_area_struct * vma,
                                new_vma->vm_ops->open(new_vma);
                        insert_vm_struct(current->mm, new_vma);
                        merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
+                       /* XXX: possible errors masked, mapping might remain */
                        do_munmap(addr, old_len);
                        current->mm->total_vm += new_len >> PAGE_SHIFT;
                        if (new_vma->vm_flags & VM_LOCKED) {
@@ -172,16 +173,26 @@ asmlinkage unsigned long sys_mremap(unsigned long addr,
        old_len = PAGE_ALIGN(old_len);
        new_len = PAGE_ALIGN(new_len);
 
+       if (old_len > TASK_SIZE || addr > TASK_SIZE - old_len)
+               goto out;
+
+       if (addr >= TASK_SIZE)
+               goto out;
+
        /*
         * Always allow a shrinking remap: that just unmaps
         * the unnecessary pages..
         */
-       ret = addr;
        if (old_len >= new_len) {
-               do_munmap(addr+new_len, old_len - new_len);
+               ret = do_munmap(addr+new_len, old_len - new_len);
+               if (!ret || old_len == new_len)
+                       ret = addr;
                goto out;
        }
 
+       if (new_len > TASK_SIZE || addr > TASK_SIZE - new_len)
+               goto out;
+
        /*
         * Ok, we need to grow..
         */
index cd8b0128851731b48e30376a634ed7372d971465..3a4d8b8939f222c3a445bea064936f64610ff6a9 100644 (file)
@@ -367,14 +367,11 @@ asmlinkage int sys_swapoff(const char * specialfile)
        for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
                p = swap_info + type;
                if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-                       if (p->swap_file) {
-                               if (p->swap_file == dentry)
-                                 break;
-                       } else {
-                               if (S_ISBLK(dentry->d_inode->i_mode)
-                                   && (p->swap_device == dentry->d_inode->i_rdev))
-                                 break;
-                       }
+                       if (p->swap_file == dentry)
+                               break;
+                       if (S_ISBLK(dentry->d_inode->i_mode) &&
+                           p->swap_device == dentry->d_inode->i_rdev)
+                               break;
                }
                prev = type;
        }
index 41ff441940c8cbc739b0f4110fda364652e75df1..25da070eef86764a421cdf3c685092adc46d5875 100644 (file)
@@ -1060,6 +1060,7 @@ static struct proc_dir_entry proc_net_udp = {
 
 extern void tcp_init(void);
 extern void tcp_v4_init(struct net_proto_family *);
+extern void ipfrag_init(void);
 
 
 /*
@@ -1168,4 +1169,6 @@ __initfunc(void inet_proto_init(struct net_proto *pro))
        proc_net_register(&proc_net_tcp);
        proc_net_register(&proc_net_udp);
 #endif         /* CONFIG_PROC_FS */
+
+       ipfrag_init();
 }
index f066e6073f5ba88f1dc32b8b23b51ccacb2c43f1..549c8e7428bf31555098fb18a19a38c02acb1afe 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/ip.h>
 #include <linux/icmp.h>
 #include <linux/netdevice.h>
+#include <linux/jhash.h>
+#include <linux/random.h>
 #include <net/sock.h>
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -72,9 +74,53 @@ struct ipq {
 #define IPQ_HASHSZ     64
 
 struct ipq *ipq_hash[IPQ_HASHSZ];
+static u32 ipfrag_hash_rnd;
 
-#define ipqhashfn(id, saddr, daddr, prot) \
-       ((((id) >> 1) ^ (saddr) ^ (daddr) ^ (prot)) & (IPQ_HASHSZ - 1))
+static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot)
+{
+       return jhash_3words((u32)id << 16 | prot, saddr, daddr,
+                           ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
+}
+
+static struct timer_list ipfrag_secret_timer;
+static int ipfrag_secret_interval = 10 * 60 * HZ;
+
+static void ipfrag_secret_rebuild(unsigned long dummy)
+{
+       unsigned long now = jiffies;
+       int i;
+
+       get_random_bytes(&ipfrag_hash_rnd, sizeof(u32));
+       for (i = 0; i < IPQ_HASHSZ; i++) {
+               struct ipq *q;
+
+               q = ipq_hash[i];
+               while (q) {
+                       struct ipq *next = q->next;
+                       unsigned int hval = ipqhashfn(q->iph->id,
+                                                     q->iph->saddr,
+                                                     q->iph->daddr,
+                                                     q->iph->protocol);
+
+                       if (hval != i) {
+                               /* Unlink. */
+                               if (q->next)
+                                       q->next->pprev = q->pprev;
+                               *q->pprev = q->next;
+
+                               /* Relink to new hash chain. */
+                               if ((q->next = ipq_hash[hval]) != NULL)
+                                       q->next->pprev = &q->next;
+                               ipq_hash[hval] = q;
+                               q->pprev = &ipq_hash[hval];
+                       }
+
+                       q = next;
+               }
+       }
+
+       mod_timer(&ipfrag_secret_timer, now + ipfrag_secret_interval);
+}
 
 atomic_t ip_frag_mem = ATOMIC_INIT(0);         /* Memory used for fragments */
 
@@ -409,6 +455,17 @@ out_fail:
        return NULL;
 }
 
+void ipfrag_init(void)
+{
+       ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+                                (jiffies ^ (jiffies >> 6)));
+
+       init_timer(&ipfrag_secret_timer);
+       ipfrag_secret_timer.function = ipfrag_secret_rebuild;
+       ipfrag_secret_timer.expires = jiffies + ipfrag_secret_interval;
+       add_timer(&ipfrag_secret_timer);
+}
+
 /* Process an incoming IP datagram fragment. */
 struct sk_buff *ip_defrag(struct sk_buff *skb)
 {
index 542353f15f11d0b2a05ed552e01e928b461bcf17..4cf7bfd476fafca5d89723343853cc4e903c5e6d 100644 (file)
@@ -82,6 +82,8 @@
 #include <linux/igmp.h>
 #include <linux/pkt_sched.h>
 #include <linux/mroute.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
 #include <net/protocol.h>
 #include <net/ip.h>
 #include <net/route.h>
@@ -112,7 +114,7 @@ int ip_rt_error_cost = HZ;
 int ip_rt_error_burst = 5*HZ;
 int ip_rt_gc_elasticity = 8;
 int ip_rt_mtu_expires = 10*60*HZ;
-
+int ip_rt_secret_interval = 10*60*HZ;
 static unsigned long rt_deadline = 0;
 
 #define RTprint(a...)  printk(KERN_DEBUG a)
@@ -123,6 +125,8 @@ static struct timer_list rt_flush_timer =
        { NULL, NULL, 0, 0L, rt_run_flush };
 static struct timer_list rt_periodic_timer =
        { NULL, NULL, 0, 0L, NULL };
+static struct timer_list rt_secret_timer =
+       { NULL, NULL, 0, 0L, NULL };
 
 /*
  *     Interface to generic destination cache.
@@ -174,16 +178,14 @@ __u8 ip_tos2prio[16] = {
  * Route cache.
  */
 
-struct rtable  *rt_hash_table[RT_HASH_DIVISOR];
+struct rtable          *rt_hash_table[RT_HASH_DIVISOR];
+static unsigned int    rt_hash_rnd;
 
 static int rt_intern_hash(unsigned hash, struct rtable * rth, struct rtable ** res);
 
-static __inline__ unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos)
+static unsigned rt_hash_code(u32 daddr, u32 saddr, u8 tos)
 {
-       unsigned hash = ((daddr&0xF0F0F0F0)>>4)|((daddr&0x0F0F0F0F)<<4);
-       hash = hash^saddr^tos;
-       hash = hash^(hash>>16);
-       return (hash^(hash>>8)) & 0xFF;
+       return (jhash_3words(daddr, saddr, (u32) tos, rt_hash_rnd) & 0xFF);
 }
 
 #ifdef CONFIG_PROC_FS
@@ -341,6 +343,8 @@ static void rt_run_flush(unsigned long dummy)
 
        rt_deadline = 0;
 
+       get_random_bytes(&rt_hash_rnd, 4);
+
        start_bh_atomic();
        for (i=0; i<RT_HASH_DIVISOR; i++) {
                if ((rth = xchg(&rt_hash_table[i], NULL)) == NULL)
@@ -399,6 +403,14 @@ void rt_cache_flush(int delay)
        end_bh_atomic();
 }
 
+static void rt_secret_rebuild(unsigned long dummy)
+{
+       unsigned long now = jiffies;
+
+       rt_cache_flush(0);
+       mod_timer(&rt_secret_timer, now + ip_rt_secret_interval);
+}
+
 /*
    Short description of GC goals.
 
@@ -1987,6 +1999,9 @@ ctl_table ipv4_route_table[] = {
        {NET_IPV4_ROUTE_MTU_EXPIRES, "mtu_expires",
          &ip_rt_mtu_expires, sizeof(int), 0644, NULL,
          &proc_dointvec_jiffies, &sysctl_jiffies},
+       {NET_IPV4_ROUTE_SECRET_INTERVAL, "secret_interval",
+         &ip_rt_secret_interval, sizeof(int), 0644, NULL,
+         &proc_dointvec_jiffies, &sysctl_jiffies},
         {0}
 };
 #endif
@@ -2034,6 +2049,7 @@ __initfunc(void ip_rt_init(void))
        devinet_init();
        ip_fib_init();
        rt_periodic_timer.function = rt_check_expire;
+       rt_secret_timer.function = rt_secret_rebuild;
        /* All the timers, started at system startup tend
           to synchronize. Perturb it a bit.
         */
@@ -2041,6 +2057,10 @@ __initfunc(void ip_rt_init(void))
                + ip_rt_gc_interval;
        add_timer(&rt_periodic_timer);
 
+       rt_periodic_timer.expires = jiffies + net_random()%ip_rt_secret_interval
+               + ip_rt_secret_interval;
+       add_timer(&rt_secret_timer);
+
 #ifdef CONFIG_PROC_FS
        proc_net_register(&(struct proc_dir_entry) {
                PROC_NET_RTCACHE, 8, "rt_cache",