First snapshot of a proposed set of fixes to make 2.0.34

Alan Cox (alan@lxorguk.ukuu.org.uk)
Sun, 18 Jan 98 15:27 GMT


I'd appreciate feedback on these - especially on the Alpha platform so I can fix any further
problems they may have caused someone and submit this on to Linus for 2.0.34

o sysctl oops
o ptrace oops
o signal oops
o i_count exploit
o autofw help text
o LDT memory leak
o Warning in cdrom.c
o Warning in eth16i.c
o Remove experimental tag fro DLCI/SDLA support
o SMC ultra32 module fix
o eql warning
o new_tunnel warning
o kerneld/ifconfig exploit
o ignore source quench and drive by the dropped frames (current "good practice")

[Items marked "warning" indicate compiler warnings that turned out to be code that is 'wrong' from
a perfect compiler correctness viewpoint but worked correctly before]

[Items marked "oops" fix non fatal Oops events]

[Items marked "exploit" fix something that allowed you to either crash the machine as any user
or to get root]

--------------------------------------------------------------------------------------------------

diff --unified --new-file --recursive --exclude-from exclude linux.van2033/Documentation/Configure.help linux/Documentation/Configure.help
--- linux.van2033/Documentation/Configure.help Sun Jan 18 14:15:57 1998
+++ linux/Documentation/Configure.help Sun Jan 18 14:26:43 1998
@@ -976,16 +976,13 @@
IP always defragment.
If you want this, say Y.

-IP: ipautofw masquerade support
-CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental)
- ipautofw is a program by Richard Lynch allowing additional
- support for masquerading protocols which do not (as yet)
- have additional protocol helpers.
- Information and source for ipautofw is available from
- ftp://ftp.netis.com/pub/members/rlynch/
- The ipautofw code is still under development and so is currently
- marked EXPERIMENTAL.
- If you want this, say Y.
+IP: ipautofw masquerading (EXPERIMENTAL)
+CONFIG_IP_MASQUERADE_IPAUTOFW
+
+ Richard Lynch's ipautofw allows masquerading to work with protocols
+ which do not (as yet) have specific protocol helpers. Its source, and
+ other information, is available at
+ ftp://ftp.netis.com/pub/members/rlynch/.

IP: ICMP masquerading
CONFIG_IP_MASQUERADE_ICMP
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- linux.van2033/arch/i386/kernel/process.c Sun Jan 18 14:15:47 1998
+++ linux/arch/i386/kernel/process.c Sun Jan 18 14:21:45 1998
@@ -421,8 +421,9 @@
int i;

if (current->ldt) {
- free_page((unsigned long) current->ldt);
+ void * ldt = current->ldt;
current->ldt = NULL;
+ vfree(ldt);
for (i=1 ; i<NR_TASKS ; i++) {
if (task[i] == current) {
set_ldt_desc(gdt+(i<<1)+
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- linux.van2033/arch/i386/kernel/ptrace.c Sun Jan 18 14:15:47 1998
+++ linux/arch/i386/kernel/ptrace.c Sun Jan 18 14:20:09 1998
@@ -416,6 +416,60 @@
return tmp;
}

+void safe_wake_up_process(struct task_struct * p)
+{
+ struct desc_struct * d;
+ unsigned long limit;
+
+ void check(int index, int mask, int value) {
+ unsigned long selector, limit;
+
+ if (!p) return;
+
+ selector = get_stack_long(p, sizeof(long)*index - MAGICNUMBER);
+ if (selector & 4) {
+ d = p->ldt;
+ if (d) limit = get_limit(p->tss.ldt); else limit = 0;
+ } else {
+ d = gdt;
+ limit = 8 * 8;
+ }
+
+ if ((selector & 0xFFF8) >= limit) {
+ d = NULL;
+ force_sig(SIGSEGV, p); p = NULL;
+ } else {
+ d += selector >> 3;
+ if ((d->b & mask) != value ||
+ (d->b >> 13) < (selector & 3)) {
+ force_sig(SIGSEGV, p); p = NULL;
+ }
+ }
+ }
+
+ check(DS, 0x9800, 0x9000); /* Allow present data segments only */
+ check(ES, 0x9800, 0x9000);
+ check(FS, 0x9800, 0x9000);
+ check(GS, 0x9800, 0x9000);
+ check(SS, 0x9A00, 0x9200); /* Stack segment should not be read-only */
+ check(CS, 0x9800, 0x9800); /* Allow present code segments only */
+
+ if (!p) return;
+
+ if (d) {
+ limit = (d->a & 0xFFFF) | (d->b & 0xF0000);
+ if (d->b & 0x800000) {
+ limit <<= 12; limit |= 0xFFF;
+ }
+
+ if (get_stack_long(p, sizeof(long)*EIP - MAGICNUMBER) > limit) {
+ force_sig(SIGSEGV, p); return;
+ }
+ }
+
+ wake_up_process(p);
+}
+
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -609,7 +663,7 @@
else
child->flags &= ~PF_TRACESYS;
child->exit_code = data;
- wake_up_process(child);
+ safe_wake_up_process(child);
/* make sure the single step bit is not set. */
tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
@@ -642,8 +696,8 @@
child->flags &= ~PF_TRACESYS;
tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
- wake_up_process(child);
child->exit_code = data;
+ safe_wake_up_process(child);
/* give it a chance to run. */
return 0;
}
@@ -654,8 +708,8 @@
if ((unsigned long) data > NSIG)
return -EIO;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
- wake_up_process(child);
child->exit_code = data;
+ safe_wake_up_process(child);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- linux.van2033/arch/i386/kernel/signal.c Sun Jan 18 14:14:04 1998
+++ linux/arch/i386/kernel/signal.c Sun Jan 18 14:20:09 1998
@@ -15,6 +15,7 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>

+#include <asm/system.h>
#include <asm/segment.h>

#define _S(nr) (1<<((nr)-1))
@@ -80,13 +81,40 @@
asmlinkage int sys_sigreturn(unsigned long __unused)
{
#define COPY(x) regs->x = context.x
+#define CHECK_DATA(x, mask, value) \
+__asm__("larw %0,%%ax\n\t" \
+ "jnz asm_badframe\n\t" \
+ "andl $" mask ",%%eax\n\t" \
+ "cmpl $" value ",%%eax\n\t" \
+ "jne asm_badframe" \
+ : \
+ : "g" (context.x) \
+ : "ax", "cc");
+#define CHECK_CODE(x, y) \
+__asm__("larw %0,%%ax\n\t" \
+ "jnz asm_badframe\n\t" \
+ "andl $0x9800,%%eax\n\t" \
+ "cmpl $0x9800,%%eax\n\t" /* Allow present code segments only */ \
+ "jne asm_badframe\n\t" \
+ "lsll %0,%%eax\n\t" \
+ "cmp %1,%%eax\n\t" /* Check context.eip against the segment limit */ \
+ "jb asm_badframe" \
+ : \
+ : "g" (context.x), "g" (context.y) \
+ : "ax", "cc");
#define COPY_SEG(x) \
+CHECK_DATA(x, "0x9800", "0x9000") /* Allow present data segments only */ \
if ( (context.x & 0xfffc) /* not a NULL selectors */ \
&& (context.x & 0x4) != 0x4 /* not a LDT selector */ \
&& (context.x & 3) != 3 /* not a RPL3 GDT selector */ \
) goto badframe; COPY(x);
-#define COPY_SEG_STRICT(x) \
+#define COPY_STACK(x) \
+CHECK_DATA(x, "0x9A00", "0x9200") /* Stack segment should not be read-only */ \
if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
+#define COPY_CODE(x, y) \
+CHECK_CODE(x, y) \
+if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; \
+COPY(x); COPY(y);
struct sigcontext_struct context;
struct pt_regs * regs;

@@ -99,9 +127,8 @@
COPY_SEG(es);
COPY_SEG(fs);
COPY_SEG(gs);
- COPY_SEG_STRICT(ss);
- COPY_SEG_STRICT(cs);
- COPY(eip);
+ COPY_STACK(ss);
+ COPY_CODE(cs, eip);
COPY(ecx); COPY(edx);
COPY(ebx);
COPY(esp); COPY(ebp);
@@ -117,6 +144,11 @@
}
return context.eax;
badframe:
+ do_exit(SIGSEGV);
+}
+
+void asm_badframe(void)
+{
do_exit(SIGSEGV);
}

diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/block/md.c linux/drivers/block/md.c
--- linux.van2033/drivers/block/md.c Sat Jun 29 22:04:00 1996
+++ linux/drivers/block/md.c Sun Jan 18 14:42:10 1998
@@ -202,7 +202,7 @@

if (inode->i_count>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
{
- printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
+ printk ("STOP_MD md%x failed : i_count=%ld, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
return -EBUSY;
}

diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux.van2033/drivers/cdrom/cdrom.c Sat Aug 17 19:19:26 1996
+++ linux/drivers/cdrom/cdrom.c Sun Jan 18 15:40:29 1998
@@ -97,7 +97,9 @@

/* We need our own cdrom error types! This is a temporary solution. */

+#ifndef ENOMEDIUM
#define ENOMEDIUM EAGAIN /* no medium in removable device */
+#endif

/* We use the open-option O_NONBLOCK to indicate that the
* purpose of opening is only for subsequent ioctl() calls; no device
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/net/Config.in linux/drivers/net/Config.in
--- linux.van2033/drivers/net/Config.in Sun Jan 18 14:14:19 1998
+++ linux/drivers/net/Config.in Sun Jan 18 14:21:07 1998
@@ -3,13 +3,11 @@
#
tristate 'Dummy net driver support' CONFIG_DUMMY
tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Frame relay DLCI support (EXPERIMENTAL)' CONFIG_DLCI
- if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
- int ' Max open DLCI' CONFIG_DLCI_COUNT 24
- int ' Max DLCI per device' CONFIG_DLCI_MAX 8
- dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
- fi
+tristate 'Frame relay DLCI support' CONFIG_DLCI
+if [ "$CONFIG_DLCI" = "y" -o "$CONFIG_DLCI" = "m" ]; then
+ int ' Max open DLCI' CONFIG_DLCI_COUNT 24
+ int ' Max DLCI per device' CONFIG_DLCI_MAX 8
+ dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
fi
tristate 'PLIP (parallel port) support' CONFIG_PLIP
tristate 'PPP (point-to-point) support' CONFIG_PPP
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/net/Makefile linux/drivers/net/Makefile
--- linux.van2033/drivers/net/Makefile Sun Jan 18 14:14:19 1998
+++ linux/drivers/net/Makefile Sun Jan 18 14:18:32 1998
@@ -148,7 +148,7 @@
L_OBJS += smc-ultra32.o
CONFIG_8390_BUILTIN = y
else
- ifeq ($(CONFIG_ULTRA),m)
+ ifeq ($(CONFIG_ULTRA32),m)
CONFIG_8390_MODULE = y
M_OBJS += smc-ultra32.o
endif
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/net/eql.c linux/drivers/net/eql.c
--- linux.van2033/drivers/net/eql.c Sun Jan 18 14:14:21 1998
+++ linux/drivers/net/eql.c Sun Jan 18 15:39:36 1998
@@ -375,7 +375,6 @@
equalizer_t *eql = (equalizer_t *) dev->priv;
struct device *slave_dev = 0;
slave_t *slave;
- struct sk_buff *skb2;

if (skb == NULL)
return 0;
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- linux.van2033/drivers/net/eth16i.c Sun Jan 18 14:14:21 1998
+++ linux/drivers/net/eth16i.c Sun Jan 18 15:43:38 1998
@@ -332,7 +332,7 @@
static int eth16i_tx(struct sk_buff *skb, struct device *dev);
static void eth16i_rx(struct device *dev);
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void eth16i_multicast(struct device *dev, int num_addrs, void *addrs);
+static void eth16i_multicast(struct device *dev);
static void eth16i_select_regbank(unsigned char regbank, short ioaddr);
static void eth16i_initialize(struct device *dev);
static struct enet_statistics *eth16i_get_stats(struct device *dev);
@@ -1152,7 +1152,7 @@
return;
}

-static void eth16i_multicast(struct device *dev, int num_addrs, void *addrs)
+static void eth16i_multicast(struct device *dev)
{
short ioaddr = dev->base_addr;

diff --unified --new-file --recursive --exclude-from exclude linux.van2033/drivers/net/new_tunnel.c linux/drivers/net/new_tunnel.c
--- linux.van2033/drivers/net/new_tunnel.c Sun Jan 18 14:14:23 1998
+++ linux/drivers/net/new_tunnel.c Sun Jan 18 15:38:25 1998
@@ -267,7 +267,7 @@

/* Tack on our header */
new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
- new_skb->mac.raw = new_skb->ip_hdr;
+ new_skb->mac.raw = (void *)new_skb->ip_hdr;

/* Free the old packet, we no longer need it */
dev_kfree_skb(skb, FREE_WRITE);
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/ext/freelists.c linux/fs/ext/freelists.c
--- linux.van2033/fs/ext/freelists.c Sat Nov 30 10:21:19 1996
+++ linux/fs/ext/freelists.c Sun Jan 18 15:41:13 1998
@@ -188,7 +188,7 @@
return;
}
if (inode->i_count != 1) {
- printk("free_inode: inode has count=%d\n",inode->i_count);
+ printk("free_inode: inode has count=%ld\n",inode->i_count);
return;
}
if (inode->i_nlink) {
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- linux.van2033/fs/ext2/ialloc.c Sun Jan 18 14:14:37 1998
+++ linux/fs/ext2/ialloc.c Sun Jan 18 14:58:24 1998
@@ -196,7 +196,7 @@
return;
}
if (inode->i_count > 1) {
- printk ("ext2_free_inode: inode has count=%d\n",
+ printk ("ext2_free_inode: inode has count=%ld\n",
inode->i_count);
return;
}
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- linux.van2033/fs/minix/bitmap.c Sat Nov 30 10:21:20 1996
+++ linux/fs/minix/bitmap.c Sun Jan 18 15:40:51 1998
@@ -187,7 +187,7 @@
return;
}
if (inode->i_count != 1) {
- printk("free_inode: inode has count=%d\n",inode->i_count);
+ printk("free_inode: inode has count=%ld\n",inode->i_count);
return;
}
if (inode->i_nlink) {
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- linux.van2033/fs/ncpfs/inode.c Sun Jan 18 14:14:39 1998
+++ linux/fs/ncpfs/inode.c Sun Jan 18 15:42:03 1998
@@ -145,7 +145,7 @@
lock_super(sb);

if (inode->i_count > 1) {
-printk("ncp_put_inode: inode in use device %s, inode %ld, count=%d\n",
+printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n",
kdevname(inode->i_dev), inode->i_ino, inode->i_count);
goto unlock;
}
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- linux.van2033/fs/smbfs/inode.c Sun Jan 18 14:14:39 1998
+++ linux/fs/smbfs/inode.c Sun Jan 18 15:41:51 1998
@@ -99,7 +99,7 @@
__u32 mtime = inode->i_mtime;

if (inode->i_count > 1) {
- printk("smb_put_inode: in use device %s, inode %ld count=%d\n",
+ printk("smb_put_inode: in use device %s, inode %ld count=%ld\n",
kdevname(inode->i_dev), inode->i_ino, inode->i_count);
return;
}
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- linux.van2033/fs/sysv/ialloc.c Sat Nov 30 10:21:21 1996
+++ linux/fs/sysv/ialloc.c Sun Jan 18 15:41:35 1998
@@ -63,7 +63,7 @@
return;
}
if (inode->i_count != 1) {
- printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
+ printk("sysv_free_inode: inode has count=%ld\n", inode->i_count);
return;
}
if (inode->i_nlink) {
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- linux.van2033/fs/ufs/ufs_inode.c Sat Nov 30 10:21:22 1996
+++ linux/fs/ufs/ufs_inode.c Sun Jan 18 15:42:20 1998
@@ -23,7 +23,7 @@

void ufs_print_inode(struct inode * inode)
{
- printk("ino %lu mode 0%6.6o lk %d uid %d gid %d sz %lu blks %lu cnt %u\n",
+ printk("ino %lu mode 0%6.6o lk %d uid %d gid %d sz %lu blks %lu cnt %lu\n",
inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid, inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
printk(" db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x>\n",
inode->u.ufs_i.ui_db[0], inode->u.ufs_i.ui_db[1],
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/include/linux/fs.h linux/include/linux/fs.h
--- linux.van2033/include/linux/fs.h Sun Jan 18 14:15:52 1998
+++ linux/include/linux/fs.h Sun Jan 18 14:40:25 1998
@@ -304,7 +304,7 @@
struct inode *i_hash_next, *i_hash_prev;
struct inode *i_bound_to, *i_bound_by;
struct inode *i_mount;
- unsigned short i_count;
+ unsigned long i_count; /* needs to be > (address_space * tasks)>>pagebits */
unsigned short i_flags;
unsigned char i_lock;
unsigned char i_dirt;
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/kernel/sysctl.c linux/kernel/sysctl.c
--- linux.van2033/kernel/sysctl.c Sun Jan 18 14:14:45 1998
+++ linux/kernel/sysctl.c Sun Jan 18 14:20:09 1998
@@ -180,7 +180,7 @@
struct ctl_table_header *tmp;
void *context;

- if (nlen == 0 || nlen >= CTL_MAXNAME)
+ if (nlen <= 0 || nlen >= CTL_MAXNAME)
return -ENOTDIR;

error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/net/core/dev.c linux/net/core/dev.c
--- linux.van2033/net/core/dev.c Sun Jan 18 14:14:47 1998
+++ linux/net/core/dev.c Sun Jan 18 14:23:47 1998
@@ -225,7 +225,7 @@

extern __inline__ void dev_load(const char *name)
{
- if(!dev_get(name)) {
+ if(!dev_get(name) && suser()) {
#ifdef CONFIG_NET_ALIAS
const char *sptr;

diff --unified --new-file --recursive --exclude-from exclude linux.van2033/net/ipv4/Config.in linux/net/ipv4/Config.in
--- linux.van2033/net/ipv4/Config.in Sun Jan 18 14:14:47 1998
+++ linux/net/ipv4/Config.in Sun Jan 18 14:26:43 1998
@@ -15,7 +15,7 @@
if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
comment 'Protocol-specific masquerading support will be built as modules.'
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'IP: ipautofw masq support' CONFIG_IP_MASQUERADE_IPAUTOFW
+ bool 'IP: ipautofw masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
fi
bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
fi
diff --unified --new-file --recursive --exclude-from exclude linux.van2033/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux.van2033/net/ipv4/tcp.c Sun Jan 18 14:14:49 1998
+++ linux/net/ipv4/tcp.c Sun Jan 18 15:05:48 1998
@@ -740,16 +740,8 @@

if (type == ICMP_SOURCE_QUENCH)
{
- /*
- * FIXME:
- * Follow BSD for now and just reduce cong_window to 1 again.
- * It is possible that we just want to reduce the
- * window by 1/2, or that we want to reduce ssthresh by 1/2
- * here as well.
- */
- sk->cong_window = 1;
- sk->cong_count = 0;
- sk->high_seq = sk->sent_seq;
+ /* Current practice says these frames are bad, plus the drops
+ will account right anyway. If we act on this we stall doubly */
return;
}