diff -purN linux-2.4.21/drivers/pcmcia/i82092.c linux-f/drivers/pcmcia/i82092.c --- linux-2.4.21/drivers/pcmcia/i82092.c 2003-06-13 16:51:35.000000000 +0200 +++ linux-f/drivers/pcmcia/i82092.c 2003-07-14 22:09:51.000000000 +0200 @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -24,6 +26,7 @@ #include "i82092aa.h" #include "i82365.h" +#include "cirrus.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Red Hat, Inc. - Arjan Van De Ven "); @@ -41,8 +44,15 @@ static struct pci_device_id i82092aa_pci subdevice:PCI_ANY_ID, class: 0, class_mask:0, - }, - {} + }, + { + vendor:PCI_VENDOR_ID_CIRRUS, + device:PCI_DEVICE_ID_CIRRUS_6729, + subvendor:PCI_ANY_ID, + subdevice:PCI_ANY_ID, + class: 0, class_mask:0, + }, + {} }; static struct pci_driver i82092aa_pci_drv = { @@ -88,14 +98,18 @@ struct socket_info { void *info; /* to be passed to the handler */ struct pci_dev *dev; /* The PCI device for the socket */ + + int type; /* Type of socket */ +#define IS_I82092 0x0001 +#define IS_PD6729 0x0002 }; #define MAX_SOCKETS 4 static struct socket_info sockets[MAX_SOCKETS]; static int socket_count; /* shortcut */ -int membase = -1; -int isa_setup; +static int membase = -1; +static int isa_setup; MODULE_PARM(membase, "i"); MODULE_PARM(isa_setup, "i"); @@ -105,6 +119,7 @@ static int __init i82092aa_pci_probe(str unsigned char configbyte; struct pci_dev *parent; int i; + int type; enter("i82092aa_pci_probe"); @@ -114,7 +129,18 @@ static int __init i82092aa_pci_probe(str /* Since we have no memory BARs some firmware we may not have had PCI_COMMAND_MEM enabled, yet the device needs it. */ - pci_read_config_byte(dev, PCI_COMMAND, &configbyte); + + // pci_read_config_byte(dev, PCI_COMMAND, &configbyte); + if (dev->vendor == PCI_VENDOR_ID_CIRRUS) { + type = IS_PD6729; + configbyte = 0; /* always 2 sockets */ + printk(KERN_INFO "Cirrus PD6729 PCI to PCMCIA Bridge \n"); + } else { + type = IS_I82092; + pci_read_config_byte(dev, 0x40, &configbyte); /* PCI Configuration Control */ + printk(KERN_INFO "Intel I82092AA PCI to PCMCIA Bridge \n"); + } + if (!(configbyte | PCI_COMMAND_MEMORY)) { dprintk(KERN_DEBUG "Enabling PCI_COMMAND_MEMORY\n"); configbyte |= PCI_COMMAND_MEMORY; @@ -201,6 +227,7 @@ static int __init i82092aa_pci_probe(str sockets[i].cap.map_size = 0x1000; sockets[i].cap.irq_mask = 0; sockets[i].cap.pci_irq = dev->irq; + sockets[i].type = type; /* Trick the resource code into doing the right thing... */ sockets[i].cap.cb_dev = dev; @@ -213,10 +240,11 @@ static int __init i82092aa_pci_probe(str } } - /* Now, specifiy that all interrupts are to be done as PCI interrupts */ - configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */ - pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */ - + if (type == IS_I82092) { + /* Now, specifiy that all interrupts are to be done as PCI interrupts */ + configbyte = 0xFF; /* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt */ + pci_write_config_byte(dev, 0x50, configbyte); /* PCI Interrupt Routing Register */ + } /* Register the interrupt handler */ dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq); @@ -238,6 +266,7 @@ static void __devexit i82092aa_pci_remov enter("i82092aa_pci_remove"); free_irq(dev->irq, i82092aa_interrupt); + flush_scheduled_tasks(); leave("i82092aa_pci_remove"); } @@ -652,6 +681,7 @@ static int i82092aa_get_socket(unsigned static int i82092aa_set_socket(unsigned int sock, socket_state_t *state) { unsigned char reg; + unsigned long flags; enter("i82092aa_set_socket"); @@ -738,9 +768,26 @@ static int i82092aa_set_socket(unsigned /* now write the value and clear the (probably bogus) pending stuff by doing a dummy read*/ + spin_lock_irqsave(&port_lock,flags); + indirect_write(sock,I365_CSCINT,reg); (void)indirect_read(sock,I365_CSC); + if (sockets[sock].type == IS_PD6729) { + /* Configure PD6729 bridge for PCI interrupts */ + reg |= 0x30; /* management IRQ: PCI INTA = "irq 3" */ + indirect_write(sock,I365_CSCINT,reg); + (void)indirect_read(sock,I365_CSC); + + reg = indirect_read(sock,I365_INTCTL); + reg |= 0x03; /* card IRQ: PCI INTA = "irq 3" */ + indirect_write(sock,I365_INTCTL,reg); + + indirect_write(sock, PD67_EXT_INDEX, PD67_EXT_CTL_1); + indirect_write(sock, PD67_EXT_DATA, PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ); + } + spin_unlock_irqrestore(&port_lock,flags); + leave("i82092aa_set_socket"); return 0; } @@ -766,9 +813,10 @@ static int i82092aa_get_io_map(unsigned io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; /* check this out later */ io->flags = 0; - if (addr & I365_IOCTL_16BIT(map)) - io->flags |= MAP_AUTOSZ; - + io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0; + io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0; + io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0; + leave("i82092aa_get_io_map"); return 0; } @@ -786,7 +834,7 @@ static int i82092aa_set_io_map(unsigned leave("i82092aa_set_io_map with invalid map"); return -EINVAL; } - if ((io->start > 0xffff) || (io->stop > 0xffff) || (io->stop < io->start)){ + if (io->start > 0xffff || io->stop > 0xffff || io->stop < io->start){ leave("i82092aa_set_io_map with invalid io"); return -EINVAL; } @@ -803,9 +851,10 @@ static int i82092aa_set_io_map(unsigned ioctl = indirect_read(sock,I365_IOCTL) & ~I365_IOCTL_MASK(map); - if (io->flags & (MAP_16BIT|MAP_AUTOSZ)) - ioctl |= I365_IOCTL_16BIT(map); - + if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); + if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); + if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); + indirect_write(sock,I365_IOCTL,ioctl); /* Turn the window back on if needed */ @@ -864,11 +913,19 @@ static int i82092aa_get_mem_map(unsigned mem->flags |= MAP_WRPROT; if (i & I365_MEM_REG) mem->flags |= MAP_ATTRIB; - mem->card_start = ( (unsigned long)(i & 0x3fff)<12) + mem->sys_start; - mem->card_start &= 0x3ffffff; + if (sockets[sock].type == IS_PD6729) { + /* Take care of high byte */ + indirect_write(sock,PD67_EXT_INDEX, PD67_MEM_PAGE(map)); + addr = indirect_read16(sock, PD67_EXT_DATA) << 24; + mem->sys_stop += addr; mem->sys_start += addr; + mem->card_start = (unsigned long)(i) + mem->sys_start; + } else { + mem->card_start = ((unsigned long)(i & 0x3fff)<12) + mem->sys_start; + mem->card_start &= 0x3ffffff; + } + dprintk("Card %i is from %lx to %lx \n",sock,mem->sys_start,mem->sys_stop); - leave("i82092aa_get_mem_map"); return 0; @@ -895,7 +952,9 @@ static int i82092aa_set_mem_map(unsigned if (!(mem->flags & MAP_ACTIVE)) return 0; - if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || + if (sockets[sock].type == IS_PD6729) { + ; /* PD6729 accepts high byte */ + } else if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || ((mem->sys_start >> 24) != membase) || ((mem->sys_stop >> 24) != membase) || (mem->speed > 1000) ) { leave("i82092aa_set_mem_map: invalid address / speed"); @@ -904,7 +963,6 @@ static int i82092aa_set_mem_map(unsigned } - /* printk("set_mem_map: Setting map %i range to %x - %x on socket %i, speed is %i, active = %i \n",map, mem->sys_start,mem->sys_stop,sock,mem->speed,mem->flags & MAP_ACTIVE); */ /* write the start address */ @@ -935,6 +993,12 @@ static int i82092aa_set_mem_map(unsigned indirect_write16(sock,base+I365_W_STOP,i); + if (sockets[sock].type == IS_PD6729) { + /* Take care of high byte */ + indirect_write(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); + indirect_write16(sock, PD67_EXT_DATA, mem->sys_start >> 24); + } + /* card start */ i = (((mem->card_start - mem->sys_start) >> 12) - (membase << 12)) & 0x3fff; @@ -947,7 +1011,9 @@ static int i82092aa_set_mem_map(unsigned /* printk("requesting normal memory for socket %i\n",sock);*/ } indirect_write16(sock,base+I365_W_OFF,i); - indirect_write(sock, I365_CPAGE, membase); + if (sockets[sock].type == IS_I82092) { + indirect_write(sock, I365_CPAGE, membase); + } /* Enable the window if necessary */ indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map)); diff -purN linux-2.4.21/fs/binfmt_elf.c linux-f/fs/binfmt_elf.c --- linux-2.4.21/fs/binfmt_elf.c 2002-08-03 02:39:45.000000000 +0200 +++ linux-f/fs/binfmt_elf.c 2003-07-14 22:10:29.000000000 +0200 @@ -375,7 +375,6 @@ static unsigned long load_aout_interp(st unsigned long text_data, elf_entry = ~0UL; char * addr; loff_t offset; - int retval; current->mm->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; @@ -397,11 +396,9 @@ static unsigned long load_aout_interp(st } do_brk(0, text_data); - retval = -ENOEXEC; if (!interpreter->f_op || !interpreter->f_op->read) goto out; - retval = interpreter->f_op->read(interpreter, addr, text_data, &offset); - if (retval < 0) + if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) goto out; flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); @@ -444,6 +441,7 @@ static int load_elf_binary(struct linux_ struct elfhdr interp_elf_ex; struct exec interp_ex; char passed_fileno[6]; + struct files_struct *files, *ftmp; /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); @@ -475,10 +473,17 @@ static int load_elf_binary(struct linux_ retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size); if (retval < 0) goto out_free_ph; + + files = current->files; /* Refcounted so ok */ + if(unshare_files() < 0) + goto out_free_ph; + /* exec will make our files private anyway, but for the a.out + loader stuff we need to do it earlier */ + retval = get_unused_fd(); if (retval < 0) - goto out_free_ph; + goto out_free_fh; get_file(bprm->file); fd_install(elf_exec_fileno = retval, bprm->file); @@ -593,6 +598,9 @@ static int load_elf_binary(struct linux_ if (retval) goto out_free_dentry; + /* Discard our unneeded old files struct */ + put_files_struct(files); + /* OK, This is the point of no return */ current->mm->start_data = 0; current->mm->end_data = 0; @@ -711,7 +719,8 @@ static int load_elf_binary(struct linux_ printk(KERN_ERR "Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); - return 0; + retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + goto out; } } @@ -797,6 +806,10 @@ out_free_interp: kfree(elf_interpreter); out_free_file: sys_close(elf_exec_fileno); +out_free_fh: + ftmp = current->files; + current->files = files; + put_files_struct(ftmp); out_free_ph: kfree(elf_phdata); goto out; diff -purN linux-2.4.21/fs/exec.c linux-f/fs/exec.c --- linux-2.4.21/fs/exec.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-f/fs/exec.c 2003-07-14 22:10:29.000000000 +0200 @@ -557,6 +570,7 @@ int flush_old_exec(struct linux_binprm * char * name; int i, ch, retval; struct signal_struct * oldsig; + struct files_struct * files; /* * Make sure we have a private signal table @@ -565,6 +579,18 @@ int flush_old_exec(struct linux_binprm * retval = make_private_signals(); if (retval) goto flush_failed; + /* + * Make sure we have private file handles. Ask the + * fork helper to do the work for us and the exit + * helper to do the cleanup of the old one. + */ + + files = current->files; /* refcounted so safe to hold */ + retval = unshare_files(); + if(retval) + goto flush_failed; + put_files_struct(files); + /* * Release all of the old mmap stuff */ diff -purN linux-2.4.21/fs/proc/base.c linux-f/fs/proc/base.c --- linux-2.4.21/fs/proc/base.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-f/fs/proc/base.c 2003-07-14 22:10:30.000000000 +0200 @@ -124,20 +124,56 @@ static int proc_root_link(struct inode * return result; } +#define MAY_PTRACE(task) \ + (task == current || \ + (task->p_pptr == current && \ + (task->ptrace & PT_PTRACED) && task->state == TASK_STOPPED)) + +static int may_ptrace_attach(struct task_struct *task) +{ + int retval = 0; + + task_lock(task); + + if (((current->uid != task->euid) || + (current->uid != task->suid) || + (current->uid != task->uid) || + (current->gid != task->egid) || + (current->gid != task->sgid) || + (!cap_issubset(task->cap_permitted, current->cap_permitted)) || + (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) + goto out; + rmb(); + if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE)) + goto out; + + retval = 1; + +out: + task_unlock(task); + return retval; +} + static int proc_pid_environ(struct task_struct *task, char * buffer) { struct mm_struct *mm; int res = 0; + + if (!may_ptrace_attach(task)) + return -ESRCH; + task_lock(task); mm = task->mm; if (mm) atomic_inc(&mm->mm_users); task_unlock(task); if (mm) { - int len = mm->env_end - mm->env_start; + unsigned int len = mm->env_end - mm->env_start; if (len > PAGE_SIZE) len = PAGE_SIZE; res = access_process_vm(task, mm->env_start, buffer, len, 0); + if (!may_ptrace_attach(task)) + res = -ESRCH; mmput(mm); } return res; @@ -328,10 +364,6 @@ static struct file_operations proc_info_ read: proc_info_read, }; -#define MAY_PTRACE(p) \ -(p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED)) - - static int mem_open(struct inode* inode, struct file* file) { file->private_data = (void*)((long)current->self_exec_id); @@ -347,8 +379,7 @@ static ssize_t mem_read(struct file * fi int copied = 0; struct mm_struct *mm; - - if (!MAY_PTRACE(task)) + if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) return -ESRCH; page = (char *)__get_free_page(GFP_USER); @@ -370,14 +401,13 @@ static ssize_t mem_read(struct file * fi copied = -EIO; goto out_free; } - while (count > 0) { int this_len, retval; this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; retval = access_process_vm(task, src, page, this_len, 0); - if (!retval) { + if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) { if (!copied) copied = -EIO; break; @@ -411,7 +441,7 @@ static ssize_t mem_write(struct file * f struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task; unsigned long dst = *ppos; - if (!MAY_PTRACE(task)) + if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) return -ESRCH; page = (char *)__get_free_page(GFP_USER); diff -purN linux-2.4.21/fs/proc/generic.c linux-f/fs/proc/generic.c --- linux-2.4.21/fs/proc/generic.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-f/fs/proc/generic.c 2003-07-14 22:10:30.000000000 +0200 @@ -485,12 +485,12 @@ struct proc_dir_entry *proc_mknod(const return ent; } -struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) +struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, + struct proc_dir_entry *parent) { struct proc_dir_entry *ent; - ent = proc_create(&parent,name, - (S_IFDIR | S_IRUGO | S_IXUGO),2); + ent = proc_create(&parent, name, S_IFDIR | mode, 2); if (ent) { ent->proc_fops = &proc_dir_operations; ent->proc_iops = &proc_dir_inode_operations; @@ -503,6 +503,12 @@ struct proc_dir_entry *proc_mkdir(const return ent; } +struct proc_dir_entry *proc_mkdir(const char *name, + struct proc_dir_entry *parent) +{ + return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); +} + struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { diff -purN linux-2.4.21/fs/proc/proc_misc.c linux-f/fs/proc/proc_misc.c --- linux-2.4.21/fs/proc/proc_misc.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-f/fs/proc/proc_misc.c 2003-07-14 22:10:30.000000000 +0200 @@ -423,9 +428,9 @@ static int cmdline_read_proc(char *page, int count, int *eof, void *data) { extern char saved_command_line[]; - int len; + int len = 0; - len = snprintf(page, count, "%s\n", saved_command_line); + proc_sprintf(page, &off, &len, "%s\n", saved_command_line); return proc_calc_metrics(page, start, off, count, eof, len); } @@ -495,7 +500,8 @@ static ssize_t read_profile(struct file buf++; p++; count--; read++; } pnt = (char *)prof_buffer + p - sizeof(unsigned int); - copy_to_user(buf,(void *)pnt,count); + if (copy_to_user(buf,(void *)pnt,count)) + return -EFAULT; read += count; *ppos += read; return read; diff -purN linux-2.4.21/fs/proc/proc_tty.c linux-f/fs/proc/proc_tty.c --- linux-2.4.21/fs/proc/proc_tty.c 2000-04-22 00:17:57.000000000 +0200 +++ linux-f/fs/proc/proc_tty.c 2003-07-14 22:10:30.000000000 +0200 @@ -174,7 +174,13 @@ void __init proc_tty_init(void) if (!proc_mkdir("tty", 0)) return; proc_tty_ldisc = proc_mkdir("tty/ldisc", 0); - proc_tty_driver = proc_mkdir("tty/driver", 0); + /* + * /proc/tty/driver/serial reveals the exact character counts for + * serial links which is just too easy to abuse for inferring + * password lengths and inter-keystroke timings during password + * entry. + */ + proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR | S_IXUSR, 0); create_proc_read_entry("tty/ldiscs", 0, 0, tty_ldiscs_read_proc,NULL); create_proc_read_entry("tty/drivers", 0, 0, tty_drivers_read_proc,NULL); diff -purN linux-2.4.21/include/linux/fs.h linux-f/include/linux/fs.h --- linux-2.4.21/include/linux/fs.h 2003-06-13 16:51:38.000000000 +0200 +++ linux-f/include/linux/fs.h 2003-07-14 22:10:31.000000000 +0200 @@ -1523,6 +1578,9 @@ extern int generic_osync_inode(struct in extern int inode_change_ok(struct inode *, struct iattr *); extern int inode_setattr(struct inode *, struct iattr *); +/* kernel/fork.c */ +extern int unshare_files(void); + /* * Common dentry functions for inclusion in the VFS * or in other stackable file systems. Some of these diff -purN linux-2.4.21/kernel/fork.c linux-f/kernel/fork.c --- linux-2.4.21/kernel/fork.c 2003-06-13 16:51:39.000000000 +0200 +++ linux-f/kernel/fork.c 2003-07-14 22:10:31.000000000 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -537,6 +555,33 @@ out_release: goto out; } +/* + * Helper to unshare the files of the current task. + * We don't want to expose copy_files internals to + * the exec layer of the kernel. + */ + +int unshare_files(void) +{ + struct files_struct *files = current->files; + int rc; + + if(!files) + BUG(); + + /* This can race but the race causes us to copy when we don't + need to and drop the copy */ + if(atomic_read(&files->count) == 1) + { + atomic_inc(&files->count); + return 0; + } + rc = copy_files(0, current); + if(rc) + current->files = files; + return rc; +} + static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk) { struct signal_struct *sig; diff -purN linux-2.4.21/net/bridge/br_fdb.c linux-f/net/bridge/br_fdb.c --- linux-2.4.21/net/bridge/br_fdb.c 2002-02-25 20:38:14.000000000 +0100 +++ linux-f/net/bridge/br_fdb.c 2003-07-14 22:10:00.000000000 +0200 @@ -292,21 +292,30 @@ void br_fdb_insert(struct net_bridge *br write_lock_bh(&br->hash_lock); fdb = br->hash[hash]; while (fdb != NULL) { - if (!fdb->is_local && - !memcmp(fdb->addr.addr, addr, ETH_ALEN)) { + if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { + /* attempt to update an entry for a local interface */ + if (fdb->is_local) { + if (is_local) + printk(KERN_INFO "%s: attempt to add" + " interface with same source address.\n", + source->dev->name); + else if (net_ratelimit()) + printk(KERN_WARNING "%s: received packet with " + " own address as source address\n", + source->dev->name); + goto out; + } + __fdb_possibly_replace(fdb, source, is_local); - write_unlock_bh(&br->hash_lock); - return; + goto out; } fdb = fdb->next_hash; } fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC); - if (fdb == NULL) { - write_unlock_bh(&br->hash_lock); - return; - } + if (fdb == NULL) + goto out; memcpy(fdb->addr.addr, addr, ETH_ALEN); atomic_set(&fdb->use_count, 1); @@ -317,5 +326,6 @@ void br_fdb_insert(struct net_bridge *br __hash_link(br, fdb, hash); + out: write_unlock_bh(&br->hash_lock); } diff -purN linux-2.4.21/net/bridge/br_if.c linux-f/net/bridge/br_if.c --- linux-2.4.21/net/bridge/br_if.c 2003-06-13 16:51:39.000000000 +0200 +++ linux-f/net/bridge/br_if.c 2003-07-14 22:10:00.000000000 +0200 @@ -118,7 +118,7 @@ static struct net_bridge *new_nb(char *n br->bridge_id.prio[1] = 0x00; memset(br->bridge_id.addr, 0, ETH_ALEN); - br->stp_enabled = 1; + br->stp_enabled = 0; br->designated_root = br->bridge_id; br->root_path_cost = 0; br->root_port = 0; diff -purN linux-2.4.21/net/bridge/br_input.c linux-f/net/bridge/br_input.c --- linux-2.4.21/net/bridge/br_input.c 2002-08-03 02:39:46.000000000 +0200 +++ linux-f/net/bridge/br_input.c 2003-07-14 22:10:00.000000000 +0200 @@ -160,7 +160,8 @@ err_nolock: handle_special_frame: if (!dest[5]) { - br_stp_handle_bpdu(skb); + NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,NULL, + br_stp_handle_bpdu); read_unlock(&br->lock); return; } diff -purN linux-2.4.21/net/bridge/br_private.h linux-f/net/bridge/br_private.h --- linux-2.4.21/net/bridge/br_private.h 2002-02-25 20:38:14.000000000 +0100 +++ linux-f/net/bridge/br_private.h 2003-07-14 22:10:00.000000000 +0200 @@ -199,6 +199,6 @@ extern void br_stp_set_path_cost(struct int path_cost); /* br_stp_bpdu.c */ -extern void br_stp_handle_bpdu(struct sk_buff *skb); +extern int br_stp_handle_bpdu(struct sk_buff *skb); #endif diff -purN linux-2.4.21/net/bridge/br_stp_bpdu.c linux-f/net/bridge/br_stp_bpdu.c --- linux-2.4.21/net/bridge/br_stp_bpdu.c 2001-11-13 18:16:05.000000000 +0100 +++ linux-f/net/bridge/br_stp_bpdu.c 2003-07-14 22:10:00.000000000 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include #include "br_private.h" #include "br_private_stp.h" @@ -53,7 +54,8 @@ static void br_send_bpdu(struct net_brid memcpy(skb->nh.raw, data, length); memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2); - dev_queue_xmit(skb); + NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, + dev_queue_xmit); } static __inline__ void br_set_ticks(unsigned char *dest, int jiff) @@ -133,61 +135,65 @@ void br_send_tcn_bpdu(struct net_bridge_ static unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; /* called under bridge lock */ -void br_stp_handle_bpdu(struct sk_buff *skb) +int br_stp_handle_bpdu(struct sk_buff *skb) { unsigned char *buf; struct net_bridge_port *p; - buf = skb->mac.raw + 14; p = skb->dev->br_port; - if (!p->br->stp_enabled || memcmp(buf, header, 6)) { - kfree_skb(skb); - return; - } - if (buf[6] == BPDU_TYPE_CONFIG) { + if (!p->br->stp_enabled || + !pskb_may_pull(skb, sizeof(header)+1) || + memcmp(skb->data, header, sizeof(header))) + goto err; + + buf = skb_pull(skb, sizeof(header)); + if (buf[0] == BPDU_TYPE_CONFIG) { struct br_config_bpdu bpdu; - bpdu.topology_change = (buf[7] & 0x01) ? 1 : 0; - bpdu.topology_change_ack = (buf[7] & 0x80) ? 1 : 0; - bpdu.root.prio[0] = buf[8]; - bpdu.root.prio[1] = buf[9]; - bpdu.root.addr[0] = buf[10]; - bpdu.root.addr[1] = buf[11]; - bpdu.root.addr[2] = buf[12]; - bpdu.root.addr[3] = buf[13]; - bpdu.root.addr[4] = buf[14]; - bpdu.root.addr[5] = buf[15]; + if (!pskb_may_pull(skb, 32)) + goto err; + + buf = skb->data; + bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0; + bpdu.topology_change_ack = (buf[1] & 0x80) ? 1 : 0; + + bpdu.root.prio[0] = buf[2]; + bpdu.root.prio[1] = buf[3]; + bpdu.root.addr[0] = buf[4]; + bpdu.root.addr[1] = buf[5]; + bpdu.root.addr[2] = buf[6]; + bpdu.root.addr[3] = buf[7]; + bpdu.root.addr[4] = buf[8]; + bpdu.root.addr[5] = buf[9]; bpdu.root_path_cost = - (buf[16] << 24) | - (buf[17] << 16) | - (buf[18] << 8) | - buf[19]; - bpdu.bridge_id.prio[0] = buf[20]; - bpdu.bridge_id.prio[1] = buf[21]; - bpdu.bridge_id.addr[0] = buf[22]; - bpdu.bridge_id.addr[1] = buf[23]; - bpdu.bridge_id.addr[2] = buf[24]; - bpdu.bridge_id.addr[3] = buf[25]; - bpdu.bridge_id.addr[4] = buf[26]; - bpdu.bridge_id.addr[5] = buf[27]; - bpdu.port_id = (buf[28] << 8) | buf[29]; - - bpdu.message_age = br_get_ticks(buf+30); - bpdu.max_age = br_get_ticks(buf+32); - bpdu.hello_time = br_get_ticks(buf+34); - bpdu.forward_delay = br_get_ticks(buf+36); + (buf[10] << 24) | + (buf[11] << 16) | + (buf[12] << 8) | + buf[13]; + bpdu.bridge_id.prio[0] = buf[14]; + bpdu.bridge_id.prio[1] = buf[15]; + bpdu.bridge_id.addr[0] = buf[16]; + bpdu.bridge_id.addr[1] = buf[17]; + bpdu.bridge_id.addr[2] = buf[18]; + bpdu.bridge_id.addr[3] = buf[19]; + bpdu.bridge_id.addr[4] = buf[20]; + bpdu.bridge_id.addr[5] = buf[21]; + bpdu.port_id = (buf[22] << 8) | buf[23]; + + bpdu.message_age = br_get_ticks(buf+24); + bpdu.max_age = br_get_ticks(buf+26); + bpdu.hello_time = br_get_ticks(buf+28); + bpdu.forward_delay = br_get_ticks(buf+30); - kfree_skb(skb); br_received_config_bpdu(p, &bpdu); - return; } - if (buf[6] == BPDU_TYPE_TCN) { + else if (buf[0] == BPDU_TYPE_TCN) { br_received_tcn_bpdu(p); - kfree_skb(skb); - return; } - kfree_skb(skb); + err: + kfree(skb); + return 0; }