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,19 @@ int flush_old_exec(struct linux_binprm * char * name; int i, ch, retval; + struct files_struct * files; + /* + * 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 out; + 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->parent == 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->parent==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;