diff -u --recursive --new-file v2.0.32/linux/Makefile linux/Makefile --- v2.0.32/linux/Makefile Tue Dec 2 13:52:30 1997 +++ linux/Makefile Wed Nov 26 15:31:03 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 32 +SUBLEVEL = 33 ARCH = i386 diff -u --recursive --new-file v2.0.32/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.0.32/linux/arch/i386/kernel/head.S Tue Dec 2 13:52:31 1997 +++ linux/arch/i386/kernel/head.S Tue Dec 2 13:58:53 1997 @@ -260,7 +260,7 @@ movw %dx,%ax /* selector = 0x0010 = cs */ movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ - lea SYMBOL_NAME(__idt),%edi + lea SYMBOL_NAME(idt),%edi mov $256,%ecx rp_sidt: movl %eax,(%edi) @@ -342,6 +342,11 @@ .long SYMBOL_NAME(init_user_stack)+4096 .long KERNEL_DS +/* NOTE: keep the idt short behind the above '.org 0x6000' + It must fit completely within _one_ page */ +ENTRY(idt) + .fill 256,8,0 # idt is uninitialized + /* This is the default interrupt "handler" :-) */ int_msg: .asciz "Unknown interrupt\n" @@ -376,10 +381,7 @@ .word 0 idt_descr: .word 256*8-1 # idt contains 256 entries - .long 0xc0000000+SYMBOL_NAME(__idt) - -ENTRY(__idt) - .fill 256,8,0 # idt is uninitialized + .long 0xc0000000+SYMBOL_NAME(idt) ALIGN .word 0 diff -u --recursive --new-file v2.0.32/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.0.32/linux/arch/i386/kernel/traps.c Tue Dec 2 13:52:31 1997 +++ linux/arch/i386/kernel/traps.c Tue Dec 2 13:58:53 1997 @@ -337,7 +337,6 @@ #endif /* CONFIG_MATH_EMULATION */ -struct desc_struct *idt = __idt+0; struct { unsigned short limit; unsigned long addr __attribute__((packed)); @@ -348,33 +347,35 @@ pgd_t * pgd; pmd_t * pmd; pte_t * pte; - unsigned long twopage; - struct desc_struct *new_idt; + unsigned long page; + unsigned long idtpage = (unsigned long)idt; + struct desc_struct *alias_idt; - printk("moving IDT ... "); + printk("alias mapping IDT readonly ... "); - twopage = (unsigned long) vmalloc (2*PAGE_SIZE); - - new_idt = (void *)(twopage + 4096-7*8); - - memcpy(new_idt,idt,256*8); + /* just to get free address space */ + page = (unsigned long) vmalloc (PAGE_SIZE); + alias_idt = (void *)(page + (idtpage & ~PAGE_MASK)); idt_descriptor.limit = 256*8-1; - idt_descriptor.addr = VMALLOC_VMADDR(new_idt); - - __asm__ __volatile__("\tlidt %0": "=m" (idt_descriptor)); - idt = new_idt; + idt_descriptor.addr = VMALLOC_VMADDR(alias_idt); /* - * Unmap lower page: + * alias map the original idt to the alias page: */ - twopage = VMALLOC_VMADDR(twopage); - pgd = pgd_offset(current->mm, twopage); - pmd = pmd_offset(pgd, twopage); - pte = pte_offset(pmd, twopage); - - pte_clear(pte); + page = VMALLOC_VMADDR(page); + pgd = pgd_offset(&init_mm, page); + pmd = pmd_offset(pgd, page); + pte = pte_offset(pmd, page); + /* give memory back to the pool, don't need it */ + free_page(pte_page(*pte)); + /* ... and set the readonly alias */ + set_pte(pte, mk_pte(idtpage & PAGE_MASK, PAGE_KERNEL)); + *pte = pte_wrprotect(*pte); flush_tlb_all(); + + /* now we have the mapping ok, we can do LIDT */ + __asm__ __volatile__("\tlidt %0": "=m" (idt_descriptor)); printk(" ... done\n"); } diff -u --recursive --new-file v2.0.32/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.0.32/linux/arch/i386/mm/fault.c Tue Dec 2 13:52:31 1997 +++ linux/arch/i386/mm/fault.c Tue Dec 2 13:58:53 1997 @@ -21,128 +21,10 @@ extern void die_if_kernel(const char *,struct pt_regs *,long); -asmlinkage void do_divide_error (struct pt_regs *, unsigned long); -asmlinkage void do_debug (struct pt_regs *, unsigned long); -asmlinkage void do_nmi (struct pt_regs *, unsigned long); -asmlinkage void do_int3 (struct pt_regs *, unsigned long); -asmlinkage void do_overflow (struct pt_regs *, unsigned long); -asmlinkage void do_bounds (struct pt_regs *, unsigned long); asmlinkage void do_invalid_op (struct pt_regs *, unsigned long); -asmlinkage void do_general_protection (struct pt_regs *, unsigned long); extern int pentium_f00f_bug; -static int handle_intx_eip_adjust(struct pt_regs *regs) -{ - unsigned char *addr, *csp = 0; - int wrap = 0; - int count = 8; /* only check for reasonable number of bytes - * else we do it the save 'simple way' */ - unsigned long _eip; -#define XX_WRAP(x) (wrap ? *((unsigned short *)&x) : x) - - /* We rely on being able to access the memory pointed to by cs:eip - * and the bytes behind it up to the faulting instruction, - * because we just got an exception for this instruction and - * hence the memory should just be successfully accessed. - * In case of crossing a page boundary or when accessing kernel space - * we just do the simple fix (increase eip by one). - * This assumption also obsoletes checking of segment limit. - * ( should be veryfied, however, if this assumption is true ) - */ - - if (regs->cs == KERNEL_CS) { - /* not what we expect */ - regs->eip++; - return 0; - } - - if (regs->eflags & VM_MASK) { - /* we have real mode type selector */ - wrap = 1; - csp = (unsigned char *)((unsigned long)regs->cs << 4); - } - else if (regs->cs & 4) { - /* we have a LDT selector */ - struct desc_struct *p, *ldt = current->ldt; - if (!ldt) - ldt = (struct desc_struct*) &default_ldt; - p = ldt + (regs->cs >> 3); - csp = (unsigned char *)((p->a >> 16) | ((p->b & 0xff) << 16) | (p->b & 0xFF000000)); - if (!(p->b & 0x400000)) - wrap = 1; /* 16-bit segment */ - } - - _eip = regs->eip; - addr = csp+XX_WRAP(_eip); - while (count-- > 0) { - if ((unsigned long)addr >= TASK_SIZE) { - /* accessing kernel space, do the simple case */ - regs->eip++; - return 0; - } - switch (get_user(addr)) { - - case 0xCC: /* single byte INT3 */ - XX_WRAP(_eip)++; - regs->eip = _eip; - return 0; - - case 0xCD: /* two byte INT 3 */ - XX_WRAP(_eip)++; - /* fall through */ - case 0xCE: /* INTO, single byte */ - XX_WRAP(_eip)++; - if ( (regs->eflags & VM_MASK) - && ((regs->eflags & IOPL_MASK) != IOPL_MASK)) { - /* not allowed, do GP0 fault */ - do_general_protection(regs, 0); - return -1; - } - regs->eip = _eip; - return 0; - - /* the prefixes from the Intel patch */ - case 0xF2 ... 0xF3: - case 0x2E: - case 0x36: - case 0x3E: - case 0x26: - case 0x64 ... 0x67: - break; /* just skipping them */ - - default: - /* not what we handle here, - * just doing the simple fix - */ - regs->eip++; - return 0; - } - - if ( !(++XX_WRAP(_eip)) ) { - /* we wrapped around */ - regs->eip++; - return 0; - } - - addr = csp+XX_WRAP(_eip); - if ( !((unsigned long)addr & ~(PAGE_SIZE -1)) ) { - /* we would cross page boundary, not good, - * doing the simple fix - */ - regs->eip++; - return 0; - } - } - - /* if we come here something weird happened, - * just doing the simple fix - */ - regs->eip++; - return 0; -} - - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -245,22 +127,15 @@ */ if ( pentium_f00f_bug ) { unsigned long nr; + extern struct { + unsigned short limit; + unsigned long addr __attribute__((packed)); + } idt_descriptor; - nr = (address - TASK_SIZE - (unsigned long) idt) >> 3; + nr = (address - idt_descriptor.addr) >> 3; - if (nr < 7) { - static void (*handler[])(struct pt_regs *, unsigned long) = { - do_divide_error, /* 0 - divide overflow */ - do_debug, /* 1 - debug trap */ - do_nmi, /* 2 - NMI */ - do_int3, /* 3 - int 3 */ - do_overflow, /* 4 - overflow */ - do_bounds, /* 5 - bound range */ - do_invalid_op }; /* 6 - invalid opcode */ - if ((nr == 3) || (nr == 4)) - if (handle_intx_eip_adjust(regs)) - return; - handler[nr](regs, error_code); + if (nr == 6) { + do_invalid_op(regs, 0); return; } } diff -u --recursive --new-file v2.0.32/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.0.32/linux/include/asm-i386/pgtable.h Wed Oct 15 15:22:05 1997 +++ linux/include/asm-i386/pgtable.h Tue Dec 2 14:18:13 1997 @@ -42,11 +42,28 @@ #define __flush_tlb() \ do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0) +/* + * NOTE! The intel "invlpg" semantics are extremely strange. The + * chip will add the segment base to the memory address, even though + * no segment checking is done. We correct for this by using an + * offset of 0x40000000 that will wrap around the kernel segment base + * of 0xC0000000 to get the correct address (it will always be outside + * the kernel segment, but we're only interested in the final linear + * address. + */ +#define __invlpg_mem(addr) \ + (((char *)(addr))[0x40000000]) +#define __invlpg(addr) \ + __asm__ __volatile__("invlpg %0": :"m" (__invlpg_mem(addr))) + +/* + * The i386 doesn't have a page-granular invalidate. Invalidate + * everything for it. + */ #ifdef CONFIG_M386 -#define __flush_tlb_one(addr) flush_tlb() + #define __flush_tlb_one(addr) __flush_tlb() #else -#define __flush_tlb_one(addr) \ -__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr)) + #define __flush_tlb_one(addr) __invlpg(addr) #endif #ifndef __SMP__ diff -u --recursive --new-file v2.0.32/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v2.0.32/linux/include/linux/ax25.h Sat Aug 10 00:03:15 1996 +++ linux/include/linux/ax25.h Thu Dec 4 13:13:23 1997 @@ -6,7 +6,6 @@ #ifndef AX25_KERNEL_H #define AX25_KERNEL_H -#define PF_AX25 AF_AX25 #define AX25_MTU 256 #define AX25_MAX_DIGIS 6 /* This is wrong, should be 8 */ diff -u --recursive --new-file v2.0.32/linux/include/linux/head.h linux/include/linux/head.h --- v2.0.32/linux/include/linux/head.h Tue Dec 2 13:52:33 1997 +++ linux/include/linux/head.h Tue Dec 2 13:58:53 1997 @@ -5,8 +5,7 @@ unsigned long a,b; } desc_table[256]; -extern desc_table __idt,gdt; -extern struct desc_struct *idt; +extern desc_table idt,gdt; #define GDT_NUL 0 #define GDT_CODE 1 diff -u --recursive --new-file v2.0.32/linux/include/linux/netrom.h linux/include/linux/netrom.h --- v2.0.32/linux/include/linux/netrom.h Sat Aug 10 00:03:15 1996 +++ linux/include/linux/netrom.h Thu Dec 4 13:13:23 1997 @@ -7,7 +7,6 @@ #ifndef NETROM_KERNEL_H #define NETROM_KERNEL_H -#define PF_NETROM AF_NETROM #define NETROM_MTU 236 #define NETROM_T1 1 diff -u --recursive --new-file v2.0.32/linux/include/net/route.h linux/include/net/route.h --- v2.0.32/linux/include/net/route.h Wed Oct 15 15:23:10 1997 +++ linux/include/net/route.h Wed Dec 10 09:14:00 1997 @@ -14,6 +14,11 @@ * Alan Cox : Support for TCP parameters. * Alexey Kuznetsov: Major changes for new routing code. * Elliot Poger : Added support for SO_BINDTODEVICE. + * Wolfgang Walter, + * Daniel Ryde, + * Ingo Molinar : fixed bug in ip_rt_put introduced + * by SO_BINDTODEVICE support causing + * a memory leak * * FIXME: * Make atomic ops more generic and hide them in asm/... @@ -98,6 +103,7 @@ extern atomic_t ip_rt_lock; extern unsigned ip_rt_bh_mask; extern struct rtable *ip_rt_hash_table[RT_HASH_DIVISOR]; +extern void rt_free(struct rtable * rt); extern __inline__ void ip_rt_fast_lock(void) { @@ -127,6 +133,11 @@ { if (rt) atomic_dec(&rt->rt_refcnt); + + /* If this rtable entry is not in the cache, we'd better free it once the + * refcnt goes to zero, because nobody else will... */ + if ( rt && (rt->rt_flags & RTF_NOTCACHED) && (!rt->rt_refcnt) ) + rt_free(rt); } #else ; diff -u --recursive --new-file v2.0.32/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.0.32/linux/net/ipv4/ip_forward.c Tue Aug 12 11:30:25 1997 +++ linux/net/ipv4/ip_forward.c Wed Dec 10 09:14:00 1997 @@ -16,6 +16,7 @@ * use output device for accounting. * Jos Vos : Call forward firewall after routing * (always use output device). + * Philip Gladstone: Add some missing ip_rt_put() */ #include @@ -113,7 +114,7 @@ struct device *dev2; /* Output device */ struct iphdr *iph; /* Our header */ struct sk_buff *skb2; /* Output packet */ - struct rtable *rt; /* Route we use */ + struct rtable *rt = NULL; /* Route we use */ unsigned char *ptr; /* Data pointer */ unsigned long raddr; /* Router IP address */ struct options * opt = (struct options*)skb->proto_priv; @@ -301,6 +302,8 @@ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); /* fall thru */ default: + if (rt) + ip_rt_put(rt); return -1; } @@ -454,6 +457,8 @@ icmp_send(skb2, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev); if (skb != skb2) kfree_skb(skb2,FREE_WRITE); + if (rt) + ip_rt_put(rt); return -1; } #endif diff -u --recursive --new-file v2.0.32/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.0.32/linux/net/ipv4/route.c Wed Sep 17 12:00:48 1997 +++ linux/net/ipv4/route.c Wed Dec 10 09:14:01 1997 @@ -45,6 +45,7 @@ * Elliot Poger : Added support for SO_BINDTODEVICE. * Andi Kleen : Don't send multicast addresses to * kerneld. + * Wolfgang Walter : make rt_free() non-static * * Juan Jose Ciarlante : Added ip_rt_dev * This program is free software; you can redistribute it and/or @@ -891,7 +892,7 @@ } -static void rt_free(struct rtable * rt) +void rt_free(struct rtable * rt) { unsigned long flags; diff -u --recursive --new-file v2.0.32/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.0.32/linux/net/ipv4/udp.c Mon Sep 15 09:54:52 1997 +++ linux/net/ipv4/udp.c Wed Dec 10 09:14:01 1997 @@ -55,6 +55,7 @@ * Elliot Poger : Added support for SO_BINDTODEVICE. * Willy Konynenberg : Transparent proxy adapted to new * socket hash code. + * Philip Gladstone: Added missing ip_rt_put * * * This program is free software; you can redistribute it and/or @@ -874,6 +875,8 @@ sk->daddr = usin->sin_addr.s_addr; sk->dummy_th.dest = usin->sin_port; sk->state = TCP_ESTABLISHED; + if (sk->ip_route_cache) + ip_rt_put(sk->ip_route_cache); sk->ip_route_cache = rt; return(0); } diff -u --recursive --new-file v2.0.32/linux/net/unix/garbage.c linux/net/unix/garbage.c --- v2.0.32/linux/net/unix/garbage.c Mon May 13 05:31:18 1996 +++ linux/net/unix/garbage.c Thu Dec 4 10:16:31 1997 @@ -5,6 +5,16 @@ * Copyright (C) Barak A. Pearlmutter. * Released under the GPL version 2 or later. * + * 12/3/97 -- Flood + * Internal stack is only allocated one page. On systems with NR_FILE + * > 1024, this makes it quite easy for a user-space program to open + * a large number of AF_UNIX domain sockets, causing the garbage + * collection routines to run up against the wall (and panic). + * Changed the MAX_STACK to be associated to the system-wide open file + * maximum, and use vmalloc() instead of get_free_page() [as more than + * one page may be necessary]. As noted below, this should ideally be + * done with a linked list. + * * Chopped about by Alan Cox 22/3/96 to make it fit the AF_UNIX socket problem. * If it doesn't work blame me, it worked when Barak sent it. * @@ -59,10 +69,9 @@ /* Internal data structures and random procedures: */ -#define MAX_STACK 1000 /* Maximum depth of tree (about 1 page) */ static unix_socket **stack; /* stack of objects to mark */ static int in_stack = 0; /* first free entry in stack */ - +static int max_stack; /* Calculated in unix_gc() */ extern inline unix_socket *unix_get_socket(struct file *filp) { @@ -110,7 +119,7 @@ extern inline void push_stack(unix_socket *x) { - if (in_stack == MAX_STACK) + if (in_stack == max_stack) panic("can't push onto full stack"); stack[in_stack++] = x; } @@ -151,8 +160,14 @@ if(in_unix_gc) return; in_unix_gc=1; - - stack=(unix_socket **)get_free_page(GFP_KERNEL); + + max_stack = max_files; + + stack=(unix_socket **)vmalloc(max_stack * sizeof(unix_socket **)); + if (!stack) { + in_unix_gc=0; + return; + } /* * Assume everything is now unmarked @@ -276,5 +291,5 @@ in_unix_gc=0; - free_page((long)stack); + vfree(stack); }