From e0ff8aa1acd079b70e796571917ae0449b7c465b Mon Sep 17 00:00:00 2001 From: Marc Fiuczynski Date: Wed, 13 Dec 2006 17:55:50 +0000 Subject: [PATCH] Merge to Fedora kernel-2.6.18-1.2255_FC5-vs2.0.2.2-rc9 patched with stable patch-2.6.18.5-vs2.0.2.2-rc9.diff --- .config | 10 +- Documentation/kernel-parameters.txt | 4 - arch/alpha/Kconfig | 2 +- arch/alpha/kernel/asm-offsets.c | 2 +- arch/arm/kernel/irq.c | 3 - arch/arm/kernel/ptrace.c | 40 +- arch/arm26/kernel/irq.c | 4 - arch/arm26/kernel/ptrace.c | 32 +- arch/frv/kernel/irq.c | 4 - arch/frv/kernel/ptrace.c | 15 +- arch/h8300/kernel/ints.c | 5 - arch/h8300/platform/h8s/ints.c | 5 - arch/i386/Kconfig | 10 - arch/i386/kernel/apic.c | 73 +- arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 2 +- arch/i386/kernel/entry-xen.S | 7 +- arch/i386/kernel/entry.S | 7 +- arch/i386/kernel/i387.c | 143 +- arch/i386/kernel/io_apic-xen.c | 6 +- arch/i386/kernel/irq-xen.c | 4 - arch/i386/kernel/irq.c | 4 - arch/i386/kernel/microcode-xen.c | 5 - arch/i386/kernel/microcode.c | 9 +- arch/i386/kernel/mpparse.c | 5 - arch/i386/kernel/process-xen.c | 3 + arch/i386/kernel/process.c | 3 + arch/i386/kernel/ptrace.c | 861 ++++----- arch/i386/kernel/setup-xen.c | 3 + arch/i386/kernel/setup.c | 9 +- arch/i386/kernel/signal.c | 37 +- arch/i386/kernel/vm86.c | 7 + arch/i386/pci/irq-xen.c | 4 +- arch/i386/pci/irq.c | 4 +- arch/ia64/ia32/ia32_entry.S | 2 +- arch/ia64/ia32/sys_ia32.c | 23 +- arch/ia64/kernel/asm-offsets.c | 2 +- arch/ia64/kernel/fsys.S | 16 +- arch/ia64/kernel/mca.c | 2 +- arch/ia64/kernel/ptrace.c | 1673 +++++++++-------- arch/ia64/kernel/signal.c | 4 +- arch/ia64/sn/kernel/bte.c | 9 +- arch/ia64/xen/hypervisor.c | 14 + arch/mips/kernel/ptrace.c | 21 +- arch/mips/kernel/sysirix.c | 2 +- arch/powerpc/kernel/Makefile | 4 +- arch/powerpc/kernel/asm-offsets.c | 2 + arch/powerpc/kernel/irq.c | 5 - arch/powerpc/kernel/process.c | 5 + arch/powerpc/kernel/ptrace-common.h | 161 ++ arch/powerpc/kernel/ptrace.c | 949 ++++------ arch/powerpc/kernel/ptrace32.c | 436 +++++ arch/powerpc/kernel/signal_32.c | 55 - arch/powerpc/kernel/signal_64.c | 3 - arch/powerpc/kernel/sys_ppc32.c | 5 + arch/powerpc/kernel/traps.c | 18 +- arch/powerpc/lib/sstep.c | 3 - arch/powerpc/platforms/cell/spufs/run.c | 2 - arch/ppc/kernel/asm-offsets.c | 2 + arch/ppc/kernel/traps.c | 18 +- arch/s390/kernel/Makefile | 2 - arch/s390/kernel/compat_linux.c | 3 + arch/s390/kernel/compat_signal.c | 5 +- arch/s390/kernel/process.c | 3 + arch/s390/kernel/ptrace.c | 1067 ++++++----- arch/s390/kernel/s390_ext.c | 3 - arch/s390/kernel/signal.c | 3 - arch/s390/kernel/traps.c | 6 +- arch/s390/lib/uaccess.S | 10 +- arch/s390/lib/uaccess64.S | 2 +- arch/sparc/kernel/entry.S | 3 +- arch/sparc/kernel/irq.c | 7 - arch/sparc/kernel/sun4d_irq.c | 3 - arch/sparc64/kernel/Makefile | 2 - arch/sparc64/kernel/binfmt_aout32.c | 2 + arch/sparc64/kernel/entry.S | 9 +- arch/sparc64/kernel/process.c | 3 + arch/sparc64/kernel/ptrace.c | 1219 ++++++------ arch/sparc64/kernel/signal.c | 2 - arch/sparc64/kernel/signal32.c | 2 - arch/sparc64/kernel/sys_sparc32.c | 3 + arch/sparc64/kernel/systbls.S | 4 +- arch/x86_64/ia32/fpu32.c | 92 +- arch/x86_64/ia32/ia32_aout.c | 6 + arch/x86_64/ia32/ia32_signal.c | 8 + arch/x86_64/ia32/ia32entry-xen.S | 2 +- arch/x86_64/ia32/ia32entry.S | 2 +- arch/x86_64/ia32/ptrace32.c | 717 +++---- arch/x86_64/ia32/sys_ia32.c | 5 + arch/x86_64/kernel/irq-xen.c | 4 - arch/x86_64/kernel/process-xen.c | 25 +- arch/x86_64/kernel/process.c | 12 +- arch/x86_64/kernel/ptrace.c | 648 +++---- arch/x86_64/kernel/signal.c | 28 +- arch/x86_64/kernel/traps-xen.c | 11 +- arch/x86_64/kernel/traps.c | 8 + arch/x86_64/mm/fault-xen.c | 4 +- arch/x86_64/mm/fault.c | 4 +- block/scsi_ioctl.c | 5 +- configs/kernel-2.6.18-i586-smp.config | 11 +- configs/kernel-2.6.18-i586.config | 13 +- configs/kernel-2.6.18-i686-kdump.config | 11 +- configs/kernel-2.6.18-i686-smp.config | 11 +- configs/kernel-2.6.18-i686-xen.config | 11 +- configs/kernel-2.6.18-i686-xen0.config | 11 +- configs/kernel-2.6.18-i686-xenU.config | 11 +- configs/kernel-2.6.18-i686.config | 11 +- configs/kernel-2.6.18-ia64-xen.config | 10 +- configs/kernel-2.6.18-ia64.config | 10 +- configs/kernel-2.6.18-ppc-smp.config | 10 +- configs/kernel-2.6.18-ppc.config | 10 +- configs/kernel-2.6.18-ppc64-kdump.config | 10 +- configs/kernel-2.6.18-ppc64.config | 10 +- configs/kernel-2.6.18-ppc64iseries.config | 11 +- configs/kernel-2.6.18-s390.config | 10 +- configs/kernel-2.6.18-s390x.config | 10 +- configs/kernel-2.6.18-x86_64-kdump.config | 10 +- configs/kernel-2.6.18-x86_64-xen.config | 10 +- configs/kernel-2.6.18-x86_64-xen0.config | 10 +- configs/kernel-2.6.18-x86_64-xenU.config | 11 +- configs/kernel-2.6.18-x86_64.config | 10 +- drivers/block/cciss.c | 6 + drivers/block/cpqarray.c | 15 +- drivers/block/loop.c | 3 - drivers/char/agp/generic.c | 2 +- drivers/char/agp/intel-agp.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 2 +- drivers/char/isicom.c | 3 +- drivers/connector/cn_proc.c | 4 +- drivers/firmware/dmi_scan.c | 5 - drivers/input/mouse/psmouse-base.c | 8 +- drivers/media/Kconfig | 1 + drivers/net/e1000/e1000_main.c | 5 +- drivers/net/tg3.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 18 + drivers/pci/pci-sysfs.c | 3 + drivers/pcmcia/ds.c | 5 + drivers/s390/cio/cio.c | 3 - drivers/scsi/sata_promise.c | 4 +- drivers/scsi/scsi_lib.c | 1 + drivers/usb/class/usblp.c | 1 + drivers/usb/input/hid-core.c | 4 +- drivers/usb/input/hid-input.c | 17 + drivers/usb/input/hid.h | 1 + drivers/usb/input/usbtouchscreen.c | 2 +- drivers/video/nvidia/nv_hw.c | 12 +- drivers/video/nvidia/nv_setup.c | 18 +- drivers/video/nvidia/nv_type.h | 1 + drivers/video/nvidia/nvidia.c | 24 +- drivers/xen/blkback/blkback.c | 2 +- drivers/xen/core/evtchn.c | 1 - drivers/xen/netback/common.h | 2 +- drivers/xen/netback/interface.c | 24 +- drivers/xen/netback/netback.c | 70 +- drivers/xen/netback/xenbus.c | 87 +- drivers/xen/netfront/netfront.c | 120 +- drivers/xen/privcmd/privcmd.c | 27 +- drivers/xen/xenbus/xenbus_probe.c | 1 - fs/binfmt_aout.c | 6 + fs/binfmt_elf.c | 6 + fs/binfmt_elf_fdpic.c | 7 + fs/binfmt_flat.c | 3 + fs/binfmt_som.c | 2 + fs/cifs/CHANGES | 6 +- fs/cifs/file.c | 3 +- fs/cifs/inode.c | 14 +- fs/cifs/sess.c | 23 +- fs/exec.c | 11 +- fs/fuse/dir.c | 52 +- fs/hfs/super.c | 1 + fs/namei.c | 7 +- fs/nfs/dir.c | 1 + fs/nfs/mount_clnt.c | 1 + fs/nfs/super.c | 3 +- fs/proc/array.c | 16 +- fs/proc/base.c | 17 +- fs/squashfs/inode.c | 112 +- fs/squashfs/squashfs.h | 2 +- fs/squashfs/squashfs2_0.c | 13 +- include/asm-i386/apic.h | 2 - include/asm-i386/i387.h | 15 +- include/asm-i386/mach-xen/asm/system.h | 4 + include/asm-i386/signal.h | 4 +- include/asm-i386/thread_info.h | 7 +- include/asm-ia64/agp.h | 19 +- include/asm-ia64/dma-mapping.h | 2 - include/asm-ia64/elf.h | 24 - include/asm-ia64/hypervisor.h | 1 + include/asm-ia64/page.h | 2 +- include/asm-mips/irq.h | 1 + include/asm-sparc/unistd.h | 2 + include/asm-sparc64/futex.h | 18 +- include/asm-sparc64/unistd.h | 2 + include/asm-x86_64/fpu32.h | 3 - include/asm-x86_64/mach-xen/asm/dma-mapping.h | 1 - include/asm-x86_64/mach-xen/asm/processor.h | 3 +- include/asm-x86_64/thread_info.h | 2 - include/linux/dmi.h | 2 +- include/linux/init_task.h | 3 + include/linux/netfilter_ipv4.h | 2 +- include/linux/nfs_mount.h | 2 +- include/linux/ptrace.h | 222 +-- include/linux/sched.h | 25 +- include/linux/vs_base.h | 3 + include/linux/vs_network.h | 5 + include/linux/vs_socket.h | 22 +- include/linux/vserver/context.h | 1 - include/linux/vserver/cvirt_def.h | 4 +- include/linux/vserver/network.h | 2 + init/Kconfig | 29 - kernel/Makefile | 1 - kernel/exit.c | 256 ++- kernel/fork.c | 62 +- kernel/irq/handle.c | 5 - kernel/printk.c | 4 - kernel/ptrace.c | 1623 ++++------------ kernel/signal.c | 211 ++- kernel/softirq.c | 4 - kernel/sys.c | 2 +- kernel/timer.c | 6 +- kernel/vserver/context.c | 37 +- kernel/vserver/legacy.c | 4 +- kernel/vserver/legacynet.c | 1 + kernel/vserver/limit.c | 75 +- kernel/vserver/network.c | 43 +- kernel/vserver/proc.c | 2 + mm/fremap.c | 5 +- mm/slab.c | 2 +- net/bluetooth/hci_sock.c | 11 +- net/bridge/br_ioctl.c | 9 +- net/core/skbuff.c | 1 + net/core/sock.c | 2 +- net/dccp/ipv6.c | 2 +- net/ieee80211/softmac/ieee80211softmac_io.c | 2 +- net/ipv4/ipvs/ip_vs_core.c | 10 + net/ipv4/netfilter.c | 9 +- net/ipv4/netfilter/arp_tables.c | 39 +- net/ipv4/netfilter/ip_conntrack_helper_h323.c | 4 +- net/ipv4/netfilter/ip_nat_standalone.c | 3 +- net/ipv4/netfilter/ip_tables.c | 103 +- net/ipv4/netfilter/iptable_mangle.c | 3 +- net/ipv4/tcp.c | 4 +- net/ipv4/udp.c | 19 +- net/ipv6/netfilter/ip6_tables.c | 53 +- net/ipv6/udp.c | 7 +- net/netfilter/Kconfig | 6 +- scripts/basic/.docproc.cmd | 12 +- scripts/basic/.fixdep.cmd | 12 +- scripts/basic/docproc | Bin 13434 -> 13404 bytes scripts/basic/fixdep | Bin 8848 -> 8881 bytes scripts/kconfig/.conf.o.cmd | 10 +- scripts/kconfig/.kxgettext.o.cmd | 10 +- scripts/kconfig/.mconf.o.cmd | 14 +- scripts/kconfig/.zconf.tab.o.cmd | 20 +- scripts/kconfig/conf | Bin 66522 -> 67944 bytes scripts/kconfig/conf.o | Bin 10796 -> 11376 bytes scripts/kconfig/kxgettext.o | Bin 2824 -> 2416 bytes scripts/kconfig/mconf.o | Bin 29252 -> 29292 bytes scripts/kconfig/zconf.tab.o | Bin 69076 -> 70500 bytes security/seclvl.c | 2 + security/selinux/hooks.c | 54 +- security/selinux/include/objsec.h | 1 + 261 files changed, 6003 insertions(+), 6954 deletions(-) diff --git a/.config b/.config index 867d51505..8877438e8 100644 --- a/.config +++ b/.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:02 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:37 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -82,12 +82,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index f710c7586..71d05f481 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1027,10 +1027,6 @@ running once the system is up. noapic [SMP,APIC] Tells the kernel to not make use of any IOAPICs that may be present in the system. - apic [APIC,i386] Override default heuristics to enable/disable the local - APIC by CONFIG_X86_APIC_AUTO. When this option is set the kernel - will try to use the local APIC. - noasync [HW,M68K] Disables async and sync negotiation for all devices. diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 875006799..60fdd21c3 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -381,7 +381,7 @@ config ALPHA_EV56 config ALPHA_EV56 prompt "EV56 CPU (speed >= 333MHz)?" - depends on ALPHA_NORITAKE && ALPHA_PRIMO + depends on ALPHA_NORITAKE || ALPHA_PRIMO config ALPHA_EV56 prompt "EV56 CPU (speed >= 400MHz)?" diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c index 1dd2f02e6..6c56c754a 100644 --- a/arch/alpha/kernel/asm-offsets.c +++ b/arch/alpha/kernel/asm-offsets.c @@ -27,7 +27,7 @@ void foo(void) DEFINE(TASK_EUID, offsetof(struct task_struct, euid)); DEFINE(TASK_GID, offsetof(struct task_struct, gid)); DEFINE(TASK_EGID, offsetof(struct task_struct, egid)); - DEFINE(TASK_PARENT, offsetof(struct task_struct, parent)); + DEFINE(TASK_REAL_PARENT, offsetof(struct task_struct, real_parent)); DEFINE(TASK_GROUP_LEADER, offsetof(struct task_struct, group_leader)); DEFINE(TASK_TGID, offsetof(struct task_struct, tgid)); BLANK(); diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 4b9757f3b..2eba150a4 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -123,12 +122,10 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) desc = &bad_irq_desc; irq_enter(); - __enter_vx_admin(&vxis); desc_handle_irq(irq, desc, regs); /* AT91 specific workaround */ irq_finish(irq); - __leave_vx_admin(&vxis); irq_exit(); } diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index b145c7e1f..9254ba2f4 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -812,18 +812,34 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) { unsigned long ip; - if (test_thread_flag(TIF_SYSCALL_TRACE)) { - /* - * Save IP. IP is used to denote syscall entry/exit: - * IP = 0 -> entry, = 1 -> exit - */ - ip = regs->ARM_ip; - regs->ARM_ip = why; - - tracehook_report_syscall(regs, why); - - regs->ARM_ip = ip; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return scno; + if (!(current->ptrace & PT_PTRACED)) + return scno; + + /* + * Save IP. IP is used to denote syscall entry/exit: + * IP = 0 -> entry, = 1 -> exit + */ + ip = regs->ARM_ip; + regs->ARM_ip = why; + + current->ptrace_message = scno; + + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; } + regs->ARM_ip = ip; - return scno; + return current->ptrace_message; } diff --git a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c index 6f5272e59..d87d68b77 100644 --- a/arch/arm26/kernel/irq.c +++ b/arch/arm26/kernel/irq.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -332,7 +331,6 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs) { struct irqdesc *desc = irq_desc + irq; - struct vx_info_save vxis; /* * Some hardware gives randomly wrong interrupts. Rather @@ -343,9 +341,7 @@ asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs) irq_enter(); spin_lock(&irq_controller_lock); - __enter_vx_admin(&vxis); desc->handle(irq, desc, regs); - __leave_vx_admin(&vxis); spin_unlock(&irq_controller_lock); irq_exit(); } diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c index 27b852952..9343889b2 100644 --- a/arch/arm26/kernel/ptrace.c +++ b/arch/arm26/kernel/ptrace.c @@ -653,16 +653,30 @@ asmlinkage void syscall_trace(int why, struct pt_regs *regs) { unsigned long ip; - if (test_thread_flag(TIF_SYSCALL_TRACE)) { - /* - * Save IP. IP is used to denote syscall entry/exit: - * IP = 0 -> entry, = 1 -> exit - */ - ip = regs->ARM_ip; - regs->ARM_ip = why; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; - tracehook_report_syscall(regs, why); + /* + * Save IP. IP is used to denote syscall entry/exit: + * IP = 0 -> entry, = 1 -> exit + */ + ip = regs->ARM_ip; + regs->ARM_ip = why; - regs->ARM_ip = ip; + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; } + regs->ARM_ip = ip; } diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 1c2a72c1f..08967010b 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -283,7 +282,6 @@ EXPORT_SYMBOL(enable_irq); asmlinkage void do_IRQ(void) { struct irq_source *source; - struct vx_info_save vxis; int level, cpu; irq_enter(); @@ -300,10 +298,8 @@ asmlinkage void do_IRQ(void) kstat_this_cpu.irqs[level]++; - __enter_vx_admin(&vxis); for (source = frv_irq_levels[level].sources; source; source = source->next) source->doirq(source); - __leave_vx_admin(&vxis); __clr_MASK(level); diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c index 44d3df57e..fcff819b4 100644 --- a/arch/frv/kernel/ptrace.c +++ b/arch/frv/kernel/ptrace.c @@ -700,11 +700,24 @@ asmlinkage void do_syscall_trace(int leaving) if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; + if (!(current->ptrace & PT_PTRACED)) + return; + /* we need to indicate entry or exit to strace */ if (leaving) __frame->__status |= REG__STATUS_SYSC_EXIT; else __frame->__status |= REG__STATUS_SYSC_ENTRY; - tracehook_report_syscall(regs, leaving); + ptrace_notify(SIGTRAP); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } } diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c index 2984a28cb..1488b6ace 100644 --- a/arch/h8300/kernel/ints.c +++ b/arch/h8300/kernel/ints.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -217,10 +216,7 @@ void disable_irq(unsigned int irq) asmlinkage void process_int(int irq, struct pt_regs *fp) { - struct vx_info_save vxis; - irq_enter(); - __enter_vx_admin(&vxis); h8300_clear_isr(irq); if (irq >= NR_TRAPS && irq < NR_IRQS) { if (irq_list[irq]) { @@ -232,7 +228,6 @@ asmlinkage void process_int(int irq, struct pt_regs *fp) } else { BUG(); } - __leave_vx_admin(&vxis); irq_exit(); } diff --git a/arch/h8300/platform/h8s/ints.c b/arch/h8300/platform/h8s/ints.c index f103efa88..270440de4 100644 --- a/arch/h8300/platform/h8s/ints.c +++ b/arch/h8300/platform/h8s/ints.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -262,12 +261,9 @@ void disable_irq(unsigned int irq) asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) { - struct vx_info_save vxis; - irq_enter(); /* ISR clear */ /* compatible i386 */ - __enter_vx_admin(&vxis); if (vec >= EXT_IRQ0 && vec <= EXT_IRQ15) *(volatile unsigned short *)ISR &= ~(1 << (vec - EXT_IRQ0)); if (vec < NR_IRQS) { @@ -280,7 +276,6 @@ asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) } else { BUG(); } - __leave_vx_admin(&vxis); irq_exit(); } diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 51c6580dd..9c714ef0b 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -302,16 +302,6 @@ config X86_LOCAL_APIC depends on X86_UP_APIC || ((X86_VISWS || SMP) && !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)) default y -config X86_APIC_AUTO - bool "Use heuristics to enable/disable local APIC" - depends on X86_LOCAL_APIC - help - This option uses some proven heuristics to automatically enable or disable the local - APIC. All decisions can be overriden by command line options. - In a nutshell very old systems run better with APIC off and newer or multiprocessor - systems prefer APIC on - This is a useful default for distribution kernels. - config X86_IO_APIC bool depends on X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER || XEN_UNPRIVILEGED_GUEST)) diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 5bec4fbdb..8c844d078 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -54,9 +53,6 @@ static cpumask_t timer_bcast_ipi; * Knob to control our willingness to enable the local APIC. */ int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */ -int prefer_apic __initdata = 0; /* when enable_local_apic == 0 prefer APIC but don't force against - BIOS wishes */ -int apic_disabled_by_dmi __initdata; /* * Debug level @@ -757,10 +753,6 @@ static void apic_pm_activate(void) { } static int __init apic_set_verbosity(char *str) { - if (*str == '=') - ++str; - if (*str == 0) - prefer_apic = 1; if (strcmp("debug", str) == 0) apic_verbosity = APIC_DEBUG; else if (strcmp("verbose", str) == 0) @@ -768,7 +760,7 @@ static int __init apic_set_verbosity(char *str) return 1; } -__setup("apic", apic_set_verbosity); +__setup("apic=", apic_set_verbosity); static int __init detect_init_APIC (void) { @@ -799,9 +791,8 @@ static int __init detect_init_APIC (void) * APIC only if "lapic" specified. */ if (enable_local_apic <= 0) { - if (!apic_disabled_by_dmi) - printk("Local APIC disabled by BIOS -- " - "you can enable it with \"lapic\"\n"); + printk("Local APIC disabled by BIOS -- " + "you can enable it with \"lapic\"\n"); return -1; } /* @@ -1335,64 +1326,6 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) irq_exit(); } -#ifdef CONFIG_X86_APIC_AUTO - -/* Some heuristics to decide when to enable the APICs */ - -static __init int dmi_enable_apic(void) -{ - int year; - int apic; - char *vendor; - - /* If the machine has more than one CPU try to use APIC because it'll - be running the SMP kernel with APIC soon anyways. - This won't cover dual core, but they are handled by the date check - below. */ - if (dmi_cpus > 1) - return 1; - - year = dmi_get_year(DMI_BIOS_DATE); - vendor = dmi_get_system_info(DMI_BIOS_VENDOR); - apic = 0; - - /* All Intel BIOS since 1998 assumed APIC on. Don't include 1998 itself - because we're not sure for that. */ - if (vendor && !strncmp(vendor, "Intel", 5)) - apic = 1; - /* Use APIC for anything since 2001 */ - else if (year >= 2001) - apic = 1; - -#ifdef CONFIG_ACPI - /* When ACPI is disabled also default to APIC off on very new systems (>= 2004) - which typically don't have working mptables anymore */ - if (acpi_noirq && year >= 2004) - apic = 0; -#endif - - if (!apic) - apic_disabled_by_dmi = 1; - - return apic; -} - -void __init dmi_check_apic(void) -{ - if (enable_local_apic != 0 || prefer_apic) - return; - if (!dmi_enable_apic()) { - clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); - nr_ioapics = 0; - enable_local_apic = -1; - printk(KERN_INFO "IO/L-APIC disabled because your old system seems to be old\n"); - printk(KERN_INFO "overwrite with \"apic\"\n"); - return; - } - printk(KERN_INFO "IO/L-APIC allowed because system is MP or new enough\n"); -} -#endif - /* * This initializes the IO-APIC and APIC hardware if this is * a UP kernel. diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 691452c34..ec0c5c24a 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -570,7 +570,7 @@ acpi_cpufreq_init (void) acpi_cpufreq_early_init_acpi(); - return cpufreq_register_driver(&acpi_cpufreq_driver); + return cpufreq_register_driver(&acpi_cpufreq_driver); } diff --git a/arch/i386/kernel/entry-xen.S b/arch/i386/kernel/entry-xen.S index 4c571d77b..45b7f7413 100644 --- a/arch/i386/kernel/entry-xen.S +++ b/arch/i386/kernel/entry-xen.S @@ -344,7 +344,7 @@ sysenter_past_esp: GET_THREAD_INFO(%ebp) /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ - testw $(_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -395,7 +395,7 @@ ENTRY(system_call) no_singlestep: # system call tracing in operation / emulation /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ - testw $(_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -545,6 +545,9 @@ syscall_trace_entry: movl %esp, %eax xorl %edx,%edx call do_syscall_trace + cmpl $0, %eax + jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, + # so must skip actual syscall movl ORIG_EAX(%esp), %eax cmpl $(nr_syscalls), %eax jnae syscall_call diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 13eb00571..fd0f85ff5 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -314,7 +314,7 @@ sysenter_past_esp: GET_THREAD_INFO(%ebp) /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ - testw $(_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -348,7 +348,7 @@ ENTRY(system_call) no_singlestep: # system call tracing in operation / emulation /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ - testw $(_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -476,6 +476,9 @@ syscall_trace_entry: movl %esp, %eax xorl %edx,%edx call do_syscall_trace + cmpl $0, %eax + jne resume_userspace # ret != 0 -> running under PTRACE_SYSEMU, + # so must skip actual syscall movl ORIG_EAX(%esp), %eax cmpl $(nr_syscalls), %eax jnae syscall_call diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c index 8503c464f..665847281 100644 --- a/arch/i386/kernel/i387.c +++ b/arch/i386/kernel/i387.c @@ -222,10 +222,14 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd ) * FXSR floating point environment conversions. */ -static inline void -convert_fxsr_env_to_i387(unsigned long env[7], - struct i387_fxsave_struct *fxsave) +static int convert_fxsr_to_user( struct _fpstate __user *buf, + struct i387_fxsave_struct *fxsave ) { + unsigned long env[7]; + struct _fpreg __user *to; + struct _fpxreg *from; + int i; + env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; env[2] = twd_fxsr_to_i387(fxsave); @@ -233,17 +237,7 @@ convert_fxsr_env_to_i387(unsigned long env[7], env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); env[5] = fxsave->foo; env[6] = fxsave->fos; -} - -static int convert_fxsr_to_user(struct _fpstate __user *buf, - struct i387_fxsave_struct *fxsave) -{ - unsigned long env[7]; - struct _fpreg __user *to; - struct _fpxreg *from; - int i; - convert_fxsr_env_to_i387(env, fxsave); if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) return 1; @@ -261,20 +255,6 @@ static int convert_fxsr_to_user(struct _fpstate __user *buf, return 0; } -static inline void -convert_fxsr_env_from_i387(struct i387_fxsave_struct *fxsave, - const unsigned long env[7]) -{ - fxsave->cwd = (unsigned short)(env[0] & 0xffff); - fxsave->swd = (unsigned short)(env[1] & 0xffff); - fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); - fxsave->fip = env[3]; - fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); - fxsave->fcs = (env[4] & 0xffff); - fxsave->foo = env[5]; - fxsave->fos = env[6]; -} - static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate __user *buf ) { @@ -286,7 +266,14 @@ static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) return 1; - convert_fxsr_env_from_i387(fxsave, env); + fxsave->cwd = (unsigned short)(env[0] & 0xffff); + fxsave->swd = (unsigned short)(env[1] & 0xffff); + fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); + fxsave->fip = env[3]; + fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); + fxsave->fcs = (env[4] & 0xffff); + fxsave->foo = env[5]; + fxsave->fos = env[6]; to = (struct _fpxreg *) &fxsave->st_space[0]; from = &buf->_st[0]; @@ -401,82 +388,88 @@ int restore_i387( struct _fpstate __user *buf ) * ptrace request handlers. */ -static inline void get_fpregs_fsave(struct user_i387_struct *buf, - struct task_struct *tsk) +static inline int get_fpregs_fsave( struct user_i387_struct __user *buf, + struct task_struct *tsk ) { - memcpy(buf, &tsk->thread.i387.fsave, sizeof(struct user_i387_struct)); + return __copy_to_user( buf, &tsk->thread.i387.fsave, + sizeof(struct user_i387_struct) ); } -static inline void get_fpregs_fxsave(struct user_i387_struct *buf, - struct task_struct *tsk) +static inline int get_fpregs_fxsave( struct user_i387_struct __user *buf, + struct task_struct *tsk ) { - struct _fpreg *to; - const struct _fpxreg *from; - unsigned int i; - - convert_fxsr_env_to_i387((unsigned long *) buf, - &tsk->thread.i387.fxsave); - - to = (struct _fpreg *) buf->st_space; - from = (const struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0]; - for (i = 0; i < 8; i++, to++, from++) - *to = *(const struct _fpreg *) from; + return convert_fxsr_to_user( (struct _fpstate __user *)buf, + &tsk->thread.i387.fxsave ); } -int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk) +int get_fpregs( struct user_i387_struct __user *buf, struct task_struct *tsk ) { if ( HAVE_HWFP ) { - if (cpu_has_fxsr) - get_fpregs_fxsave(buf, tsk); - else - get_fpregs_fsave(buf, tsk); - return 0; + if ( cpu_has_fxsr ) { + return get_fpregs_fxsave( buf, tsk ); + } else { + return get_fpregs_fsave( buf, tsk ); + } } else { return save_i387_soft( &tsk->thread.i387.soft, (struct _fpstate __user *)buf ); } } -static inline void set_fpregs_fsave(struct task_struct *tsk, - const struct user_i387_struct *buf) +static inline int set_fpregs_fsave( struct task_struct *tsk, + struct user_i387_struct __user *buf ) { - memcpy(&tsk->thread.i387.fsave, buf, sizeof(struct user_i387_struct)); + return __copy_from_user( &tsk->thread.i387.fsave, buf, + sizeof(struct user_i387_struct) ); } -static inline void set_fpregs_fxsave(struct task_struct *tsk, - const struct user_i387_struct *buf) +static inline int set_fpregs_fxsave( struct task_struct *tsk, + struct user_i387_struct __user *buf ) { - struct _fpxreg *to; - const struct _fpreg *from; - unsigned int i; - - convert_fxsr_env_from_i387(&tsk->thread.i387.fxsave, - (unsigned long *) buf); - - to = (struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0]; - from = (const struct _fpreg *) buf->st_space; - for (i = 0; i < 8; i++, to++, from++) - *(struct _fpreg *) to = *from; + return convert_fxsr_from_user( &tsk->thread.i387.fxsave, + (struct _fpstate __user *)buf ); } -int set_fpregs(struct task_struct *tsk, const struct user_i387_struct *buf) +int set_fpregs( struct task_struct *tsk, struct user_i387_struct __user *buf ) { if ( HAVE_HWFP ) { - if (cpu_has_fxsr) - set_fpregs_fxsave(tsk, buf); - else - set_fpregs_fsave(tsk, buf); - return 0; + if ( cpu_has_fxsr ) { + return set_fpregs_fxsave( tsk, buf ); + } else { + return set_fpregs_fsave( tsk, buf ); + } } else { return restore_i387_soft( &tsk->thread.i387.soft, (struct _fpstate __user *)buf ); } } -void updated_fpxregs(struct task_struct *tsk) +int get_fpxregs( struct user_fxsr_struct __user *buf, struct task_struct *tsk ) { - /* mxcsr reserved bits must be masked to zero for security reasons */ - tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; + if ( cpu_has_fxsr ) { + if (__copy_to_user( buf, &tsk->thread.i387.fxsave, + sizeof(struct user_fxsr_struct) )) + return -EFAULT; + return 0; + } else { + return -EIO; + } +} + +int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct __user *buf ) +{ + int ret = 0; + + if ( cpu_has_fxsr ) { + if (__copy_from_user( &tsk->thread.i387.fxsave, buf, + sizeof(struct user_fxsr_struct) )) + ret = -EFAULT; + /* mxcsr reserved bits must be masked to zero for security reasons */ + tsk->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; + } else { + ret = -EIO; + } + return ret; } /* diff --git a/arch/i386/kernel/io_apic-xen.c b/arch/i386/kernel/io_apic-xen.c index dc20fcc12..f25eb9be6 100644 --- a/arch/i386/kernel/io_apic-xen.c +++ b/arch/i386/kernel/io_apic-xen.c @@ -2201,6 +2201,8 @@ static inline void init_IO_APIC_traps(void) } } +int timer_uses_ioapic_pin_0; + #ifndef CONFIG_XEN static void enable_lapic_irq (unsigned int irq) { @@ -2315,9 +2317,7 @@ static inline void unlock_ExtINT_logic(void) io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0)); spin_unlock_irqrestore(&ioapic_lock, flags); } -#endif /* CONFIG_XEN */ -int timer_uses_ioapic_pin_0; -#ifdef CONFI_XEN + /* * This code may look a bit paranoid, but it's supposed to cooperate with * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ diff --git a/arch/i386/kernel/irq-xen.c b/arch/i386/kernel/irq-xen.c index fd749ff92..280c8fb4b 100644 --- a/arch/i386/kernel/irq-xen.c +++ b/arch/i386/kernel/irq-xen.c @@ -18,7 +18,6 @@ #include #include #include -#include DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); @@ -56,7 +55,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) { /* high bit used in ret_from_ code */ int irq = ~regs->orig_eax; - struct vx_info_save vxis; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; u32 *isp; @@ -83,7 +81,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) } } #endif - __enter_vx_admin(&vxis); #ifdef CONFIG_4KSTACKS curctx = (union irq_ctx *) current_thread_info(); @@ -122,7 +119,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) } else #endif __do_IRQ(irq, regs); - __leave_vx_admin(&vxis); irq_exit(); diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 97a05914a..535312cf5 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -18,7 +18,6 @@ #include #include #include -#include DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); @@ -56,7 +55,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) { /* high bit used in ret_from_ code */ int irq = ~regs->orig_eax; - struct vx_info_save vxis; #ifdef CONFIG_4KSTACKS union irq_ctx *curctx, *irqctx; u32 *isp; @@ -83,7 +81,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) } } #endif - __enter_vx_admin(&vxis); #ifdef CONFIG_4KSTACKS curctx = (union irq_ctx *) current_thread_info(); @@ -122,7 +119,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) } else #endif __do_IRQ(irq, regs); - __leave_vx_admin(&vxis); irq_exit(); diff --git a/arch/i386/kernel/microcode-xen.c b/arch/i386/kernel/microcode-xen.c index bf511a7d5..f010a9089 100644 --- a/arch/i386/kernel/microcode-xen.c +++ b/arch/i386/kernel/microcode-xen.c @@ -84,11 +84,6 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ { ssize_t ret; - if (len < DEFAULT_UCODE_TOTALSIZE) { - printk(KERN_ERR "microcode: not enough data\n"); - return -EINVAL; - } - if ((len >> PAGE_SHIFT) > num_physpages) { printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages); return -EINVAL; diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 40b44cc0d..e5520eb87 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -250,14 +250,14 @@ static int find_matching_ucodes (void) } total_size = get_totalsize(&mc_header); - if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) { + if (cursor + total_size > user_buffer_size) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; } data_size = get_datasize(&mc_header); - if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) { + if (data_size + MC_HEADER_SIZE > total_size) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; @@ -460,11 +460,6 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ { ssize_t ret; - if (len < DEFAULT_UCODE_TOTALSIZE) { - printk(KERN_ERR "microcode: not enough data\n"); - return -EINVAL; - } - if ((len >> PAGE_SHIFT) > num_physpages) { printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages); return -EINVAL; diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 6eb88e86a..a70b5fa0e 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -673,11 +673,6 @@ void __init get_smp_config (void) else if (acpi_lapic) printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n"); - else if (enable_local_apic < 0) { - smp_found_config = 0; - return; - } - printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { printk(KERN_INFO " IMCR and PIC compatibility mode.\n"); diff --git a/arch/i386/kernel/process-xen.c b/arch/i386/kernel/process-xen.c index 6cad288d5..a9508f64d 100644 --- a/arch/i386/kernel/process-xen.c +++ b/arch/i386/kernel/process-xen.c @@ -655,6 +655,9 @@ asmlinkage int sys_execve(struct pt_regs regs) (char __user * __user *) regs.edx, ®s); if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); /* Make sure we don't return using sysenter.. */ set_thread_flag(TIF_IRET); } diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 9abe5abbc..ea4ffbbda 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -748,6 +748,9 @@ asmlinkage int sys_execve(struct pt_regs regs) (char __user * __user *) regs.edx, ®s); if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); /* Make sure we don't return using sysenter.. */ set_thread_flag(TIF_IRET); } diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index 0c6074fc2..d3db03f40 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -12,15 +12,12 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include @@ -30,6 +27,10 @@ #include #include +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ /* * Determines which flags the user has access to [1 = access, 0 = no access]. @@ -38,6 +39,9 @@ */ #define FLAG_MASK 0x00050dd5 +/* set's the trap flag. */ +#define TRAP_FLAG 0x100 + /* * Offset of eflags on child stack.. */ @@ -110,7 +114,6 @@ static int putreg(struct task_struct *child, case EFL: value &= FLAG_MASK; value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; - clear_tsk_thread_flag(child, TIF_FORCED_TF); break; } if (regno > GS*4) @@ -131,10 +134,6 @@ static unsigned long getreg(struct task_struct *child, case GS: retval = child->thread.gs; break; - case EFL: - if (test_tsk_thread_flag(child, TIF_FORCED_TF)) - retval &= ~X86_EFLAGS_TF; - goto fetch; case DS: case ES: case SS: @@ -142,12 +141,10 @@ static unsigned long getreg(struct task_struct *child, retval = 0xffff; /* fall through */ default: - fetch: if (regno > GS*4) regno -= 2*4; regno = regno - sizeof(struct pt_regs); retval &= get_stack_long(child, regno); - break; } return retval; } @@ -225,7 +222,7 @@ static inline int is_at_popf(struct task_struct *child, struct pt_regs *regs) return 0; } -void tracehook_enable_single_step(struct task_struct *child) +static void set_singlestep(struct task_struct *child) { struct pt_regs *regs = get_child_regs(child); @@ -239,11 +236,11 @@ void tracehook_enable_single_step(struct task_struct *child) /* * If TF was already set, don't do anything else */ - if (regs->eflags & X86_EFLAGS_TF) + if (regs->eflags & TRAP_FLAG) return; /* Set TF on the kernel stack.. */ - regs->eflags |= X86_EFLAGS_TF; + regs->eflags |= TRAP_FLAG; /* * ..but if TF is changed by the instruction we will trace, @@ -253,323 +250,43 @@ void tracehook_enable_single_step(struct task_struct *child) if (is_at_popf(child, regs)) return; - set_tsk_thread_flag(child, TIF_FORCED_TF); + child->ptrace |= PT_DTRACE; } -void tracehook_disable_single_step(struct task_struct *child) +static void clear_singlestep(struct task_struct *child) { /* Always clear TIF_SINGLESTEP... */ clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* But touch TF only if it was set by us.. */ - if (test_and_clear_tsk_thread_flag(child, TIF_FORCED_TF)) { + if (child->ptrace & PT_DTRACE) { struct pt_regs *regs = get_child_regs(child); - regs->eflags &= ~X86_EFLAGS_TF; - } -} - - -static int -genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (kbuf) { - unsigned long *kp = kbuf; - while (count > 0) { - *kp++ = getreg(target, pos); - pos += 4; - count -= 4; - } - } - else { - unsigned long __user *up = ubuf; - while (count > 0) { - if (__put_user(getreg(target, pos), up++)) - return -EFAULT; - pos += 4; - count -= 4; - } - } - - return 0; -} - -static int -genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret = 0; - - if (kbuf) { - const unsigned long *kp = kbuf; - while (!ret && count > 0) { - ret = putreg(target, pos, *kp++); - pos += 4; - count -= 4; - } - } - else { - int ret = 0; - const unsigned long __user *up = ubuf; - while (!ret && count > 0) { - unsigned long val; - ret = __get_user(val, up++); - if (!ret) - ret = putreg(target, pos, val); - pos += 4; - count -= 4; - } - } - - return ret; -} - -static int -fpregs_active(struct task_struct *target, const struct utrace_regset *regset) -{ - return tsk_used_math(target) ? regset->n : 0; -} - -static int -fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct user_i387_struct fp; - int ret; - - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); - } - else - init_fpu(target); - - ret = get_fpregs(&fp, target); - if (ret == 0) - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &fp, 0, -1); - - return ret; -} - -static int -fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - struct user_i387_struct fp; - int ret; - - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); - } - else if (pos == 0 && count == sizeof(fp)) - set_stopped_child_used_math(target); - else - init_fpu(target); - - if (pos > 0 || count < sizeof(fp)) { - ret = get_fpregs(&fp, target); - if (ret == 0) - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fp, 0, -1); - if (ret) - return ret; - kbuf = &fp; + regs->eflags &= ~TRAP_FLAG; + child->ptrace &= ~PT_DTRACE; } - else if (kbuf == NULL) { - if (__copy_from_user(&fp, ubuf, sizeof(fp))) - return -EFAULT; - kbuf = &fp; - } - - return set_fpregs(target, kbuf); } -static int -fpxregs_active(struct task_struct *target, const struct utrace_regset *regset) -{ - return !cpu_has_fxsr ? -ENODEV : tsk_used_math(target) ? regset->n : 0; -} - -static int -fpxregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (!cpu_has_fxsr) - return -ENODEV; - - if (tsk_used_math(target)) - unlazy_fpu(target); - else - init_fpu(target); - - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.i387.fxsave, 0, -1); -} - -static int -fpxregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret; - - if (!cpu_has_fxsr) - return -ENODEV; - - if (tsk_used_math(target)) - unlazy_fpu(target); - else if (pos == 0 && count == sizeof(target->thread.i387.fxsave)) - set_stopped_child_used_math(target); - else - init_fpu(target); - - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.i387.fxsave, 0, -1); - - updated_fpxregs(target); - - return ret; -} - - -static int -dbregs_active(struct task_struct *tsk, const struct utrace_regset *regset) -{ - if (tsk->thread.debugreg[DR_CONTROL] | tsk->thread.debugreg[DR_STATUS]) - return 8; - return 0; -} - -static int -dbregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. + */ +void ptrace_disable(struct task_struct *child) { - /* - * The hardware updates the status register on a debug trap, - * but do_debug (traps.c) save it for us when that happens. - * So whether the target is current or not, thread.debugreg is good. - */ - - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - target->thread.debugreg, 0, -1); + clear_singlestep(child); + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); } -static int -dbregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - for (pos >>= 2, count >>= 2; count > 0; --count, ++pos) { - unsigned long val; - unsigned int i; - - if (kbuf) { - val = *(const unsigned long *) kbuf; - kbuf += sizeof(unsigned long); - } - else { - if (__get_user(val, (unsigned long __user *) ubuf)) - return -EFAULT; - ubuf += sizeof(unsigned long); - } - - if (pos < 4) { - if (val >= TASK_SIZE - 3) - return -EIO; - goto set; - } - else if (pos < 6) { - if (val != 0) - return -EIO; - continue; - } - else if (pos < 7) - goto set; - - /* Sanity-check data. Take one half-byte at once with - * check = (val >> (16 + 4*i)) & 0xf. It contains the - * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits - * 2 and 3 are LENi. Given a list of invalid values, - * we do mask |= 1 << invalid_value, so that - * (mask >> check) & 1 is a correct test for invalid - * values. - * - * R/Wi contains the type of the breakpoint / - * watchpoint, LENi contains the length of the watched - * data in the watchpoint case. - * - * The invalid values are: - * - LENi == 0x10 (undefined), so mask |= 0x0f00. - * - R/Wi == 0x10 (break on I/O reads or writes), so - * mask |= 0x4444. - * - R/Wi == 0x00 && LENi != 0x00, so we have mask |= - * 0x1110. - * - * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54. - * - * See the Intel Manual "System Programming Guide", - * 15.2.4 - * - * Note that LENi == 0x10 is defined on x86_64 in long - * mode (i.e. even for 32-bit userspace software, but - * 64-bit kernel), so the x86_64 mask value is 0x5454. - * See the AMD manual no. 24593 (AMD64 System - * Programming)*/ - val &= ~DR_CONTROL_RESERVED; - for (i = 0; i < 4; i++) - if ((0x5f54 >> ((val >> (16 + 4*i)) & 0xf)) & 1) - return -EIO; - if (val) - set_tsk_thread_flag(target, TIF_DEBUG); - else - clear_tsk_thread_flag(target, TIF_DEBUG); - - set: - target->thread.debugreg[pos] = val; - if (target == current) - switch (pos) { -#define DBREG(n) case n: set_debugreg(target->thread.debugreg[n], n); break - DBREG(0); - DBREG(1); - DBREG(2); - DBREG(3); - DBREG(6); - DBREG(7); -#undef DBREG - } - } - - return 0; -} - - /* * Perform get_thread_area on behalf of the traced child. */ static int -tls_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +ptrace_get_thread_area(struct task_struct *child, + int idx, struct user_desc __user *user_desc) { - struct user_desc info, *ip; - const struct desc_struct *desc; + struct user_desc info; + struct desc_struct *desc; /* * Get the current Thread-Local Storage area: @@ -591,29 +308,23 @@ tls_get(struct task_struct *target, #define GET_PRESENT(desc) (((desc)->b >> 15) & 1) #define GET_USEABLE(desc) (((desc)->b >> 20) & 1) - desc = &target->thread.tls_array[pos / sizeof(struct user_desc)]; - ip = kbuf ?: &info; - memset(ip, 0, sizeof *ip); - for (; count > 0; count -= sizeof(struct user_desc), ++desc) { - ip->entry_number = (desc - &target->thread.tls_array[0] - + GDT_ENTRY_TLS_MIN); - ip->base_addr = GET_BASE(desc); - ip->limit = GET_LIMIT(desc); - ip->seg_32bit = GET_32BIT(desc); - ip->contents = GET_CONTENTS(desc); - ip->read_exec_only = !GET_WRITABLE(desc); - ip->limit_in_pages = GET_LIMIT_PAGES(desc); - ip->seg_not_present = !GET_PRESENT(desc); - ip->useable = GET_USEABLE(desc); - - if (kbuf) - ++ip; - else { - if (__copy_to_user(ubuf, &info, sizeof(info))) - return -EFAULT; - ubuf += sizeof(info); - } - } + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; + + info.entry_number = idx; + info.base_addr = GET_BASE(desc); + info.limit = GET_LIMIT(desc); + info.seg_32bit = GET_32BIT(desc); + info.contents = GET_CONTENTS(desc); + info.read_exec_only = !GET_WRITABLE(desc); + info.limit_in_pages = GET_LIMIT_PAGES(desc); + info.seg_not_present = !GET_PRESENT(desc); + info.useable = GET_USEABLE(desc); + + if (copy_to_user(user_desc, &info, sizeof(info))) + return -EFAULT; return 0; } @@ -622,154 +333,308 @@ tls_get(struct task_struct *target, * Perform set_thread_area on behalf of the traced child. */ static int -tls_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +ptrace_set_thread_area(struct task_struct *child, + int idx, struct user_desc __user *user_desc) { struct user_desc info; struct desc_struct *desc; - struct desc_struct newtls[GDT_ENTRY_TLS_ENTRIES]; - unsigned int i; - int cpu; - - pos /= sizeof(struct user_desc); - count /= sizeof(struct user_desc); - - desc = newtls; - for (i = 0; i < count; ++i, ++desc) { - const struct user_desc *ip; - if (kbuf) { - ip = kbuf; - kbuf += sizeof(struct user_desc); - } - else { - ip = &info; - if (__copy_from_user(&info, ubuf, sizeof(info))) - return -EFAULT; - ubuf += sizeof(struct user_desc); - } - if (LDT_empty(ip)) { - desc->a = 0; - desc->b = 0; - } else { - desc->a = LDT_entry_a(ip); - desc->b = LDT_entry_b(ip); - } - } + if (copy_from_user(&info, user_desc, sizeof(info))) + return -EFAULT; - /* - * We must not get preempted while modifying the TLS. - */ - cpu = get_cpu(); - memcpy(&target->thread.tls_array[pos], newtls, - count * sizeof(newtls[0])); - if (target == current) - load_TLS(&target->thread, cpu); - put_cpu(); + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = child->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; + if (LDT_empty(&info)) { + desc->a = 0; + desc->b = 0; + } else { + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } return 0; } - -/* - * Determine how many TLS slots are in use. - */ -static int -tls_active(struct task_struct *target, const struct utrace_regset *regset) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - int i; - for (i = GDT_ENTRY_TLS_ENTRIES; i > 0; --i) { - struct desc_struct *desc = &target->thread.tls_array[i - 1]; - if ((desc->a | desc->b) != 0) + struct user * dummy = NULL; + int i, ret; + unsigned long __user *datap = (unsigned long __user *)data; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) break; + ret = put_user(tmp, datap); + break; } - return i; -} + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + tmp = 0; /* Default return condition */ + if(addr < FRAME_SIZE*sizeof(long)) + tmp = getreg(child, addr); + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[7]){ + addr -= (long) &dummy->u_debugreg[0]; + addr = addr >> 2; + tmp = child->thread.debugreg[addr]; + } + ret = put_user(tmp, datap); + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + if (addr < FRAME_SIZE*sizeof(long)) { + ret = putreg(child, addr, data); + break; + } + /* We need to be very careful here. We implicitly + want to modify a portion of the task_struct, and we + have to be selective about what portions we allow someone + to modify. */ + + ret = -EIO; + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[7]){ + + if(addr == (long) &dummy->u_debugreg[4]) break; + if(addr == (long) &dummy->u_debugreg[5]) break; + if(addr < (long) &dummy->u_debugreg[4] && + ((unsigned long) data) >= TASK_SIZE-3) break; + + /* Sanity-check data. Take one half-byte at once with + * check = (val >> (16 + 4*i)) & 0xf. It contains the + * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits + * 2 and 3 are LENi. Given a list of invalid values, + * we do mask |= 1 << invalid_value, so that + * (mask >> check) & 1 is a correct test for invalid + * values. + * + * R/Wi contains the type of the breakpoint / + * watchpoint, LENi contains the length of the watched + * data in the watchpoint case. + * + * The invalid values are: + * - LENi == 0x10 (undefined), so mask |= 0x0f00. + * - R/Wi == 0x10 (break on I/O reads or writes), so + * mask |= 0x4444. + * - R/Wi == 0x00 && LENi != 0x00, so we have mask |= + * 0x1110. + * + * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54. + * + * See the Intel Manual "System Programming Guide", + * 15.2.4 + * + * Note that LENi == 0x10 is defined on x86_64 in long + * mode (i.e. even for 32-bit userspace software, but + * 64-bit kernel), so the x86_64 mask value is 0x5454. + * See the AMD manual no. 24593 (AMD64 System + * Programming)*/ + + if(addr == (long) &dummy->u_debugreg[7]) { + data &= ~DR_CONTROL_RESERVED; + for(i=0; i<4; i++) + if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) + goto out_tsk; + if (data) + set_tsk_thread_flag(child, TIF_DEBUG); + else + clear_tsk_thread_flag(child, TIF_DEBUG); + } + addr -= (long) &dummy->u_debugreg; + addr = addr >> 2; + child->thread.debugreg[addr] = data; + ret = 0; + } + break; + + case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */ + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: /* restart after signal. */ + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSEMU) { + set_tsk_thread_flag(child, TIF_SYSCALL_EMU); + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } else if (request == PTRACE_SYSCALL) { + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + } else { + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_singlestep(child); + wake_up_process(child); + ret = 0; + break; /* - * These are our native regset flavors. - * XXX ioperm? vm86? + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. */ -static const struct utrace_regset native_regsets[] = { - { - .n = FRAME_SIZE, .size = sizeof(long), .align = sizeof(long), - .get = genregs_get, .set = genregs_set - }, - { - .n = sizeof(struct user_i387_struct) / sizeof(long), - .size = sizeof(long), .align = sizeof(long), - .active = fpregs_active, - .get = fpregs_get, .set = fpregs_set - }, - { - .n = sizeof(struct user_fxsr_struct) / sizeof(long), - .size = sizeof(long), .align = sizeof(long), - .active = fpxregs_active, - .get = fpxregs_get, .set = fpxregs_set - }, - { - .n = GDT_ENTRY_TLS_ENTRIES, - .bias = GDT_ENTRY_TLS_MIN, - .size = sizeof(struct user_desc), - .align = sizeof(struct user_desc), - .active = tls_active, .get = tls_get, .set = tls_set - }, - { - .n = 8, .size = sizeof(long), .align = sizeof(long), - .active = dbregs_active, - .get = dbregs_get, .set = dbregs_set - }, -}; - -const struct utrace_regset_view utrace_i386_native = { - .name = "i386", .e_machine = EM_386, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_i386_native); - -#ifdef CONFIG_PTRACE -static const struct ptrace_layout_segment i386_uarea[] = { - {0, FRAME_SIZE*4, 0, 0}, - {offsetof(struct user, u_debugreg[0]), - offsetof(struct user, u_debugreg[8]), 4, 0}, - {0, 0, -1, 0} -}; - -fastcall int arch_ptrace(long *req, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, long *val) -{ - switch (*req) { - case PTRACE_PEEKUSR: - return ptrace_peekusr(child, engine, i386_uarea, addr, data); - case PTRACE_POKEUSR: - return ptrace_pokeusr(child, engine, i386_uarea, addr, data); - case PTRACE_GETREGS: - return ptrace_whole_regset(child, engine, data, 0, 0); - case PTRACE_SETREGS: - return ptrace_whole_regset(child, engine, data, 0, 1); - case PTRACE_GETFPREGS: - return ptrace_whole_regset(child, engine, data, 1, 0); - case PTRACE_SETFPREGS: - return ptrace_whole_regset(child, engine, data, 1, 1); - case PTRACE_GETFPXREGS: - return ptrace_whole_regset(child, engine, data, 2, 0); - case PTRACE_SETFPXREGS: - return ptrace_whole_regset(child, engine, data, 2, 1); + case PTRACE_KILL: + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_singlestep(child); + wake_up_process(child); + break; + + case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */ + case PTRACE_SINGLESTEP: /* set the trap flag. */ + ret = -EIO; + if (!valid_signal(data)) + break; + + if (request == PTRACE_SYSEMU_SINGLESTEP) + set_tsk_thread_flag(child, TIF_SYSCALL_EMU); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + set_singlestep(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + + case PTRACE_DETACH: + /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + if (!access_ok(VERIFY_WRITE, datap, FRAME_SIZE*sizeof(long))) { + ret = -EIO; + break; + } + for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { + __put_user(getreg(child, i), datap); + datap++; + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + unsigned long tmp; + if (!access_ok(VERIFY_READ, datap, FRAME_SIZE*sizeof(long))) { + ret = -EIO; + break; + } + for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) { + __get_user(tmp, datap); + putreg(child, i, tmp); + datap++; + } + ret = 0; + break; + } + + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + if (!access_ok(VERIFY_WRITE, datap, + sizeof(struct user_i387_struct))) { + ret = -EIO; + break; + } + ret = 0; + if (!tsk_used_math(child)) + init_fpu(child); + get_fpregs((struct user_i387_struct __user *)data, child); + break; + } + + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + if (!access_ok(VERIFY_READ, datap, + sizeof(struct user_i387_struct))) { + ret = -EIO; + break; + } + set_stopped_child_used_math(child); + set_fpregs(child, (struct user_i387_struct __user *)data); + ret = 0; + break; + } + + case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */ + if (!access_ok(VERIFY_WRITE, datap, + sizeof(struct user_fxsr_struct))) { + ret = -EIO; + break; + } + if (!tsk_used_math(child)) + init_fpu(child); + ret = get_fpxregs((struct user_fxsr_struct __user *)data, child); + break; + } + + case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */ + if (!access_ok(VERIFY_READ, datap, + sizeof(struct user_fxsr_struct))) { + ret = -EIO; + break; + } + set_stopped_child_used_math(child); + ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data); + break; + } + case PTRACE_GET_THREAD_AREA: + ret = ptrace_get_thread_area(child, addr, + (struct user_desc __user *) data); + break; + case PTRACE_SET_THREAD_AREA: - return ptrace_onereg_access(child, engine, - utrace_native_view(current), 3, - addr, (void __user *)data, - *req == PTRACE_SET_THREAD_AREA); + ret = ptrace_set_thread_area(child, addr, + (struct user_desc __user *) data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; } - return -ENOSYS; + out_tsk: + return ret; } -#endif void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) { @@ -793,24 +658,78 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) * - triggered by current->work.syscall_trace */ __attribute__((regparm(3))) -void do_syscall_trace(struct pt_regs *regs, int entryexit) +int do_syscall_trace(struct pt_regs *regs, int entryexit) { + int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU); + /* + * With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall + * interception + */ + int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP); + int ret = 0; + /* do the secure computing check first */ if (!entryexit) secure_computing(regs->orig_eax); - if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(AUDITSC_RESULT(regs->eax), regs->eax); + if (unlikely(current->audit_context)) { + if (entryexit) + audit_syscall_exit(AUDITSC_RESULT(regs->eax), + regs->eax); + /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only + * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is + * not used, entry.S will call us only on syscall exit, not + * entry; so when TIF_SYSCALL_AUDIT is used we must avoid + * calling send_sigtrap() on syscall entry. + * + * Note that when PTRACE_SYSEMU_SINGLESTEP is used, + * is_singlestep is false, despite his name, so we will still do + * the correct thing. + */ + else if (is_singlestep) + goto out; + } - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, entryexit); + if (!(current->ptrace & PT_PTRACED)) + goto out; - if (test_thread_flag(TIF_SINGLESTEP) && entryexit) { - send_sigtrap(current, regs, 0); /* XXX */ - tracehook_report_syscall_step(regs); - } + /* If a process stops on the 1st tracepoint with SYSCALL_TRACE + * and then is resumed with SYSEMU_SINGLESTEP, it will come in + * here. We have to check this and return */ + if (is_sysemu && entryexit) + return 0; + + /* Fake a debug trap */ + if (is_singlestep) + send_sigtrap(current, regs, 0); + + if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu) + goto out; + + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + /* Note that the debugger could change the result of test_thread_flag!*/ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80:0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } + ret = is_sysemu; +out: if (unlikely(current->audit_context) && !entryexit) audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_eax, regs->ebx, regs->ecx, regs->edx, regs->esi); + if (ret == 0) + return 0; + + regs->orig_eax = -1; /* force skip of syscall restarting */ + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->eax), regs->eax); + return 1; } diff --git a/arch/i386/kernel/setup-xen.c b/arch/i386/kernel/setup-xen.c index c7d2b0018..be4e01c5d 100644 --- a/arch/i386/kernel/setup-xen.c +++ b/arch/i386/kernel/setup-xen.c @@ -43,6 +43,9 @@ #include #include #include +#include +#include +#include #include #include #include diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 7b949e250..f1682206d 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -61,7 +61,6 @@ #include #include #include -#include /* Forward Declaration. */ void __init find_max_pfn(void); @@ -866,7 +865,7 @@ static void __init parse_cmdline_early (char ** cmdline_p) #ifdef CONFIG_X86_LOCAL_APIC /* enable local APIC */ - else if (!memcmp(from, "lapic", 5) || !memcmp(from, "apic", 4)) + else if (!memcmp(from, "lapic", 5)) lapic_enable(); /* disable local APIC */ @@ -1544,10 +1543,6 @@ void __init setup_arch(char **cmdline_p) if (efi_enabled) efi_map_memmap(); -#ifdef CONFIG_X86_APIC_AUTO - dmi_check_apic(); -#endif - #ifdef CONFIG_ACPI /* * Parse the ACPI tables for possible boot-time SMP configuration. @@ -1570,7 +1565,7 @@ void __init setup_arch(char **cmdline_p) #endif #endif #ifdef CONFIG_X86_LOCAL_APIC - if (smp_found_config && cpu_has_apic) + if (smp_found_config) get_smp_config(); #endif diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 0f187c95f..43002cfb4 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -385,6 +385,16 @@ static int setup_frame(int sig, struct k_sigaction *ka, regs->xss = __USER_DS; regs->xcs = __USER_CS; + /* + * Clear TF when entering the signal handler, but + * notify any tracer that was single-stepping it. + * The tracer may want to single-step inside the + * handler too. + */ + regs->eflags &= ~TF_MASK; + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); + #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->eip, frame->pretcode); @@ -469,6 +479,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->xss = __USER_DS; regs->xcs = __USER_CS; + /* + * Clear TF when entering the signal handler, but + * notify any tracer that was single-stepping it. + * The tracer may want to single-step inside the + * handler too. + */ + regs->eflags &= ~TF_MASK; + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); + #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->eip, frame->pretcode); @@ -513,12 +533,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, } /* - * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF flag so + * If TF is set due to a debugger (PT_DTRACE), clear the TF flag so * that register information in the sigcontext is correct. */ if (unlikely(regs->eflags & TF_MASK) - && likely(test_and_clear_thread_flag(TIF_FORCED_TF))) + && likely(current->ptrace & PT_DTRACE)) { + current->ptrace &= ~PT_DTRACE; regs->eflags &= ~TF_MASK; + } /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) @@ -533,15 +555,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - - /* - * Clear TF when entering the signal handler, but - * notify any tracer that was single-stepping it. - * The tracer may want to single-step inside the - * handler too. - */ - regs->eflags &= ~TF_MASK; - tracehook_report_handle_signal(sig, ka, oldset, regs); } return ret; diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 65f92219c..76ed78094 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -541,6 +541,13 @@ int handle_vm86_trap(struct kernel_vm86_regs * regs, long error_code, int trapno } if (trapno !=1) return 1; /* we let this handle by the calling routine */ + if (current->ptrace & PT_PTRACED) { + unsigned long flags; + spin_lock_irqsave(¤t->sighand->siglock, flags); + sigdelset(¤t->blocked, SIGTRAP); + recalc_sigpending(); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); + } send_sig(SIGTRAP, current, 1); current->thread.trap_no = trapno; current->thread.error_code = error_code; diff --git a/arch/i386/pci/irq-xen.c b/arch/i386/pci/irq-xen.c index cb0542293..68e7e6638 100644 --- a/arch/i386/pci/irq-xen.c +++ b/arch/i386/pci/irq-xen.c @@ -260,13 +260,13 @@ static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i */ static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - static const unsigned int pirqmap[4] = { 3, 2, 5, 1 }; + static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; return read_config_nybble(router, 0x55, pirqmap[pirq-1]); } static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - static const unsigned int pirqmap[4] = { 3, 2, 5, 1 }; + static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); return 1; } diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 4a8995c9c..65a2ce8c7 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -255,13 +255,13 @@ static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i */ static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - static const unsigned int pirqmap[4] = { 3, 2, 5, 1 }; + static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; return read_config_nybble(router, 0x55, pirqmap[pirq-1]); } static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - static const unsigned int pirqmap[4] = { 3, 2, 5, 1 }; + static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 }; write_config_nybble(router, 0x55, pirqmap[pirq-1], irq); return 1; } diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index 722eb76b2..368c36084 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -236,7 +236,7 @@ ia32_syscall_table: data8 sys_setuid /* 16-bit version */ data8 sys_getuid /* 16-bit version */ data8 compat_sys_stime /* 25 */ - data8 compat_sys_ptrace + data8 sys32_ptrace data8 sys32_alarm data8 sys_ni_syscall data8 sys32_pause diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index 9f7ac0665..bb86b8a92 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -1432,6 +1432,25 @@ sys32_waitpid (int pid, unsigned int *stat_addr, int options) return compat_sys_wait4(pid, stat_addr, options, NULL); } +static unsigned int +ia32_peek (struct task_struct *child, unsigned long addr, unsigned int *val) +{ + size_t copied; + unsigned int ret; + + copied = access_process_vm(child, addr, val, sizeof(*val), 0); + return (copied != sizeof(ret)) ? -EIO : 0; +} + +static unsigned int +ia32_poke (struct task_struct *child, unsigned long addr, unsigned int val) +{ + + if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) + return -EIO; + return 0; +} + /* * The order in which registers are stored in the ptrace regs structure */ @@ -1729,7 +1748,6 @@ restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __u return 0; } -#if 0 /* XXX */ asmlinkage long sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data) { @@ -1837,11 +1855,9 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data) compat_ptr(data)); break; -#if 0 /* XXX */ case PTRACE_GETEVENTMSG: ret = put_user(child->ptrace_message, (unsigned int __user *) compat_ptr(data)); break; -#endif case PTRACE_SYSCALL: /* continue, stop after next syscall */ case PTRACE_CONT: /* restart after signal. */ @@ -1862,7 +1878,6 @@ sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data) unlock_kernel(); return ret; } -#endif typedef struct { unsigned int ss_sp; diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index a20750503..9ada8fc28 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c @@ -44,7 +44,7 @@ void foo(void) DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); DEFINE(IA64_TASK_PENDING_OFFSET,offsetof (struct task_struct, pending)); DEFINE(IA64_TASK_PID_OFFSET, offsetof (struct task_struct, pid)); - DEFINE(IA64_TASK_PARENT_OFFSET, offsetof (struct task_struct, parent)); + DEFINE(IA64_TASK_REAL_PARENT_OFFSET, offsetof (struct task_struct, real_parent)); DEFINE(IA64_TASK_SIGHAND_OFFSET,offsetof (struct task_struct, sighand)); DEFINE(IA64_TASK_SIGNAL_OFFSET,offsetof (struct task_struct, signal)); DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid)); diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 06b05742d..7a05b1cb2 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -83,29 +83,29 @@ ENTRY(fsys_getppid) ;; ld4 r9=[r9] - add r17=IA64_TASK_PARENT_OFFSET,r17 // r17 = ¤t->group_leader->parent + add r17=IA64_TASK_REAL_PARENT_OFFSET,r17 // r17 = ¤t->group_leader->real_parent ;; and r9=TIF_ALLWORK_MASK,r9 -1: ld8 r18=[r17] // r18 = current->group_leader->parent +1: ld8 r18=[r17] // r18 = current->group_leader->real_parent ;; cmp.ne p8,p0=0,r9 - add r8=IA64_TASK_TGID_OFFSET,r18 // r8 = ¤t->group_leader->parent->tgid + add r8=IA64_TASK_TGID_OFFSET,r18 // r8 = ¤t->group_leader->real_parent->tgid ;; /* * The .acq is needed to ensure that the read of tgid has returned its data before - * we re-check "parent". + * we re-check "real_parent". */ - ld4.acq r8=[r8] // r8 = current->group_leader->parent->tgid + ld4.acq r8=[r8] // r8 = current->group_leader->real_parent->tgid #ifdef CONFIG_SMP /* - * Re-read current->group_leader->parent. + * Re-read current->group_leader->real_parent. */ - ld8 r19=[r17] // r19 = current->group_leader->parent + ld8 r19=[r17] // r19 = current->group_leader->real_parent (p8) br.spnt.many fsys_fallback_syscall ;; - cmp.ne p6,p0=r18,r19 // did parent change? + cmp.ne p6,p0=r18,r19 // did real_parent change? mov r19=0 // i must not leak kernel bits... (p6) br.cond.spnt.few 1b // yes -> redo the read of tgid and the check ;; diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index e90caec1b..2fbe4536f 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -1515,7 +1515,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset, p->state = TASK_UNINTERRUPTIBLE; cpu_set(cpu, p->cpus_allowed); INIT_LIST_HEAD(&p->tasks); - p->parent = p->group_leader = p; + p->parent = p->real_parent = p->group_leader = p; INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); strncpy(p->comm, type, sizeof(p->comm)-1); diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 1a2513109..004f8b67f 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -3,9 +3,6 @@ * * Copyright (C) 1999-2005 Hewlett-Packard Co * David Mosberger-Tang - * Copyright (C) 2006 Intel Co - * 2006-08-12 - IA64 Native Utrace implementation support added by - * Anil S Keshavamurthy * * Derived from the x86 and Alpha versions. */ @@ -15,22 +12,18 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include #include #include #include -#include #include #ifdef CONFIG_PERFMON #include @@ -554,6 +547,79 @@ ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw, return 0; } +static inline int +thread_matches (struct task_struct *thread, unsigned long addr) +{ + unsigned long thread_rbs_end; + struct pt_regs *thread_regs; + + if (ptrace_check_attach(thread, 0) < 0) + /* + * If the thread is not in an attachable state, we'll + * ignore it. The net effect is that if ADDR happens + * to overlap with the portion of the thread's + * register backing store that is currently residing + * on the thread's kernel stack, then ptrace() may end + * up accessing a stale value. But if the thread + * isn't stopped, that's a problem anyhow, so we're + * doing as well as we can... + */ + return 0; + + thread_regs = task_pt_regs(thread); + thread_rbs_end = ia64_get_user_rbs_end(thread, thread_regs, NULL); + if (!on_kernel_rbs(addr, thread_regs->ar_bspstore, thread_rbs_end)) + return 0; + + return 1; /* looks like we've got a winner */ +} + +/* + * GDB apparently wants to be able to read the register-backing store + * of any thread when attached to a given process. If we are peeking + * or poking an address that happens to reside in the kernel-backing + * store of another thread, we need to attach to that thread, because + * otherwise we end up accessing stale data. + * + * task_list_lock must be read-locked before calling this routine! + */ +static struct task_struct * +find_thread_for_addr (struct task_struct *child, unsigned long addr) +{ + struct task_struct *p; + struct mm_struct *mm; + struct list_head *this, *next; + int mm_users; + + if (!(mm = get_task_mm(child))) + return child; + + /* -1 because of our get_task_mm(): */ + mm_users = atomic_read(&mm->mm_users) - 1; + if (mm_users <= 1) + goto out; /* not multi-threaded */ + + /* + * Traverse the current process' children list. Every task that + * one attaches to becomes a child. And it is only attached children + * of the debugger that are of interest (ptrace_check_attach checks + * for this). + */ + list_for_each_safe(this, next, ¤t->children) { + p = list_entry(this, struct task_struct, sibling); + if (p->mm != mm) + continue; + if (thread_matches(p, addr)) { + child = p; + goto out; + } + } + + out: + mmput(mm); + return child; +} + /* * Write f32-f127 back to task->thread.fph if it has been modified. */ @@ -597,7 +663,6 @@ ia64_sync_fph (struct task_struct *task) psr->dfh = 1; } -#if 0 static int access_fr (struct unw_frame_info *info, int regnum, int hi, unsigned long *data, int write_access) @@ -616,7 +681,6 @@ access_fr (struct unw_frame_info *info, int regnum, int hi, *data = fpval.u.bits[hi]; return ret; } -#endif /* access_fr() */ /* * Change the machine-state of CHILD such that it will return via the normal @@ -717,121 +781,321 @@ access_nat_bits (struct task_struct *child, struct pt_regs *pt, return 0; } - -/* "asmlinkage" so the input arguments are preserved... */ - -asmlinkage void -syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6, long arg7, - struct pt_regs regs) +static int +access_uarea (struct task_struct *child, unsigned long addr, + unsigned long *data, int write_access) { - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(®s, 0); + unsigned long *ptr, regnum, urbs_end, rnat_addr, cfm; + struct switch_stack *sw; + struct pt_regs *pt; +# define pt_reg_addr(pt, reg) ((void *) \ + ((unsigned long) (pt) \ + + offsetof(struct pt_regs, reg))) - if (unlikely(current->audit_context)) { - long syscall; - int arch; - if (IS_IA32_PROCESS(®s)) { - syscall = regs.r1; - arch = AUDIT_ARCH_I386; - } else { - syscall = regs.r15; - arch = AUDIT_ARCH_IA64; - } + pt = task_pt_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); - audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3); + if ((addr & 0x7) != 0) { + dprintk("ptrace: unaligned register address 0x%lx\n", addr); + return -1; } -} + if (addr < PT_F127 + 16) { + /* accessing fph */ + if (write_access) + ia64_sync_fph(child); + else + ia64_flush_fph(child); + ptr = (unsigned long *) + ((unsigned long) &child->thread.fph + addr); + } else if ((addr >= PT_F10) && (addr < PT_F11 + 16)) { + /* scratch registers untouched by kernel (saved in pt_regs) */ + ptr = pt_reg_addr(pt, f10) + (addr - PT_F10); + } else if (addr >= PT_F12 && addr < PT_F15 + 16) { + /* + * Scratch registers untouched by kernel (saved in + * switch_stack). + */ + ptr = (unsigned long *) ((long) sw + + (addr - PT_NAT_BITS - 32)); + } else if (addr < PT_AR_LC + 8) { + /* preserved state: */ + struct unw_frame_info info; + char nat = 0; + int ret; + + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) + return -1; -/* "asmlinkage" so the input arguments are preserved... */ + switch (addr) { + case PT_NAT_BITS: + return access_nat_bits(child, pt, &info, + data, write_access); -asmlinkage void -syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6, long arg7, - struct pt_regs regs) -{ - if (unlikely(current->audit_context)) { - int success = AUDITSC_RESULT(regs.r10); - long result = regs.r8; + case PT_R4: case PT_R5: case PT_R6: case PT_R7: + if (write_access) { + /* read NaT bit first: */ + unsigned long dummy; - if (success != AUDITSC_SUCCESS) - result = -result; - audit_syscall_exit(success, result); - } + ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, + &dummy, &nat); + if (ret < 0) + return ret; + } + return unw_access_gr(&info, (addr - PT_R4)/8 + 4, data, + &nat, write_access); + + case PT_B1: case PT_B2: case PT_B3: + case PT_B4: case PT_B5: + return unw_access_br(&info, (addr - PT_B1)/8 + 1, data, + write_access); + + case PT_AR_EC: + return unw_access_ar(&info, UNW_AR_EC, data, + write_access); + + case PT_AR_LC: + return unw_access_ar(&info, UNW_AR_LC, data, + write_access); + + default: + if (addr >= PT_F2 && addr < PT_F5 + 16) + return access_fr(&info, (addr - PT_F2)/16 + 2, + (addr & 8) != 0, data, + write_access); + else if (addr >= PT_F16 && addr < PT_F31 + 16) + return access_fr(&info, + (addr - PT_F16)/16 + 16, + (addr & 8) != 0, + data, write_access); + else { + dprintk("ptrace: rejecting access to register " + "address 0x%lx\n", addr); + return -1; + } + } + } else if (addr < PT_F9+16) { + /* scratch state */ + switch (addr) { + case PT_AR_BSP: + /* + * By convention, we use PT_AR_BSP to refer to + * the end of the user-level backing store. + * Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof) + * to get the real value of ar.bsp at the time + * the kernel was entered. + * + * Furthermore, when changing the contents of + * PT_AR_BSP (or PT_CFM) we MUST copy any + * users-level stacked registers that are + * stored on the kernel stack back to + * user-space because otherwise, we might end + * up clobbering kernel stacked registers. + * Also, if this happens while the task is + * blocked in a system call, which convert the + * state such that the non-system-call exit + * path is used. This ensures that the proper + * state will be picked up when resuming + * execution. However, it *also* means that + * once we write PT_AR_BSP/PT_CFM, it won't be + * possible to modify the syscall arguments of + * the pending system call any longer. This + * shouldn't be an issue because modifying + * PT_AR_BSP/PT_CFM generally implies that + * we're either abandoning the pending system + * call or that we defer it's re-execution + * (e.g., due to GDB doing an inferior + * function call). + */ + urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); + if (write_access) { + if (*data != urbs_end) { + if (ia64_sync_user_rbs(child, sw, + pt->ar_bspstore, + urbs_end) < 0) + return -1; + if (in_syscall(pt)) + convert_to_non_syscall(child, + pt, + cfm); + /* + * Simulate user-level write + * of ar.bsp: + */ + pt->loadrs = 0; + pt->ar_bspstore = *data; + } + } else + *data = urbs_end; + return 0; - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(®s, 1); -} + case PT_CFM: + urbs_end = ia64_get_user_rbs_end(child, pt, &cfm); + if (write_access) { + if (((cfm ^ *data) & PFM_MASK) != 0) { + if (ia64_sync_user_rbs(child, sw, + pt->ar_bspstore, + urbs_end) < 0) + return -1; + if (in_syscall(pt)) + convert_to_non_syscall(child, + pt, + cfm); + pt->cr_ifs = ((pt->cr_ifs & ~PFM_MASK) + | (*data & PFM_MASK)); + } + } else + *data = cfm; + return 0; + case PT_CR_IPSR: + if (write_access) + pt->cr_ipsr = ((*data & IPSR_MASK) + | (pt->cr_ipsr & ~IPSR_MASK)); + else + *data = (pt->cr_ipsr & IPSR_MASK); + return 0; -#ifdef CONFIG_UTRACE + case PT_AR_RSC: + if (write_access) + pt->ar_rsc = *data | (3 << 2); /* force PL3 */ + else + *data = pt->ar_rsc; + return 0; -/* Utrace implementation starts here */ + case PT_AR_RNAT: + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + rnat_addr = (long) ia64_rse_rnat_addr((long *) + urbs_end); + if (write_access) + return ia64_poke(child, sw, urbs_end, + rnat_addr, *data); + else + return ia64_peek(child, sw, urbs_end, + rnat_addr, data); + + case PT_R1: + ptr = pt_reg_addr(pt, r1); + break; + case PT_R2: case PT_R3: + ptr = pt_reg_addr(pt, r2) + (addr - PT_R2); + break; + case PT_R8: case PT_R9: case PT_R10: case PT_R11: + ptr = pt_reg_addr(pt, r8) + (addr - PT_R8); + break; + case PT_R12: case PT_R13: + ptr = pt_reg_addr(pt, r12) + (addr - PT_R12); + break; + case PT_R14: + ptr = pt_reg_addr(pt, r14); + break; + case PT_R15: + ptr = pt_reg_addr(pt, r15); + break; + case PT_R16: case PT_R17: case PT_R18: case PT_R19: + case PT_R20: case PT_R21: case PT_R22: case PT_R23: + case PT_R24: case PT_R25: case PT_R26: case PT_R27: + case PT_R28: case PT_R29: case PT_R30: case PT_R31: + ptr = pt_reg_addr(pt, r16) + (addr - PT_R16); + break; + case PT_B0: + ptr = pt_reg_addr(pt, b0); + break; + case PT_B6: + ptr = pt_reg_addr(pt, b6); + break; + case PT_B7: + ptr = pt_reg_addr(pt, b7); + break; + case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: + case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: + ptr = pt_reg_addr(pt, f6) + (addr - PT_F6); + break; + case PT_AR_BSPSTORE: + ptr = pt_reg_addr(pt, ar_bspstore); + break; + case PT_AR_UNAT: + ptr = pt_reg_addr(pt, ar_unat); + break; + case PT_AR_PFS: + ptr = pt_reg_addr(pt, ar_pfs); + break; + case PT_AR_CCV: + ptr = pt_reg_addr(pt, ar_ccv); + break; + case PT_AR_FPSR: + ptr = pt_reg_addr(pt, ar_fpsr); + break; + case PT_CR_IIP: + ptr = pt_reg_addr(pt, cr_iip); + break; + case PT_PR: + ptr = pt_reg_addr(pt, pr); + break; + /* scratch register */ -typedef struct utrace_get { - void *kbuf; - void __user *ubuf; -} utrace_get_t; + default: + /* disallow accessing anything else... */ + dprintk("ptrace: rejecting access to register " + "address 0x%lx\n", addr); + return -1; + } + } else if (addr <= PT_AR_SSD) { + ptr = pt_reg_addr(pt, ar_csd) + (addr - PT_AR_CSD); + } else { + /* access debug registers */ -typedef struct utrace_set { - const void *kbuf; - const void __user *ubuf; -} utrace_set_t; + if (addr >= PT_IBR) { + regnum = (addr - PT_IBR) >> 3; + ptr = &child->thread.ibr[0]; + } else { + regnum = (addr - PT_DBR) >> 3; + ptr = &child->thread.dbr[0]; + } -typedef struct utrace_getset { - struct task_struct *target; - const struct utrace_regset *regset; - union { - utrace_get_t get; - utrace_set_t set; - } u; - unsigned int pos; - unsigned int count; - int ret; -} utrace_getset_t; + if (regnum >= 8) { + dprintk("ptrace: rejecting access to register " + "address 0x%lx\n", addr); + return -1; + } +#ifdef CONFIG_PERFMON + /* + * Check if debug registers are used by perfmon. This + * test must be done once we know that we can do the + * operation, i.e. the arguments are all valid, but + * before we start modifying the state. + * + * Perfmon needs to keep a count of how many processes + * are trying to modify the debug registers for system + * wide monitoring sessions. + * + * We also include read access here, because they may + * cause the PMU-installed debug register state + * (dbr[], ibr[]) to be reset. The two arrays are also + * used by perfmon, but we do not use + * IA64_THREAD_DBG_VALID. The registers are restored + * by the PMU context switch code. + */ + if (pfm_use_debug_registers(child)) return -1; +#endif -static int -access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info, - unsigned long addr, unsigned long *data, int write_access) -{ - struct pt_regs *pt; - unsigned long *ptr = NULL; - int ret; - char nat=0; + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; + memset(child->thread.dbr, 0, + sizeof(child->thread.dbr)); + memset(child->thread.ibr, 0, + sizeof(child->thread.ibr)); + } - pt = task_pt_regs(target); - switch (addr) { - case ELF_GR_OFFSET(1): - ptr = &pt->r1; - break; - case ELF_GR_OFFSET(2): - case ELF_GR_OFFSET(3): - ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2)); - break; - case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7): - if (write_access) { - /* read NaT bit first: */ - unsigned long dummy; + ptr += regnum; - ret = unw_get_gr(info, addr/8, &dummy, &nat); - if (ret < 0) - return ret; - } - return unw_access_gr(info, addr/8, data, &nat, write_access); - case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11): - ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8); - break; - case ELF_GR_OFFSET(12): - case ELF_GR_OFFSET(13): - ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12); - break; - case ELF_GR_OFFSET(14): - ptr = &pt->r14; - break; - case ELF_GR_OFFSET(15): - ptr = &pt->r15; + if ((regnum & 1) && write_access) { + /* don't let the user set kernel-level breakpoints: */ + *ptr = *data & ~(7UL << 56); + return 0; + } } if (write_access) *ptr = *data; @@ -840,809 +1104,570 @@ access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info, return 0; } -static int -access_elf_breg(struct task_struct *target, struct unw_frame_info *info, - unsigned long addr, unsigned long *data, int write_access) +static long +ptrace_getregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { + unsigned long psr, ec, lc, rnat, bsp, cfm, nat_bits, val; + struct unw_frame_info info; + struct ia64_fpreg fpval; + struct switch_stack *sw; struct pt_regs *pt; - unsigned long *ptr = NULL; + long ret, retval = 0; + char nat = 0; + int i; - pt = task_pt_regs(target); - switch (addr) { - case ELF_BR_OFFSET(0): - ptr = &pt->b0; - break; - case ELF_BR_OFFSET(1) ... ELF_BR_OFFSET(5): - return unw_access_br(info, (addr - ELF_BR_OFFSET(0))/8, - data, write_access); - case ELF_BR_OFFSET(6): - ptr = &pt->b6; - break; - case ELF_BR_OFFSET(7): - ptr = &pt->b7; + if (!access_ok(VERIFY_WRITE, ppr, sizeof(struct pt_all_user_regs))) + return -EIO; + + pt = task_pt_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) { + return -EIO; } - if (write_access) - *ptr = *data; - else - *data = *ptr; - return 0; -} -static int -access_elf_areg(struct task_struct *target, struct unw_frame_info *info, - unsigned long addr, unsigned long *data, int write_access) -{ - struct pt_regs *pt; - unsigned long cfm, urbs_end, rnat_addr; - unsigned long *ptr = NULL; + if (((unsigned long) ppr & 0x7) != 0) { + dprintk("ptrace:unaligned register address %p\n", ppr); + return -EIO; + } - pt = task_pt_regs(target); - if (addr >= ELF_AR_RSC_OFFSET && addr <= ELF_AR_SSD_OFFSET) { - switch (addr) { - case ELF_AR_RSC_OFFSET: - /* force PL3 */ - if (write_access) - pt->ar_rsc = *data | (3 << 2); - else - *data = pt->ar_rsc; - return 0; - case ELF_AR_BSP_OFFSET: - /* - * By convention, we use PT_AR_BSP to refer to - * the end of the user-level backing store. - * Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof) - * to get the real value of ar.bsp at the time - * the kernel was entered. - * - * Furthermore, when changing the contents of - * PT_AR_BSP (or PT_CFM) we MUST copy any - * users-level stacked registers that are - * stored on the kernel stack back to - * user-space because otherwise, we might end - * up clobbering kernel stacked registers. - * Also, if this happens while the task is - * blocked in a system call, which convert the - * state such that the non-system-call exit - * path is used. This ensures that the proper - * state will be picked up when resuming - * execution. However, it *also* means that - * once we write PT_AR_BSP/PT_CFM, it won't be - * possible to modify the syscall arguments of - * the pending system call any longer. This - * shouldn't be an issue because modifying - * PT_AR_BSP/PT_CFM generally implies that - * we're either abandoning the pending system - * call or that we defer it's re-execution - * (e.g., due to GDB doing an inferior - * function call). - */ - urbs_end = ia64_get_user_rbs_end(target, pt, &cfm); - if (write_access) { - if (*data != urbs_end) { - if (ia64_sync_user_rbs(target, info->sw, - pt->ar_bspstore, - urbs_end) < 0) - return -1; - if (in_syscall(pt)) - convert_to_non_syscall(target, - pt, - cfm); - /* - * Simulate user-level write - * of ar.bsp: - */ - pt->loadrs = 0; - pt->ar_bspstore = *data; - } - } else - *data = urbs_end; - return 0; - case ELF_AR_BSPSTORE_OFFSET: // ar_bsp_store - ptr = &pt->ar_bspstore; - break; - case ELF_AR_RNAT_OFFSET: // ar_rnat - urbs_end = ia64_get_user_rbs_end(target, pt, NULL); - rnat_addr = (long) ia64_rse_rnat_addr((long *) - urbs_end); - if (write_access) - return ia64_poke(target, info->sw, urbs_end, - rnat_addr, *data); - else - return ia64_peek(target, info->sw, urbs_end, - rnat_addr, data); - case ELF_AR_CCV_OFFSET: // ar_ccv - ptr = &pt->ar_ccv; - break; - case ELF_AR_UNAT_OFFSET: // ar_unat - ptr = &pt->ar_unat; - break; - case ELF_AR_FPSR_OFFSET: // ar_fpsr - ptr = &pt->ar_fpsr; - break; - case ELF_AR_PFS_OFFSET: // ar_pfs - ptr = &pt->ar_pfs; - break; - case ELF_AR_LC_OFFSET: // ar_lc - return unw_access_ar(info, UNW_AR_LC, data, - write_access); - case ELF_AR_EC_OFFSET: // ar_ec - return unw_access_ar(info, UNW_AR_EC, data, - write_access); - case ELF_AR_CSD_OFFSET: // ar_csd - ptr = &pt->ar_csd; - break; - case ELF_AR_SSD_OFFSET: // ar_ssd - ptr = &pt->ar_ssd; - } - } else if (addr >= ELF_CR_IIP_OFFSET && addr <= ELF_CR_IPSR_OFFSET) { - switch (addr) { - case ELF_CR_IIP_OFFSET: - ptr = &pt->cr_iip; - break; - case ELF_CFM_OFFSET: - urbs_end = ia64_get_user_rbs_end(target, pt, &cfm); - if (write_access) { - if (((cfm ^ *data) & PFM_MASK) != 0) { - if (ia64_sync_user_rbs(target, info->sw, - pt->ar_bspstore, - urbs_end) < 0) - return -1; - if (in_syscall(pt)) - convert_to_non_syscall(target, - pt, - cfm); - pt->cr_ifs = ((pt->cr_ifs & ~PFM_MASK) - | (*data & PFM_MASK)); - } - } else - *data = cfm; - return 0; - case ELF_CR_IPSR_OFFSET: - if (write_access) - pt->cr_ipsr = ((*data & IPSR_MASK) - | (pt->cr_ipsr & ~IPSR_MASK)); - else - *data = (pt->cr_ipsr & IPSR_MASK); - return 0; - } - } else if (addr == ELF_NAT_OFFSET) - return access_nat_bits(target, pt, info, - data, write_access); - else if (addr == ELF_PR_OFFSET) - ptr = &pt->pr; - else - return -1; + if (access_uarea(child, PT_CR_IPSR, &psr, 0) < 0 + || access_uarea(child, PT_AR_EC, &ec, 0) < 0 + || access_uarea(child, PT_AR_LC, &lc, 0) < 0 + || access_uarea(child, PT_AR_RNAT, &rnat, 0) < 0 + || access_uarea(child, PT_AR_BSP, &bsp, 0) < 0 + || access_uarea(child, PT_CFM, &cfm, 0) + || access_uarea(child, PT_NAT_BITS, &nat_bits, 0)) + return -EIO; - if (write_access) - *ptr = *data; - else - *data = *ptr; + /* control regs */ - return 0; -} + retval |= __put_user(pt->cr_iip, &ppr->cr_iip); + retval |= __put_user(psr, &ppr->cr_ipsr); -static int -access_elf_reg(struct task_struct *target, struct unw_frame_info *info, - unsigned long addr, unsigned long *data, int write_access) -{ - if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15)) - return access_elf_gpreg(target, info, addr, data, write_access); - else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7)) - return access_elf_breg(target, info, addr, data, write_access); - else - return access_elf_areg(target, info, addr, data, write_access); -} + /* app regs */ -void do_gpregs_get(struct unw_frame_info *info, void *arg) -{ - struct pt_regs *pt; - utrace_getset_t *dst = arg; - elf_greg_t tmp[16]; - unsigned int i, index, min_copy; + retval |= __put_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); + retval |= __put_user(pt->ar_rsc, &ppr->ar[PT_AUR_RSC]); + retval |= __put_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); + retval |= __put_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); + retval |= __put_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); + retval |= __put_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); - if (unw_unwind_to_user(info) < 0) - return; + retval |= __put_user(ec, &ppr->ar[PT_AUR_EC]); + retval |= __put_user(lc, &ppr->ar[PT_AUR_LC]); + retval |= __put_user(rnat, &ppr->ar[PT_AUR_RNAT]); + retval |= __put_user(bsp, &ppr->ar[PT_AUR_BSP]); + retval |= __put_user(cfm, &ppr->cfm); - /* - * coredump format: - * r0-r31 - * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT) - * predicate registers (p0-p63) - * b0-b7 - * ip cfm user-mask - * ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec - */ + /* gr1-gr3 */ + retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long)); + retval |= __copy_to_user(&ppr->gr[2], &pt->r2, sizeof(long) *2); - /* Skip r0 */ - if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { - dst->ret = utrace_regset_copyout_zero(&dst->pos, &dst->count, - &dst->u.get.kbuf, - &dst->u.get.ubuf, - 0, ELF_GR_OFFSET(1)); - if (dst->ret || dst->count == 0) - return; + /* gr4-gr7 */ + + for (i = 4; i < 8; i++) { + if (unw_access_gr(&info, i, &val, &nat, 0) < 0) + return -EIO; + retval |= __put_user(val, &ppr->gr[i]); } - /* gr1 - gr15 */ - if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { - index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); - min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ? - (dst->pos + dst->count) : ELF_GR_OFFSET(16); - for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) - if (access_elf_reg(dst->target, info, i, - &tmp[index], 0) < 0) { - dst->ret = -EIO; - return; - } - dst->ret = utrace_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); - if (dst->ret || dst->count == 0) - return; + /* gr8-gr11 */ + + retval |= __copy_to_user(&ppr->gr[8], &pt->r8, sizeof(long) * 4); + + /* gr12-gr15 */ + + retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 2); + retval |= __copy_to_user(&ppr->gr[14], &pt->r14, sizeof(long)); + retval |= __copy_to_user(&ppr->gr[15], &pt->r15, sizeof(long)); + + /* gr16-gr31 */ + + retval |= __copy_to_user(&ppr->gr[16], &pt->r16, sizeof(long) * 16); + + /* b0 */ + + retval |= __put_user(pt->b0, &ppr->br[0]); + + /* b1-b5 */ + + for (i = 1; i < 6; i++) { + if (unw_access_br(&info, i, &val, 0) < 0) + return -EIO; + __put_user(val, &ppr->br[i]); } - /* r16-r31 */ - if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { - pt = task_pt_regs(dst->target); - dst->ret = utrace_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16, - ELF_GR_OFFSET(16), ELF_NAT_OFFSET); - if (dst->ret || dst->count == 0) - return; + /* b6-b7 */ + + retval |= __put_user(pt->b6, &ppr->br[6]); + retval |= __put_user(pt->b7, &ppr->br[7]); + + /* fr2-fr5 */ + + for (i = 2; i < 6; i++) { + if (unw_get_fr(&info, i, &fpval) < 0) + return -EIO; + retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } - /* nat, pr, b0 - b7 */ - if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { - index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); - min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ? - (dst->pos + dst->count) : ELF_CR_IIP_OFFSET; - for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) - if (access_elf_reg(dst->target, info, i, - &tmp[index], 0) < 0) { - dst->ret = -EIO; - return; - } - dst->ret = utrace_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); - if (dst->ret || dst->count == 0) - return; + /* fr6-fr11 */ + + retval |= __copy_to_user(&ppr->fr[6], &pt->f6, + sizeof(struct ia64_fpreg) * 6); + + /* fp scratch regs(12-15) */ + + retval |= __copy_to_user(&ppr->fr[12], &sw->f12, + sizeof(struct ia64_fpreg) * 4); + + /* fr16-fr31 */ + + for (i = 16; i < 32; i++) { + if (unw_get_fr(&info, i, &fpval) < 0) + return -EIO; + retval |= __copy_to_user(&ppr->fr[i], &fpval, sizeof (fpval)); } - /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd - */ - if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { - index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); - min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ? - (dst->pos + dst->count) : ELF_AR_END_OFFSET; - for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t), index++) - if (access_elf_reg(dst->target, info, i, - &tmp[index], 0) < 0) { - dst->ret = -EIO; - return; - } - dst->ret = utrace_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); - } + /* fph */ + + ia64_flush_fph(child); + retval |= __copy_to_user(&ppr->fr[32], &child->thread.fph, + sizeof(ppr->fr[32]) * 96); + + /* preds */ + + retval |= __put_user(pt->pr, &ppr->pr); + + /* nat bits */ + + retval |= __put_user(nat_bits, &ppr->nat); + + ret = retval ? -EIO : 0; + return ret; } -void do_gpregs_set(struct unw_frame_info *info, void *arg) +static long +ptrace_setregs (struct task_struct *child, struct pt_all_user_regs __user *ppr) { + unsigned long psr, rsc, ec, lc, rnat, bsp, cfm, nat_bits, val = 0; + struct unw_frame_info info; + struct switch_stack *sw; + struct ia64_fpreg fpval; struct pt_regs *pt; - utrace_getset_t *dst = arg; - elf_greg_t tmp[16]; - unsigned int i, index; + long ret, retval = 0; + int i; - if (unw_unwind_to_user(info) < 0) - return; + memset(&fpval, 0, sizeof(fpval)); - /* Skip r0 */ - if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) { - dst->ret = utrace_regset_copyin_ignore(&dst->pos, &dst->count, - &dst->u.set.kbuf, - &dst->u.set.ubuf, - 0, ELF_GR_OFFSET(1)); - if (dst->ret || dst->count == 0) - return; - } + if (!access_ok(VERIFY_READ, ppr, sizeof(struct pt_all_user_regs))) + return -EIO; - /* gr1-gr15 */ - if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) { - i = dst->pos; - index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t); - dst->ret = utrace_regset_copyin(&dst->pos, &dst->count, - &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, - ELF_GR_OFFSET(1), ELF_GR_OFFSET(16)); - if (dst->ret) - return; - for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) - if (access_elf_reg(dst->target, info, i, - &tmp[index], 1) < 0) { - dst->ret = -EIO; - return; - } - if (dst->count == 0) - return; + pt = task_pt_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); + unw_init_from_blocked_task(&info, child); + if (unw_unwind_to_user(&info) < 0) { + return -EIO; } - /* gr16-gr31 */ - if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) { - pt = task_pt_regs(dst->target); - dst->ret = utrace_regset_copyin(&dst->pos, &dst->count, - &dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16, - ELF_GR_OFFSET(16), ELF_NAT_OFFSET); - if (dst->ret || dst->count == 0) - return; + if (((unsigned long) ppr & 0x7) != 0) { + dprintk("ptrace:unaligned register address %p\n", ppr); + return -EIO; } - /* nat, pr, b0 - b7 */ - if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) { - i = dst->pos; - index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t); - dst->ret = utrace_regset_copyin(&dst->pos, &dst->count, - &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, - ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET); - if (dst->ret) - return; - for (; i < dst->pos; i += sizeof(elf_greg_t), index++) - if (access_elf_reg(dst->target, info, i, - &tmp[index], 1) < 0) { - dst->ret = -EIO; - return; - } - if (dst->count == 0) - return; - } + /* control regs */ - /* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd - */ - if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) { - i = dst->pos; - index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t); - dst->ret = utrace_regset_copyin(&dst->pos, &dst->count, - &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, - ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET); - if (dst->ret) - return; - for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++) - if (access_elf_reg(dst->target, info, i, - &tmp[index], 1) < 0) { - dst->ret = -EIO; - return; - } - } -} + retval |= __get_user(pt->cr_iip, &ppr->cr_iip); + retval |= __get_user(psr, &ppr->cr_ipsr); -#define ELF_FP_OFFSET(i) (i * sizeof(elf_fpreg_t)) + /* app regs */ -void do_fpregs_get(struct unw_frame_info *info, void *arg) -{ - utrace_getset_t *dst = arg; - struct task_struct *task = dst->target; - elf_fpreg_t tmp[30]; - int index, min_copy, i; + retval |= __get_user(pt->ar_pfs, &ppr->ar[PT_AUR_PFS]); + retval |= __get_user(rsc, &ppr->ar[PT_AUR_RSC]); + retval |= __get_user(pt->ar_bspstore, &ppr->ar[PT_AUR_BSPSTORE]); + retval |= __get_user(pt->ar_unat, &ppr->ar[PT_AUR_UNAT]); + retval |= __get_user(pt->ar_ccv, &ppr->ar[PT_AUR_CCV]); + retval |= __get_user(pt->ar_fpsr, &ppr->ar[PT_AUR_FPSR]); - if (unw_unwind_to_user(info) < 0) - return; + retval |= __get_user(ec, &ppr->ar[PT_AUR_EC]); + retval |= __get_user(lc, &ppr->ar[PT_AUR_LC]); + retval |= __get_user(rnat, &ppr->ar[PT_AUR_RNAT]); + retval |= __get_user(bsp, &ppr->ar[PT_AUR_BSP]); + retval |= __get_user(cfm, &ppr->cfm); - /* Skip pos 0 and 1 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) { - dst->ret = utrace_regset_copyout_zero(&dst->pos, &dst->count, - &dst->u.get.kbuf, - &dst->u.get.ubuf, - 0, ELF_FP_OFFSET(2)); - if (dst->count == 0 || dst->ret) - return; - } + /* gr1-gr3 */ - /* fr2-fr31 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) { - index = (dst->pos - ELF_FP_OFFSET(2)) / sizeof(elf_fpreg_t); - min_copy = min(((unsigned int)ELF_FP_OFFSET(32)), - dst->pos + dst->count); - for (i = dst->pos; i < min_copy; i += sizeof(elf_fpreg_t), index++) - if (unw_get_fr(info, i / sizeof(elf_fpreg_t), - &tmp[index])) { - dst->ret = -EIO; - return; - } - dst->ret = utrace_regset_copyout(&dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, tmp, - ELF_FP_OFFSET(2), ELF_FP_OFFSET(32)); - if (dst->count == 0 || dst->ret) - return; + retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long)); + retval |= __copy_from_user(&pt->r2, &ppr->gr[2], sizeof(long) * 2); + + /* gr4-gr7 */ + + for (i = 4; i < 8; i++) { + retval |= __get_user(val, &ppr->gr[i]); + /* NaT bit will be set via PT_NAT_BITS: */ + if (unw_set_gr(&info, i, val, 0) < 0) + return -EIO; } - /* fph */ - if (dst->count > 0) { - ia64_flush_fph(dst->target); - if (task->thread.flags & IA64_THREAD_FPH_VALID) - dst->ret = utrace_regset_copyout( - &dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, - &dst->target->thread.fph, - ELF_FP_OFFSET(32), -1); - else - /* Zero fill instead. */ - dst->ret = utrace_regset_copyout_zero( - &dst->pos, &dst->count, - &dst->u.get.kbuf, &dst->u.get.ubuf, - ELF_FP_OFFSET(32), -1); + /* gr8-gr11 */ + + retval |= __copy_from_user(&pt->r8, &ppr->gr[8], sizeof(long) * 4); + + /* gr12-gr15 */ + + retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 2); + retval |= __copy_from_user(&pt->r14, &ppr->gr[14], sizeof(long)); + retval |= __copy_from_user(&pt->r15, &ppr->gr[15], sizeof(long)); + + /* gr16-gr31 */ + + retval |= __copy_from_user(&pt->r16, &ppr->gr[16], sizeof(long) * 16); + + /* b0 */ + + retval |= __get_user(pt->b0, &ppr->br[0]); + + /* b1-b5 */ + + for (i = 1; i < 6; i++) { + retval |= __get_user(val, &ppr->br[i]); + unw_set_br(&info, i, val); } -} -void do_fpregs_set(struct unw_frame_info *info, void *arg) -{ - utrace_getset_t *dst = arg; - elf_fpreg_t fpreg, tmp[30]; - int index, start, end; + /* b6-b7 */ - if (unw_unwind_to_user(info) < 0) - return; + retval |= __get_user(pt->b6, &ppr->br[6]); + retval |= __get_user(pt->b7, &ppr->br[7]); - /* Skip pos 0 and 1 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(2)) { - dst->ret = utrace_regset_copyin_ignore(&dst->pos, &dst->count, - &dst->u.set.kbuf, - &dst->u.set.ubuf, - 0, ELF_FP_OFFSET(2)); - if (dst->count == 0 || dst->ret) - return; + /* fr2-fr5 */ + + for (i = 2; i < 6; i++) { + retval |= __copy_from_user(&fpval, &ppr->fr[i], sizeof(fpval)); + if (unw_set_fr(&info, i, fpval) < 0) + return -EIO; } - /* fr2-fr31 */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(32)) { - start = dst->pos; - end = min(((unsigned int)ELF_FP_OFFSET(32)), - dst->pos + dst->count); - dst->ret = utrace_regset_copyin(&dst->pos, &dst->count, - &dst->u.set.kbuf, &dst->u.set.ubuf, tmp, - ELF_FP_OFFSET(2), ELF_FP_OFFSET(32)); - if (dst->ret) - return; + /* fr6-fr11 */ - if (start & 0xF) { // only write high part - if (unw_get_fr(info, start / sizeof(elf_fpreg_t), - &fpreg)) { - dst->ret = -EIO; - return; - } - tmp[start / sizeof(elf_fpreg_t) - 2].u.bits[0] - = fpreg.u.bits[0]; - start &= ~0xFUL; - } - if (end & 0xF) { // only write low part - if (unw_get_fr(info, end / sizeof(elf_fpreg_t), &fpreg)) { - dst->ret = -EIO; - return; - } - tmp[end / sizeof(elf_fpreg_t) -2].u.bits[1] - = fpreg.u.bits[1]; - end = (end + 0xF) & ~0xFUL; - } + retval |= __copy_from_user(&pt->f6, &ppr->fr[6], + sizeof(ppr->fr[6]) * 6); - for ( ; start < end ; start += sizeof(elf_fpreg_t)) { - index = start / sizeof(elf_fpreg_t); - if (unw_set_fr(info, index, tmp[index - 2])){ - dst->ret = -EIO; - return; - } - } - if (dst->ret || dst->count == 0) - return; + /* fp scratch regs(12-15) */ + + retval |= __copy_from_user(&sw->f12, &ppr->fr[12], + sizeof(ppr->fr[12]) * 4); + + /* fr16-fr31 */ + + for (i = 16; i < 32; i++) { + retval |= __copy_from_user(&fpval, &ppr->fr[i], + sizeof(fpval)); + if (unw_set_fr(&info, i, fpval) < 0) + return -EIO; } /* fph */ - if (dst->count > 0 && dst->pos < ELF_FP_OFFSET(128)) { - ia64_sync_fph(dst->target); - dst->ret = utrace_regset_copyin(&dst->pos, &dst->count, - &dst->u.set.kbuf, - &dst->u.set.ubuf, - &dst->target->thread.fph, - ELF_FP_OFFSET(32), -1); - } -} -static int -do_regset_call(void (*call)(struct unw_frame_info *, void *), - struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - utrace_getset_t info = { .target = target, .regset = regset, - .pos = pos, .count = count, - .u.set = { .kbuf = kbuf, .ubuf = ubuf }, - .ret = 0 }; + ia64_sync_fph(child); + retval |= __copy_from_user(&child->thread.fph, &ppr->fr[32], + sizeof(ppr->fr[32]) * 96); - if (target == current) - unw_init_running(call, &info); - else { - struct unw_frame_info ufi; - memset(&ufi, 0, sizeof(ufi)); - unw_init_from_blocked_task(&ufi, target); - (*call)(&ufi, &info); - } + /* preds */ - return info.ret; -} + retval |= __get_user(pt->pr, &ppr->pr); -static int -gpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - return do_regset_call(do_gpregs_get, target, regset, pos, count, kbuf, ubuf); -} + /* nat bits */ -static int gpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - return do_regset_call(do_gpregs_set, target, regset, pos, count, kbuf, ubuf); + retval |= __get_user(nat_bits, &ppr->nat); + + retval |= access_uarea(child, PT_CR_IPSR, &psr, 1); + retval |= access_uarea(child, PT_AR_RSC, &rsc, 1); + retval |= access_uarea(child, PT_AR_EC, &ec, 1); + retval |= access_uarea(child, PT_AR_LC, &lc, 1); + retval |= access_uarea(child, PT_AR_RNAT, &rnat, 1); + retval |= access_uarea(child, PT_AR_BSP, &bsp, 1); + retval |= access_uarea(child, PT_CFM, &cfm, 1); + retval |= access_uarea(child, PT_NAT_BITS, &nat_bits, 1); + + ret = retval ? -EIO : 0; + return ret; } /* - * This is called to write back the register backing store. - * ptrace does this before it stops, so that a tracer reading the user - * memory after the thread stops will get the current register data. + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. */ -static int -gpregs_writeback(struct task_struct *target, - const struct utrace_regset *regset, - int now) +void +ptrace_disable (struct task_struct *child) { - unsigned long urbs_end, cfm; - struct pt_regs *pt = task_pt_regs(target); - struct switch_stack *sw = (void *) (target->thread.ksp + 16); - urbs_end = ia64_get_user_rbs_end(target, pt, &cfm); - return ia64_sync_user_rbs(target, sw, pt->ar_bspstore, urbs_end); -} + struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child)); -static int -fpregs_active(struct task_struct *target, const struct utrace_regset *regset) -{ - return (target->thread.flags & IA64_THREAD_FPH_VALID) ? 128 : 32; + /* make sure the single step/taken-branch trap bits are not set: */ + child_psr->ss = 0; + child_psr->tb = 0; } -static int fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +asmlinkage long +sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) { - return do_regset_call(do_fpregs_get, target, regset, pos, count, kbuf, ubuf); -} + struct pt_regs *pt; + unsigned long urbs_end, peek_or_poke; + struct task_struct *child; + struct switch_stack *sw; + long ret; -static int fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - return do_regset_call(do_fpregs_set, target, regset, pos, count, kbuf, ubuf); -} + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); + goto out; + } -static int dbregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - int ret; + peek_or_poke = (request == PTRACE_PEEKTEXT + || request == PTRACE_PEEKDATA + || request == PTRACE_POKETEXT + || request == PTRACE_POKEDATA); + ret = -ESRCH; + read_lock(&tasklist_lock); + { + child = find_task_by_pid(pid); + if (child) { + if (peek_or_poke) + child = find_thread_for_addr(child, addr); + get_task_struct(child); + } + } + read_unlock(&tasklist_lock); + if (!child) + goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; + + ret = -EPERM; + if (pid == 1) /* no messing around with init! */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } -#ifdef CONFIG_PERFMON - /* - * Check if debug registers are used by perfmon. This - * test must be done once we know that we can do the - * operation, i.e. the arguments are all valid, but - * before we start modifying the state. - * - * Perfmon needs to keep a count of how many processes - * are trying to modify the debug registers for system - * wide monitoring sessions. - * - * We also include read access here, because they may - * cause the PMU-installed debug register state - * (dbr[], ibr[]) to be reset. The two arrays are also - * used by perfmon, but we do not use - * IA64_THREAD_DBG_VALID. The registers are restored - * by the PMU context switch code. - */ - if (pfm_use_debug_registers(target)) - return -EIO; -#endif + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out_tsk; + + pt = task_pt_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); + + switch (request) { + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + /* read word at location addr */ + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + ret = ia64_peek(child, sw, urbs_end, addr, &data); + if (ret == 0) { + ret = data; + /* ensure "ret" is not mistaken as an error code: */ + force_successful_syscall_return(); + } + goto out_tsk; + + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + /* write the word at location addr */ + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + ret = ia64_poke(child, sw, urbs_end, addr, data); + goto out_tsk; + + case PTRACE_PEEKUSR: + /* read the word at addr in the USER area */ + if (access_uarea(child, addr, &data, 0) < 0) { + ret = -EIO; + goto out_tsk; + } + ret = data; + /* ensure "ret" is not mistaken as an error code */ + force_successful_syscall_return(); + goto out_tsk; + + case PTRACE_POKEUSR: + /* write the word at addr in the USER area */ + if (access_uarea(child, addr, &data, 1) < 0) { + ret = -EIO; + goto out_tsk; + } + ret = 0; + goto out_tsk; + + case PTRACE_OLD_GETSIGINFO: + /* for backwards-compatibility */ + ret = ptrace_request(child, PTRACE_GETSIGINFO, addr, data); + goto out_tsk; + + case PTRACE_OLD_SETSIGINFO: + /* for backwards-compatibility */ + ret = ptrace_request(child, PTRACE_SETSIGINFO, addr, data); + goto out_tsk; + + case PTRACE_SYSCALL: + /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: + /* restart after signal. */ + ret = -EIO; + if (!valid_signal(data)) + goto out_tsk; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; - if (!(target->thread.flags & IA64_THREAD_DBG_VALID)) - ret = utrace_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, - 0, -1); - else { - preempt_disable(); - if (target == current) - ia64_load_debug_regs(&target->thread.dbr[0]); - preempt_enable_no_resched(); - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.dbr, 0, -1); - } + /* + * Make sure the single step/taken-branch trap bits + * are not set: + */ + ia64_psr(pt)->ss = 0; + ia64_psr(pt)->tb = 0; + wake_up_process(child); + ret = 0; + goto out_tsk; + + case PTRACE_KILL: + /* + * Make the child exit. Best I can do is send it a + * sigkill. Perhaps it should be put in the status + * that it wants to exit. + */ + if (child->exit_state == EXIT_ZOMBIE) + /* already dead */ + goto out_tsk; + child->exit_code = SIGKILL; + + ptrace_disable(child); + wake_up_process(child); + ret = 0; + goto out_tsk; + + case PTRACE_SINGLESTEP: + /* let child execute for one instruction */ + case PTRACE_SINGLEBLOCK: + ret = -EIO; + if (!valid_signal(data)) + goto out_tsk; + + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + if (request == PTRACE_SINGLESTEP) { + ia64_psr(pt)->ss = 1; + } else { + ia64_psr(pt)->tb = 1; + } + child->exit_code = data; + + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + goto out_tsk; + + case PTRACE_DETACH: + /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + goto out_tsk; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, + (struct pt_all_user_regs __user *) data); + goto out_tsk; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, + (struct pt_all_user_regs __user *) data); + goto out_tsk; + + default: + ret = ptrace_request(child, request, addr, data); + goto out_tsk; + } + out_tsk: + put_task_struct(child); + out: + unlock_kernel(); return ret; } -static int dbregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int i, ret; -#ifdef CONFIG_PERFMON - if (pfm_use_debug_registers(target)) - return -EIO; -#endif +void +syscall_trace (void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + /* + * The 0x80 provides a way for the tracing parent to + * distinguish between a syscall stop and SIGTRAP delivery. + */ + ptrace_notify(SIGTRAP + | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); - ret = 0; - if (!(target->thread.flags & IA64_THREAD_DBG_VALID)){ - target->thread.flags |= IA64_THREAD_DBG_VALID; - memset(target->thread.dbr, 0, 2 * sizeof(target->thread.dbr)); - } else if (target == current){ - preempt_disable(); - ia64_save_debug_regs(&target->thread.dbr[0]); - preempt_enable_no_resched(); + /* + * This isn't the same as continuing with a signal, but it + * will do for normal use. strace only continues with a + * signal if the stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; } +} - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.dbr, 0, -1); +/* "asmlinkage" so the input arguments are preserved... */ - for (i = 1; i < IA64_NUM_DBG_REGS; i += 2) { - target->thread.dbr[i] &= ~(7UL << 56); - target->thread.ibr[i] &= ~(7UL << 56); - } +asmlinkage void +syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, + struct pt_regs regs) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + syscall_trace(); - if (ret) - return ret; + if (unlikely(current->audit_context)) { + long syscall; + int arch; + + if (IS_IA32_PROCESS(®s)) { + syscall = regs.r1; + arch = AUDIT_ARCH_I386; + } else { + syscall = regs.r15; + arch = AUDIT_ARCH_IA64; + } - if (target == current){ - preempt_disable(); - ia64_load_debug_regs(&target->thread.dbr[0]); - preempt_enable_no_resched(); + audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3); } - return 0; + } -static const struct utrace_regset native_regsets[] = { - { - .n = ELF_NGREG, - .size = sizeof(elf_greg_t), .align = sizeof(elf_greg_t), - .get = gpregs_get, .set = gpregs_set, - .writeback = gpregs_writeback - }, - { - .n = ELF_NFPREG, - .size = sizeof(elf_fpreg_t), .align = sizeof(elf_fpreg_t), - .get = fpregs_get, .set = fpregs_set, .active = fpregs_active - }, - { - .n = 2 * IA64_NUM_DBG_REGS, .size = sizeof(long), - .align = sizeof(long), - .get = dbregs_get, .set = dbregs_set - } -}; - -const struct utrace_regset_view utrace_ia64_native = { - .name = "ia64", - .e_machine = EM_IA_64, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_ia64_native); - -#endif /* CONFIG_UTRACE */ - - -#ifdef CONFIG_PTRACE - -#define WORD(member, num) \ - offsetof(struct pt_all_user_regs, member), \ - offsetof(struct pt_all_user_regs, member) + num * sizeof(long) -static const struct ptrace_layout_segment pt_all_user_regs_layout[] = { - {WORD(nat, 1), 0, ELF_NAT_OFFSET}, - {WORD(cr_iip, 1), 0, ELF_CR_IIP_OFFSET}, - {WORD(cfm, 1), 0, ELF_CFM_OFFSET}, - {WORD(cr_ipsr, 1), 0, ELF_CR_IPSR_OFFSET}, - {WORD(pr, 1), 0, ELF_PR_OFFSET}, - {WORD(gr[0], 32), 0, ELF_GR_OFFSET(0)}, - {WORD(br[0], 8), 0, ELF_BR_OFFSET(0)}, - {WORD(ar[PT_AUR_RSC], 4), 0, ELF_AR_RSC_OFFSET}, - {WORD(ar[PT_AUR_CCV], 1), 0, ELF_AR_CCV_OFFSET}, - {WORD(ar[PT_AUR_UNAT], 1), 0, ELF_AR_UNAT_OFFSET}, - {WORD(ar[PT_AUR_FPSR], 1), 0, ELF_AR_FPSR_OFFSET}, - {WORD(ar[PT_AUR_PFS], 3), 0, ELF_AR_PFS_OFFSET}, - {offsetof(struct pt_all_user_regs, fr[0]), - offsetof(struct pt_all_user_regs, fr[128]), - 1, 0}, - {0, 0, -1, 0} -}; -#undef WORD - -#define NEXT(addr, sum) (addr + sum * sizeof(long)) -static const struct ptrace_layout_segment pt_uarea_layout[] = { - {PT_F32, PT_NAT_BITS, 1, ELF_FP_OFFSET(32)}, - {PT_NAT_BITS, NEXT(PT_NAT_BITS, 1), 0, ELF_NAT_OFFSET}, - {PT_F2, PT_F10, 1, ELF_FP_OFFSET(2)}, - {PT_F10, PT_R4, 1, ELF_FP_OFFSET(10)}, - {PT_R4, PT_B1, 0, ELF_GR_OFFSET(4)}, - {PT_B1, PT_AR_EC, 0, ELF_BR_OFFSET(1)}, - {PT_AR_EC, PT_AR_LC, 0, ELF_AR_EC_OFFSET}, - {PT_AR_LC, NEXT(PT_AR_LC, 1), 0, ELF_AR_LC_OFFSET}, - {PT_CR_IPSR, PT_CR_IIP, 0, ELF_CR_IPSR_OFFSET}, - {PT_CR_IIP, PT_AR_UNAT, 0, ELF_CR_IIP_OFFSET}, - {PT_AR_UNAT, PT_AR_PFS, 0, ELF_AR_UNAT_OFFSET}, - {PT_AR_PFS, PT_AR_RSC, 0, ELF_AR_PFS_OFFSET}, - {PT_AR_RSC, PT_AR_RNAT, 0, ELF_AR_RSC_OFFSET}, - {PT_AR_RNAT, PT_AR_BSPSTORE, 0, ELF_AR_RNAT_OFFSET}, - {PT_AR_BSPSTORE,PT_PR, 0, ELF_AR_BSPSTORE_OFFSET}, - {PT_PR, PT_B6, 0, ELF_PR_OFFSET}, - {PT_B6, PT_AR_BSP, 0, ELF_BR_OFFSET(6)}, - {PT_AR_BSP, PT_R1, 0, ELF_AR_BSP_OFFSET}, - {PT_R1, PT_R12, 0, ELF_GR_OFFSET(1)}, - {PT_R12, PT_R8, 0, ELF_GR_OFFSET(12)}, - {PT_R8, PT_R16, 0, ELF_GR_OFFSET(8)}, - {PT_R16, PT_AR_CCV, 0, ELF_GR_OFFSET(16)}, - {PT_AR_CCV, PT_AR_FPSR, 0, ELF_AR_CCV_OFFSET}, - {PT_AR_FPSR, PT_B0, 0, ELF_AR_FPSR_OFFSET}, - {PT_B0, PT_B7, 0, ELF_BR_OFFSET(0)}, - {PT_B7, PT_F6, 0, ELF_BR_OFFSET(7)}, - {PT_F6, PT_AR_CSD, 1, ELF_FP_OFFSET(6)}, - {PT_AR_CSD, NEXT(PT_AR_CSD, 2), 0, ELF_AR_CSD_OFFSET}, - {PT_DBR, NEXT(PT_DBR, 8), 2, 0}, - {PT_IBR, NEXT(PT_IBR, 8), 2, 8 * sizeof(long)}, - {0, 0, -1, 0} -}; -#undef NEXT - -fastcall int arch_ptrace(long *request, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, long *val) +/* "asmlinkage" so the input arguments are preserved... */ + +asmlinkage void +syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, + struct pt_regs regs) { - int ret = -ENOSYS; - switch (*request) { - case PTRACE_OLD_GETSIGINFO: - *request = PTRACE_GETSIGINFO; - break; - case PTRACE_OLD_SETSIGINFO: - *request = PTRACE_SETSIGINFO; - break; - - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = access_process_vm(child, addr, val, sizeof(*val), 0); - ret = ret == sizeof(*val) ? 0 : -EIO; - break; - - case PTRACE_PEEKUSR: - return ptrace_layout_access(child, engine, - utrace_native_view(current), - pt_uarea_layout, - addr, sizeof(long), - NULL, val, 0); - case PTRACE_POKEUSR: - return ptrace_pokeusr(child, engine, - pt_uarea_layout, addr, data); - - case PTRACE_GETREGS: - case PTRACE_SETREGS: - return ptrace_layout_access(child, engine, - utrace_native_view(current), - pt_all_user_regs_layout, - 0, sizeof(struct pt_all_user_regs), - (void __user *) data, NULL, - *request == PTRACE_SETREGS); + if (unlikely(current->audit_context)) { + int success = AUDITSC_RESULT(regs.r10); + long result = regs.r8; + + if (success != AUDITSC_SUCCESS) + result = -result; + audit_syscall_exit(success, result); } - return ret; -} -#endif /* CONFIG_PTRACE */ + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + syscall_trace(); +} diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index fd0145d14..77f8b49c7 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -471,8 +471,6 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse sigaddset(¤t->blocked, sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - - tracehook_report_handle_signal(sig, ka, oldset, &scr->pt); return 1; } diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 27dee4584..c55f487b6 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c @@ -382,14 +382,13 @@ bte_result_t bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) * bcopy to the destination. */ - /* Add the leader from source */ - headBteLen = len + (src & L1_CACHE_MASK); - /* Add the trailing bytes from footer. */ - headBteLen += L1_CACHE_BYTES - (headBteLen & L1_CACHE_MASK); - headBteSource = src & ~L1_CACHE_MASK; headBcopySrcOffset = src & L1_CACHE_MASK; headBcopyDest = dest; headBcopyLen = len; + + headBteSource = src - headBcopySrcOffset; + /* Add the leading and trailing bytes from source */ + headBteLen = L1_CACHE_ALIGN(len + headBcopySrcOffset); } if (headBcopyLen > 0) { diff --git a/arch/ia64/xen/hypervisor.c b/arch/ia64/xen/hypervisor.c index 0b286047b..93de46536 100644 --- a/arch/ia64/xen/hypervisor.c +++ b/arch/ia64/xen/hypervisor.c @@ -546,6 +546,7 @@ struct xen_ia64_privcmd_range { }; struct xen_ia64_privcmd_vma { + int is_privcmd_mmapped; struct xen_ia64_privcmd_range* range; unsigned long num_entries; @@ -684,12 +685,15 @@ __xen_ia64_privcmd_vma_open(struct vm_area_struct* vma, static void xen_ia64_privcmd_vma_open(struct vm_area_struct* vma) { + struct xen_ia64_privcmd_vma* old_privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data; struct xen_ia64_privcmd_vma* privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data; struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range; atomic_inc(&privcmd_range->ref_count); // vm_op->open() can't fail. privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL | __GFP_NOFAIL); + // copy original value if necessary + privcmd_vma->is_privcmd_mmapped = old_privcmd_vma->is_privcmd_mmapped; __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range); } @@ -724,6 +728,14 @@ xen_ia64_privcmd_vma_close(struct vm_area_struct* vma) } } +int +privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) +{ + struct xen_ia64_privcmd_vma* privcmd_vma = + (struct xen_ia64_privcmd_vma *)vma->vm_private_data; + return (xchg(&privcmd_vma->is_privcmd_mmapped, 1) == 0); +} + int privcmd_mmap(struct file * file, struct vm_area_struct * vma) { @@ -749,6 +761,8 @@ privcmd_mmap(struct file * file, struct vm_area_struct * vma) if (privcmd_vma == NULL) { goto out_enomem1; } + privcmd_vma->is_privcmd_mmapped = 0; + res = kzalloc(sizeof(*res), GFP_KERNEL); if (res == NULL) { goto out_enomem1; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 25b696ffa..1c74235f7 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -478,9 +478,26 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), regs->regs[2]); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, entryexit); + if (!(current->ptrace & PT_PTRACED)) + goto out; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + goto out; + /* The 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? + 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } + out: if (unlikely(current->audit_context) && !entryexit) audit_syscall_entry(audit_arch(), regs->regs[2], regs->regs[4], regs->regs[5], diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 59e2da85d..3371005ba 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -583,7 +583,7 @@ out: asmlinkage int irix_getpid(struct pt_regs *regs) { - regs->regs[3] = current->parent->pid; + regs->regs[3] = current->real_parent->pid; return current->pid; } diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index edddd3450..7d32ad019 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -10,14 +10,12 @@ CFLAGS_prom_init.o += -fPIC CFLAGS_btext.o += -fPIC endif -CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' - obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ irq.o align.o signal_32.o pmc.o vdso.o \ init_task.o process.o systbl.o idle.o obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ - signal_64.o \ + signal_64.o ptrace32.o \ paca.o cpu_setup_power4.o \ firmware.o sysfs.o obj-$(CONFIG_PPC64) += vdso64/ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ba2394f3c..7ee849680 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -58,6 +58,7 @@ int main(void) DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); #endif /* CONFIG_PPC64 */ DEFINE(KSP, offsetof(struct thread_struct, ksp)); @@ -78,6 +79,7 @@ int main(void) DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); + DEFINE(PT_PTRACED, PT_PTRACED); #endif #ifdef CONFIG_SPE DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0])); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index f53b244b1..34c5104c4 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include @@ -219,9 +218,6 @@ void do_IRQ(struct pt_regs *regs) irq = ppc_md.get_irq(regs); if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { - struct vx_info_save vxis; - - __enter_vx_admin(&vxis); #ifdef CONFIG_IRQSTACKS /* Switch to the irq stack to handle this */ curtp = current_thread_info(); @@ -240,7 +236,6 @@ void do_IRQ(struct pt_regs *regs) } else #endif generic_handle_irq(irq, regs); - __leave_vx_admin(&vxis); } else if (irq != NO_IRQ_IGNORE) /* That's not SMP safe ... but who cares ? */ ppc_spurious_interrupts++; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index a5766d01c..f5e91f0ec 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -815,6 +815,11 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, flush_spe_to_thread(current); error = do_execve(filename, (char __user * __user *) a1, (char __user * __user *) a2, regs); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } putname(filename); out: return error; diff --git a/arch/powerpc/kernel/ptrace-common.h b/arch/powerpc/kernel/ptrace-common.h index e69de29bb..8797ae737 100644 --- a/arch/powerpc/kernel/ptrace-common.h +++ b/arch/powerpc/kernel/ptrace-common.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2002 Stephen Rothwell, IBM Coproration + * Extracted from ptrace.c and ptrace32.c + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file README.legal in the main directory of + * this archive for more details. + */ + +#ifndef _PPC64_PTRACE_COMMON_H +#define _PPC64_PTRACE_COMMON_H + +#include + +/* + * Set of msr bits that gdb can change on behalf of a process. + */ +#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) + +/* + * Get contents of register REGNO in task TASK. + */ +static inline unsigned long get_reg(struct task_struct *task, int regno) +{ + unsigned long tmp = 0; + + /* + * Put the correct FP bits in, they might be wrong as a result + * of our lazy FP restore. + */ + if (regno == PT_MSR) { + tmp = ((unsigned long *)task->thread.regs)[PT_MSR]; + tmp |= task->thread.fpexc_mode; + } else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) { + tmp = ((unsigned long *)task->thread.regs)[regno]; + } + + return tmp; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + if (regno < PT_SOFTE) { + if (regno == PT_MSR) + data = (data & MSR_DEBUGCHANGE) + | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((unsigned long *)task->thread.regs)[regno] = data; + return 0; + } + return -EIO; +} + +static inline void set_single_step(struct task_struct *task) +{ + struct pt_regs *regs = task->thread.regs; + if (regs != NULL) + regs->msr |= MSR_SE; + set_tsk_thread_flag(task, TIF_SINGLESTEP); +} + +static inline void clear_single_step(struct task_struct *task) +{ + struct pt_regs *regs = task->thread.regs; + if (regs != NULL) + regs->msr &= ~MSR_SE; + clear_tsk_thread_flag(task, TIF_SINGLESTEP); +} + +#ifdef CONFIG_ALTIVEC +/* + * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. + * The transfer totals 34 quadword. Quadwords 0-31 contain the + * corresponding vector registers. Quadword 32 contains the vscr as the + * last word (offset 12) within that quadword. Quadword 33 contains the + * vrsave as the first word (offset 0) within the quadword. + * + * This definition of the VMX state is compatible with the current PPC32 + * ptrace interface. This allows signal handling and ptrace to use the + * same structures. This also simplifies the implementation of a bi-arch + * (combined (32- and 64-bit) gdb. + */ + +/* + * Get contents of AltiVec register state in task TASK + */ +static inline int get_vrregs(unsigned long __user *data, + struct task_struct *task) +{ + unsigned long regsize; + + /* copy AltiVec registers VR[0] .. VR[31] */ + regsize = 32 * sizeof(vector128); + if (copy_to_user(data, task->thread.vr, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VSCR */ + regsize = 1 * sizeof(vector128); + if (copy_to_user(data, &task->thread.vscr, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VRSAVE */ + if (put_user(task->thread.vrsave, (u32 __user *)data)) + return -EFAULT; + + return 0; +} + +/* + * Write contents of AltiVec register state into task TASK. + */ +static inline int set_vrregs(struct task_struct *task, + unsigned long __user *data) +{ + unsigned long regsize; + + /* copy AltiVec registers VR[0] .. VR[31] */ + regsize = 32 * sizeof(vector128); + if (copy_from_user(task->thread.vr, data, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VSCR */ + regsize = 1 * sizeof(vector128); + if (copy_from_user(&task->thread.vscr, data, regsize)) + return -EFAULT; + data += (regsize / sizeof(unsigned long)); + + /* copy VRSAVE */ + if (get_user(task->thread.vrsave, (u32 __user *)data)) + return -EFAULT; + + return 0; +} +#endif + +static inline int ptrace_set_debugreg(struct task_struct *task, + unsigned long addr, unsigned long data) +{ + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + return -EINVAL; + + /* The bottom 3 bits are flags */ + if ((data & ~0x7UL) >= TASK_SIZE) + return -EIO; + + /* Ensure translation is on */ + if (data && !(data & DABR_TRANSLATION)) + return -EIO; + + task->thread.dabr = data; + return 0; +} + +#endif /* _PPC64_PTRACE_COMMON_H */ diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 866ee7d71..dea75d73f 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -22,239 +22,128 @@ #include #include #include -#include #include #include #include #include #include -#include +#ifdef CONFIG_PPC32 #include +#endif #include #include #include #include -#include +#ifdef CONFIG_PPC64 +#include "ptrace-common.h" +#endif + +#ifdef CONFIG_PPC32 /* * Set of msr bits that gdb can change on behalf of a process. */ -#ifdef CONFIG_PPC64 -#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) -#elif defined(CONFIG_40x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) #define MSR_DEBUGCHANGE 0 -#else /* CONFIG_PPC32 */ +#else #define MSR_DEBUGCHANGE (MSR_SE | MSR_BE) -#endif /* CONFIG_PPC64 */ +#endif +#endif /* CONFIG_PPC32 */ /* - * Last register that can be changed via ptrace. + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. */ -#ifdef CONFIG_PPC64 -#define PT_LAST PT_SOFTE -#else -#define PT_LAST PT_MQ -#endif - -static int -genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (target->thread.regs == NULL) - return -EIO; - -#ifdef CONFIG_PPC32 - CHECK_FULL_REGS(target->thread.regs); -#endif - - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - target->thread.regs, 0, -1); -} - -static int -genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - unsigned long msr_save; - int ret = 0; - - if (target->thread.regs == NULL) - return -EIO; #ifdef CONFIG_PPC32 - CHECK_FULL_REGS(target->thread.regs); -#endif - - /* - * Just ignore attempts to set the registers beyond PT_LAST. - * They are read-only. - */ - - msr_save = target->thread.regs->msr &~ MSR_DEBUGCHANGE; - - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - target->thread.regs, 0, - (PT_LAST + 1) * sizeof(long)); - - target->thread.regs->msr &= MSR_DEBUGCHANGE; - target->thread.regs->msr |= msr_save; - - return ret; -} - -static int -fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +/* + * Get contents of register REGNO in task TASK. + */ +static inline unsigned long get_reg(struct task_struct *task, int regno) { - BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) - != offsetof(struct thread_struct, fpr[32])); - - flush_fp_to_thread(target); - - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fpr, 0, -1); + if (regno < sizeof(struct pt_regs) / sizeof(unsigned long) + && task->thread.regs != NULL) + return ((unsigned long *)task->thread.regs)[regno]; + return (0); } -static int -fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) { - return utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fpr, 0, -1); + if (regno <= PT_MQ && task->thread.regs != NULL) { + if (regno == PT_MSR) + data = (data & MSR_DEBUGCHANGE) + | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((unsigned long *)task->thread.regs)[regno] = data; + return 0; + } + return -EIO; } #ifdef CONFIG_ALTIVEC /* - * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. - * The transfer totals 34 quadword. Quadwords 0-31 contain the - * corresponding vector registers. Quadword 32 contains the vscr as the - * last word (offset 12) within that quadword. Quadword 33 contains the - * vrsave as the first word (offset 0) within the quadword. - * - * This definition of the VMX state is compatible with the current PPC32 - * ptrace interface. This allows signal handling and ptrace to use the - * same structures. This also simplifies the implementation of a bi-arch - * (combined (32- and 64-bit) gdb. + * Get contents of AltiVec register state in task TASK */ - -static int -vrregs_active(struct task_struct *target, const struct utrace_regset *regset) -{ - flush_altivec_to_thread(target); - return target->thread.used_vr ? regset->n : 0; -} - -static int -vrregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +static inline int get_vrregs(unsigned long __user *data, struct task_struct *task) { - BUILD_BUG_ON(offsetof(struct thread_struct, vscr) - != offsetof(struct thread_struct, vr[32])); - BUILD_BUG_ON(offsetof(struct thread_struct, vscr) + sizeof(vector128) - != offsetof(struct thread_struct, vrsave)); + int i, j; - flush_altivec_to_thread(target); + if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long))) + return -EFAULT; - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.vr, 0, -1); -} - -static int -vrregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - flush_altivec_to_thread(target); - - return utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.vr, 0, -1); -} -#endif /* CONFIG_ALTIVEC */ - -#ifdef CONFIG_PPC64 -/* We only support one DABR and no IABRS at the moment */ + /* copy AltiVec registers VR[0] .. VR[31] */ + for (i = 0; i < 32; i++) + for (j = 0; j < 4; j++, data++) + if (__put_user(task->thread.vr[i].u[j], data)) + return -EFAULT; -static int -set_thread_dabr(struct task_struct *tsk, unsigned long dabr) -{ - /* The bottom 3 bits are flags */ - if ((dabr & ~0x7UL) >= TASK_SIZE) - return -EIO; + /* copy VSCR */ + for (i = 0; i < 4; i++, data++) + if (__put_user(task->thread.vscr.u[i], data)) + return -EFAULT; - /* Ensure translation is on */ - if (dabr && !(dabr & DABR_TRANSLATION)) - return -EIO; + /* copy VRSAVE */ + if (__put_user(task->thread.vrsave, data)) + return -EFAULT; - tsk->thread.dabr = dabr; return 0; } -static int -debugreg_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.dabr, 0, -1); -} - -static int -debugreg_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +/* + * Write contents of AltiVec register state into task TASK. + */ +static inline int set_vrregs(struct task_struct *task, unsigned long __user *data) { - unsigned long dabr; - int ret; + int i, j; - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, &dabr, 0, -1); - if (ret == 0) - ret = set_thread_dabr(target, dabr); + if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long))) + return -EFAULT; - return ret; -} - -static int -ppc32_dabr_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - u32 dabr = target->thread.dabr; - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, &dabr, 0, -1); -} + /* copy AltiVec registers VR[0] .. VR[31] */ + for (i = 0; i < 32; i++) + for (j = 0; j < 4; j++, data++) + if (__get_user(task->thread.vr[i].u[j], data)) + return -EFAULT; -static int -ppc32_dabr_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - u32 dabr; - int ret; + /* copy VSCR */ + for (i = 0; i < 4; i++, data++) + if (__get_user(task->thread.vscr.u[i], data)) + return -EFAULT; - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, &dabr, 0, -1); - if (ret == 0) - ret = set_thread_dabr(target, dabr); + /* copy VRSAVE */ + if (__get_user(task->thread.vrsave, data)) + return -EFAULT; - return ret; + return 0; } -#endif /* CONFIG_PPC64 */ +#endif #ifdef CONFIG_SPE + /* * For get_evrregs/set_evrregs functions 'data' has the following layout: * @@ -265,447 +154,375 @@ ppc32_dabr_set(struct task_struct *target, * } */ -static int -evrregs_active(struct task_struct *target, const struct utrace_regset *regset) +/* + * Get contents of SPE register state in task TASK. + */ +static inline int get_evrregs(unsigned long *data, struct task_struct *task) { - if (target->thread.regs->msr & MSR_SPE) - giveup_spe(target); - return target->thread.used_spe ? regset->n : 0; -} + int i; -static int -evrregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - BUILD_BUG_ON(offsetof(struct thread_struct, acc) - != offsetof(struct thread_struct, evr[32])); - BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) - != offsetof(struct thread_struct, spefscr)); + if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long))) + return -EFAULT; - if (target->thread.regs->msr & MSR_SPE) - giveup_spe(target); + /* copy SPEFSCR */ + if (__put_user(task->thread.spefscr, &data[34])) + return -EFAULT; - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.evr, 0, -1); -} + /* copy SPE registers EVR[0] .. EVR[31] */ + for (i = 0; i < 32; i++, data++) + if (__put_user(task->thread.evr[i], data)) + return -EFAULT; -static int -evrregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - /* this is to clear the MSR_SPE bit to force a reload - * of register state from memory */ - if (target->thread.regs->msr & MSR_SPE) - giveup_spe(target); + /* copy ACC */ + if (__put_user64(task->thread.acc, (unsigned long long *)data)) + return -EFAULT; - return utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.evr, 0, -1); + return 0; } -#endif /* CONFIG_SPE */ - /* - * These are our native regset flavors. + * Write contents of SPE register state into task TASK. */ -static const struct utrace_regset native_regsets[] = { - { - .n = ELF_NGREG, .size = sizeof(long), .align = sizeof(long), - .get = genregs_get, .set = genregs_set - }, - { - .n = ELF_NFPREG, - .size = sizeof(double), .align = sizeof(double), - .get = fpregs_get, .set = fpregs_set - }, -#ifdef CONFIG_ALTIVEC - { - .n = 33*4+1, .size = sizeof(u32), .align = sizeof(u32), - .active = vrregs_active, .get = vrregs_get, .set = vrregs_set - }, -#endif -#ifdef CONFIG_SPE - { - .n = 35, .size = sizeof(long), .align = sizeof(long), - .active = evrregs_active, - .get = evrregs_get, .set = evrregs_set - }, -#endif -#ifdef CONFIG_PPC64 - { - .n = 1, .size = sizeof(long), .align = sizeof(long), - .get = debugreg_get, .set = debugreg_set - }, -#endif -}; - -const struct utrace_regset_view utrace_ppc_native_view = { - .name = UTS_MACHINE, .e_machine = ELF_ARCH, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_ppc_native_view); - - -#ifdef CONFIG_PPC64 -#include - -static int -ppc32_gpr_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +static inline int set_evrregs(struct task_struct *task, unsigned long *data) { - unsigned long *regs = (unsigned long *) target->thread.regs; + int i; - if (regs == NULL) - return -EIO; + if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long))) + return -EFAULT; - regs += pos / sizeof(u32); + /* copy SPEFSCR */ + if (__get_user(task->thread.spefscr, &data[34])) + return -EFAULT; - if (kbuf) { - u32 *out = kbuf; - for (; count > 0; count -= sizeof(u32)) - *out++ = *regs++; - } - else { - u32 __user *out = ubuf; - for (; count > 0; count -= sizeof(u32)) - if (put_user((u32) *regs++, out++)) - return -EFAULT; - } + /* copy SPE registers EVR[0] .. EVR[31] */ + for (i = 0; i < 32; i++, data++) + if (__get_user(task->thread.evr[i], data)) + return -EFAULT; + /* copy ACC */ + if (__get_user64(task->thread.acc, (unsigned long long*)data)) + return -EFAULT; return 0; } +#endif /* CONFIG_SPE */ -static int -ppc32_gpr_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +static inline void +set_single_step(struct task_struct *task) { - unsigned long *regs = (unsigned long *) target->thread.regs; + struct pt_regs *regs = task->thread.regs; - if (regs == NULL) - return -EIO; - - /* - * Just ignore attempts to set the registers beyond PT_LAST. - * They are read-only. - */ - if (count > (PT_LAST + 1) * sizeof(u32) - pos) - count = (PT_LAST + 1) * sizeof(u32) - pos; - - pos /= sizeof(u32); - - if (kbuf) { - const u32 *in = kbuf; - for (; count > 0; count -= sizeof(u32), ++pos, ++in) { - if (pos == PT_MSR) - regs[pos] = ((regs[pos] &~ MSR_DEBUGCHANGE) - | (*in & MSR_DEBUGCHANGE)); - else - regs[pos] = *in; - } - } - else { - const u32 __user *in = kbuf; - for (; count > 0; count -= sizeof(u32), ++pos) { - u32 val; - if (get_user(val, in++)) - return -EFAULT; - else if (pos == PT_MSR) - regs[pos] = ((regs[pos] &~ MSR_DEBUGCHANGE) - | (val & MSR_DEBUGCHANGE)); - else - regs[pos] = val; - } + if (regs != NULL) { +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC; + regs->msr |= MSR_DE; +#else + regs->msr |= MSR_SE; +#endif } - - return 0; } -/* - * These are the regset flavors matching the CONFIG_PPC32 native set. - */ -static const struct utrace_regset ppc32_regsets[] = { - { - .n = ELF_NGREG, - .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), - .get = ppc32_gpr_get, .set = ppc32_gpr_set - }, - { - .n = ELF_NFPREG, - .size = sizeof(double), .align = sizeof(double), - .get = fpregs_get, .set = fpregs_set - }, -#ifdef CONFIG_ALTIVEC - { - .n = 33*4+1, .size = sizeof(u32), .align = sizeof(u32), - .active = vrregs_active, .get = vrregs_get, .set = vrregs_set - }, -#endif - { - .n = 1, - .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), - .get = ppc32_dabr_get, .set = ppc32_dabr_set - }, -}; - -const struct utrace_regset_view utrace_ppc32_view = { - .name = "ppc", .e_machine = EM_PPC, - .regsets = ppc32_regsets, - .n = sizeof ppc32_regsets / sizeof ppc32_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_ppc32_view); -#endif - - -#ifdef CONFIG_PTRACE -static const struct ptrace_layout_segment ppc_uarea[] = { - {0, PT_FPR0 * sizeof(long), 0, 0}, - {PT_FPR0 * sizeof(long), (PT_FPSCR + 1) * sizeof(long), 1, 0}, - {0, 0, -1, 0} -}; - -fastcall int arch_ptrace(long *request, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, long *val) +static inline void +clear_single_step(struct task_struct *task) { - switch (*request) { - case PTRACE_PEEKUSR: - return ptrace_peekusr(child, engine, ppc_uarea, addr, data); - case PTRACE_POKEUSR: - return ptrace_pokeusr(child, engine, ppc_uarea, addr, data); - case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ - case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ - return ptrace_regset_access(child, engine, - utrace_native_view(current), 0, - 0, 32 * sizeof(long), - (void __user *)addr, - *request == PPC_PTRACE_SETREGS); - case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ - case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */ - return ptrace_regset_access(child, engine, - utrace_native_view(current), 1, - 0, 32 * sizeof(double), - (void __user *)addr, - *request == PPC_PTRACE_SETFPREGS); -#ifdef CONFIG_PPC64 - case PTRACE_GET_DEBUGREG: - case PTRACE_SET_DEBUGREG: - return ptrace_onereg_access(child, engine, - utrace_native_view(current), 3, - addr, (unsigned long __user *)data, - *request == PTRACE_SET_DEBUGREG); -#endif /* CONFIG_PPC64 */ -#ifdef CONFIG_ALTIVEC - case PTRACE_GETVRREGS: - return ptrace_whole_regset(child, engine, data, 2, 0); - case PTRACE_SETVRREGS: - return ptrace_whole_regset(child, engine, data, 2, 1); -#endif -#ifdef CONFIG_SPE -#ifdef CONFIG_ALTIVEC -#define REGSET_EVR 3 + struct pt_regs *regs = task->thread.regs; + + if (regs != NULL) { +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + task->thread.dbcr0 = 0; + regs->msr &= ~MSR_DE; #else -#define REGSET_EVR 2 -#endif - case PTRACE_GETEVRREGS: - return ptrace_whole_regset(child, engine, data, REGSET_EVR, 0); - case PTRACE_SETEVRREGS: - return ptrace_whole_regset(child, engine, data, REGSET_EVR, 1); + regs->msr &= ~MSR_SE; #endif } - return -ENOSYS; } +#endif /* CONFIG_PPC32 */ -#ifdef CONFIG_COMPAT -#include -#include +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* make sure the single step bit is not set. */ + clear_single_step(child); +} -static const struct ptrace_layout_segment ppc32_uarea[] = { - {0, PT_FPR0 * sizeof(u32), 0, 0}, - {PT_FPR0 * sizeof(u32), (PT_FPSCR32 + 1) * sizeof(u32), 1, 0}, - {0, 0, -1, 0} -}; - -fastcall int arch_compat_ptrace(compat_long_t *request, - struct task_struct *child, - struct utrace_attached_engine *engine, - compat_ulong_t addr, compat_ulong_t data, - compat_long_t *val) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - void __user *uaddr = (void __user *) (unsigned long) addr; - int ret = -ENOSYS; - - switch (*request) { - case PTRACE_PEEKUSR: - return ptrace_compat_peekusr(child, engine, ppc32_uarea, - addr, data); - case PTRACE_POKEUSR: - return ptrace_compat_pokeusr(child, engine, ppc32_uarea, - addr, data); - - case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ - case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ - return ptrace_regset_access(child, engine, - utrace_native_view(current), 0, - 0, 32 * sizeof(compat_long_t), - uaddr, - *request == PPC_PTRACE_SETREGS); - case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ - case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */ - return ptrace_regset_access(child, engine, - utrace_native_view(current), 1, - 0, 32 * sizeof(double), - uaddr, - *request == PPC_PTRACE_SETFPREGS); -#ifdef CONFIG_ALTIVEC - case PTRACE_GETVRREGS: - return ptrace_whole_regset(child, engine, data, 2, 0); - case PTRACE_SETVRREGS: - return ptrace_whole_regset(child, engine, data, 2, 1); -#endif - case PTRACE_GET_DEBUGREG: - case PTRACE_SET_DEBUGREG: - return ptrace_onereg_access(child, engine, - utrace_native_view(current), 3, - addr, - (unsigned long __user *) - (unsigned long) data, - *request == PTRACE_SET_DEBUGREG); + int ret = -EPERM; - /* - * Read 4 bytes of the other process' storage - * data is a pointer specifying where the user wants the - * 4 bytes copied into - * addr is a pointer in the user's storage that contains an 8 byte - * address in the other process of the 4 bytes that is to be read - * (this is run in a 32-bit process looking at a 64-bit process) - * when I and D space are separate, these will need to be fixed. - */ - case PPC_PTRACE_PEEKTEXT_3264: - case PPC_PTRACE_PEEKDATA_3264: { - u32 tmp; + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; int copied; - u32 __user * addrOthers; + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); ret = -EIO; - - /* Get the addr in the other process that we want to read */ - if (get_user(addrOthers, ((u32 __user * __user *) - (unsigned long) addr)) != 0) - break; - - copied = access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 0); if (copied != sizeof(tmp)) break; - ret = put_user(tmp, (u32 __user *)(unsigned long)data); + ret = put_user(tmp,(unsigned long __user *) data); break; } - /* - * Write 4 bytes into the other process' storage - * data is the 4 bytes that the user wants written - * addr is a pointer in the user's storage that contains an - * 8 byte address in the other process where the 4 bytes - * that is to be written - * (this is run in a 32-bit process looking at a 64-bit process) - * when I and D space are separate, these will need to be fixed. - */ - case PPC_PTRACE_POKETEXT_3264: - case PPC_PTRACE_POKEDATA_3264: { - u32 tmp = data; - u32 __user * addrOthers; + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long index, tmp; - /* Get the addr in the other process that we want to write into */ ret = -EIO; - if (get_user(addrOthers, ((u32 __user * __user *) - (unsigned long) addr)) != 0) + /* convert to index and check */ +#ifdef CONFIG_PPC32 + index = (unsigned long) addr >> 2; + if ((addr & 3) || (index > PT_FPSCR) + || (child->thread.regs == NULL)) +#else + index = (unsigned long) addr >> 3; + if ((addr & 7) || (index > PT_FPSCR)) +#endif break; + +#ifdef CONFIG_PPC32 + CHECK_FULL_REGS(child->thread.regs); +#endif + if (index < PT_FPR0) { + tmp = get_reg(child, (int) index); + } else { + flush_fp_to_thread(child); + tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; + } + ret = put_user(tmp,(unsigned long __user *) data); + break; + } + + /* If I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: ret = 0; - if (access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 1) == sizeof(tmp)) + if (access_process_vm(child, addr, &data, sizeof(data), 1) + == sizeof(data)) break; ret = -EIO; break; - } - /* - * This is like PTRACE_PEEKUSR on a 64-bit process, - * but here we access only 4 bytes at a time. - */ - case PPC_PTRACE_PEEKUSR_3264: { - union - { - u64 whole; - u32 half[2]; - } reg; - int setno; - const struct utrace_regset *regset; + /* write the word at location addr in the USER area */ + case PTRACE_POKEUSR: { + unsigned long index; ret = -EIO; - if ((addr & 3) || addr > PT_FPSCR*8) + /* convert to index and check */ +#ifdef CONFIG_PPC32 + index = (unsigned long) addr >> 2; + if ((addr & 3) || (index > PT_FPSCR) + || (child->thread.regs == NULL)) +#else + index = (unsigned long) addr >> 3; + if ((addr & 7) || (index > PT_FPSCR)) +#endif break; - setno = 0; - if (addr >= PT_FPR0*8) { - setno = 1; - addr -= PT_FPR0*8; +#ifdef CONFIG_PPC32 + CHECK_FULL_REGS(child->thread.regs); +#endif + if (index == PT_ORIG_R3) + break; + if (index < PT_FPR0) { + ret = put_reg(child, index, data); + } else { + flush_fp_to_thread(child); + ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; + ret = 0; } - regset = utrace_regset(child, NULL, - &utrace_ppc_native_view, setno); - ret = (*regset->get)(child, regset, addr &~ 7, - sizeof(reg.whole), ®.whole, NULL); - if (ret == 0) - ret = put_user(reg.half[(addr >> 2) & 1], - (u32 __user *)(unsigned long)data); break; } - /* - * This is like PTRACE_POKEUSR on a 64-bit process, - * but here we access only 4 bytes at a time. - */ - case PPC_PTRACE_POKEUSR_3264: { - union - { - u64 whole; - u32 half[2]; - } reg; - int setno; - const struct utrace_regset *regset; + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + ret = 0; + break; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + break; + } + case PTRACE_SINGLESTEP: { /* set the trap flag. */ ret = -EIO; - if ((addr & 3) || addr > PT_FPSCR*8) + if (!valid_signal(data)) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + set_single_step(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + +#ifdef CONFIG_PPC64 + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) break; + ret = put_user(child->thread.dabr, + (unsigned long __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; +#endif + + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + for (i = 0; i < 32; i++) { + ret = put_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + for (i = 0; i < 32; i++) { + ret = get_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; + + flush_fp_to_thread(child); + + for (i = 0; i < 32; i++) { + ret = put_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; + unsigned long __user *tmp = (unsigned long __user *)addr; - setno = 0; - if (addr >= PT_FPR0*8) { - setno = 1; - addr -= PT_FPR0*8; + flush_fp_to_thread(child); + + for (i = 0; i < 32; i++) { + ret = get_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; } - regset = utrace_regset(child, NULL, - &utrace_ppc_native_view, setno); - ret = (*regset->get)(child, regset, addr &~ 7, - sizeof(reg.whole), ®.whole, NULL); - BUG_ON(ret); - reg.half[(addr >> 2) & 1] = data; - ret = (*regset->set)(child, regset, addr &~ 7, - sizeof(reg.whole), ®.whole, NULL); break; } + +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif +#ifdef CONFIG_SPE + case PTRACE_GETEVRREGS: + /* Get the child spe register state. */ + if (child->thread.regs->msr & MSR_SPE) + giveup_spe(child); + ret = get_evrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETEVRREGS: + /* Set the child spe register state. */ + /* this is to clear the MSR_SPE bit to force a reload + * of register state from memory */ + if (child->thread.regs->msr & MSR_SPE) + giveup_spe(child); + ret = set_evrregs(child, (unsigned long __user *)data); + break; +#endif + + default: + ret = ptrace_request(child, request, addr, data); + break; } + return ret; } -#endif /* CONFIG_COMPAT */ -#endif /* CONFIG_PTRACE */ +static void do_syscall_trace(void) +{ + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} void do_syscall_trace_enter(struct pt_regs *regs) { @@ -713,8 +530,9 @@ void do_syscall_trace_enter(struct pt_regs *regs) secure_computing(regs->gpr[0]); #endif - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, 0); + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); if (unlikely(current->audit_context)) audit_syscall_entry( @@ -738,13 +556,10 @@ void do_syscall_trace_leave(struct pt_regs *regs) audit_syscall_exit((regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, regs->result); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, 1); - - if (test_thread_flag(TIF_SINGLESTEP)) { - force_sig(SIGTRAP, current); /* XXX */ - tracehook_report_syscall_step(regs); - } + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); } #ifdef CONFIG_PPC32 diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index e69de29bb..9b9a23034 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -0,0 +1,436 @@ +/* + * ptrace for 32-bit processes running on a 64-bit kernel. + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Derived from "arch/m68k/kernel/ptrace.c" + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * Modified by Cort Dougan (cort@hq.fsmlabs.com) + * and Paul Mackerras (paulus@samba.org). + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ptrace-common.h" + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +long compat_sys_ptrace(int request, int pid, unsigned long addr, + unsigned long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); + goto out; + } + + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out_tsk; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned int tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp, (u32 __user *)data); + break; + } + + /* + * Read 4 bytes of the other process' storage + * data is a pointer specifying where the user wants the + * 4 bytes copied into + * addr is a pointer in the user's storage that contains an 8 byte + * address in the other process of the 4 bytes that is to be read + * (this is run in a 32-bit process looking at a 64-bit process) + * when I and D space are separate, these will need to be fixed. + */ + case PPC_PTRACE_PEEKTEXT_3264: + case PPC_PTRACE_PEEKDATA_3264: { + u32 tmp; + int copied; + u32 __user * addrOthers; + + ret = -EIO; + + /* Get the addr in the other process that we want to read */ + if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) + break; + + copied = access_process_vm(child, (u64)addrOthers, &tmp, + sizeof(tmp), 0); + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp, (u32 __user *)data); + break; + } + + /* Read a register (specified by ADDR) out of the "user area" */ + case PTRACE_PEEKUSR: { + int index; + unsigned long tmp; + + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 2; + if ((addr & 3) || (index > PT_FPSCR32)) + break; + + if (index < PT_FPR0) { + tmp = get_reg(child, index); + } else { + flush_fp_to_thread(child); + /* + * the user space code considers the floating point + * to be an array of unsigned int (32 bits) - the + * index passed in is based on this assumption. + */ + tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0]; + } + ret = put_user((unsigned int)tmp, (u32 __user *)data); + break; + } + + /* + * Read 4 bytes out of the other process' pt_regs area + * data is a pointer specifying where the user wants the + * 4 bytes copied into + * addr is the offset into the other process' pt_regs structure + * that is to be read + * (this is run in a 32-bit process looking at a 64-bit process) + */ + case PPC_PTRACE_PEEKUSR_3264: { + u32 index; + u32 reg32bits; + u64 tmp; + u32 numReg; + u32 part; + + ret = -EIO; + /* Determine which register the user wants */ + index = (u64)addr >> 2; + numReg = index / 2; + /* Determine which part of the register the user wants */ + if (index % 2) + part = 1; /* want the 2nd half of the register (right-most). */ + else + part = 0; /* want the 1st half of the register (left-most). */ + + /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ + if ((addr & 3) || numReg > PT_FPSCR) + break; + + if (numReg >= PT_FPR0) { + flush_fp_to_thread(child); + tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; + } else { /* register within PT_REGS struct */ + tmp = get_reg(child, numReg); + } + reg32bits = ((u32*)&tmp)[part]; + ret = put_user(reg32bits, (u32 __user *)data); + break; + } + + /* If I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: { + unsigned int tmp; + tmp = data; + ret = 0; + if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) + == sizeof(tmp)) + break; + ret = -EIO; + break; + } + + /* + * Write 4 bytes into the other process' storage + * data is the 4 bytes that the user wants written + * addr is a pointer in the user's storage that contains an + * 8 byte address in the other process where the 4 bytes + * that is to be written + * (this is run in a 32-bit process looking at a 64-bit process) + * when I and D space are separate, these will need to be fixed. + */ + case PPC_PTRACE_POKETEXT_3264: + case PPC_PTRACE_POKEDATA_3264: { + u32 tmp = data; + u32 __user * addrOthers; + + /* Get the addr in the other process that we want to write into */ + ret = -EIO; + if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) + break; + ret = 0; + if (access_process_vm(child, (u64)addrOthers, &tmp, + sizeof(tmp), 1) == sizeof(tmp)) + break; + ret = -EIO; + break; + } + + /* write the word at location addr in the USER area */ + case PTRACE_POKEUSR: { + unsigned long index; + + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 2; + if ((addr & 3) || (index > PT_FPSCR32)) + break; + + if (index == PT_ORIG_R3) + break; + if (index < PT_FPR0) { + ret = put_reg(child, index, data); + } else { + flush_fp_to_thread(child); + /* + * the user space code considers the floating point + * to be an array of unsigned int (32 bits) - the + * index passed in is based on this assumption. + */ + ((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data; + ret = 0; + } + break; + } + + /* + * Write 4 bytes into the other process' pt_regs area + * data is the 4 bytes that the user wants written + * addr is the offset into the other process' pt_regs structure + * that is to be written into + * (this is run in a 32-bit process looking at a 64-bit process) + */ + case PPC_PTRACE_POKEUSR_3264: { + u32 index; + u32 numReg; + + ret = -EIO; + /* Determine which register the user wants */ + index = (u64)addr >> 2; + numReg = index / 2; + /* + * Validate the input - check to see if address is on the + * wrong boundary or beyond the end of the user area + */ + if ((addr & 3) || (numReg > PT_FPSCR)) + break; + /* Insure it is a register we let them change */ + if ((numReg == PT_ORIG_R3) + || ((numReg > PT_CCR) && (numReg < PT_FPR0))) + break; + if (numReg >= PT_FPR0) { + flush_fp_to_thread(child); + } + if (numReg == PT_MSR) + data = (data & MSR_DEBUGCHANGE) + | (child->thread.regs->msr & ~MSR_DEBUGCHANGE); + ((u32*)child->thread.regs)[index] = data; + ret = 0; + break; + } + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + ret = 0; + break; + } + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if (!valid_signal(data)) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + set_single_step(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_GET_DEBUGREG: { + ret = -EINVAL; + /* We only support one DABR and no IABRS at the moment */ + if (addr > 0) + break; + ret = put_user(child->thread.dabr, (u32 __user *)data); + break; + } + + case PTRACE_SET_DEBUGREG: + ret = ptrace_set_debugreg(child, addr, data); + break; + + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; + unsigned int __user *tmp = (unsigned int __user *)addr; + + for (i = 0; i < 32; i++) { + ret = put_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; + unsigned int __user *tmp = (unsigned int __user *)addr; + + for (i = 0; i < 32; i++) { + ret = get_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; + unsigned int __user *tmp = (unsigned int __user *)addr; + + flush_fp_to_thread(child); + + for (i = 0; i < 32; i++) { + ret = put_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ + int i; + unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; + unsigned int __user *tmp = (unsigned int __user *)addr; + + flush_fp_to_thread(child); + + for (i = 0; i < 32; i++) { + ret = get_user(*reg, tmp); + if (ret) + break; + reg++; + tmp++; + } + break; + } + + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, (unsigned int __user *) data); + break; + +#ifdef CONFIG_ALTIVEC + case PTRACE_GETVRREGS: + /* Get the child altivec register state. */ + flush_altivec_to_thread(child); + ret = get_vrregs((unsigned long __user *)data, child); + break; + + case PTRACE_SETVRREGS: + /* Set the child altivec register state. */ + flush_altivec_to_thread(child); + ret = set_vrregs(child, (unsigned long __user *)data); + break; +#endif + + default: + ret = ptrace_request(child, request, addr, data); + break; + } +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return ret; +} diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 9c97be0c1..320353f09 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -25,7 +25,6 @@ #include #include #include -#include #ifdef CONFIG_PPC64 #include #include @@ -632,58 +631,6 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s) #define copy_siginfo_to_user copy_siginfo_to_user32 -/* mostly stolen from arch/s390/kernel/compat_signal.c */ -int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) -{ - int err; - u32 tmp; - - if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t))) - return -EFAULT; - - err = __get_user(to->si_signo, &from->si_signo); - err |= __get_user(to->si_errno, &from->si_errno); - err |= __get_user(to->si_code, &from->si_code); - - if (to->si_code < 0) - err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); - else { - switch (to->si_code >> 16) { - case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ - case __SI_MESGQ >> 16: - err |= __get_user(to->si_int, &from->si_int); - /* fallthrough */ - case __SI_KILL >> 16: - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - break; - case __SI_CHLD >> 16: - err |= __get_user(to->si_pid, &from->si_pid); - err |= __get_user(to->si_uid, &from->si_uid); - err |= __get_user(to->si_utime, &from->si_utime); - err |= __get_user(to->si_stime, &from->si_stime); - err |= __get_user(to->si_status, &from->si_status); - break; - case __SI_FAULT >> 16: - err |= __get_user(tmp, &from->si_addr); - to->si_addr = (void __user *)(u64) tmp; - break; - case __SI_POLL >> 16: - err |= __get_user(to->si_band, &from->si_band); - err |= __get_user(to->si_fd, &from->si_fd); - break; - case __SI_TIMER >> 16: - err |= __get_user(to->si_tid, &from->si_tid); - err |= __get_user(to->si_overrun, &from->si_overrun); - err |= __get_user(to->si_int, &from->si_int); - break; - default: - break; - } - } - return err; -} - /* * Note: it is necessary to treat pid and sig as unsigned ints, with the * corresponding cast to a signed int to insure that the proper conversion @@ -1269,8 +1216,6 @@ no_signal: its frame, and we can clear the TIF_RESTORE_SIGMASK flag */ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); - - tracehook_report_handle_signal(signr, &ka, oldset, regs); } return ret; diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index ab6ceaa85..f72e8e823 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -460,8 +459,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - - tracehook_report_handle_signal(sig, ka, oldset, regs); } return ret; diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 4b3b2af86..245717844 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -438,6 +438,11 @@ long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } putname(filename); out: diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 9b352bd0a..20780f83f 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -818,7 +818,7 @@ void __kprobes program_check_exception(struct pt_regs *regs) void alignment_exception(struct pt_regs *regs) { - int fixed = 0; + int sig, code, fixed = 0; /* we don't implement logging of alignment exceptions */ if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) @@ -832,14 +832,16 @@ void alignment_exception(struct pt_regs *regs) /* Operand address was bad */ if (fixed == -EFAULT) { - if (user_mode(regs)) - _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); - else - /* Search exception table */ - bad_page_fault(regs, regs->dar, SIGSEGV); - return; + sig = SIGSEGV; + code = SEGV_ACCERR; + } else { + sig = SIGBUS; + code = BUS_ADRALN; } - _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); + if (user_mode(regs)) + _exception(sig, regs, code, regs->dar); + else + bad_page_fault(regs, regs->dar, sig); } void StackOverflow(struct pt_regs *regs) diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 50f6b7a93..9590ba780 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -12,9 +12,6 @@ #include #include #include -#ifdef CONFIG_PPC64 -#include -#endif extern char system_call_common[]; diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 545d85c70..483c8b762 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -51,7 +51,6 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, if (signal_pending(current)) ret = -ERESTARTSYS; -#if 0 /* XXX */ if (unlikely(current->ptrace & PT_PTRACED)) { if ((*status & SPU_STATUS_STOPPED_BY_STOP) && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { @@ -59,7 +58,6 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, ret = -ERESTARTSYS; } } -#endif return ret; } diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c index 99b09f934..1f91eca2f 100644 --- a/arch/ppc/kernel/asm-offsets.c +++ b/arch/ppc/kernel/asm-offsets.c @@ -37,6 +37,7 @@ main(void) DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(KSP, offsetof(struct thread_struct, ksp)); DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall)); @@ -46,6 +47,7 @@ main(void) DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); + DEFINE(PT_PTRACED, PT_PTRACED); #endif #ifdef CONFIG_ALTIVEC DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index d7a433049..0193cc471 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -708,7 +708,7 @@ void single_step_exception(struct pt_regs *regs) void alignment_exception(struct pt_regs *regs) { - int fixed; + int sig, code, fixed = 0; fixed = fix_alignment(regs); if (fixed == 1) { @@ -717,14 +717,16 @@ void alignment_exception(struct pt_regs *regs) return; } if (fixed == -EFAULT) { - /* fixed == -EFAULT means the operand address was bad */ - if (user_mode(regs)) - _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); - else - bad_page_fault(regs, regs->dar, SIGSEGV); - return; + sig = SIGSEGV; + code = SEGV_ACCERR; + } else { + sig = SIGBUS; + code = BUS_ADRALN; } - _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); + if (user_mode(regs)) + _exception(sig, regs, code, regs->dar); + else + bad_page_fault(regs, regs->dar, sig); } void StackOverflow(struct pt_regs *regs) diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index c7483744a..9a33ed6ca 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -34,5 +34,3 @@ obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS) # This is just to get the dependencies... # binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c - -CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index e41ba9f6a..86e5f9983 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -545,6 +545,9 @@ sys32_execve(struct pt_regs regs) compat_ptr(regs.gprs[4]), ®s); if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); current->thread.fp_regs.fpc=0; __asm__ __volatile__ ("sr 0,0\n\t" diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 310d16891..d49b876a8 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -28,7 +28,6 @@ #include #include #include -#include #include "compat_linux.h" #include "compat_ptrace.h" @@ -580,9 +579,7 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - - tracehook_report_handle_signal(sig, ka, oldset, regs); } - return ret; } + diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 12e98a089..4bffc3aa9 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -331,6 +331,9 @@ asmlinkage long sys_execve(struct pt_regs regs) error = do_execve(filename, (char __user * __user *) regs.gprs[3], (char __user * __user *) regs.gprs[4], ®s); if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); current->thread.fp_regs.fpc = 0; if (MACHINE_HAS_IEEE) asm volatile("sfpc %0,%0" : : "d" (0)); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 395bd3a50..5a3bb177f 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -29,8 +29,6 @@ #include #include #include -#include -#include #include #include #include @@ -43,7 +41,6 @@ #include #include #include -#include #ifdef CONFIG_COMPAT #include "compat_ptrace.h" @@ -87,598 +84,657 @@ FixPerRegisters(struct task_struct *task) per_info->control_regs.bits.storage_alt_space_ctl = 1; else per_info->control_regs.bits.storage_alt_space_ctl = 0; - - if (task == current) - /* - * These registers are loaded in __switch_to on - * context switch. We must load them now if - * touching the current thread. - */ - __ctl_load(per_info->control_regs.words.cr, 9, 11); } void -tracehook_enable_single_step(struct task_struct *task) +set_single_step(struct task_struct *task) { task->thread.per_info.single_step = 1; FixPerRegisters(task); } void -tracehook_disable_single_step(struct task_struct *task) +clear_single_step(struct task_struct *task) { task->thread.per_info.single_step = 0; FixPerRegisters(task); - clear_tsk_thread_flag(task, TIF_SINGLE_STEP); } -int -tracehook_single_step_enabled(struct task_struct *task) +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void +ptrace_disable(struct task_struct *child) { - return task->thread.per_info.single_step; + /* make sure the single step bit is not set. */ + clear_single_step(child); } +#ifndef CONFIG_64BIT +# define __ADDR_MASK 3 +#else +# define __ADDR_MASK 7 +#endif +/* + * Read the word at offset addr from the user area of a process. The + * trouble here is that the information is littered over different + * locations. The process registers are found on the kernel stack, + * the floating point stuff and the trace settings are stored in + * the task structure. In addition the different structures in + * struct user contain pad bytes that should be read as zeroes. + * Lovely... + */ static int -genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +peek_user(struct task_struct *child, addr_t addr, addr_t data) { - struct pt_regs *regs = task_pt_regs(target); - unsigned long pswmask; - int ret; - - /* Remove per bit from user psw. */ - pswmask = regs->psw.mask & ~PSW_MASK_PER; - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &pswmask, PT_PSWMASK, PT_PSWADDR); - - /* The rest of the PSW and the GPRs are directly on the stack. */ - if (ret == 0) - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - ®s->psw.addr, PT_PSWADDR, - PT_ACR0); - - /* The ACRs are kept in the thread_struct. */ - if (ret == 0 && count > 0 && pos < PT_ORIGGPR2) { - if (target == current) - save_access_regs(target->thread.acrs); - - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - target->thread.acrs, - PT_ACR0, PT_ORIGGPR2); - } + struct user *dummy = NULL; + addr_t offset, tmp, mask; - /* Finally, the ORIG_GPR2 value. */ - if (ret == 0) - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - ®s->orig_gpr2, PT_ORIGGPR2, -1); + /* + * Stupid gdb peeks/pokes the access registers in 64 bit with + * an alignment of 4. Programmers from hell... + */ + mask = __ADDR_MASK; +#ifdef CONFIG_64BIT + if (addr >= (addr_t) &dummy->regs.acrs && + addr < (addr_t) &dummy->regs.orig_gpr2) + mask = 3; +#endif + if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) + return -EIO; - return ret; -} + if (addr < (addr_t) &dummy->regs.acrs) { + /* + * psw and gprs are stored on the stack + */ + tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr); + if (addr == (addr_t) &dummy->regs.psw.mask) + /* Remove per bit from user psw. */ + tmp &= ~PSW_MASK_PER; -static int -genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - struct pt_regs *regs = task_pt_regs(target); - int ret = 0; - - /* Check for an invalid PSW mask. */ - if (count > 0 && pos == PT_PSWMASK) { - unsigned long pswmask = regs->psw.mask; - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &pswmask, PT_PSWMASK, PT_PSWADDR); - if (pswmask != PSW_MASK_MERGE(PSW_USER_BITS, pswmask) -#ifdef CONFIG_COMPAT - && pswmask != PSW_MASK_MERGE(PSW_USER32_BITS, pswmask) + } else if (addr < (addr_t) &dummy->regs.orig_gpr2) { + /* + * access registers are stored in the thread structure + */ + offset = addr - (addr_t) &dummy->regs.acrs; +#ifdef CONFIG_64BIT + /* + * Very special case: old & broken 64 bit gdb reading + * from acrs[15]. Result is a 64 bit value. Read the + * 32 bit acrs[15] value and shift it by 32. Sick... + */ + if (addr == (addr_t) &dummy->regs.acrs[15]) + tmp = ((unsigned long) child->thread.acrs[15]) << 32; + else #endif - ) - /* Invalid psw mask. */ - return -EINVAL; - regs->psw.mask = pswmask; - FixPerRegisters(target); - } + tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset); - /* The rest of the PSW and the GPRs are directly on the stack. */ - if (ret == 0) { - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - ®s->psw.addr, PT_PSWADDR, - PT_ACR0); -#ifndef CONFIG_64BIT - /* I'd like to reject addresses without the - high order bit but older gdb's rely on it */ - regs->psw.addr |= PSW_ADDR_AMODE; -#endif - } + } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { + /* + * orig_gpr2 is stored on the kernel stack + */ + tmp = (addr_t) task_pt_regs(child)->orig_gpr2; - /* The ACRs are kept in the thread_struct. */ - if (ret == 0 && count > 0 && pos < PT_ORIGGPR2) { - if (target == current - && (pos != PT_ACR0 || count < sizeof(target->thread.acrs))) - save_access_regs(target->thread.acrs); - - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - target->thread.acrs, - PT_ACR0, PT_ORIGGPR2); - if (ret == 0 && target == current) - restore_access_regs(target->thread.acrs); - } + } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { + /* + * floating point regs. are stored in the thread structure + */ + offset = addr - (addr_t) &dummy->regs.fp_regs; + tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); + if (addr == (addr_t) &dummy->regs.fp_regs.fpc) + tmp &= (unsigned long) FPC_VALID_MASK + << (BITS_PER_LONG - 32); - /* Finally, the ORIG_GPR2 value. */ - if (ret == 0) - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - ®s->orig_gpr2, PT_ORIGGPR2, -1); + } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { + /* + * per_info is found in the thread structure + */ + offset = addr - (addr_t) &dummy->regs.per_info; + tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset); - return ret; + } else + tmp = 0; + + return put_user(tmp, (addr_t __user *) data); } +/* + * Write a word to the user area of a process at location addr. This + * operation does have an additional problem compared to peek_user. + * Stores to the program status word and on the floating point + * control register needs to get checked for validity. + */ static int -fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +poke_user(struct task_struct *child, addr_t addr, addr_t data) { - if (target == current) - save_fp_regs(&target->thread.fp_regs); + struct user *dummy = NULL; + addr_t offset, mask; - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fp_regs, 0, -1); -} + /* + * Stupid gdb peeks/pokes the access registers in 64 bit with + * an alignment of 4. Programmers from hell indeed... + */ + mask = __ADDR_MASK; +#ifdef CONFIG_64BIT + if (addr >= (addr_t) &dummy->regs.acrs && + addr < (addr_t) &dummy->regs.orig_gpr2) + mask = 3; +#endif + if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) + return -EIO; -static int -fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret = 0; + if (addr < (addr_t) &dummy->regs.acrs) { + /* + * psw and gprs are stored on the stack + */ + if (addr == (addr_t) &dummy->regs.psw.mask && +#ifdef CONFIG_COMPAT + data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && +#endif + data != PSW_MASK_MERGE(PSW_USER_BITS, data)) + /* Invalid psw mask. */ + return -EINVAL; +#ifndef CONFIG_64BIT + if (addr == (addr_t) &dummy->regs.psw.addr) + /* I'd like to reject addresses without the + high order bit but older gdb's rely on it */ + data |= PSW_ADDR_AMODE; +#endif + *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; - if (target == current && (pos != 0 || count != sizeof(s390_fp_regs))) - save_fp_regs(&target->thread.fp_regs); + } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { + /* + * access registers are stored in the thread structure + */ + offset = addr - (addr_t) &dummy->regs.acrs; +#ifdef CONFIG_64BIT + /* + * Very special case: old & broken 64 bit gdb writing + * to acrs[15] with a 64 bit value. Ignore the lower + * half of the value and write the upper 32 bit to + * acrs[15]. Sick... + */ + if (addr == (addr_t) &dummy->regs.acrs[15]) + child->thread.acrs[15] = (unsigned int) (data >> 32); + else +#endif + *(addr_t *)((addr_t) &child->thread.acrs + offset) = data; - /* If setting FPC, must validate it first. */ - if (count > 0 && pos == 0) { - unsigned long fpc; - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpc, 0, sizeof(fpc)); - if (ret) - return ret; + } else if (addr == (addr_t) &dummy->regs.orig_gpr2) { + /* + * orig_gpr2 is stored on the kernel stack + */ + task_pt_regs(child)->orig_gpr2 = data; - if ((fpc & ~((unsigned long) FPC_VALID_MASK - << (BITS_PER_LONG - 32))) != 0) + } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { + /* + * floating point regs. are stored in the thread structure + */ + if (addr == (addr_t) &dummy->regs.fp_regs.fpc && + (data & ~((unsigned long) FPC_VALID_MASK + << (BITS_PER_LONG - 32))) != 0) return -EINVAL; + offset = addr - (addr_t) &dummy->regs.fp_regs; + *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; - memcpy(&target->thread.fp_regs, &fpc, sizeof(fpc)); - } - - if (ret == 0) - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.fp_regs, 0, -1); + } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { + /* + * per_info is found in the thread structure + */ + offset = addr - (addr_t) &dummy->regs.per_info; + *(addr_t *)((addr_t) &child->thread.per_info + offset) = data; - if (ret == 0 && target == current) - restore_fp_regs(&target->thread.fp_regs); + } - return ret; + FixPerRegisters(child); + return 0; } static int -per_info_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +do_ptrace_normal(struct task_struct *child, long request, long addr, long data) { - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.per_info, 0, -1); -} + unsigned long tmp; + ptrace_area parea; + int copied, ret; -static int -per_info_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.per_info, 0, -1); + switch (request) { + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + /* Remove high order bit from address (only for 31 bit). */ + addr &= PSW_ADDR_INSN; + /* read word at location addr. */ + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (copied != sizeof(tmp)) + return -EIO; + return put_user(tmp, (unsigned long __user *) data); - FixPerRegisters(target); + case PTRACE_PEEKUSR: + /* read the word at location addr in the USER area. */ + return peek_user(child, addr, data); - return ret; -} + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + /* Remove high order bit from address (only for 31 bit). */ + addr &= PSW_ADDR_INSN; + /* write the word at location addr. */ + copied = access_process_vm(child, addr, &data, sizeof(data),1); + if (copied != sizeof(data)) + return -EIO; + return 0; + + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area */ + return poke_user(child, addr, data); + case PTRACE_PEEKUSR_AREA: + case PTRACE_POKEUSR_AREA: + if (copy_from_user(&parea, (void __user *) addr, + sizeof(parea))) + return -EFAULT; + addr = parea.kernel_addr; + data = parea.process_addr; + copied = 0; + while (copied < parea.len) { + if (request == PTRACE_PEEKUSR_AREA) + ret = peek_user(child, addr, data); + else { + addr_t tmp; + if (get_user (tmp, (addr_t __user *) data)) + return -EFAULT; + ret = poke_user(child, addr, tmp); + } + if (ret) + return ret; + addr += sizeof(unsigned long); + data += sizeof(unsigned long); + copied += sizeof(unsigned long); + } + return 0; + } + return ptrace_request(child, request, addr, data); +} +#ifdef CONFIG_COMPAT /* - * These are our native regset flavors. + * Now the fun part starts... a 31 bit program running in the + * 31 bit emulation tracing another program. PTRACE_PEEKTEXT, + * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy + * to handle, the difference to the 64 bit versions of the requests + * is that the access is done in multiples of 4 byte instead of + * 8 bytes (sizeof(unsigned long) on 31/64 bit). + * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA, + * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program + * is a 31 bit program too, the content of struct user can be + * emulated. A 31 bit program peeking into the struct user of + * a 64 bit program is a no-no. */ -static const struct utrace_regset native_regsets[] = { - { - .size = sizeof(long), .align = sizeof(long), - .n = sizeof(s390_regs) / sizeof(long), - .get = genregs_get, .set = genregs_set - }, - { - .size = sizeof(long), .align = sizeof(long), - .n = sizeof(s390_fp_regs) / sizeof(long), - .get = fpregs_get, .set = fpregs_set - }, - { - .size = sizeof(long), .align = sizeof(long), - .n = sizeof(per_struct) / sizeof(long), - .get = per_info_get, .set = per_info_set - }, -}; - -const struct utrace_regset_view utrace_s390_native_view = { - .name = UTS_MACHINE, .e_machine = ELF_ARCH, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_s390_native_view); - -#ifdef CONFIG_COMPAT +/* + * Same as peek_user but for a 31 bit program. + */ static int -s390_genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) { - struct pt_regs *regs = task_pt_regs(target); - int ret = 0; - - /* Fake a 31 bit psw mask. */ - if (count > 0 && pos == PT_PSWMASK / 2) { - u32 pswmask = PSW32_MASK_MERGE(PSW32_USER_BITS, - (u32) (regs->psw.mask >> 32)); - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &pswmask, PT_PSWMASK / 2, - PT_PSWADDR / 2); - } + struct user32 *dummy32 = NULL; + per_struct32 *dummy_per32 = NULL; + addr_t offset; + __u32 tmp; - /* Fake a 31 bit psw address. */ - if (ret == 0 && count > 0 && pos == PT_PSWADDR / 2) { - u32 pswaddr = (u32) regs->psw.addr | PSW32_ADDR_AMODE31; - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &pswaddr, PT_PSWADDR / 2, - PT_GPR0 / 2); - } + if (!test_thread_flag(TIF_31BIT) || + (addr & 3) || addr > sizeof(struct user) - 3) + return -EIO; - /* The GPRs are directly on the stack. Just truncate them. */ - while (ret == 0 && count > 0 && pos < PT_ACR0 / 2) { - u32 value = regs->gprs[(pos - PT_GPR0 / 2) / sizeof(u32)]; - if (kbuf) { - *(u32 *) kbuf = value; - kbuf += sizeof(u32); + if (addr < (addr_t) &dummy32->regs.acrs) { + /* + * psw and gprs are stored on the stack + */ + if (addr == (addr_t) &dummy32->regs.psw.mask) { + /* Fake a 31 bit psw mask. */ + tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32); + tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); + } else if (addr == (addr_t) &dummy32->regs.psw.addr) { + /* Fake a 31 bit psw address. */ + tmp = (__u32) task_pt_regs(child)->psw.addr | + PSW32_ADDR_AMODE31; + } else { + /* gpr 0-15 */ + tmp = *(__u32 *)((addr_t) &task_pt_regs(child)->psw + + addr*2 + 4); } - else if (put_user(value, (u32 __user *) ubuf)) - ret = -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } + } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { + /* + * access registers are stored in the thread structure + */ + offset = addr - (addr_t) &dummy32->regs.acrs; + tmp = *(__u32*)((addr_t) &child->thread.acrs + offset); - /* The ACRs are kept in the thread_struct. */ - if (ret == 0 && count > 0 && pos < PT_ACR0 / 2 + NUM_ACRS * ACR_SIZE) { - if (target == current) - save_access_regs(target->thread.acrs); + } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { + /* + * orig_gpr2 is stored on the kernel stack + */ + tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - target->thread.acrs, - PT_ACR0 / 2, - PT_ACR0 / 2 + NUM_ACRS * ACR_SIZE); - } + } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { + /* + * floating point regs. are stored in the thread structure + */ + offset = addr - (addr_t) &dummy32->regs.fp_regs; + tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); - /* Finally, the ORIG_GPR2 value. */ - if (count > 0) { - if (kbuf) - *(u32 *) kbuf = regs->orig_gpr2; - else if (put_user((u32) regs->orig_gpr2, - (u32 __user *) ubuf)) - return -EFAULT; - } + } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { + /* + * per_info is found in the thread structure + */ + offset = addr - (addr_t) &dummy32->regs.per_info; + /* This is magic. See per_struct and per_struct32. */ + if ((offset >= (addr_t) &dummy_per32->control_regs && + offset < (addr_t) (&dummy_per32->control_regs + 1)) || + (offset >= (addr_t) &dummy_per32->starting_addr && + offset <= (addr_t) &dummy_per32->ending_addr) || + offset == (addr_t) &dummy_per32->lowcore.words.address) + offset = offset*2 + 4; + else + offset = offset*2; + tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset); - return 0; + } else + tmp = 0; + + return put_user(tmp, (__u32 __user *) data); } +/* + * Same as poke_user but for a 31 bit program. + */ static int -s390_genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) { - struct pt_regs *regs = task_pt_regs(target); - int ret = 0; - - /* Check for an invalid PSW mask. */ - if (count > 0 && pos == PT_PSWMASK / 2) { - u32 pswmask; - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &pswmask, PT_PSWMASK / 2, - PT_PSWADDR / 2); - if (ret) - return ret; - - if (pswmask != PSW_MASK_MERGE(PSW_USER32_BITS, pswmask)) - /* Invalid psw mask. */ - return -EINVAL; + struct user32 *dummy32 = NULL; + per_struct32 *dummy_per32 = NULL; + addr_t offset; + __u32 tmp; - /* Build a 64 bit psw mask from 31 bit mask. */ - regs->psw.mask = PSW_MASK_MERGE(PSW_USER32_BITS, - (u64) pswmask << 32); - FixPerRegisters(target); - } + if (!test_thread_flag(TIF_31BIT) || + (addr & 3) || addr > sizeof(struct user32) - 3) + return -EIO; + + tmp = (__u32) data; - /* Build a 64 bit psw address from 31 bit address. */ - if (count > 0 && pos == PT_PSWADDR / 2) { - u32 pswaddr; - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &pswaddr, PT_PSWADDR / 2, - PT_GPR0 / 2); - if (ret == 0) + if (addr < (addr_t) &dummy32->regs.acrs) { + /* + * psw, gprs, acrs and orig_gpr2 are stored on the stack + */ + if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Build a 64 bit psw mask from 31 bit mask. */ - regs->psw.addr = pswaddr & PSW32_ADDR_INSN; - } + if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) + /* Invalid psw mask. */ + return -EINVAL; + task_pt_regs(child)->psw.mask = + PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); + } else if (addr == (addr_t) &dummy32->regs.psw.addr) { + /* Build a 64 bit psw address from 31 bit address. */ + task_pt_regs(child)->psw.addr = + (__u64) tmp & PSW32_ADDR_INSN; + } else { + /* gpr 0-15 */ + *(__u32*)((addr_t) &task_pt_regs(child)->psw + + addr*2 + 4) = tmp; + } + } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) { + /* + * access registers are stored in the thread structure + */ + offset = addr - (addr_t) &dummy32->regs.acrs; + *(__u32*)((addr_t) &child->thread.acrs + offset) = tmp; - /* The GPRs are directly onto the stack. */ - while (ret == 0 && count > 0 && pos < PT_ACR0 / 2) { - u32 value; + } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) { + /* + * orig_gpr2 is stored on the kernel stack + */ + *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; - if (kbuf) { - value = *(const u32 *) kbuf; - kbuf += sizeof(u32); - } - else if (get_user(value, (const u32 __user *) ubuf)) - return -EFAULT; + } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { + /* + * floating point regs. are stored in the thread structure + */ + if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && + (tmp & ~FPC_VALID_MASK) != 0) + /* Invalid floating point control. */ + return -EINVAL; + offset = addr - (addr_t) &dummy32->regs.fp_regs; + *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; + + } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { + /* + * per_info is found in the thread structure. + */ + offset = addr - (addr_t) &dummy32->regs.per_info; + /* + * This is magic. See per_struct and per_struct32. + * By incident the offsets in per_struct are exactly + * twice the offsets in per_struct32 for all fields. + * The 8 byte fields need special handling though, + * because the second half (bytes 4-7) is needed and + * not the first half. + */ + if ((offset >= (addr_t) &dummy_per32->control_regs && + offset < (addr_t) (&dummy_per32->control_regs + 1)) || + (offset >= (addr_t) &dummy_per32->starting_addr && + offset <= (addr_t) &dummy_per32->ending_addr) || + offset == (addr_t) &dummy_per32->lowcore.words.address) + offset = offset*2 + 4; else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); + offset = offset*2; + *(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp; - regs->gprs[(pos - PT_GPR0 / 2) / sizeof(u32)] = value; } - /* The ACRs are kept in the thread_struct. */ - if (count > 0 && pos < PT_ORIGGPR2 / 2) { - if (target == current - && (pos != PT_ACR0 / 2 - || count < sizeof(target->thread.acrs))) - save_access_regs(target->thread.acrs); - - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - target->thread.acrs, - PT_ACR0 / 2, - PT_ACR0 / 2 + NUM_ACRS * ACR_SIZE); + FixPerRegisters(child); + return 0; +} - if (ret == 0 && target == current) - restore_access_regs(target->thread.acrs); - } +static int +do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) +{ + unsigned int tmp; /* 4 bytes !! */ + ptrace_area_emu31 parea; + int copied, ret; - /* Finally, the ORIG_GPR2 value. */ - if (ret == 0 && count > 0) { - u32 value; - if (kbuf) - value = *(const u32 *) kbuf; - else if (get_user(value, (const u32 __user *) ubuf)) - return -EFAULT; - regs->orig_gpr2 = value; - } + switch (request) { + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + /* read word at location addr. */ + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + if (copied != sizeof(tmp)) + return -EIO; + return put_user(tmp, (unsigned int __user *) data); - return ret; -} + case PTRACE_PEEKUSR: + /* read the word at location addr in the USER area. */ + return peek_user_emu31(child, addr, data); + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + /* write the word at location addr. */ + tmp = data; + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1); + if (copied != sizeof(tmp)) + return -EIO; + return 0; -/* - * This is magic. See per_struct and per_struct32. - * By incident the offsets in per_struct are exactly - * twice the offsets in per_struct32 for all fields. - * The 8 byte fields need special handling though, - * because the second half (bytes 4-7) is needed and - * not the first half. - */ -static unsigned int -offset_from_per32(unsigned int offset) -{ - BUILD_BUG_ON(offsetof(per_struct32, control_regs) != 0); - if (offset - offsetof(per_struct32, control_regs) < 3*sizeof(u32) - || (offset >= offsetof(per_struct32, starting_addr) && - offset <= offsetof(per_struct32, ending_addr)) - || offset == offsetof(per_struct32, lowcore.words.address)) - offset = offset*2 + 4; - else - offset = offset*2; - return offset; -} + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area */ + return poke_user_emu31(child, addr, data); -static int -s390_per_info_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - while (count > 0) { - u32 val = *(u32 *) ((char *) &target->thread.per_info - + offset_from_per32 (pos)); - if (kbuf) { - *(u32 *) kbuf = val; - kbuf += sizeof(u32); - } - else if (put_user(val, (u32 __user *) ubuf)) + case PTRACE_PEEKUSR_AREA: + case PTRACE_POKEUSR_AREA: + if (copy_from_user(&parea, (void __user *) addr, + sizeof(parea))) return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); + addr = parea.kernel_addr; + data = parea.process_addr; + copied = 0; + while (copied < parea.len) { + if (request == PTRACE_PEEKUSR_AREA) + ret = peek_user_emu31(child, addr, data); + else { + __u32 tmp; + if (get_user (tmp, (__u32 __user *) data)) + return -EFAULT; + ret = poke_user_emu31(child, addr, tmp); + } + if (ret) + return ret; + addr += sizeof(unsigned int); + data += sizeof(unsigned int); + copied += sizeof(unsigned int); + } + return 0; + case PTRACE_GETEVENTMSG: + return put_user((__u32) child->ptrace_message, + (unsigned int __user *) data); + case PTRACE_GETSIGINFO: + if (child->last_siginfo == NULL) + return -EINVAL; + return copy_siginfo_to_user32((compat_siginfo_t __user *) data, + child->last_siginfo); + case PTRACE_SETSIGINFO: + if (child->last_siginfo == NULL) + return -EINVAL; + return copy_siginfo_from_user32(child->last_siginfo, + (compat_siginfo_t __user *) data); } - return 0; + return ptrace_request(child, request, addr, data); } +#endif + +#define PT32_IEEE_IP 0x13c static int -s390_per_info_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +do_ptrace(struct task_struct *child, long request, long addr, long data) { - while (count > 0) { - u32 val; + int ret; - if (kbuf) { - val = *(const u32 *) kbuf; - kbuf += sizeof(u32); - } - else if (get_user(val, (const u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); + if (request == PTRACE_ATTACH) + return ptrace_attach(child); - *(u32 *) ((char *) &target->thread.per_info - + offset_from_per32 (pos)) = val; + /* + * Special cases to get/store the ieee instructions pointer. + */ + if (child == current) { + if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP) + return peek_user(child, addr, data); + if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP) + return poke_user(child, addr, data); +#ifdef CONFIG_COMPAT + if (request == PTRACE_PEEKUSR && + addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) + return peek_user_emu31(child, addr, data); + if (request == PTRACE_POKEUSR && + addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT)) + return poke_user_emu31(child, addr, data); +#endif } - return 0; -} + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + return ret; -static const struct utrace_regset s390_compat_regsets[] = { - { - .size = sizeof(u32), .align = sizeof(u32), - .n = sizeof(s390_regs) / sizeof(long), - .get = s390_genregs_get, .set = s390_genregs_set - }, - { - .size = sizeof(u32), .align = sizeof(u32), - .n = sizeof(s390_fp_regs) / sizeof(u32), - .get = fpregs_get, .set = fpregs_set - }, - { - .size = sizeof(u32), .align = sizeof(u32), - .n = sizeof(per_struct) / sizeof(u32), - .get = s390_per_info_get, .set = s390_per_info_set - }, -}; - -const struct utrace_regset_view utrace_s390_compat_view = { - .name = "s390", .e_machine = EM_S390, - .regsets = s390_compat_regsets, - .n = sizeof s390_compat_regsets / sizeof s390_compat_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_s390_compat_view); -#endif /* CONFIG_COMPAT */ - - -#ifdef CONFIG_PTRACE -static const struct ptrace_layout_segment s390_uarea[] = { - {PT_PSWMASK, PT_FPC, 0, 0}, - {PT_FPC, PT_CR_9, 1, 0}, - {PT_CR_9, PT_IEEE_IP, 2, 0}, - {PT_IEEE_IP, sizeof(struct user), -1, -1}, - {0, 0, -1, 0} -}; - -fastcall int arch_ptrace(long *request, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, long *val) -{ - ptrace_area parea; - unsigned long tmp; - int copied; - - switch (*request) { - case PTRACE_PEEKUSR: - return ptrace_peekusr(child, engine, s390_uarea, addr, data); - case PTRACE_POKEUSR: - return ptrace_pokeusr(child, engine, s390_uarea, addr, data); - - case PTRACE_PEEKUSR_AREA: - case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (ptrace_area __user *) addr, - sizeof(parea))) - return -EFAULT; - if ((parea.kernel_addr | parea.len) & (sizeof(data) - 1)) + switch (request) { + case PTRACE_SYSCALL: + /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: + /* restart after signal. */ + if (!valid_signal(data)) return -EIO; - return ptrace_layout_access(child, engine, - utrace_native_view(current), - s390_uarea, - parea.kernel_addr, parea.len, - (void __user *) parea.process_addr, - NULL, - *request == PTRACE_POKEUSR_AREA); + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + return 0; - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - /* Remove high order bit from address (only for 31 bit). */ - addr &= PSW_ADDR_INSN; - /* read word at location addr. */ - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - if (copied != sizeof(tmp)) - return -EIO; - return put_user(tmp, (unsigned long __user *) data); + case PTRACE_KILL: + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + return 0; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + return 0; - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - /* Remove high order bit from address (only for 31 bit). */ - addr &= PSW_ADDR_INSN; - /* write the word at location addr. */ - copied = access_process_vm(child, addr, &data, sizeof(data),1); - if (copied != sizeof(data)) + case PTRACE_SINGLESTEP: + /* set the trap flag. */ + if (!valid_signal(data)) return -EIO; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + if (data) + set_tsk_thread_flag(child, TIF_SINGLE_STEP); + else + set_single_step(child); + /* give it a chance to run. */ + wake_up_process(child); return 0; - } - return -ENOSYS; -} + case PTRACE_DETACH: + /* detach a process that was attached. */ + return ptrace_detach(child, data); + + /* Do requests that differ for 31/64 bit */ + default: #ifdef CONFIG_COMPAT -static const struct ptrace_layout_segment s390_compat_uarea[] = { - {PT_PSWMASK / 2, PT_FPC / 2, 0, 0}, - {PT_FPC / 2, PT_CR_9 / 2, 1, 0}, - {PT_CR_9 / 2, PT_IEEE_IP / 2, 2, 0}, - {PT_IEEE_IP / 2, sizeof(struct user32), -1, -1}, - {0, 0, -1, 0} -}; - -fastcall int arch_compat_ptrace(compat_long_t *request, - struct task_struct *child, - struct utrace_attached_engine *engine, - compat_ulong_t addr, compat_ulong_t data, - compat_long_t *val) + if (test_thread_flag(TIF_31BIT)) + return do_ptrace_emu31(child, request, addr, data); +#endif + return do_ptrace_normal(child, request, addr, data); + } + /* Not reached. */ + return -EIO; +} + +asmlinkage long +sys_ptrace(long request, long pid, long addr, long data) { - ptrace_area_emu31 parea; + struct task_struct *child; + int ret; - switch (*request) { - case PTRACE_PEEKUSR: - return ptrace_compat_peekusr(child, engine, s390_compat_uarea, - addr, data); - case PTRACE_POKEUSR: - return ptrace_compat_pokeusr(child, engine, s390_compat_uarea, - addr, data); - case PTRACE_PEEKUSR_AREA: - case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, ((ptrace_area_emu31 __user *) - (unsigned long) addr), - sizeof(parea))) - return -EFAULT; - if ((parea.kernel_addr | parea.len) & (sizeof(data) - 1)) - return -EIO; - return ptrace_layout_access(child, engine, - utrace_native_view(current), - s390_compat_uarea, - parea.kernel_addr, parea.len, - (void __user *) - (unsigned long) parea.process_addr, - NULL, - *request == PTRACE_POKEUSR_AREA); + lock_kernel(); + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); + goto out; } - return -ENOSYS; -} -#endif /* CONFIG_COMPAT */ -#endif /* CONFIG_PTRACE */ + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + goto out; + } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + ret = -EPERM; + goto out_tsk; + } + + ret = do_ptrace(child, request, addr, data); +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return ret; +} asmlinkage void syscall_trace(struct pt_regs *regs, int entryexit) @@ -686,17 +742,30 @@ syscall_trace(struct pt_regs *regs, int entryexit) if (unlikely(current->audit_context) && entryexit) audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); - if (test_thread_flag(TIF_SYSCALL_TRACE)) { - tracehook_report_syscall(regs, entryexit); + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + goto out; + if (!(current->ptrace & PT_PTRACED)) + goto out; + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); - /* - * If the debugger has set an invalid system call number, - * we prepare to skip the system call restart handling. - */ - if (!entryexit && regs->gprs[2] >= NR_syscalls) - regs->trap = -1; - } + /* + * If the debuffer has set an invalid system call number, + * we prepare to skip the system call restart handling. + */ + if (!entryexit && regs->gprs[2] >= NR_syscalls) + regs->trap = -1; + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } + out: if (unlikely(current->audit_context) && !entryexit) audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, regs->gprs[2], regs->orig_gpr2, regs->gprs[3], diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index 6f5bafba7..b0df464b1 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -114,7 +114,6 @@ int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler, void do_extint(struct pt_regs *regs, unsigned short code) { ext_int_info_t *p; - struct vx_info_save vxis; int index; irq_enter(); @@ -127,14 +126,12 @@ void do_extint(struct pt_regs *regs, unsigned short code) account_ticks(regs); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; index = ext_hash(code); - __enter_vx_admin(&vxis); for (p = ext_int_hash[index]; p; p = p->next) { if (likely(p->code == code)) { if (likely(p->handler)) p->handler(regs, code); } } - __leave_vx_admin(&vxis); irq_exit(); } diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 3ed0a526c..a887b686f 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -404,8 +403,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - - tracehook_report_handle_signal(sig, ka, oldset, regs); } return ret; diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index c8319534a..bde1d1d59 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -338,7 +338,7 @@ static inline void __user *get_check_address(struct pt_regs *regs) void do_single_step(struct pt_regs *regs) { - if (tracehook_consider_fatal_signal(current, SIGTRAP)) + if ((current->ptrace & PT_PTRACED) != 0) force_sig(SIGTRAP, current); } @@ -439,7 +439,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) if (regs->psw.mask & PSW_MASK_PSTATE) { get_user(*((__u16 *) opcode), (__u16 __user *) location); if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { - if (tracehook_consider_fatal_signal(current, SIGTRAP)) + if (current->ptrace & PT_PTRACED) force_sig(SIGTRAP, current); else signal = SIGILL; diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S index 3f5511dd2..90443e742 100644 --- a/arch/s390/lib/uaccess.S +++ b/arch/s390/lib/uaccess.S @@ -41,15 +41,15 @@ __copy_from_user_asm: 5: mvcp 0(%r5,%r2),0(%r4),%r0 slr %r3,%r5 alr %r2,%r5 -6: lgr %r5,%r3 # copy remaining size +6: lr %r5,%r3 # copy remaining size ahi %r5,-1 # subtract 1 for xc loop bras %r4,8f - xc 0(1,%2),0(%2) -7: xc 0(256,%2),0(%2) + xc 0(1,%r2),0(%r2) +7: xc 0(256,%r2),0(%r2) la %r2,256(%r2) -8: ahji %r5,-256 +8: ahi %r5,-256 jnm 7b - ex %r5,0(%r2) + ex %r5,0(%r4) 9: lr %r2,%r3 br %r14 .section __ex_table,"a" diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S index 9376df013..2d42c7e8c 100644 --- a/arch/s390/lib/uaccess64.S +++ b/arch/s390/lib/uaccess64.S @@ -49,7 +49,7 @@ __copy_from_user_asm: la %r2,256(%r2) 8: aghi %r5,-256 jnm 7b - ex %r5,0(%r2) + ex %r5,0(%r4) 9: lgr %r2,%r3 br %r14 .section __ex_table,"a" diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index a4edff4c3..831f54025 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -32,13 +32,12 @@ #include #include #include +#include #include #define curptr g6 -#define NR_SYSCALLS 300 /* Each OS is different... */ - /* These are just handy. */ #define _SV save %sp, -STACKFRAME_SZ, %sp #define _RS restore diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 1c7e6e3ee..72f020105 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -322,7 +321,6 @@ void handler_irq(int irq, struct pt_regs * regs) { struct irqaction * action; int cpu = smp_processor_id(); - struct vx_info_save vxis; #ifdef CONFIG_SMP extern void smp4m_irq_rotate(int cpu); #endif @@ -337,14 +335,12 @@ void handler_irq(int irq, struct pt_regs * regs) action = sparc_irq[irq].action; sparc_irq[irq].flags |= SPARC_IRQ_INPROGRESS; kstat_cpu(cpu).irqs[irq]++; - __enter_vx_admin(&vxis); do { if (!action || !action->handler) unexpected_irq(irq, NULL, regs); action->handler(irq, action->dev_id, regs); action = action->next; } while (action); - __leave_vx_admin(&vxis); sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS; enable_pil_irq(irq); irq_exit(); @@ -356,14 +352,11 @@ extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) { int cpu = smp_processor_id(); - struct vx_info_save vxis; disable_pil_irq(irq); irq_enter(); kstat_cpu(cpu).irqs[irq]++; - __enter_vx_admin(&vxis); floppy_interrupt(irq, dev_id, regs); - __leave_vx_admin(&vxis); irq_exit(); enable_pil_irq(irq); // XXX Eek, it's totally changed with preempt_count() and such diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index e271941be..77f51b5cb 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -200,7 +200,6 @@ extern void unexpected_irq(int, void *, struct pt_regs *); void sun4d_handler_irq(int irq, struct pt_regs * regs) { struct irqaction * action; - struct vx_info_save vxis; int cpu = smp_processor_id(); /* SBUS IRQ level (1 - 7) */ int sbusl = pil_to_sbus[irq]; @@ -212,7 +211,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) irq_enter(); kstat_cpu(cpu).irqs[irq]++; - __enter_vx_admin(&vxis); if (!sbusl) { action = *(irq + irq_action); if (!action) @@ -252,7 +250,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) } } } - __leave_vx_admin(&vxis); irq_exit(); } diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 14d0d4f11..e1eabebae 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -5,8 +5,6 @@ EXTRA_AFLAGS := -ansi EXTRA_CFLAGS := -Werror -CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' - extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 8baa4db0a..c0422213d 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -336,6 +336,8 @@ beyond_if: tsb_context_switch(current->mm); start_thread32(regs, ex.a_entry, current->mm->start_stack); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); return 0; } diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index bd4688c2c..6f28bec0a 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -22,11 +22,10 @@ #include #include #include +#include #define curptr g6 -#define NR_SYSCALLS 300 /* Each OS is different... */ - .text .align 32 @@ -1410,6 +1409,7 @@ execve_merge: .globl sys_pipe, sys_sigpause, sys_nis_syscall .globl sys_rt_sigreturn + .globl sys_ptrace .globl sys_sigaltstack .align 32 sys_pipe: ba,pt %xcc, sparc_pipe @@ -1452,6 +1452,11 @@ sys32_rt_sigreturn: add %o7, 1f-.-4, %o7 nop #endif +sys_ptrace: add %sp, PTREGS_OFF, %o0 + call do_ptrace + add %o7, 1f-.-4, %o7 + nop + .align 32 1: ldx [%curptr + TI_FLAGS], %l5 andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 be,pt %icc, rtrap diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 3b453da43..7d75cd4eb 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -808,6 +808,9 @@ asmlinkage int sparc_execve(struct pt_regs *regs) current_thread_info()->xfsr[0] = 0; current_thread_info()->fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); } out: return error; diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index d8cfba61c..ded40464e 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -1,6 +1,6 @@ -/* ptrace.c: Sparc64 process tracing support. +/* ptrace.c: Sparc process tracing support. * - * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, @@ -11,601 +11,103 @@ */ #include -#include #include #include +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include +#include #include #include #include +#include +#include +#include #include #include #include -#include - -#define GENREG_G0 0 -#define GENREG_O0 8 -#define GENREG_L0 16 -#define GENREG_I0 24 -#define GENREG_TSTATE 32 -#define GENREG_TPC 33 -#define GENREG_TNPC 34 -#define GENREG_Y 35 - -#define SPARC64_NGREGS 36 - -static int genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct pt_regs *regs = task_pt_regs(target); - int err; - - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, regs->u_regs, - GENREG_G0 * 8, GENREG_L0 * 8); - - if (err == 0 && count > 0 && pos < (GENREG_TSTATE * 8)) { - struct thread_info *t = task_thread_info(target); - unsigned long rwindow[16], fp, *win; - int wsaved; - - if (target == current) - flushw_user(); - - wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED]; - fp = regs->u_regs[UREG_FP] + STACK_BIAS; - if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp) - win = &t->reg_window[wsaved - 1].locals[0]; - else { - if (target == current) { - if (copy_from_user(rwindow, - (void __user *) fp, - 16 * sizeof(long))) - err = -EFAULT; - } else - err = access_process_vm(target, fp, rwindow, - 16 * sizeof(long), 0); - if (err) - return err; - win = rwindow; - } - - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - win, GENREG_L0 * 8, - GENREG_TSTATE * 8); - } - - if (err == 0) - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - ®s->tstate, GENREG_TSTATE * 8, - GENREG_Y * 8); - if (err == 0 && count > 0) { - if (kbuf) - *(unsigned long *) kbuf = regs->y; - else if (put_user(regs->y, (unsigned long __user *) ubuf)) - return -EFAULT; - } - - return err; -} -/* Consistent with signal handling, we only allow userspace to - * modify the %asi, %icc, and %xcc fields of the %tstate register. +/* Returning from ptrace is a bit tricky because the syscall return + * low level code assumes any value returned which is negative and + * is a valid errno will mean setting the condition codes to indicate + * an error return. This doesn't work, so we have this hook. */ -#define TSTATE_DEBUGCHANGE (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC) - -static int genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +static inline void pt_error_return(struct pt_regs *regs, unsigned long error) { - struct pt_regs *regs = task_pt_regs(target); - unsigned long tstate_save; - int err; - - err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, regs->u_regs, - GENREG_G0 * 8, GENREG_L0 * 8); - - if (err == 0 && count > 0 && pos < (GENREG_TSTATE * 8)) { - unsigned long fp = regs->u_regs[UREG_FP] + STACK_BIAS; - unsigned long rwindow[16], *winbuf; - unsigned int copy = (GENREG_TSTATE * 8) - pos; - unsigned int off; - int err; - - if (target == current) - flushw_user(); - - if (count < copy) - copy = count; - off = pos - (GENREG_L0 * 8); - - if (kbuf) { - winbuf = (unsigned long *) kbuf; - kbuf += copy; - } - else { - winbuf = rwindow; - if (copy_from_user(winbuf, ubuf, copy)) - return -EFAULT; - ubuf += copy; - } - count -= copy; - pos += copy; - - if (target == current) - err = copy_to_user((void __user *) fp + off, - winbuf, copy); - else - err = access_process_vm(target, fp + off, - winbuf, copy, 1); - } - - tstate_save = regs->tstate &~ TSTATE_DEBUGCHANGE; - - if (err == 0) - err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - ®s->tstate, GENREG_TSTATE * 8, - GENREG_Y * 8); - - regs->tstate &= TSTATE_DEBUGCHANGE; - regs->tstate |= tstate_save; - - if (err == 0 && count > 0) { - if (kbuf) - regs->y = *(unsigned long *) kbuf; - else if (get_user(regs->y, (unsigned long __user *) ubuf)) - return -EFAULT; - } - - return err; + regs->u_regs[UREG_I0] = error; + regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY); + regs->tpc = regs->tnpc; + regs->tnpc += 4; } -#define FPREG_F0 0 -#define FPREG_FSR 32 -#define FPREG_GSR 33 -#define FPREG_FPRS 34 - -#define SPARC64_NFPREGS 35 - -static int fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) { - struct thread_info *t = task_thread_info(target); - int err; - - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8); - - if (err == 0) - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &t->xfsr[0], FPREG_FSR * 8, - FPREG_GSR * 8); - - if (err == 0) - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &t->gsr[0], FPREG_GSR * 8, - FPREG_FPRS * 8); - - if (err == 0 && count > 0) { - struct pt_regs *regs = task_pt_regs(target); - - if (kbuf) - *(unsigned long *) kbuf = regs->fprs; - else if (put_user(regs->fprs, (unsigned long __user *) ubuf)) - return -EFAULT; - } - if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { - pt_error_return(regs, ESRCH); - goto out_tsk; - } - - return err; + regs->u_regs[UREG_I0] = value; + regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); + regs->tpc = regs->tnpc; + regs->tnpc += 4; } -static int fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +static inline void +pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr) { - struct thread_info *t = task_thread_info(target); - int err; - - err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - t->fpregs, FPREG_F0 * 8, FPREG_FSR * 8); - - if (err == 0) - err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &t->xfsr[0], FPREG_FSR * 8, - FPREG_GSR * 8); - - if (err == 0) - err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &t->gsr[0], FPREG_GSR * 8, - FPREG_FPRS * 8); - - if (err == 0 && count > 0) { - struct pt_regs *regs = task_pt_regs(target); - - if (kbuf) - regs->fprs = *(unsigned long *) kbuf; - else if (get_user(regs->fprs, (unsigned long __user *) ubuf)) - return -EFAULT; - } - - return err; -} - -static const struct utrace_regset native_regsets[] = { - { - .n = SPARC64_NGREGS, - .size = sizeof(long), .align = sizeof(long), - .get = genregs_get, .set = genregs_set - }, - { - .n = SPARC64_NFPREGS, - .size = sizeof(long), .align = sizeof(long), - .get = fpregs_get, .set = fpregs_set - }, -}; - -const struct utrace_regset_view utrace_sparc64_native_view = { - .name = UTS_MACHINE, .e_machine = ELF_ARCH, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_sparc64_native_view); - -#ifdef CONFIG_COMPAT - -#define GENREG32_G0 0 -#define GENREG32_O0 8 -#define GENREG32_L0 16 -#define GENREG32_I0 24 -#define GENREG32_PSR 32 -#define GENREG32_PC 33 -#define GENREG32_NPC 34 -#define GENREG32_Y 35 -#define GENREG32_WIM 36 -#define GENREG32_TBR 37 - -#define SPARC32_NGREGS 38 - -static int genregs32_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct pt_regs *regs = task_pt_regs(target); - - while (count > 0 && pos < (GENREG32_L0 * 4)) { - u32 val = regs->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)]; - if (kbuf) { - *(u32 *) kbuf = val; - kbuf += sizeof(u32); - } else if (put_user(val, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos < (GENREG32_PSR * 4)) { - struct thread_info *t = task_thread_info(target); - unsigned long fp; - u32 rwindow[16]; - int wsaved; - - if (target == current) - flushw_user(); - - wsaved = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_WSAVED]; - fp = regs->u_regs[UREG_FP] & 0xffffffffUL; - if (wsaved && t->rwbuf_stkptrs[wsaved - 1] == fp) { - int i; - for (i = 0; i < 8; i++) - rwindow[i + 0] = - t->reg_window[wsaved-1].locals[i]; - for (i = 0; i < 8; i++) - rwindow[i + 8] = - t->reg_window[wsaved-1].ins[i]; - } else { - int err; - - if (target == current) { - err = 0; - if (copy_from_user(rwindow, (void __user *) fp, - 16 * sizeof(u32))) - err = -EFAULT; - } else - err = access_process_vm(target, fp, rwindow, - 16 * sizeof(u32), 0); - if (err) - return err; + if (test_thread_flag(TIF_32BIT)) { + if (put_user(value, (unsigned int __user *) addr)) { + pt_error_return(regs, EFAULT); + return; } - - while (count > 0 && pos < (GENREG32_PSR * 4)) { - u32 val = rwindow[(pos - (GENREG32_L0*4))/sizeof(u32)]; - - if (kbuf) { - *(u32 *) kbuf = val; - kbuf += sizeof(u32); - } else if (put_user(val, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); + } else { + if (put_user(value, (long __user *) addr)) { + pt_error_return(regs, EFAULT); + return; } } - - if (count > 0 && pos == (GENREG32_PSR * 4)) { - u32 psr = tstate_to_psr(regs->tstate); - - if (kbuf) { - *(u32 *) kbuf = psr; - kbuf += sizeof(u32); - } else if (put_user(psr, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos == (GENREG32_PC * 4)) { - u32 val = regs->tpc; - - if (kbuf) { - *(u32 *) kbuf = val; - kbuf += sizeof(u32); - } else if (put_user(val, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos == (GENREG32_NPC * 4)) { - u32 val = regs->tnpc; - - if (kbuf) { - *(u32 *) kbuf = val; - kbuf += sizeof(u32); - } else if (put_user(val, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos == (GENREG32_Y * 4)) { - if (kbuf) { - *(u32 *) kbuf = regs->y; - kbuf += sizeof(u32); - } else if (put_user(regs->y, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0) { - if (kbuf) - memset(kbuf, 0, count); - else if (clear_user(ubuf, count)) - return -EFAULT; - } - - return 0; + regs->u_regs[UREG_I0] = 0; + regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); + regs->tpc = regs->tnpc; + regs->tnpc += 4; } -static int genregs32_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +static void +pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr) { - struct pt_regs *regs = task_pt_regs(target); - - while (count > 0 && pos < (GENREG32_L0 * 4)) { - unsigned long *loc; - loc = ®s->u_regs[(pos - (GENREG32_G0*4))/sizeof(u32)]; - if (kbuf) { - *loc = *(u32 *) kbuf; - kbuf += sizeof(u32); - } else if (get_user(*loc, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos < (GENREG32_PSR * 4)) { - unsigned long fp; - u32 regbuf[16]; - unsigned int off, copy; - int err; - - if (target == current) - flushw_user(); - - copy = (GENREG32_PSR * 4) - pos; - if (count < copy) - copy = count; - BUG_ON(copy > 16 * sizeof(u32)); - - fp = regs->u_regs[UREG_FP] & 0xffffffffUL; - off = pos - (GENREG32_L0 * 4); - if (kbuf) { - memcpy(regbuf, kbuf, copy); - kbuf += copy; - } else if (copy_from_user(regbuf, ubuf, copy)) - return -EFAULT; - else - ubuf += copy; - pos += copy; - count -= copy; - - if (target == current) { - err = 0; - if (copy_to_user((void __user *) fp + off, - regbuf, count)) - err = -EFAULT; - } else - err = access_process_vm(target, fp + off, - regbuf, count, 1); - if (err) - return err; - } - - if (count > 0 && pos == (GENREG32_PSR * 4)) { - unsigned long tstate, tstate_save; - u32 psr; - - tstate_save = regs->tstate&~(TSTATE_ICC|TSTATE_XCC); - - if (kbuf) { - psr = *(u32 *) kbuf; - kbuf += sizeof(u32); - } else if (get_user(psr, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - - tstate = psr_to_tstate_icc(psr); - regs->tstate = tstate_save | tstate; - } - - if (count > 0 && pos == (GENREG32_PC * 4)) { - if (kbuf) { - regs->tpc = *(u32 *) kbuf; - kbuf += sizeof(u32); - } else if (get_user(regs->tpc, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos == (GENREG32_NPC * 4)) { - if (kbuf) { - regs->tnpc = *(u32 *) kbuf; - kbuf += sizeof(u32); - } else if (get_user(regs->tnpc, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - if (count > 0 && pos == (GENREG32_Y * 4)) { - if (kbuf) { - regs->y = *(u32 *) kbuf; - kbuf += sizeof(u32); - } else if (get_user(regs->y, (u32 __user *) ubuf)) - return -EFAULT; - else - ubuf += sizeof(u32); - pos += sizeof(u32); - count -= sizeof(u32); - } - - /* Ignore WIM and TBR */ - - return 0; + if (current->personality == PER_SUNOS) + pt_succ_return (regs, val); + else + pt_succ_return_linux (regs, val, addr); } -#define FPREG32_F0 0 -#define FPREG32_FSR 32 - -#define SPARC32_NFPREGS 33 - -static int fpregs32_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct thread_info *t = task_thread_info(target); - int err; - - err = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - t->fpregs, FPREG32_F0 * 4, - FPREG32_FSR * 4); - - if (err == 0 && count > 0) { - if (kbuf) { - *(u32 *) kbuf = t->xfsr[0]; - } else if (put_user(t->xfsr[0], (u32 __user *) ubuf)) - return -EFAULT; - } - - return err; -} +/* #define ALLOW_INIT_TRACING */ +/* #define DEBUG_PTRACE */ + +#ifdef DEBUG_PTRACE +char *pt_rq [] = { + /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR", + /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT", + /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH", + /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS", + /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT", + /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown", + /* 24 */ "SYSCALL", "" +}; +#endif -static int fpregs32_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure single step bits etc are not set. + */ +void ptrace_disable(struct task_struct *child) { - struct thread_info *t = task_thread_info(target); - int err; - - err = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - t->fpregs, FPREG32_F0 * 4, - FPREG32_FSR * 4); - - if (err == 0 && count > 0) { - u32 fsr; - if (kbuf) { - fsr = *(u32 *) kbuf; - } else if (get_user(fsr, (u32 __user *) ubuf)) - return -EFAULT; - t->xfsr[0] = (t->xfsr[0] & 0xffffffff00000000UL) | fsr; - } - - return 0; + /* nothing to do */ } -static const struct utrace_regset sparc32_regsets[] = { - { - .n = SPARC32_NGREGS, - .size = sizeof(u32), .align = sizeof(u32), - .get = genregs32_get, .set = genregs32_set - }, - { - .n = SPARC32_NFPREGS, - .size = sizeof(u32), .align = sizeof(u32), - .get = fpregs32_get, .set = fpregs32_set - }, -}; - -const struct utrace_regset_view utrace_sparc32_view = { - .name = "sparc", .e_machine = EM_SPARC, - .regsets = sparc32_regsets, - .n = sizeof sparc32_regsets / sizeof sparc32_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_sparc32_view); - -#endif /* CONFIG_COMPAT */ - /* To get the necessary page struct, access_process_vm() first calls * get_user_pages(). This has done a flush_dcache_page() on the * accessed page. Then our caller (copy_{to,from}_user_page()) did @@ -665,124 +167,488 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, } } -#ifdef CONFIG_PTRACE -static const struct ptrace_layout_segment sparc64_getregs_layout[] = { - { 0, offsetof(struct pt_regs, u_regs[15]), 0, sizeof(long) }, - { offsetof(struct pt_regs, u_regs[15]), - offsetof(struct pt_regs, tstate), - -1, 0 }, - { offsetof(struct pt_regs, tstate), offsetof(struct pt_regs, y), - 0, 32 * sizeof(long) }, - {0, 0, -1, 0} -}; - -int arch_ptrace(long *request, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, - long *retval) +asmlinkage void do_ptrace(struct pt_regs *regs) { - void __user *uaddr = (void __user *) addr; - struct pt_regs *uregs = uaddr; - int err = -ENOSYS; - - switch (*request) { - case PTRACE_GETREGS64: - err = ptrace_layout_access(child, engine, - &utrace_sparc64_native_view, - sparc64_getregs_layout, - 0, offsetof(struct pt_regs, y), - uaddr, NULL, 0); - if (!err && - (put_user(task_pt_regs(child)->y, &uregs->y) || - put_user(task_pt_regs(child)->fprs, &uregs->fprs))) - err = -EFAULT; - break; + int request = regs->u_regs[UREG_I0]; + pid_t pid = regs->u_regs[UREG_I1]; + unsigned long addr = regs->u_regs[UREG_I2]; + unsigned long data = regs->u_regs[UREG_I3]; + unsigned long addr2 = regs->u_regs[UREG_I4]; + struct task_struct *child; + int ret; + + if (test_thread_flag(TIF_32BIT)) { + addr &= 0xffffffffUL; + data &= 0xffffffffUL; + addr2 &= 0xffffffffUL; + } + lock_kernel(); +#ifdef DEBUG_PTRACE + { + char *s; - case PTRACE_SETREGS64: - err = ptrace_layout_access(child, engine, - &utrace_sparc64_native_view, - sparc64_getregs_layout, - 0, offsetof(struct pt_regs, y), - uaddr, NULL, 1); - if (!err && - (get_user(task_pt_regs(child)->y, &uregs->y) || - get_user(task_pt_regs(child)->fprs, &uregs->fprs))) - err = -EFAULT; - break; + if ((request >= 0) && (request <= 24)) + s = pt_rq [request]; + else + s = "unknown"; + + if (request == PTRACE_POKEDATA && data == 0x91d02001){ + printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", + pid, addr, addr2); + } else + printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n", + s, request, pid, addr, data, addr2); + } +#endif + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); + pt_succ_return(regs, 0); + goto out; + } - case PTRACE_GETFPREGS64: - case PTRACE_SETFPREGS64: - err = ptrace_regset_access(child, engine, - utrace_native_view(current), - 2, 0, 34 * sizeof(long), uaddr, - (*request == PTRACE_SETFPREGS64)); - break; + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); + pt_error_return(regs, -ret); + goto out; + } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + pt_error_return(regs, ESRCH); + goto out_tsk; + } - case PTRACE_SUNDETACH: - *request = PTRACE_DETACH; - break; + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) + || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { + if (ptrace_attach(child)) { + pt_error_return(regs, EPERM); + goto out_tsk; + } + pt_succ_return(regs, 0); + goto out_tsk; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) { + pt_error_return(regs, -ret); + goto out_tsk; + } + + if (!(test_thread_flag(TIF_32BIT)) && + ((request == PTRACE_READDATA64) || + (request == PTRACE_WRITEDATA64) || + (request == PTRACE_READTEXT64) || + (request == PTRACE_WRITETEXT64) || + (request == PTRACE_PEEKTEXT64) || + (request == PTRACE_POKETEXT64) || + (request == PTRACE_PEEKDATA64) || + (request == PTRACE_POKEDATA64))) { + addr = regs->u_regs[UREG_G2]; + addr2 = regs->u_regs[UREG_G3]; + request -= 30; /* wheee... */ + } + + switch(request) { + case PTRACE_PEEKUSR: + if (addr != 0) + pt_error_return(regs, EIO); + else + pt_succ_return(regs, 0); + goto out_tsk; + + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp64; + unsigned int tmp32; + int res, copied; + + res = -EIO; + if (test_thread_flag(TIF_32BIT)) { + copied = access_process_vm(child, addr, + &tmp32, sizeof(tmp32), 0); + tmp64 = (unsigned long) tmp32; + if (copied == sizeof(tmp32)) + res = 0; + } else { + copied = access_process_vm(child, addr, + &tmp64, sizeof(tmp64), 0); + if (copied == sizeof(tmp64)) + res = 0; + } + if (res < 0) + pt_error_return(regs, -res); + else + pt_os_succ_return(regs, tmp64, (void __user *) data); + goto out_tsk; + } + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: { + unsigned long tmp64; + unsigned int tmp32; + int copied, res = -EIO; + + if (test_thread_flag(TIF_32BIT)) { + tmp32 = data; + copied = access_process_vm(child, addr, + &tmp32, sizeof(tmp32), 1); + if (copied == sizeof(tmp32)) + res = 0; + } else { + tmp64 = data; + copied = access_process_vm(child, addr, + &tmp64, sizeof(tmp64), 1); + if (copied == sizeof(tmp64)) + res = 0; + } + if (res < 0) + pt_error_return(regs, -res); + else + pt_succ_return(regs, res); + goto out_tsk; + } + + case PTRACE_GETREGS: { + struct pt_regs32 __user *pregs = + (struct pt_regs32 __user *) addr; + struct pt_regs *cregs = task_pt_regs(child); + int rval; + + if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || + __put_user(cregs->tpc, (&pregs->pc)) || + __put_user(cregs->tnpc, (&pregs->npc)) || + __put_user(cregs->y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + for (rval = 1; rval < 16; rval++) + if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + pt_succ_return(regs, 0); +#ifdef DEBUG_PTRACE + printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); +#endif + goto out_tsk; + } + + case PTRACE_GETREGS64: { + struct pt_regs __user *pregs = (struct pt_regs __user *) addr; + struct pt_regs *cregs = task_pt_regs(child); + unsigned long tpc = cregs->tpc; + int rval; + + if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) + tpc &= 0xffffffff; + if (__put_user(cregs->tstate, (&pregs->tstate)) || + __put_user(tpc, (&pregs->tpc)) || + __put_user(cregs->tnpc, (&pregs->tnpc)) || + __put_user(cregs->y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + for (rval = 1; rval < 16; rval++) + if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + pt_succ_return(regs, 0); +#ifdef DEBUG_PTRACE + printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); +#endif + goto out_tsk; + } + + case PTRACE_SETREGS: { + struct pt_regs32 __user *pregs = + (struct pt_regs32 __user *) addr; + struct pt_regs *cregs = task_pt_regs(child); + unsigned int psr, pc, npc, y; + int i; + + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + if (__get_user(psr, (&pregs->psr)) || + __get_user(pc, (&pregs->pc)) || + __get_user(npc, (&pregs->npc)) || + __get_user(y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + cregs->tstate &= ~(TSTATE_ICC); + cregs->tstate |= psr_to_tstate_icc(psr); + if (!((pc | npc) & 3)) { + cregs->tpc = pc; + cregs->tnpc = npc; + } + cregs->y = y; + for (i = 1; i < 16; i++) { + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + } + pt_succ_return(regs, 0); + goto out_tsk; + } + + case PTRACE_SETREGS64: { + struct pt_regs __user *pregs = (struct pt_regs __user *) addr; + struct pt_regs *cregs = task_pt_regs(child); + unsigned long tstate, tpc, tnpc, y; + int i; + + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + if (__get_user(tstate, (&pregs->tstate)) || + __get_user(tpc, (&pregs->tpc)) || + __get_user(tnpc, (&pregs->tnpc)) || + __get_user(y, (&pregs->y))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { + tpc &= 0xffffffff; + tnpc &= 0xffffffff; + } + tstate &= (TSTATE_ICC | TSTATE_XCC); + cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + cregs->tstate |= tstate; + if (!((tpc | tnpc) & 3)) { + cregs->tpc = tpc; + cregs->tnpc = tnpc; + } + cregs->y = y; + for (i = 1; i < 16; i++) { + if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + } + pt_succ_return(regs, 0); + goto out_tsk; + } + + case PTRACE_GETFPREGS: { + struct fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; + }; + struct fps __user *fps = (struct fps __user *) addr; + unsigned long *fpregs = task_thread_info(child)->fpregs; + + if (copy_to_user(&fps->regs[0], fpregs, + (32 * sizeof(unsigned int))) || + __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || + __put_user(0, (&fps->fpqd)) || + __put_user(0, (&fps->flags)) || + __put_user(0, (&fps->extra)) || + clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + pt_succ_return(regs, 0); + goto out_tsk; + } + + case PTRACE_GETFPREGS64: { + struct fps { + unsigned int regs[64]; + unsigned long fsr; + }; + struct fps __user *fps = (struct fps __user *) addr; + unsigned long *fpregs = task_thread_info(child)->fpregs; + + if (copy_to_user(&fps->regs[0], fpregs, + (64 * sizeof(unsigned int))) || + __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + pt_succ_return(regs, 0); + goto out_tsk; + } + + case PTRACE_SETFPREGS: { + struct fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; + }; + struct fps __user *fps = (struct fps __user *) addr; + unsigned long *fpregs = task_thread_info(child)->fpregs; + unsigned fsr; + + if (copy_from_user(fpregs, &fps->regs[0], + (32 * sizeof(unsigned int))) || + __get_user(fsr, (&fps->fsr))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; + task_thread_info(child)->xfsr[0] |= fsr; + if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) + task_thread_info(child)->gsr[0] = 0; + task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); + pt_succ_return(regs, 0); + goto out_tsk; + } + + case PTRACE_SETFPREGS64: { + struct fps { + unsigned int regs[64]; + unsigned long fsr; + }; + struct fps __user *fps = (struct fps __user *) addr; + unsigned long *fpregs = task_thread_info(child)->fpregs; + + if (copy_from_user(fpregs, &fps->regs[0], + (64 * sizeof(unsigned int))) || + __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { + pt_error_return(regs, EFAULT); + goto out_tsk; + } + if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) + task_thread_info(child)->gsr[0] = 0; + task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); + pt_succ_return(regs, 0); + goto out_tsk; + } + + case PTRACE_READTEXT: + case PTRACE_READDATA: { + int res = ptrace_readdata(child, addr, + (char __user *)addr2, data); + if (res == data) { + pt_succ_return(regs, 0); + goto out_tsk; + } + if (res >= 0) + res = -EIO; + pt_error_return(regs, -res); + goto out_tsk; + } + + case PTRACE_WRITETEXT: + case PTRACE_WRITEDATA: { + int res = ptrace_writedata(child, (char __user *) addr2, + addr, data); + if (res == data) { + pt_succ_return(regs, 0); + goto out_tsk; + } + if (res >= 0) + res = -EIO; + pt_error_return(regs, -res); + goto out_tsk; + } + case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ + addr = 1; + + case PTRACE_CONT: { /* restart after signal. */ + if (!valid_signal(data)) { + pt_error_return(regs, EIO); + goto out_tsk; + } + + if (request == PTRACE_SYSCALL) { + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } else { + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } + + child->exit_code = data; +#ifdef DEBUG_PTRACE + printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, + child->pid, child->exit_code, + task_pt_regs(child)->tpc, + task_pt_regs(child)->tnpc); - default: - break; - }; - return err; -} +#endif + wake_up_process(child); + pt_succ_return(regs, 0); + goto out_tsk; + } -#ifdef CONFIG_COMPAT -static const struct ptrace_layout_segment sparc32_getregs_layout[] = { - { 0, offsetof(struct pt_regs32, u_regs[0]), - 0, GENREG32_PSR * sizeof(u32) }, - { offsetof(struct pt_regs32, u_regs[0]), - offsetof(struct pt_regs32, u_regs[15]), - 0, 1 * sizeof(u32) }, - { offsetof(struct pt_regs32, u_regs[15]), sizeof(struct pt_regs32), - -1, 0 }, - {0, 0, -1, 0} -}; +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + if (child->exit_state == EXIT_ZOMBIE) { /* already dead */ + pt_succ_return(regs, 0); + goto out_tsk; + } + child->exit_code = SIGKILL; + wake_up_process(child); + pt_succ_return(regs, 0); + goto out_tsk; + } -int arch_compat_ptrace(compat_long_t *request, struct task_struct *child, - struct utrace_attached_engine *engine, - compat_ulong_t addr, compat_ulong_t data, - compat_long_t *retval) -{ - void __user *uaddr = (void __user *) (unsigned long) addr; - int err = -ENOSYS; - - switch (*request) { - case PTRACE_GETREGS: - case PTRACE_SETREGS: - err = ptrace_layout_access(child, engine, - &utrace_sparc32_view, - sparc32_getregs_layout, - 0, sizeof(struct pt_regs32), - uaddr, NULL, - (*request == - PTRACE_SETREGS)); - break; + case PTRACE_SUNDETACH: { /* detach a process that was attached. */ + int error = ptrace_detach(child, data); + if (error) { + pt_error_return(regs, EIO); + goto out_tsk; + } + pt_succ_return(regs, 0); + goto out_tsk; + } - case PTRACE_GETFPREGS: - case PTRACE_SETFPREGS: - err = ptrace_whole_regset(child, engine, addr, 1, - (*request == PTRACE_SETFPREGS)); - break; + /* PTRACE_DUMPCORE unsupported... */ - case PTRACE_SUNDETACH: - *request = PTRACE_DETACH; - break; + case PTRACE_GETEVENTMSG: { + int err; - default: + if (test_thread_flag(TIF_32BIT)) + err = put_user(child->ptrace_message, + (unsigned int __user *) data); + else + err = put_user(child->ptrace_message, + (unsigned long __user *) data); + if (err) + pt_error_return(regs, -err); + else + pt_succ_return(regs, 0); break; - }; - return err; + } + + default: { + int err = ptrace_request(child, request, addr, data); + if (err) + pt_error_return(regs, -err); + else + pt_succ_return(regs, 0); + goto out_tsk; + } + } +out_tsk: + if (child) + put_task_struct(child); +out: + unlock_kernel(); } -#endif /* CONFIG_COMPAT */ -#endif /* CONFIG_PTRACE */ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) { /* do the secure computing check first */ - if (!syscall_exit_p) - secure_computing(regs->u_regs[UREG_G1]); + secure_computing(regs->u_regs[UREG_G1]); if (unlikely(current->audit_context) && syscall_exit_p) { unsigned long tstate = regs->tstate; @@ -794,9 +660,26 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) audit_syscall_exit(result, regs->u_regs[UREG_I0]); } - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, syscall_exit_p); + if (!(current->ptrace & PT_PTRACED)) + goto out; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + goto out; + + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +out: if (unlikely(current->audit_context) && !syscall_exit_p) audit_syscall_entry((test_thread_flag(TIF_32BIT) ? AUDIT_ARCH_SPARC : diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index f6b792660..96d56a841 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -492,7 +491,6 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, sigaddset(¤t->blocked,signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - tracehook_report_handle_signal(signr, ka, oldset, regs); } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 6ee9ddee7..708ba9b42 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -1237,7 +1236,6 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, sigaddset(¤t->blocked,signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - tracehook_report_handle_signal(signr, ka, oldset, regs); } static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index a9492cecd..b4967df83 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -745,6 +745,9 @@ asmlinkage long sparc32_execve(struct pt_regs *regs) current_thread_info()->xfsr[0] = 0; current_thread_info()->fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); } out: return error; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 53ba8a09b..d3a5cd553 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -24,7 +24,7 @@ sys_call_table32: /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod /*15*/ .word sys_chmod, sys32_lchown16, sparc_brk, sys32_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16 -/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause +/*25*/ .word sys32_vmsplice, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid @@ -166,7 +166,7 @@ sunos_sys_table: .word sys_chmod, sys32_lchown16, sunos_brk .word sunos_nosys, sys32_lseek, sunos_getpid .word sunos_nosys, sunos_nosys, sunos_nosys - .word sunos_getuid, sunos_nosys, compat_sys_ptrace + .word sunos_getuid, sunos_nosys, sys_ptrace .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys, sunos_nosys .word sys_access, sunos_nosys, sunos_nosys diff --git a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c index c17168be0..2c8209a36 100644 --- a/arch/x86_64/ia32/fpu32.c +++ b/arch/x86_64/ia32/fpu32.c @@ -9,7 +9,6 @@ #include #include #include -#include static inline unsigned short twd_i387_to_fxsr(unsigned short twd) { @@ -25,8 +24,7 @@ static inline unsigned short twd_i387_to_fxsr(unsigned short twd) return tmp; } -static inline unsigned long -twd_fxsr_to_i387(const struct i387_fxsave_struct *fxsave) +static inline unsigned long twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave) { struct _fpxreg *st = NULL; unsigned long tos = (fxsave->swd >> 11) & 7; @@ -73,11 +71,16 @@ twd_fxsr_to_i387(const struct i387_fxsave_struct *fxsave) } -static inline void -convert_fxsr_env_from_i387(struct i387_fxsave_struct *fxsave, const u32 env[7]) +static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, + struct _fpstate_ia32 __user *buf) { + struct _fpxreg *to; + struct _fpreg __user *from; + int i; u32 v; -#define G(num,val) val = env[num] + int err = 0; + +#define G(num,val) err |= __get_user(val, num + (u32 __user *)buf) G(0, fxsave->cwd); G(1, fxsave->swd); G(2, fxsave->twd); @@ -88,21 +91,9 @@ convert_fxsr_env_from_i387(struct i387_fxsave_struct *fxsave, const u32 env[7]) G(5, fxsave->rdp); /* 6: ds ignored */ #undef G -} - -static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, - struct _fpstate_ia32 __user *buf) -{ - u32 env[7]; - struct _fpxreg *to; - struct _fpreg __user *from; - int i; - - if (__copy_from_user(env, buf, sizeof(env))) + if (err) return -1; - convert_fxsr_env_from_i387(fxsave, env); - to = (struct _fpxreg *)&fxsave->st_space[0]; from = &buf->_st[0]; for (i = 0 ; i < 8 ; i++, to++, from++) { @@ -113,11 +104,16 @@ static inline int convert_fxsr_from_user(struct i387_fxsave_struct *fxsave, } -static inline void -convert_fxsr_env_to_i387(struct task_struct *tsk, struct pt_regs *regs, - u32 env[7], const struct i387_fxsave_struct *fxsave) +static inline int convert_fxsr_to_user(struct _fpstate_ia32 __user *buf, + struct i387_fxsave_struct *fxsave, + struct pt_regs *regs, + struct task_struct *tsk) { + struct _fpreg __user *to; + struct _fpxreg *from; + int i; u16 cs,ds; + int err = 0; if (tsk == current) { /* should be actually ds/cs at fpu exception time, @@ -129,7 +125,7 @@ convert_fxsr_env_to_i387(struct task_struct *tsk, struct pt_regs *regs, cs = regs->cs; } -#define P(num,val) env[num] = val +#define P(num,val) err |= __put_user(val, num + (u32 __user *)buf) P(0, (u32)fxsave->cwd | 0xffff0000); P(1, (u32)fxsave->swd | 0xffff0000); P(2, twd_fxsr_to_i387(fxsave)); @@ -138,21 +134,8 @@ convert_fxsr_env_to_i387(struct task_struct *tsk, struct pt_regs *regs, P(5, fxsave->rdp); P(6, 0xffff0000 | ds); #undef P -} - -static inline int convert_fxsr_to_user(struct _fpstate_ia32 __user *buf, - struct i387_fxsave_struct *fxsave, - struct pt_regs *regs, - struct task_struct *tsk) -{ - struct _fpreg __user *to; - struct _fpxreg *from; - int i; - u32 env[7]; - - convert_fxsr_env_to_i387(tsk, regs, env, fxsave); - if (__copy_to_user(buf, env, sizeof(env))) + if (err) return -1; to = &buf->_st[0]; @@ -198,38 +181,3 @@ int save_i387_ia32(struct task_struct *tsk, sizeof(struct i387_fxsave_struct)); return err ? -1 : 1; } - -int get_fpregs32(struct user_i387_ia32_struct *buf, struct task_struct *tsk) -{ - struct pt_regs *regs = ((struct pt_regs *)tsk->thread.rsp0) - 1; - struct _fpreg *to; - const struct _fpxreg *from; - unsigned int i; - - convert_fxsr_env_to_i387(tsk, regs, - (u32 *) buf, &tsk->thread.i387.fxsave); - - to = (struct _fpreg *) buf->st_space; - from = (const struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0]; - for (i = 0; i < 8; i++, to++, from++) - *to = *(const struct _fpreg *) from; - - return 0; -} - -int -set_fpregs32(struct task_struct *tsk, const struct user_i387_ia32_struct *buf) -{ - struct _fpxreg *to; - const struct _fpreg *from; - unsigned int i; - - convert_fxsr_env_from_i387(&tsk->thread.i387.fxsave, (u32 *) buf); - - to = (struct _fpxreg *) &tsk->thread.i387.fxsave.st_space[0]; - from = (const struct _fpreg *) buf->st_space; - for (i = 0; i < 8; i++, to++, from++) - *(struct _fpreg *) to = *from; - - return 0; -} diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c index 7c1c840af..7aac2ca96 100644 --- a/arch/x86_64/ia32/ia32_aout.c +++ b/arch/x86_64/ia32/ia32_aout.c @@ -422,6 +422,12 @@ beyond_if: (regs)->cs = __USER32_CS; (regs)->ss = __USER32_DS; set_fs(USER_DS); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } return 0; } diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c index ebda4a63f..bddaefdb8 100644 --- a/arch/x86_64/ia32/ia32_signal.c +++ b/arch/x86_64/ia32/ia32_signal.c @@ -491,7 +491,11 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, regs->cs = __USER32_CS; regs->ss = __USER32_DS; + set_fs(USER_DS); + regs->eflags &= ~TF_MASK; + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", @@ -583,7 +587,11 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->cs = __USER32_CS; regs->ss = __USER32_DS; + set_fs(USER_DS); + regs->eflags &= ~TF_MASK; + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", diff --git a/arch/x86_64/ia32/ia32entry-xen.S b/arch/x86_64/ia32/ia32entry-xen.S index 6e84b863f..cc1afebfa 100644 --- a/arch/x86_64/ia32/ia32entry-xen.S +++ b/arch/x86_64/ia32/ia32entry-xen.S @@ -444,7 +444,7 @@ ia32_sys_call_table: .quad sys_setuid16 .quad sys_getuid16 .quad compat_sys_stime /* stime */ /* 25 */ - .quad compat_sys_ptrace /* ptrace */ + .quad sys32_ptrace /* ptrace */ .quad sys_alarm .quad sys_fstat /* (old)fstat */ .quad sys_pause diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 29930d750..e1b1a99c5 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -417,7 +417,7 @@ ia32_sys_call_table: .quad sys_setuid16 .quad sys_getuid16 .quad compat_sys_stime /* stime */ /* 25 */ - .quad compat_sys_ptrace /* ptrace */ + .quad sys32_ptrace /* ptrace */ .quad sys_alarm .quad sys_fstat /* (old)fstat */ .quad sys_pause diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c index e8dcff98b..659c0722f 100644 --- a/arch/x86_64/ia32/ptrace32.c +++ b/arch/x86_64/ia32/ptrace32.c @@ -16,11 +16,7 @@ #include #include #include -#include -#include -#include #include -#include #include #include #include @@ -29,8 +25,7 @@ #include #include #include -#include -#include +#include /* * Determines which flags the user has access to [1 = access, 0 = no access]. @@ -40,33 +35,34 @@ #define FLAG_MASK 0x54dd5UL #define R32(l,q) \ - case offsetof(struct user_regs_struct32, l): stack[offsetof(struct pt_regs, q)/8] = val; break + case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break static int putreg32(struct task_struct *child, unsigned regno, u32 val) { + int i; __u64 *stack = (__u64 *)task_pt_regs(child); switch (regno) { - case offsetof(struct user_regs_struct32, fs): + case offsetof(struct user32, regs.fs): if (val && (val & 3) != 3) return -EIO; child->thread.fsindex = val & 0xffff; break; - case offsetof(struct user_regs_struct32, gs): + case offsetof(struct user32, regs.gs): if (val && (val & 3) != 3) return -EIO; child->thread.gsindex = val & 0xffff; break; - case offsetof(struct user_regs_struct32, ds): + case offsetof(struct user32, regs.ds): if (val && (val & 3) != 3) return -EIO; child->thread.ds = val & 0xffff; break; - case offsetof(struct user_regs_struct32, es): + case offsetof(struct user32, regs.es): child->thread.es = val & 0xffff; break; - case offsetof(struct user_regs_struct32, ss): + case offsetof(struct user32, regs.ss): if ((val & 3) != 3) return -EIO; stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff; break; - case offsetof(struct user_regs_struct32, cs): + case offsetof(struct user32, regs.cs): if ((val & 3) != 3) return -EIO; stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff; break; @@ -82,16 +78,53 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val) R32(eip, rip); R32(esp, rsp); - case offsetof(struct user_regs_struct32, eflags): { + case offsetof(struct user32, regs.eflags): { __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8]; val &= FLAG_MASK; *flags = val | (*flags & ~FLAG_MASK); - clear_tsk_thread_flag(child, TIF_FORCED_TF); break; } + case offsetof(struct user32, u_debugreg[4]): + case offsetof(struct user32, u_debugreg[5]): + return -EIO; + + case offsetof(struct user32, u_debugreg[0]): + child->thread.debugreg0 = val; + break; + + case offsetof(struct user32, u_debugreg[1]): + child->thread.debugreg1 = val; + break; + + case offsetof(struct user32, u_debugreg[2]): + child->thread.debugreg2 = val; + break; + + case offsetof(struct user32, u_debugreg[3]): + child->thread.debugreg3 = val; + break; + + case offsetof(struct user32, u_debugreg[6]): + child->thread.debugreg6 = val; + break; + + case offsetof(struct user32, u_debugreg[7]): + val &= ~DR_CONTROL_RESERVED; + /* See arch/i386/kernel/ptrace.c for an explanation of + * this awkward check.*/ + for(i=0; i<4; i++) + if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1) + return -EIO; + child->thread.debugreg7 = val; + break; + default: - BUG(); + if (regno > sizeof(struct user32) || (regno & 3)) + return -EIO; + + /* Other dummy fields in the virtual user structure are ignored */ + break; } return 0; } @@ -99,25 +132,24 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val) #undef R32 #define R32(l,q) \ - case offsetof(struct user_regs_struct32, l): val = stack[offsetof(struct pt_regs, q)/8]; break + case offsetof(struct user32, regs.l): *val = stack[offsetof(struct pt_regs, q)/8]; break -static int getreg32(struct task_struct *child, unsigned regno) +static int getreg32(struct task_struct *child, unsigned regno, u32 *val) { __u64 *stack = (__u64 *)task_pt_regs(child); - u32 val; switch (regno) { - case offsetof(struct user_regs_struct32, fs): - val = child->thread.fsindex; + case offsetof(struct user32, regs.fs): + *val = child->thread.fsindex; break; - case offsetof(struct user_regs_struct32, gs): - val = child->thread.gsindex; + case offsetof(struct user32, regs.gs): + *val = child->thread.gsindex; break; - case offsetof(struct user_regs_struct32, ds): - val = child->thread.ds; + case offsetof(struct user32, regs.ds): + *val = child->thread.ds; break; - case offsetof(struct user_regs_struct32, es): - val = child->thread.es; + case offsetof(struct user32, regs.es): + *val = child->thread.es; break; R32(cs, cs); @@ -131,503 +163,232 @@ static int getreg32(struct task_struct *child, unsigned regno) R32(eax, rax); R32(orig_eax, orig_rax); R32(eip, rip); + R32(eflags, eflags); R32(esp, rsp); - case offsetof(struct user_regs_struct32, eflags): - val = stack[offsetof(struct pt_regs, eflags) / 8]; - if (test_tsk_thread_flag(child, TIF_FORCED_TF)) - val &= ~X86_EFLAGS_TF; + case offsetof(struct user32, u_debugreg[0]): + *val = child->thread.debugreg0; + break; + case offsetof(struct user32, u_debugreg[1]): + *val = child->thread.debugreg1; + break; + case offsetof(struct user32, u_debugreg[2]): + *val = child->thread.debugreg2; + break; + case offsetof(struct user32, u_debugreg[3]): + *val = child->thread.debugreg3; + break; + case offsetof(struct user32, u_debugreg[6]): + *val = child->thread.debugreg6; + break; + case offsetof(struct user32, u_debugreg[7]): + *val = child->thread.debugreg7; break; default: - BUG(); - val = -1; - break; - } - - return val; -} - -#undef R32 + if (regno > sizeof(struct user32) || (regno & 3)) + return -EIO; -static int -ia32_genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (kbuf) { - u32 *kp = kbuf; - while (count > 0) { - *kp++ = getreg32(target, pos); - pos += 4; - count -= 4; - } - } - else { - u32 __user *up = ubuf; - while (count > 0) { - if (__put_user(getreg32(target, pos), up++)) - return -EFAULT; - pos += 4; - count -= 4; - } + /* Other dummy fields in the virtual user structure are ignored */ + *val = 0; + break; } - return 0; } -static int -ia32_genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret = 0; - - if (kbuf) { - const u32 *kp = kbuf; - while (!ret && count > 0) { - ret = putreg32(target, pos, *kp++); - pos += 4; - count -= 4; - } - } - else { - int ret = 0; - const u32 __user *up = ubuf; - while (!ret && count > 0) { - u32 val; - ret = __get_user(val, up++); - if (!ret) - ret = putreg32(target, pos, val); - pos += 4; - count -= 4; - } - } - - return ret; -} - -static int -ia32_fpregs_active(struct task_struct *target, - const struct utrace_regset *regset) -{ - return tsk_used_math(target) ? regset->n : 0; -} - -static int -ia32_fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct user_i387_ia32_struct fp; - int ret; - - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); - } - else - init_fpu(target); - - ret = get_fpregs32(&fp, target); - if (ret == 0) - ret = utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &fp, 0, -1); - - return ret; -} +#undef R32 -static int -ia32_fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) +static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data) { - struct user_i387_ia32_struct fp; int ret; - - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); - } - else if (pos == 0 && count == sizeof(fp)) - set_stopped_child_used_math(target); - else - init_fpu(target); - - if (pos > 0 || count < sizeof(fp)) { - ret = get_fpregs32(&fp, target); - if (ret == 0) - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fp, 0, -1); + compat_siginfo_t *si32 = (compat_siginfo_t *)compat_ptr(data); + siginfo_t ssi; + siginfo_t *si = compat_alloc_user_space(sizeof(siginfo_t)); + if (request == PTRACE_SETSIGINFO) { + memset(&ssi, 0, sizeof(siginfo_t)); + ret = copy_siginfo_from_user32(&ssi, si32); if (ret) return ret; - kbuf = &fp; - } - else if (kbuf == NULL) { - if (__copy_from_user(&fp, ubuf, sizeof(fp))) + if (copy_to_user(si, &ssi, sizeof(siginfo_t))) return -EFAULT; - kbuf = &fp; } - - return set_fpregs32(target, kbuf); -} - -static int -ia32_fpxregs_active(struct task_struct *target, - const struct utrace_regset *regset) -{ - return tsk_used_math(target) ? regset->n : 0; -} - -static int -ia32_fpxregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); + ret = sys_ptrace(request, pid, addr, (unsigned long)si); + if (ret) + return ret; + if (request == PTRACE_GETSIGINFO) { + if (copy_from_user(&ssi, si, sizeof(siginfo_t))) + return -EFAULT; + ret = copy_siginfo_to_user32(si32, &ssi); } - else - init_fpu(target); - - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.i387.fxsave, 0, -1); + return ret; } -static int -ia32_fpxregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) - +asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data) { + struct task_struct *child; + struct pt_regs *childregs; + void __user *datap = compat_ptr(data); int ret; + __u32 val; + + switch (request) { + case PTRACE_TRACEME: + case PTRACE_ATTACH: + case PTRACE_KILL: + case PTRACE_CONT: + case PTRACE_SINGLESTEP: + case PTRACE_DETACH: + case PTRACE_SYSCALL: + case PTRACE_SETOPTIONS: + return sys_ptrace(request, pid, addr, data); - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); - } - else if (pos == 0 && count == sizeof(struct i387_fxsave_struct)) - set_stopped_child_used_math(target); - else - init_fpu(target); - - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.i387.fxsave, 0, -1); - - target->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; - - return ret; -} - -static int -ia32_dbregs_active(struct task_struct *tsk, const struct utrace_regset *regset) -{ - if (tsk->thread.debugreg6 | tsk->thread.debugreg7) - return 8; - return 0; -} + default: + return -EINVAL; -static int -ia32_dbregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - for (pos >>= 2, count >>= 2; count > 0; --count, ++pos) { - u32 val; - - /* - * The hardware updates the status register on a debug trap, - * but do_debug (traps.c) saves it for us when that happens. - * So whether the target is current or not, debugregN is good. - */ - val = 0; - switch (pos) { - case 0: val = target->thread.debugreg0; break; - case 1: val = target->thread.debugreg1; break; - case 2: val = target->thread.debugreg2; break; - case 3: val = target->thread.debugreg3; break; - case 6: val = target->thread.debugreg6; break; - case 7: val = target->thread.debugreg7; break; - } + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + case PTRACE_POKEDATA: + case PTRACE_POKETEXT: + case PTRACE_POKEUSR: + case PTRACE_PEEKUSR: + case PTRACE_GETREGS: + case PTRACE_SETREGS: + case PTRACE_SETFPREGS: + case PTRACE_GETFPREGS: + case PTRACE_SETFPXREGS: + case PTRACE_GETFPXREGS: + case PTRACE_GETEVENTMSG: + break; - if (kbuf) { - *(u32 *) kbuf = val; - kbuf += sizeof(u32); - } - else { - if (__put_user(val, (u32 __user *) ubuf)) - return -EFAULT; - ubuf += sizeof(u32); - } + case PTRACE_SETSIGINFO: + case PTRACE_GETSIGINFO: + return ptrace32_siginfo(request, pid, addr, data); } - return 0; -} + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) + return PTR_ERR(child); -static int -ia32_dbregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - /* - * We'll just hijack the native setter to do the real work for us. - */ - const struct utrace_regset *dbregset = &utrace_x86_64_native.regsets[2]; - - int ret = 0; - - for (pos >>= 2, count >>= 2; count > 0; --count, ++pos) { - unsigned long val; - - if (kbuf) { - val = *(const u32 *) kbuf; - kbuf += sizeof(u32); - } - else { - if (__get_user(val, (u32 __user *) ubuf)) - return -EFAULT; - ubuf += sizeof(u32); - } + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out; - ret = (*dbregset->set)(target, dbregset, pos * sizeof(long), - sizeof(val), &val, NULL); - if (ret) - break; - } + childregs = task_pt_regs(child); - return ret; -} + switch (request) { + case PTRACE_PEEKDATA: + case PTRACE_PEEKTEXT: + ret = 0; + if (access_process_vm(child, addr, &val, sizeof(u32), 0)!=sizeof(u32)) + ret = -EIO; + else + ret = put_user(val, (unsigned int __user *)datap); + break; + case PTRACE_POKEDATA: + case PTRACE_POKETEXT: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(u32), 1)!=sizeof(u32)) + ret = -EIO; + break; -/* - * Perform get_thread_area on behalf of the traced child. - */ -static int -ia32_tls_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct user_desc info, *ip; - const struct n_desc_struct *desc; - const struct n_desc_struct *tls; + case PTRACE_PEEKUSR: + ret = getreg32(child, addr, &val); + if (ret == 0) + ret = put_user(val, (__u32 __user *)datap); + break; -/* - * Get the current Thread-Local Storage area: - */ + case PTRACE_POKEUSR: + ret = putreg32(child, addr, data); + break; -#define GET_BASE(desc) ( \ - (((desc)->a >> 16) & 0x0000ffff) | \ - (((desc)->b << 16) & 0x00ff0000) | \ - ( (desc)->b & 0xff000000) ) - -#define GET_LIMIT(desc) ( \ - ((desc)->a & 0x0ffff) | \ - ((desc)->b & 0xf0000) ) - -#define GET_32BIT(desc) (((desc)->b >> 22) & 1) -#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) -#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) -#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) -#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) -#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) - - tls = (struct n_desc_struct *) target->thread.tls_array; - desc = &tls[pos]; - ip = kbuf ?: &info; - memset(ip, 0, sizeof *ip); - for (; count > 0; count -= sizeof(struct user_desc), ++desc) { - ip->entry_number = desc - tls + GDT_ENTRY_TLS_MIN; - ip->base_addr = GET_BASE(desc); - ip->limit = GET_LIMIT(desc); - ip->seg_32bit = GET_32BIT(desc); - ip->contents = GET_CONTENTS(desc); - ip->read_exec_only = !GET_WRITABLE(desc); - ip->limit_in_pages = GET_LIMIT_PAGES(desc); - ip->seg_not_present = !GET_PRESENT(desc); - ip->useable = GET_USEABLE(desc); - - if (kbuf) - ++ip; - else { - if (__copy_to_user(ubuf, &info, sizeof(info))) - return -EFAULT; - ubuf += sizeof(info); + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + if (!access_ok(VERIFY_WRITE, datap, 16*4)) { + ret = -EIO; + break; } + ret = 0; + for ( i = 0; i <= 16*4 ; i += sizeof(__u32) ) { + getreg32(child, i, &val); + ret |= __put_user(val,(u32 __user *)datap); + datap += sizeof(u32); + } + break; } - return 0; -} - -/* - * Perform set_thread_area on behalf of the traced child. - */ -static int -ia32_tls_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - struct user_desc info; - struct n_desc_struct *desc; - struct n_desc_struct newtls[GDT_ENTRY_TLS_ENTRIES]; - unsigned int i; - int cpu; - - pos /= sizeof(struct user_desc); - count /= sizeof(struct user_desc); - - desc = &newtls[pos]; - for (i = 0; i < count; ++i, ++desc) { - const struct user_desc *ip; - if (kbuf) { - ip = kbuf; - kbuf += sizeof(struct user_desc); - } - else { - ip = &info; - if (__copy_from_user(&info, ubuf, sizeof(info))) - return -EFAULT; - ubuf += sizeof(struct user_desc); + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + unsigned long tmp; + int i; + if (!access_ok(VERIFY_READ, datap, 16*4)) { + ret = -EIO; + break; } - - if (LDT_empty(ip)) { - desc->a = 0; - desc->b = 0; - } else { - desc->a = LDT_entry_a(ip); - desc->b = LDT_entry_b(ip); + ret = 0; + for ( i = 0; i <= 16*4; i += sizeof(u32) ) { + ret |= __get_user(tmp, (u32 __user *)datap); + putreg32(child, i, tmp); + datap += sizeof(u32); } + break; } - /* - * We must not get preempted while modifying the TLS. - */ - cpu = get_cpu(); - memcpy(&target->thread.tls_array[pos], newtls, - count * sizeof(newtls[0])); - if (target == current) - load_TLS(&target->thread, cpu); - put_cpu(); + case PTRACE_GETFPREGS: + ret = -EIO; + if (!access_ok(VERIFY_READ, compat_ptr(data), + sizeof(struct user_i387_struct))) + break; + save_i387_ia32(child, datap, childregs, 1); + ret = 0; + break; - return 0; -} + case PTRACE_SETFPREGS: + ret = -EIO; + if (!access_ok(VERIFY_WRITE, datap, + sizeof(struct user_i387_struct))) + break; + ret = 0; + /* don't check EFAULT to be bug-to-bug compatible to i386 */ + restore_i387_ia32(child, datap, 1); + break; -/* - * Determine how many TLS slots are in use. - */ -static int -ia32_tls_active(struct task_struct *target, const struct utrace_regset *regset) -{ - int i; - for (i = GDT_ENTRY_TLS_ENTRIES; i > 0; --i) { - struct n_desc_struct *desc = (struct n_desc_struct *) - &target->thread.tls_array[i - 1]; - if ((desc->a | desc->b) != 0) + case PTRACE_GETFPXREGS: { + struct user32_fxsr_struct __user *u = datap; + init_fpu(child); + ret = -EIO; + if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + break; + ret = -EFAULT; + if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u))) break; + ret = __put_user(childregs->cs, &u->fcs); + ret |= __put_user(child->thread.ds, &u->fos); + break; + } + case PTRACE_SETFPXREGS: { + struct user32_fxsr_struct __user *u = datap; + unlazy_fpu(child); + ret = -EIO; + if (!access_ok(VERIFY_READ, u, sizeof(*u))) + break; + /* no checking to be bug-to-bug compatible with i386 */ + __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)); + set_stopped_child_used_math(child); + child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; + ret = 0; + break; } - return i; -} - -/* - * This should match arch/i386/kernel/ptrace.c:native_regsets. - * XXX ioperm? vm86? - */ -static const struct utrace_regset ia32_regsets[] = { - { - .n = sizeof(struct user_regs_struct32)/4, - .size = 4, .align = 4, - .get = ia32_genregs_get, .set = ia32_genregs_set - }, - { - .n = sizeof(struct user_i387_ia32_struct) / 4, - .size = 4, .align = 4, - .active = ia32_fpregs_active, - .get = ia32_fpregs_get, .set = ia32_fpregs_set - }, - { - .n = sizeof(struct user32_fxsr_struct) / 4, - .size = 4, .align = 4, - .active = ia32_fpxregs_active, - .get = ia32_fpxregs_get, .set = ia32_fpxregs_set - }, - { - .n = GDT_ENTRY_TLS_ENTRIES, - .bias = GDT_ENTRY_TLS_MIN, - .size = sizeof(struct user_desc), - .align = sizeof(struct user_desc), - .active = ia32_tls_active, - .get = ia32_tls_get, .set = ia32_tls_set - }, - { - .n = 8, .size = 4, .align = 4, - .active = ia32_dbregs_active, - .get = ia32_dbregs_get, .set = ia32_dbregs_set - }, -}; - -const struct utrace_regset_view utrace_ia32_view = { - .name = "i386", .e_machine = EM_386, - .regsets = ia32_regsets, - .n = sizeof ia32_regsets / sizeof ia32_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_ia32_view); - - -#ifdef CONFIG_PTRACE -/* - * This matches the arch/i386/kernel/ptrace.c definitions. - */ + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data)); + break; -static const struct ptrace_layout_segment ia32_uarea[] = { - {0, sizeof(struct user_regs_struct32), 0, 0}, - {offsetof(struct user32, u_debugreg[0]), - offsetof(struct user32, u_debugreg[8]), 4, 0}, - {0, 0, -1, 0} -}; - -fastcall int arch_compat_ptrace(compat_long_t *req, struct task_struct *child, - struct utrace_attached_engine *engine, - compat_ulong_t addr, compat_ulong_t data, - compat_long_t *val) -{ - switch (*req) { - case PTRACE_PEEKUSR: - return ptrace_compat_peekusr(child, engine, ia32_uarea, - addr, data); - case PTRACE_POKEUSR: - return ptrace_compat_pokeusr(child, engine, ia32_uarea, - addr, data); - case PTRACE_GETREGS: - return ptrace_whole_regset(child, engine, data, 0, 0); - case PTRACE_SETREGS: - return ptrace_whole_regset(child, engine, data, 0, 1); - case PTRACE_GETFPREGS: - return ptrace_whole_regset(child, engine, data, 1, 0); - case PTRACE_SETFPREGS: - return ptrace_whole_regset(child, engine, data, 1, 1); - case PTRACE_GETFPXREGS: - return ptrace_whole_regset(child, engine, data, 2, 0); - case PTRACE_SETFPXREGS: - return ptrace_whole_regset(child, engine, data, 2, 1); - case PTRACE_GET_THREAD_AREA: - case PTRACE_SET_THREAD_AREA: - return ptrace_onereg_access(child, engine, - &utrace_ia32_view, 3, - addr, - (void __user *)(unsigned long)data, - *req == PTRACE_SET_THREAD_AREA); + default: + BUG(); } - return -ENOSYS; + + out: + put_task_struct(child); + return ret; } -#endif /* CONFIG_PTRACE */ + diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index 5ab4d2e2e..49bfe957c 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -863,6 +863,11 @@ asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv, if (IS_ERR(filename)) return error; error = compat_do_execve(filename, argv, envp, regs); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } putname(filename); return error; } diff --git a/arch/x86_64/kernel/irq-xen.c b/arch/x86_64/kernel/irq-xen.c index a5b06c97c..05ddad3c5 100644 --- a/arch/x86_64/kernel/irq-xen.c +++ b/arch/x86_64/kernel/irq-xen.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -118,7 +117,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) { /* high bit used in ret_from_ code */ unsigned irq = ~regs->orig_rax; - struct vx_info_save vxis; if (unlikely(irq >= NR_IRQS)) { printk(KERN_EMERG "%s: cannot handle IRQ %d\n", @@ -132,9 +130,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) #ifdef CONFIG_DEBUG_STACKOVERFLOW stack_overflow_check(regs); #endif - __enter_vx_admin(&vxis); __do_IRQ(irq, regs); - __leave_vx_admin(&vxis); irq_exit(); return 1; diff --git a/arch/x86_64/kernel/process-xen.c b/arch/x86_64/kernel/process-xen.c index 28640a0e7..a89ff9157 100644 --- a/arch/x86_64/kernel/process-xen.c +++ b/arch/x86_64/kernel/process-xen.c @@ -527,25 +527,19 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) if (next->gs) HYPERVISOR_set_segment_base(SEGBASE_GS_USER, next->gs); + /* Must be after DS reload */ + if (prev_p->thread_info->status & TS_USEDFPU) { + __save_init_fpu(prev_p); /* _not_ save_init_fpu() */ + HYPERVISOR_fpu_taskswitch(1); + } + /* - * Switch the PDA and FPU context. + * Switch the PDA and FPU contexts. */ prev->userrsp = read_pda(oldrsp); write_pda(oldrsp, next->userrsp); write_pda(pcurrent, next_p); - /* This must be here to ensure both math_state_restore() and - kernel_fpu_begin() work consistently. - And the AMD workaround requires it to be after DS reload. */ - /* - * This is basically '__unlazy_fpu', except that we queue a - * multicall to indicate FPU task switch, rather than - * synchronously trapping to Xen. - */ - if (prev_p->thread_info->status & TS_USEDFPU) { - __save_init_fpu(prev_p); /* _not_ save_init_fpu() */ - HYPERVISOR_fpu_taskswitch(1); - } write_pda(kernelstack, task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); @@ -580,6 +574,11 @@ long sys_execve(char __user *name, char __user * __user *argv, if (IS_ERR(filename)) return error; error = do_execve(filename, argv, envp, ®s); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } putname(filename); return error; } diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index c8c644087..583d96f22 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -571,6 +571,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) prev->gsindex = gsindex; } + /* Must be after DS reload */ + unlazy_fpu(prev_p); + /* * Switch the PDA and FPU contexts. */ @@ -578,10 +581,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) write_pda(oldrsp, next->userrsp); write_pda(pcurrent, next_p); - /* This must be here to ensure both math_state_restore() and - kernel_fpu_begin() work consistently. - And the AMD workaround requires it to be after DS reload. */ - unlazy_fpu(prev_p); write_pda(kernelstack, task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); @@ -636,6 +635,11 @@ long sys_execve(char __user *name, char __user * __user *argv, if (IS_ERR(filename)) return error; error = do_execve(filename, argv, envp, ®s); + if (error == 0) { + task_lock(current); + current->ptrace &= ~PT_DTRACE; + task_unlock(current); + } putname(filename); return error; } diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 280bc88f2..2d50024c9 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -13,14 +13,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include @@ -32,7 +30,6 @@ #include #include #include -#include /* * does not yet catch signals sent when the child dies. @@ -165,7 +162,7 @@ static int is_at_popf(struct task_struct *child, struct pt_regs *regs) return 0; } -void tracehook_enable_single_step(struct task_struct *child) +static void set_singlestep(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); @@ -195,18 +192,19 @@ void tracehook_enable_single_step(struct task_struct *child) if (is_at_popf(child, regs)) return; - set_tsk_thread_flag(child, TIF_FORCED_TF); + child->ptrace |= PT_DTRACE; } -void tracehook_disable_single_step(struct task_struct *child) +static void clear_singlestep(struct task_struct *child) { /* Always clear TIF_SINGLESTEP... */ clear_tsk_thread_flag(child, TIF_SINGLESTEP); /* But touch TF only if it was set by us.. */ - if (test_and_clear_tsk_thread_flag(child, TIF_FORCED_TF)) { + if (child->ptrace & PT_DTRACE) { struct pt_regs *regs = task_pt_regs(child); regs->eflags &= ~TRAP_FLAG; + child->ptrace &= ~PT_DTRACE; } } @@ -217,7 +215,7 @@ void tracehook_disable_single_step(struct task_struct *child) */ void ptrace_disable(struct task_struct *child) { - tracehook_disable_single_step(child); + clear_singlestep(child); } static int putreg(struct task_struct *child, @@ -270,7 +268,6 @@ static int putreg(struct task_struct *child, tmp = get_stack_long(child, EFL_OFFSET); tmp &= ~FLAG_MASK; value |= tmp; - clear_tsk_thread_flag(child, TIF_FORCED_TF); break; case offsetof(struct user_regs_struct,cs): if ((value & 3) != 3) @@ -303,431 +300,303 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno) val = get_stack_long(child, regno); if (test_tsk_thread_flag(child, TIF_IA32)) val &= 0xffffffff; - if (regno == (offsetof(struct user_regs_struct, eflags) - - sizeof(struct pt_regs)) - && test_tsk_thread_flag(child, TIF_FORCED_TF)) - val &= ~X86_EFLAGS_TF; return val; } } -static int -genregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - if (kbuf) { - unsigned long *kp = kbuf; - while (count > 0) { - *kp++ = getreg(target, pos); - pos += sizeof(long); - count -= sizeof(long); - } - } - else { - unsigned long __user *up = ubuf; - while (count > 0) { - if (__put_user(getreg(target, pos), up++)) - return -EFAULT; - pos += sizeof(long); - count -= sizeof(long); - } - } - - return 0; -} - -static int -genregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret = 0; - - if (kbuf) { - const unsigned long *kp = kbuf; - while (!ret && count > 0) { - ret = putreg(target, pos, *kp++); - pos += sizeof(long); - count -= sizeof(long); - } - } - else { - int ret = 0; - const unsigned long __user *up = ubuf; - while (!ret && count > 0) { - unsigned long val; - ret = __get_user(val, up++); - if (!ret) - ret = putreg(target, pos, val); - pos += sizeof(long); - count -= sizeof(long); - } + long i, ret; + unsigned ui; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long __user *) data); + break; } - return ret; -} - + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; -static int -dbregs_active(struct task_struct *tsk, const struct utrace_regset *regset) -{ - if (tsk->thread.debugreg6 | tsk->thread.debugreg7) - return 8; - return 0; -} - -static int -dbregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - for (pos >>= 3, count >>= 3; count > 0; --count, ++pos) { - unsigned long val; - - /* - * The hardware updates the status register on a debug trap, - * but do_debug (traps.c) saves it for us when that happens. - * So whether the target is current or not, debugregN is good. - */ - val = 0; - switch (pos) { - case 0: val = target->thread.debugreg0; break; - case 1: val = target->thread.debugreg1; break; - case 2: val = target->thread.debugreg2; break; - case 3: val = target->thread.debugreg3; break; - case 6: val = target->thread.debugreg6; break; - case 7: val = target->thread.debugreg7; break; - } - - if (kbuf) { - *(unsigned long *) kbuf = val; - kbuf += sizeof(unsigned long); - } - else { - if (__put_user(val, (unsigned long __user *) ubuf)) - return -EFAULT; - ubuf += sizeof(unsigned long); - } - } - - return 0; -} - -static int -dbregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - unsigned long maxaddr = TASK_SIZE_OF(target); - maxaddr -= test_tsk_thread_flag(target, TIF_IA32) ? 3 : 7; - - for (pos >>= 3, count >>= 3; count > 0; --count, ++pos) { - unsigned long val; - unsigned int i; - - if (kbuf) { - val = *(const unsigned long *) kbuf; - kbuf += sizeof(unsigned long); - } - else { - if (__get_user(val, (unsigned long __user *) ubuf)) - return -EFAULT; - ubuf += sizeof(unsigned long); - } - - switch (pos) { -#define SET_DBREG(n) \ - target->thread.debugreg##n = val; \ - if (target == current) \ - set_debugreg(target->thread.debugreg##n, n) + ret = -EIO; + if ((addr & 7) || + addr > sizeof(struct user) - 7) + break; - case 0: - if (val >= maxaddr) - return -EIO; - SET_DBREG(0); + switch (addr) { + case 0 ... sizeof(struct user_regs_struct) - sizeof(long): + tmp = getreg(child, addr); break; - case 1: - if (val >= maxaddr) - return -EIO; - SET_DBREG(1); + case offsetof(struct user, u_debugreg[0]): + tmp = child->thread.debugreg0; break; - case 2: - if (val >= maxaddr) - return -EIO; - SET_DBREG(2); + case offsetof(struct user, u_debugreg[1]): + tmp = child->thread.debugreg1; break; - case 3: - if (val >= maxaddr) - return -EIO; - SET_DBREG(3); + case offsetof(struct user, u_debugreg[2]): + tmp = child->thread.debugreg2; break; - case 4: - case 5: - if (val != 0) - return -EIO; + case offsetof(struct user, u_debugreg[3]): + tmp = child->thread.debugreg3; break; - case 6: - if (val >> 32) - return -EIO; - SET_DBREG(6); + case offsetof(struct user, u_debugreg[6]): + tmp = child->thread.debugreg6; break; - case 7: - /* - * See arch/i386/kernel/ptrace.c for an explanation - * of this awkward check. - */ - val &= ~DR_CONTROL_RESERVED; - for (i = 0; i < 4; i++) - if ((0x5554 >> ((val >> (16 + 4*i)) & 0xf)) - & 1) - return -EIO; - SET_DBREG(7); + case offsetof(struct user, u_debugreg[7]): + tmp = child->thread.debugreg7; + break; + default: + tmp = 0; break; -#undef SET_DBREG } + ret = put_user(tmp,(unsigned long __user *) data); + break; } - return 0; -} - + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; -static int -fpregs_active(struct task_struct *target, const struct utrace_regset *regset) -{ - return tsk_used_math(target) ? regset->n : 0; -} + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + { + int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7; + ret = -EIO; + if ((addr & 7) || + addr > sizeof(struct user) - 7) + break; -static int -fpregs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); + switch (addr) { + case 0 ... sizeof(struct user_regs_struct) - sizeof(long): + ret = putreg(child, addr, data); + break; + /* Disallows to set a breakpoint into the vsyscall */ + case offsetof(struct user, u_debugreg[0]): + if (data >= TASK_SIZE_OF(child) - dsize) break; + child->thread.debugreg0 = data; + ret = 0; + break; + case offsetof(struct user, u_debugreg[1]): + if (data >= TASK_SIZE_OF(child) - dsize) break; + child->thread.debugreg1 = data; + ret = 0; + break; + case offsetof(struct user, u_debugreg[2]): + if (data >= TASK_SIZE_OF(child) - dsize) break; + child->thread.debugreg2 = data; + ret = 0; + break; + case offsetof(struct user, u_debugreg[3]): + if (data >= TASK_SIZE_OF(child) - dsize) break; + child->thread.debugreg3 = data; + ret = 0; + break; + case offsetof(struct user, u_debugreg[6]): + if (data >> 32) + break; + child->thread.debugreg6 = data; + ret = 0; + break; + case offsetof(struct user, u_debugreg[7]): + /* See arch/i386/kernel/ptrace.c for an explanation of + * this awkward check.*/ + data &= ~DR_CONTROL_RESERVED; + for(i=0; i<4; i++) + if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1) + break; + if (i == 4) { + child->thread.debugreg7 = data; + ret = 0; + } + break; + } + break; } - else - init_fpu(target); + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: /* restart after signal. */ - return utrace_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.i387.fxsave, 0, -1); -} + ret = -EIO; + if (!valid_signal(data)) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child,TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); + clear_tsk_thread_flag(child, TIF_SINGLESTEP); + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_singlestep(child); + wake_up_process(child); + ret = 0; + break; -static int -fpregs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret; +#ifdef CONFIG_IA32_EMULATION + /* This makes only sense with 32bit programs. Allow a + 64bit debugger to fully examine them too. Better + don't use it against 64bit processes, use + PTRACE_ARCH_PRCTL instead. */ + case PTRACE_SET_THREAD_AREA: { + struct user_desc __user *p; + int old; + p = (struct user_desc __user *)data; + get_user(old, &p->entry_number); + put_user(addr, &p->entry_number); + ret = do_set_thread_area(&child->thread, p); + put_user(old, &p->entry_number); + break; + case PTRACE_GET_THREAD_AREA: + p = (struct user_desc __user *)data; + get_user(old, &p->entry_number); + put_user(addr, &p->entry_number); + ret = do_get_thread_area(&child->thread, p); + put_user(old, &p->entry_number); + break; + } +#endif + /* normal 64bit interface to access TLS data. + Works just like arch_prctl, except that the arguments + are reversed. */ + case PTRACE_ARCH_PRCTL: + ret = do_arch_prctl(child, data, addr); + break; - if (tsk_used_math(target)) { - if (target == current) - unlazy_fpu(target); +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ + break; + clear_tsk_thread_flag(child, TIF_SINGLESTEP); + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_singlestep(child); + wake_up_process(child); + break; + + case PTRACE_SINGLESTEP: /* set the trap flag. */ + ret = -EIO; + if (!valid_signal(data)) + break; + clear_tsk_thread_flag(child,TIF_SYSCALL_TRACE); + set_singlestep(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + + case PTRACE_DETACH: + /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, + sizeof(struct user_regs_struct))) { + ret = -EIO; + break; + } + ret = 0; + for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { + ret |= __put_user(getreg(child, ui),(unsigned long __user *) data); + data += sizeof(long); + } + break; } - else if (pos == 0 && count == sizeof(struct user_i387_struct)) - set_stopped_child_used_math(target); - else - init_fpu(target); - - ret = utrace_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.i387.fxsave, 0, -1); - - target->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; - - return ret; -} - -static int -fsgs_active(struct task_struct *tsk, const struct utrace_regset *regset) -{ - if (tsk->thread.gsindex == GS_TLS_SEL || tsk->thread.gs) - return 2; - if (tsk->thread.fsindex == FS_TLS_SEL || tsk->thread.fs) - return 1; - return 0; -} - -static inline u32 read_32bit_tls(struct task_struct *t, int tls) -{ - struct desc_struct *desc = (void *)t->thread.tls_array; - desc += tls; - return desc->base0 | - (((u32)desc->base1) << 16) | - (((u32)desc->base2) << 24); -} - -static int -fsgs_get(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - const unsigned long *kaddr = kbuf; - const unsigned long __user *uaddr = ubuf; - unsigned long addr; - /* - * XXX why the MSR reads here? - * Can anything change the MSRs without changing thread.fs first? - */ - if (pos == 0) { /* FS */ - if (kaddr) - addr = *kaddr++; - else if (__get_user(addr, uaddr++)) - return -EFAULT; - if (target->thread.fsindex == FS_TLS_SEL) - addr = read_32bit_tls(target, FS_TLS); - else if (target == current) { - rdmsrl(MSR_FS_BASE, addr); + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + unsigned long tmp; + if (!access_ok(VERIFY_READ, (unsigned __user *)data, + sizeof(struct user_regs_struct))) { + ret = -EIO; + break; } - else - addr = target->thread.fs; + ret = 0; + for (ui = 0; ui < sizeof(struct user_regs_struct); ui += sizeof(long)) { + ret |= __get_user(tmp, (unsigned long __user *) data); + putreg(child, ui, tmp); + data += sizeof(long); + } + break; } - if (count > sizeof(unsigned long)) { /* GS */ - if (kaddr) - addr = *kaddr; - else if (__get_user(addr, uaddr)) - return -EFAULT; - if (target->thread.fsindex == GS_TLS_SEL) - addr = read_32bit_tls(target, GS_TLS); - else if (target == current) { - rdmsrl(MSR_GS_BASE, addr); + case PTRACE_GETFPREGS: { /* Get the child extended FPU state. */ + if (!access_ok(VERIFY_WRITE, (unsigned __user *)data, + sizeof(struct user_i387_struct))) { + ret = -EIO; + break; } - else - addr = target->thread.fs; + ret = get_fpregs((struct user_i387_struct __user *)data, child); + break; } - return 0; -} - -static int -fsgs_set(struct task_struct *target, - const struct utrace_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - const unsigned long *kaddr = kbuf; - const unsigned long __user *uaddr = ubuf; - unsigned long addr; - int ret = 0; - - if (pos == 0) { /* FS */ - if (kaddr) - addr = *kaddr++; - else if (__get_user(addr, uaddr++)) - return -EFAULT; - ret = do_arch_prctl(target, ARCH_SET_FS, addr); + case PTRACE_SETFPREGS: { /* Set the child extended FPU state. */ + if (!access_ok(VERIFY_READ, (unsigned __user *)data, + sizeof(struct user_i387_struct))) { + ret = -EIO; + break; + } + set_stopped_child_used_math(child); + ret = set_fpregs(child, (struct user_i387_struct __user *)data); + break; } - if (!ret && count > sizeof(unsigned long)) { /* GS */ - if (kaddr) - addr = *kaddr; - else if (__get_user(addr, uaddr)) - return -EFAULT; - ret = do_arch_prctl(target, ARCH_SET_GS, addr); + default: + ret = ptrace_request(child, request, addr, data); + break; } - return ret; } - -/* - * These are our native regset flavors. - * XXX ioperm? vm86? - */ -static const struct utrace_regset native_regsets[] = { - { - .n = sizeof(struct user_regs_struct)/8, .size = 8, .align = 8, - .get = genregs_get, .set = genregs_set - }, - { - .n = sizeof(struct user_i387_struct) / sizeof(long), - .size = sizeof(long), .align = sizeof(long), - .active = fpregs_active, - .get = fpregs_get, .set = fpregs_set - }, - { - .n = 2, .size = sizeof(long), .align = sizeof(long), - .active = fsgs_active, - .get = fsgs_get, .set = fsgs_set - }, - { - .n = 8, .size = sizeof(long), .align = sizeof(long), - .active = dbregs_active, - .get = dbregs_get, .set = dbregs_set - }, -}; - -const struct utrace_regset_view utrace_x86_64_native = { - .name = "x86-64", .e_machine = EM_X86_64, - .regsets = native_regsets, - .n = sizeof native_regsets / sizeof native_regsets[0], -}; -EXPORT_SYMBOL_GPL(utrace_x86_64_native); - - -#ifdef CONFIG_PTRACE -static const struct ptrace_layout_segment x86_64_uarea[] = { - {0, sizeof(struct user_regs_struct), 0, 0}, - {offsetof(struct user, u_debugreg[0]), - offsetof(struct user, u_debugreg[4]), 3, 0}, - {offsetof(struct user, u_debugreg[6]), - offsetof(struct user, u_debugreg[8]), 3, 6 * sizeof(long)}, - {0, 0, -1, 0} -}; - -fastcall int arch_ptrace(long *req, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, long *val) +static void syscall_trace(struct pt_regs *regs) { - switch (*req) { - case PTRACE_PEEKUSR: - return ptrace_peekusr(child, engine, x86_64_uarea, addr, data); - case PTRACE_POKEUSR: - return ptrace_pokeusr(child, engine, x86_64_uarea, addr, data); - case PTRACE_GETREGS: - return ptrace_whole_regset(child, engine, data, 0, 0); - case PTRACE_SETREGS: - return ptrace_whole_regset(child, engine, data, 0, 1); - case PTRACE_GETFPREGS: - return ptrace_whole_regset(child, engine, data, 1, 0); - case PTRACE_SETFPREGS: - return ptrace_whole_regset(child, engine, data, 1, 1); -#ifdef CONFIG_IA32_EMULATION - case PTRACE_GET_THREAD_AREA: - case PTRACE_SET_THREAD_AREA: - return ptrace_onereg_access(child, engine, - &utrace_ia32_view, 3, - addr, (void __user *)data, - *req == PTRACE_SET_THREAD_AREA); + +#if 0 + printk("trace %s rip %lx rsp %lx rax %d origrax %d caller %lx tiflags %x ptrace %x\n", + current->comm, + regs->rip, regs->rsp, regs->rax, regs->orig_rax, __builtin_return_address(0), + current_thread_info()->flags, current->ptrace); #endif - /* normal 64bit interface to access TLS data. - Works just like arch_prctl, except that the arguments - are reversed. */ - case PTRACE_ARCH_PRCTL: - return do_arch_prctl(child, data, addr); + + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; } - return -ENOSYS; } -#endif /* CONFIG_PTRACE */ - asmlinkage void syscall_trace_enter(struct pt_regs *regs) { /* do the secure computing check first */ secure_computing(regs->orig_rax); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, 0); + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + syscall_trace(regs); if (unlikely(current->audit_context)) { if (test_thread_flag(TIF_IA32)) { @@ -749,11 +618,8 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs) if (unlikely(current->audit_context)) audit_syscall_exit(AUDITSC_RESULT(regs->rax), regs->rax); - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall(regs, 1); - - if (test_thread_flag(TIF_SINGLESTEP)) { - force_sig(SIGTRAP, current); /* XXX */ - tracehook_report_syscall_step(regs); - } + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) + && (current->ptrace & PT_PTRACED)) + syscall_trace(regs); } diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index e92087a11..7f58bc9a0 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -302,6 +302,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, see include/asm-x86_64/uaccess.h for details. */ set_fs(USER_DS); + regs->eflags &= ~TF_MASK; + if (test_thread_flag(TIF_SINGLESTEP)) + ptrace_notify(SIGTRAP); #ifdef DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->rip, frame->pretcode); @@ -353,12 +356,16 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, } /* - * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF flag so - * that register information in the sigcontext is correct. + * If TF is set due to a debugger (PT_DTRACE), clear the TF + * flag so that register information in the sigcontext is + * correct. */ - if (unlikely(regs->eflags & TF_MASK) - && likely(test_and_clear_thread_flag(TIF_FORCED_TF))) - regs->eflags &= ~TF_MASK; + if (unlikely(regs->eflags & TF_MASK)) { + if (likely(current->ptrace & PT_DTRACE)) { + current->ptrace &= ~PT_DTRACE; + regs->eflags &= ~TF_MASK; + } + } #ifdef CONFIG_IA32_EMULATION if (test_thread_flag(TIF_IA32)) { @@ -377,15 +384,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - - /* - * Clear TF when entering the signal handler, but - * notify any tracer that was single-stepping it. - * The tracer may want to single-step inside the - * handler too. - */ - regs->eflags &= ~TF_MASK; - tracehook_report_handle_signal(sig, ka, oldset, regs); } return ret; diff --git a/arch/x86_64/kernel/traps-xen.c b/arch/x86_64/kernel/traps-xen.c index a551b73a3..13c6d3d47 100644 --- a/arch/x86_64/kernel/traps-xen.c +++ b/arch/x86_64/kernel/traps-xen.c @@ -115,7 +115,6 @@ static int call_trace = 1; #define call_trace (-1) #endif - #ifdef CONFIG_KALLSYMS # include void printk_address(unsigned long address) @@ -182,7 +181,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, break; #endif default: - end = per_cpu(orig_tss, cpu).ist[k]; + end = per_cpu(orig_ist, cpu).ist[k]; break; } /* @@ -936,6 +935,14 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs, */ if (!user_mode(regs)) goto clear_TF_reenable; + /* + * Was the TF flag set by a debugger? If so, clear it now, + * so that register information is correct. + */ + if (tsk->ptrace & PT_DTRACE) { + regs->eflags &= ~TF_MASK; + tsk->ptrace &= ~PT_DTRACE; + } } /* Ok, finally something we can handle */ diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 2df603e12..6d38a2d58 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -931,6 +931,14 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs, */ if (!user_mode(regs)) goto clear_TF_reenable; + /* + * Was the TF flag set by a debugger? If so, clear it now, + * so that register information is correct. + */ + if (tsk->ptrace & PT_DTRACE) { + regs->eflags &= ~TF_MASK; + tsk->ptrace &= ~PT_DTRACE; + } } /* Ok, finally something we can handle */ diff --git a/arch/x86_64/mm/fault-xen.c b/arch/x86_64/mm/fault-xen.c index 438cf548d..3693d5d9f 100644 --- a/arch/x86_64/mm/fault-xen.c +++ b/arch/x86_64/mm/fault-xen.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -250,7 +250,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) { if (tsk->pid == 1) return 1; - if (tracehook_consider_fatal_signal(tsk, sig)) + if (tsk->ptrace & PT_PTRACED) return 0; return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 94ae93dc2..a371e1b9d 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -252,7 +252,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) { if (tsk->pid == 1) return 1; - if (tracehook_consider_fatal_signal(tsk, sig)) + if (tsk->ptrace & PT_PTRACED) return 0; return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index b33eda26e..848ac4223 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -246,10 +246,10 @@ static int sg_io(struct file *file, request_queue_t *q, switch (hdr->dxfer_direction) { default: return -EINVAL; - case SG_DXFER_TO_FROM_DEV: case SG_DXFER_TO_DEV: writing = 1; break; + case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } @@ -286,9 +286,8 @@ static int sg_io(struct file *file, request_queue_t *q, * fill in request structure */ rq->cmd_len = hdr->cmd_len; + memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ memcpy(rq->cmd, cmd, hdr->cmd_len); - if (sizeof(rq->cmd) != hdr->cmd_len) - memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len); memset(sense, 0, sizeof(sense)); rq->sense = sense; diff --git a/configs/kernel-2.6.18-i586-smp.config b/configs/kernel-2.6.18-i586-smp.config index 61a83171d..74a7737de 100644 --- a/configs/kernel-2.6.18-i586-smp.config +++ b/configs/kernel-2.6.18-i586-smp.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:57 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:30 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -78,12 +78,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -165,7 +159,6 @@ CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set CONFIG_PREEMPT_BKL=y CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_APIC_AUTO=y CONFIG_X86_IO_APIC=y CONFIG_X86_MCE=y # CONFIG_X86_MCE_NONFATAL is not set diff --git a/configs/kernel-2.6.18-i586.config b/configs/kernel-2.6.18-i586.config index f47689d56..4bb100b19 100644 --- a/configs/kernel-2.6.18-i586.config +++ b/configs/kernel-2.6.18-i586.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:57 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:31 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -76,12 +76,6 @@ CONFIG_MODULE_SIG=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_KMOD=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -2019,7 +2013,7 @@ CONFIG_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_SONYPI is not set +CONFIG_SONYPI=m # # Ftape, the floppy tape device driver @@ -2234,6 +2228,7 @@ CONFIG_VIDEO_ZORAN_DC30=m CONFIG_VIDEO_ZORAN_LML33=m CONFIG_VIDEO_ZORAN_LML33R10=m CONFIG_VIDEO_ZORAN_AVS6EYES=m +CONFIG_VIDEO_MEYE=m CONFIG_VIDEO_SAA7134=m CONFIG_VIDEO_SAA7134_ALSA=m CONFIG_VIDEO_SAA7134_DVB=m diff --git a/configs/kernel-2.6.18-i686-kdump.config b/configs/kernel-2.6.18-i686-kdump.config index d42285daa..128ca73f9 100644 --- a/configs/kernel-2.6.18-i686-kdump.config +++ b/configs/kernel-2.6.18-i686-kdump.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:57 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:31 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -76,12 +76,6 @@ CONFIG_MODULE_SIG=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_KMOD=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -162,7 +156,6 @@ CONFIG_PREEMPT_VOLUNTARY=y CONFIG_X86_UP_APIC=y CONFIG_X86_UP_IOAPIC=y CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_APIC_AUTO=y CONFIG_X86_IO_APIC=y CONFIG_X86_MCE=y # CONFIG_X86_MCE_NONFATAL is not set diff --git a/configs/kernel-2.6.18-i686-smp.config b/configs/kernel-2.6.18-i686-smp.config index 52cad3423..224e29a3c 100644 --- a/configs/kernel-2.6.18-i686-smp.config +++ b/configs/kernel-2.6.18-i686-smp.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:58 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:31 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -78,12 +78,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -167,7 +161,6 @@ CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set CONFIG_PREEMPT_BKL=y CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_APIC_AUTO=y CONFIG_X86_IO_APIC=y CONFIG_X86_MCE=y # CONFIG_X86_MCE_NONFATAL is not set diff --git a/configs/kernel-2.6.18-i686-xen.config b/configs/kernel-2.6.18-i686-xen.config index d01024b43..7fb1817e1 100644 --- a/configs/kernel-2.6.18-i686-xen.config +++ b/configs/kernel-2.6.18-i686-xen.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:58 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:32 2006 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y @@ -77,12 +77,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -160,7 +154,6 @@ CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set CONFIG_PREEMPT_BKL=y CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_APIC_AUTO=y CONFIG_X86_IO_APIC=y CONFIG_VM86=y CONFIG_TOSHIBA=m diff --git a/configs/kernel-2.6.18-i686-xen0.config b/configs/kernel-2.6.18-i686-xen0.config index 71aa7cc9e..4ca808586 100644 --- a/configs/kernel-2.6.18-i686-xen0.config +++ b/configs/kernel-2.6.18-i686-xen0.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:58 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:32 2006 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y @@ -77,12 +77,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -160,7 +154,6 @@ CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set CONFIG_PREEMPT_BKL=y CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_APIC_AUTO=y CONFIG_X86_IO_APIC=y CONFIG_VM86=y CONFIG_TOSHIBA=m diff --git a/configs/kernel-2.6.18-i686-xenU.config b/configs/kernel-2.6.18-i686-xenU.config index 50ea265a7..b60115464 100644 --- a/configs/kernel-2.6.18-i686-xenU.config +++ b/configs/kernel-2.6.18-i686-xenU.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:58 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:32 2006 # CONFIG_X86_32=y CONFIG_LOCKDEP_SUPPORT=y @@ -77,12 +77,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -1094,7 +1088,6 @@ CONFIG_HANGCHECK_TIMER=m # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices diff --git a/configs/kernel-2.6.18-i686.config b/configs/kernel-2.6.18-i686.config index f11ce5410..ceaff0f28 100644 --- a/configs/kernel-2.6.18-i686.config +++ b/configs/kernel-2.6.18-i686.config @@ -1,8 +1,8 @@ # i386 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:58 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:33 2006 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -76,12 +76,6 @@ CONFIG_MODULE_SIG=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_KMOD=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -162,7 +156,6 @@ CONFIG_PREEMPT_VOLUNTARY=y CONFIG_X86_UP_APIC=y CONFIG_X86_UP_IOAPIC=y CONFIG_X86_LOCAL_APIC=y -CONFIG_X86_APIC_AUTO=y CONFIG_X86_IO_APIC=y CONFIG_X86_MCE=y # CONFIG_X86_MCE_NONFATAL is not set diff --git a/configs/kernel-2.6.18-ia64-xen.config b/configs/kernel-2.6.18-ia64-xen.config index f701d613c..20030da26 100644 --- a/configs/kernel-2.6.18-ia64-xen.config +++ b/configs/kernel-2.6.18-ia64-xen.config @@ -1,8 +1,8 @@ # ia64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:59 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:33 2006 # CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -65,12 +65,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-ia64.config b/configs/kernel-2.6.18-ia64.config index 7b62204a1..50a65eb13 100644 --- a/configs/kernel-2.6.18-ia64.config +++ b/configs/kernel-2.6.18-ia64.config @@ -1,8 +1,8 @@ # ia64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:59 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:34 2006 # CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" @@ -65,12 +65,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-ppc-smp.config b/configs/kernel-2.6.18-ppc-smp.config index 1e88dacdc..90fedf19d 100644 --- a/configs/kernel-2.6.18-ppc-smp.config +++ b/configs/kernel-2.6.18-ppc-smp.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:31:59 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:34 2006 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -106,12 +106,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-ppc.config b/configs/kernel-2.6.18-ppc.config index 4105f9639..ef5ea67ae 100644 --- a/configs/kernel-2.6.18-ppc.config +++ b/configs/kernel-2.6.18-ppc.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:00 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:34 2006 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -103,12 +103,6 @@ CONFIG_MODULE_SIG=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_KMOD=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-ppc64-kdump.config b/configs/kernel-2.6.18-ppc64-kdump.config index 00a75efd0..7792d069c 100644 --- a/configs/kernel-2.6.18-ppc64-kdump.config +++ b/configs/kernel-2.6.18-ppc64-kdump.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:00 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:34 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -99,12 +99,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-ppc64.config b/configs/kernel-2.6.18-ppc64.config index 885dfeccd..9ee604bd4 100644 --- a/configs/kernel-2.6.18-ppc64.config +++ b/configs/kernel-2.6.18-ppc64.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:00 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:35 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -99,12 +99,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-ppc64iseries.config b/configs/kernel-2.6.18-ppc64iseries.config index 22f751443..726bc8d02 100644 --- a/configs/kernel-2.6.18-ppc64iseries.config +++ b/configs/kernel-2.6.18-ppc64iseries.config @@ -1,8 +1,8 @@ # powerpc # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:00 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:35 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -99,12 +99,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -1134,7 +1128,6 @@ CONFIG_TCG_ATMEL=m # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices diff --git a/configs/kernel-2.6.18-s390.config b/configs/kernel-2.6.18-s390.config index 9853ff344..57879c585 100644 --- a/configs/kernel-2.6.18-s390.config +++ b/configs/kernel-2.6.18-s390.config @@ -1,8 +1,8 @@ # s390 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:00 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:35 2006 # CONFIG_MMU=y CONFIG_LOCKDEP_SUPPORT=y @@ -73,12 +73,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-s390x.config b/configs/kernel-2.6.18-s390x.config index 25dc399df..79e22c138 100644 --- a/configs/kernel-2.6.18-s390x.config +++ b/configs/kernel-2.6.18-s390x.config @@ -1,8 +1,8 @@ # s390 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:01 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:35 2006 # CONFIG_MMU=y CONFIG_LOCKDEP_SUPPORT=y @@ -72,12 +72,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-x86_64-kdump.config b/configs/kernel-2.6.18-x86_64-kdump.config index f9b450d02..64e99b25f 100644 --- a/configs/kernel-2.6.18-x86_64-kdump.config +++ b/configs/kernel-2.6.18-x86_64-kdump.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:01 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:36 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -81,12 +81,6 @@ CONFIG_MODULE_SIG=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_KMOD=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-x86_64-xen.config b/configs/kernel-2.6.18-x86_64-xen.config index efb0ffc4a..11ebc6cdb 100644 --- a/configs/kernel-2.6.18-x86_64-xen.config +++ b/configs/kernel-2.6.18-x86_64-xen.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:01 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:36 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -82,12 +82,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-x86_64-xen0.config b/configs/kernel-2.6.18-x86_64-xen0.config index 18ad8c72e..85a593cd0 100644 --- a/configs/kernel-2.6.18-x86_64-xen0.config +++ b/configs/kernel-2.6.18-x86_64-xen0.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:01 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:36 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -82,12 +82,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/configs/kernel-2.6.18-x86_64-xenU.config b/configs/kernel-2.6.18-x86_64-xenU.config index ed4279c00..b3f4b2ac3 100644 --- a/configs/kernel-2.6.18-x86_64-xenU.config +++ b/configs/kernel-2.6.18-x86_64-xenU.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:01 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:36 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -82,12 +82,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # @@ -1054,7 +1048,6 @@ CONFIG_HANGCHECK_TIMER=m # Multimedia devices # # CONFIG_VIDEO_DEV is not set -CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices diff --git a/configs/kernel-2.6.18-x86_64.config b/configs/kernel-2.6.18-x86_64.config index 99308ef8b..a6e596316 100644 --- a/configs/kernel-2.6.18-x86_64.config +++ b/configs/kernel-2.6.18-x86_64.config @@ -1,8 +1,8 @@ # x86_64 # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18.2 -# Mon Nov 13 09:32:02 2006 +# Linux kernel version: 2.6.18.5 +# Wed Dec 13 17:11:37 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -83,12 +83,6 @@ CONFIG_MODULE_SIG=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -# -# Process debugging support -# -CONFIG_UTRACE=y -CONFIG_PTRACE=y - # # Block layer # diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index fdb3e1e8f..90d98b79a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1302,6 +1302,12 @@ static void cciss_softirq_done(struct request *rq) complete_buffers(rq->bio, rq->errors); + if (blk_fs_request(rq)) { + const int rw = rq_data_dir(rq); + + disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors); + } + #ifdef CCISS_DEBUG printk("Done with %p\n", rq); #endif /* CCISS_DEBUG */ diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index fe7b2a77d..2e0b8d571 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1001,6 +1001,7 @@ static inline void complete_buffers(struct bio *bio, int ok) */ static inline void complete_command(cmdlist_t *cmd, int timeout) { + struct request *rq = cmd->rq; int ok=1; int i, ddir; @@ -1032,12 +1033,18 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) pci_unmap_page(hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr, cmd->req.sg[i].size, ddir); - complete_buffers(cmd->rq->bio, ok); + complete_buffers(rq->bio, ok); - add_disk_randomness(cmd->rq->rq_disk); + if (blk_fs_request(rq)) { + const int rw = rq_data_dir(rq); - DBGPX(printk("Done with %p\n", cmd->rq);); - end_that_request_last(cmd->rq, ok ? 1 : -EIO); + disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors); + } + + add_disk_randomness(rq->rq_disk); + + DBGPX(printk("Done with %p\n", rq);); + end_that_request_last(rq, ok ? 1 : -EIO); } /* diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b35bf492c..eebdf1aa1 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -743,7 +743,6 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, struct file *file, *f; struct inode *inode; struct address_space *mapping; - struct vx_info_save vxis; unsigned lo_blocksize; int lo_flags = 0; int error; @@ -842,9 +841,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, set_blocksize(bdev, lo_blocksize); - __enter_vx_admin(&vxis); error = kernel_thread(loop_thread, lo, CLONE_KERNEL); - __leave_vx_admin(&vxis); if (error < 0) goto out_putf; wait_for_completion(&lo->lo_done); diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 35d6b33c0..8824632d7 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1051,7 +1051,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) { struct page * page; - page = alloc_page(GFP_KERNEL); + page = alloc_page(GFP_KERNEL | GFP_DMA32); if (page == NULL) return NULL; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d1ede7db5..7475eaece 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -169,7 +169,7 @@ static void *i8xx_alloc_pages(void) { struct page * page; - page = alloc_pages(GFP_KERNEL, 2); + page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); if (page == NULL) return NULL; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index abca98bea..5292258cc 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1845,7 +1845,7 @@ static int ipmi_pci_resume(struct pci_dev *pdev) static struct pci_device_id ipmi_pci_devices[] = { { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, - { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE) } + { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) } }; MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 913be23e0..d4f6361a1 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1062,11 +1062,12 @@ static void isicom_shutdown_port(struct isi_port *port) static void isicom_close(struct tty_struct *tty, struct file *filp) { struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; + struct isi_board *card; unsigned long flags; if (!port) return; + card = port->card; if (isicom_paranoia_check(port, tty->name, "isicom_close")) return; diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 59e5d50a8..3ece69231 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -62,8 +62,8 @@ void proc_fork_connector(struct task_struct *task) ktime_get_ts(&ts); /* get high res monotonic timestamp */ ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_FORK; - ev->event_data.fork.parent_pid = task->parent->pid; - ev->event_data.fork.parent_tgid = task->parent->tgid; + ev->event_data.fork.parent_pid = task->real_parent->pid; + ev->event_data.fork.parent_tgid = task->real_parent->tgid; ev->event_data.fork.child_pid = task->pid; ev->event_data.fork.child_tgid = task->tgid; diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 852157dc6..b9e3886d9 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -154,8 +154,6 @@ static void __init dmi_save_ipmi_device(struct dmi_header *dm) list_add(&dev->list, &dmi_devices); } -int dmi_cpus; - /* * Process a DMI table entry. Right now all we care about are the BIOS * and machine entries. For 2.5 we should pull the smbus controller info @@ -180,9 +178,6 @@ static void __init dmi_decode(struct dmi_header *dm) dmi_save_ident(dm, DMI_BOARD_NAME, 5); dmi_save_ident(dm, DMI_BOARD_VERSION, 6); break; - case 4: /* Central Processor */ - dmi_cpus++; - break; case 10: /* Onboard Devices Information */ dmi_save_devices(dm); break; diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 343afa38f..07b060438 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1332,20 +1332,22 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf) { - unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset); + unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset); - return sprintf(buf, "%lu\n", *field); + return sprintf(buf, "%u\n", *field); } static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count) { - unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset); + unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset); unsigned long value; char *rest; value = simple_strtoul(buf, &rest, 10); if (*rest) return -EINVAL; + if ((unsigned int)value != value) + return -EINVAL; *field = value; diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index ed4aa4e79..9f7e1fe8c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -54,6 +54,7 @@ config VIDEO_V4L1_COMPAT config VIDEO_V4L2 bool + depends on VIDEO_DEV default y source "drivers/media/video/Kconfig" diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index a6dbfef66..aefcba701 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4704,7 +4704,6 @@ e1000_resume(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); uint32_t manc, ret_val; - int err; pci_set_power_state(pdev, PCI_D0); e1000_pci_restore_state(adapter); @@ -4714,8 +4713,8 @@ e1000_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); - if (netif_running(netdev) && (err = e1000_request_irq(adapter))) - return err; + if (netif_running(netdev) && (ret_val = e1000_request_irq(adapter))) + return ret_val; e1000_power_up_phy(adapter); e1000_reset(adapter); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eafabb253..fa620aeb7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6889,8 +6889,10 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); err = tg3_set_power_state(tp, PCI_D0); - if (err) + if (err) { + tg3_full_unlock(tp); return err; + } tg3_disable_ints(tp); tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index f24ba4d42..42eecf252 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1463,6 +1463,23 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm) } } +static void drain_txstatus_queue(struct bcm43xx_private *bcm) +{ + u32 dummy; + + if (bcm->current_core->rev < 5) + return; + /* Read all entries from the microcode TXstatus FIFO + * and throw them away. + */ + while (1) { + dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); + if (!dummy) + break; + dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); + } +} + static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) { bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); @@ -3517,6 +3534,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); bcm43xx_security_init(bcm); + drain_txstatus_queue(bcm); ieee80211softmac_start(bcm->net_dev); /* Let's go! Be careful after enabling the IRQs. diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index fdefa7dcd..a9c7d41d2 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -571,6 +571,9 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev) */ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) { + if (!sysfs_initialized) + return; + if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 74b3124e8..95d5e880f 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1264,6 +1264,11 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev, socket->pcmcia_state.dead = 1; pccard_register_pcmcia(socket, NULL); + /* unregister any unbound devices */ + mutex_lock(&socket->skt_mutex); + pcmcia_card_remove(socket, NULL); + mutex_unlock(&socket->skt_mutex); + pcmcia_put_socket(socket); return; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index d0148e5fb..15874c867 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -640,16 +640,13 @@ do_IRQ (struct pt_regs *regs) spin_lock(&sch->lock); /* Store interrupt response block to lowcore. */ if (tsch (tpi_info->schid, irb) == 0 && sch) { - struct vx_info_save vxis; /* Keep subchannel information word up to date. */ memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw)); /* Call interrupt handler if there is one. */ - __enter_vx_admin(&vxis); if (sch->driver && sch->driver->irq) sch->driver->irq(&sch->dev); - __leave_vx_admin(&vxis); } if (sch) spin_unlock(&sch->lock); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index b1d865e52..25da6260e 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -412,7 +412,7 @@ static void pdc_pata_phy_reset(struct ata_port *ap) static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { - if (sc_reg > SCR_CONTROL) + if ((sc_reg > SCR_CONTROL) || (ap->flags & ATA_FLAG_SLAVE_POSS)) return 0xffffffffU; return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -421,7 +421,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - if (sc_reg > SCR_CONTROL) + if ((sc_reg > SCR_CONTROL) || (ap->flags & ATA_FLAG_SLAVE_POSS)) return; writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 077c1c691..3031078f5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -408,6 +408,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, goto free_req; req->cmd_len = cmd_len; + memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ memcpy(req->cmd, cmd, req->cmd_len); req->sense = sioc->sense; req->sense_len = 0; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 48dee4b8d..acc7cd8ec 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -701,6 +701,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usblp->wcomplete = 0; err = usb_submit_urb(usblp->writeurb, GFP_KERNEL); if (err) { + usblp->wcomplete = 1; if (err != -ENOMEM) count = -EIO; else diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a2c56b2de..19aaf5681 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1734,10 +1734,10 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, { USB_VENDOR_ID_APPLE, 0x0219, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 7208839f2..2ae4fb9a7 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -123,6 +123,12 @@ static struct hidinput_key_translation powerbook_numlock_keys[] = { { } }; +static struct hidinput_key_translation powerbook_iso_keyboard[] = { + { KEY_GRAVE, KEY_102ND }, + { KEY_102ND, KEY_GRAVE }, + { } +}; + static int usbhid_pb_fnmode = 1; module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); MODULE_PARM_DESC(pb_fnmode, @@ -197,6 +203,14 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, } } + if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { + trans = find_translation(powerbook_iso_keyboard, usage->code); + if (trans) { + input_event(input, usage->type, trans->to, value); + return 1; + } + } + return 0; } @@ -212,6 +226,9 @@ static void hidinput_pb_setup(struct input_dev *input) for (trans = powerbook_numlock_keys; trans->from; trans++) set_bit(trans->to, input->keybit); + + for (trans = powerbook_iso_keyboard; trans->from; trans++) + set_bit(trans->to, input->keybit); } #else static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 778e575de..aa85d0b08 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -260,6 +260,7 @@ struct hid_item { #define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 #define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 #define HID_QUIRK_INVERT_HWHEEL 0x00004000 +#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00010000 /* * This is the global environment of the parser. This information is diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index 4094ef47d..1cb8117f8 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -521,7 +521,7 @@ static int usbtouch_probe(struct usb_interface *intf, type->max_press, 0, 0); usb_fill_int_urb(usbtouch->irq, usbtouch->udev, - usb_rcvintpipe(usbtouch->udev, 0x81), + usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch, endpoint->bInterval); diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index 9ed640d35..ea426115c 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c @@ -145,12 +145,18 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, if (par->Architecture >= NV_ARCH_40) { pll = NV_RD32(par->PMC, 0x4020); - P = (pll >> 16) & 0x03; + P = (pll >> 16) & 0x07; pll = NV_RD32(par->PMC, 0x4024); M = pll & 0xFF; N = (pll >> 8) & 0xFF; - MB = (pll >> 16) & 0xFF; - NB = (pll >> 24) & 0xFF; + if (((par->Chipset & 0xfff0) == 0x0290) || + ((par->Chipset & 0xfff0) == 0x0390)) { + MB = 1; + NB = 1; + } else { + MB = (pll >> 16) & 0xFF; + NB = (pll >> 24) & 0xFF; + } *MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P; pll = NV_RD32(par->PMC, 0x4000); diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index a18a9aebf..61dc46fec 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -359,6 +359,7 @@ int NVCommonSetup(struct fb_info *info) case 0x0186: case 0x0187: case 0x018D: + case 0x0228: case 0x0286: case 0x028C: case 0x0316: @@ -382,6 +383,10 @@ int NVCommonSetup(struct fb_info *info) case 0x034C: case 0x0160: case 0x0166: + case 0x0169: + case 0x016B: + case 0x016C: + case 0x016D: case 0x00C8: case 0x00CC: case 0x0144: @@ -639,12 +644,23 @@ int NVCommonSetup(struct fb_info *info) par->fpHeight = NV_RD32(par->PRAMDAC, 0x0800) + 1; par->fpSyncs = NV_RD32(par->PRAMDAC, 0x0848) & 0x30000033; - printk("Panel size is %i x %i\n", par->fpWidth, par->fpHeight); + printk("nvidiafb: Panel size is %i x %i\n", par->fpWidth, par->fpHeight); } if (monA) info->monspecs = *monA; + if (!par->FlatPanel || !par->twoHeads) + par->FPDither = 0; + + par->LVDS = 0; + if (par->FlatPanel && par->twoHeads) { + NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004); + if (par->PRAMDAC0[0x08b4] & 1) + par->LVDS = 1; + printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS"); + } + kfree(edidA); kfree(edidB); done: diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h index acdc26693..86e65dea6 100644 --- a/drivers/video/nvidia/nv_type.h +++ b/drivers/video/nvidia/nv_type.h @@ -129,6 +129,7 @@ struct nvidia_par { int fpHeight; int PanelTweak; int paneltweak; + int LVDS; int pm_state; u32 crtcSync_read; u32 fpSyncs; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index d4f850117..2a961f89c 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -1145,20 +1145,20 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info) case 0x0340: /* GeForceFX 5700 */ arch = NV_ARCH_30; break; - case 0x0040: - case 0x00C0: - case 0x0120: + case 0x0040: /* GeForce 6800 */ + case 0x00C0: /* GeForce 6800 */ + case 0x0120: /* GeForce 6800 */ case 0x0130: - case 0x0140: - case 0x0160: - case 0x01D0: - case 0x0090: - case 0x0210: - case 0x0220: + case 0x0140: /* GeForce 6600 */ + case 0x0160: /* GeForce 6200 */ + case 0x01D0: /* GeForce 7200, 7300, 7400 */ + case 0x0090: /* GeForce 7800 */ + case 0x0210: /* GeForce 6800 */ + case 0x0220: /* GeForce 6200 */ case 0x0230: - case 0x0240: - case 0x0290: - case 0x0390: + case 0x0240: /* GeForce 6100 */ + case 0x0290: /* GeForce 7900 */ + case 0x0390: /* GeForce 7600 */ arch = NV_ARCH_40; break; case 0x0020: /* TNT, TNT2 */ diff --git a/drivers/xen/blkback/blkback.c b/drivers/xen/blkback/blkback.c index 406090f20..6c80bafa1 100644 --- a/drivers/xen/blkback/blkback.c +++ b/drivers/xen/blkback/blkback.c @@ -510,7 +510,7 @@ static int __init blkif_init(void) if (!is_running_on_xen()) return -ENODEV; - mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST; + mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST; pending_reqs = kmalloc(sizeof(pending_reqs[0]) * blkif_reqs, GFP_KERNEL); diff --git a/drivers/xen/core/evtchn.c b/drivers/xen/core/evtchn.c index 85c716bc7..77ca1bfc2 100644 --- a/drivers/xen/core/evtchn.c +++ b/drivers/xen/core/evtchn.c @@ -478,7 +478,6 @@ static int retrigger(unsigned int irq) shared_info_t *s = HYPERVISOR_shared_info; if (!VALID_EVTCHN(evtchn)) return 1; - BUG_ON(!synch_test_bit(evtchn, &s->evtchn_mask[0])); synch_set_bit(evtchn, &s->evtchn_pending[0]); return 1; } diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h index 6ed47e427..4306bc8f4 100644 --- a/drivers/xen/netback/common.h +++ b/drivers/xen/netback/common.h @@ -106,7 +106,7 @@ typedef struct netif_st { void netif_disconnect(netif_t *netif); -netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]); +netif_t *netif_alloc(domid_t domid, unsigned int handle); int netif_map(netif_t *netif, unsigned long tx_ring_ref, unsigned long rx_ring_ref, unsigned int evtchn); diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c index d70955fd1..a698ccc77 100644 --- a/drivers/xen/netback/interface.c +++ b/drivers/xen/netback/interface.c @@ -126,7 +126,7 @@ static struct ethtool_ops network_ethtool_ops = .get_link = ethtool_op_get_link, }; -netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]) +netif_t *netif_alloc(domid_t domid, unsigned int handle) { int err = 0, i; struct net_device *dev; @@ -169,20 +169,14 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle, u8 be_mac[ETH_ALEN]) printk(KERN_WARNING "netbk: WARNING: device '%s' has non-zero " "queue length (%lu)!\n", dev->name, dev->tx_queue_len); - for (i = 0; i < ETH_ALEN; i++) - if (be_mac[i] != 0) - break; - if (i == ETH_ALEN) { - /* - * Initialise a dummy MAC address. We choose the numerically - * largest non-broadcast address to prevent the address getting - * stolen by an Ethernet bridge for STP purposes. - * (FE:FF:FF:FF:FF:FF) - */ - memset(dev->dev_addr, 0xFF, ETH_ALEN); - dev->dev_addr[0] &= ~0x01; - } else - memcpy(dev->dev_addr, be_mac, ETH_ALEN); + /* + * Initialise a dummy MAC address. We choose the numerically + * largest non-broadcast address to prevent the address getting + * stolen by an Ethernet bridge for STP purposes. + * (FE:FF:FF:FF:FF:FF) + */ + memset(dev->dev_addr, 0xFF, ETH_ALEN); + dev->dev_addr[0] &= ~0x01; rtnl_lock(); err = register_netdevice(dev); diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c index 89a196b73..681d4b5a9 100644 --- a/drivers/xen/netback/netback.c +++ b/drivers/xen/netback/netback.c @@ -79,7 +79,7 @@ static inline unsigned long idx_to_kaddr(unsigned int idx) #define PKT_PROT_LEN 64 -static struct { +static struct pending_tx_info { netif_tx_request_t req; netif_t *netif; } pending_tx_info[MAX_PENDING_REQS]; @@ -375,14 +375,22 @@ static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta, flipped. */ meta->copy = 1; copy_gop = npo->copy + npo->copy_prod++; - copy_gop->source.domid = DOMID_SELF; + copy_gop->flags = GNTCOPY_dest_gref; + if (PageForeign(page)) { + struct pending_tx_info *src_pend = + &pending_tx_info[page->index]; + copy_gop->source.domid = src_pend->netif->domid; + copy_gop->source.u.ref = src_pend->req.gref; + copy_gop->flags |= GNTCOPY_source_gref; + } else { + copy_gop->source.domid = DOMID_SELF; + copy_gop->source.u.gmfn = old_mfn; + } copy_gop->source.offset = offset; - copy_gop->source.u.gmfn = old_mfn; copy_gop->dest.domid = netif->domid; copy_gop->dest.offset = 0; copy_gop->dest.u.ref = req->gref; copy_gop->len = size; - copy_gop->flags = GNTCOPY_dest_gref; } else { meta->copy = 0; if (!xen_feature(XENFEAT_auto_translated_physmap)) { @@ -876,20 +884,28 @@ static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end) netif_put(netif); } -static int netbk_count_requests(netif_t *netif, netif_tx_request_t *txp, - int work_to_do) +static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first, + netif_tx_request_t *txp, int work_to_do) { - netif_tx_request_t *first = txp; RING_IDX cons = netif->tx.req_cons; int frags = 0; - while (txp->flags & NETTXF_more_data) { + if (!(first->flags & NETTXF_more_data)) + return 0; + + do { if (frags >= work_to_do) { DPRINTK("Need more frags\n"); return -frags; } - txp = RING_GET_REQUEST(&netif->tx, cons + frags); + if (unlikely(frags >= MAX_SKB_FRAGS)) { + DPRINTK("Too many frags\n"); + return -frags; + } + + memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags), + sizeof(*txp)); if (txp->size > first->size) { DPRINTK("Frags galore\n"); return -frags; @@ -903,27 +919,25 @@ static int netbk_count_requests(netif_t *netif, netif_tx_request_t *txp, txp->offset, txp->size); return -frags; } - } + } while ((txp++)->flags & NETTXF_more_data); return frags; } static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif, struct sk_buff *skb, + netif_tx_request_t *txp, gnttab_map_grant_ref_t *mop) { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; - netif_tx_request_t *txp; unsigned long pending_idx = *((u16 *)skb->data); - RING_IDX cons = netif->tx.req_cons; int i, start; /* Skip first skb fragment if it is on same page as header fragment. */ start = ((unsigned long)shinfo->frags[0].page == pending_idx); - for (i = start; i < shinfo->nr_frags; i++) { - txp = RING_GET_REQUEST(&netif->tx, cons++); + for (i = start; i < shinfo->nr_frags; i++, txp++) { pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)]; gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx), @@ -1037,7 +1051,7 @@ static void netbk_fill_frags(struct sk_buff *skb) int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras, int work_to_do) { - struct netif_extra_info *extra; + struct netif_extra_info extra; RING_IDX cons = netif->tx.req_cons; do { @@ -1046,18 +1060,18 @@ int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras, return -EBADR; } - extra = (struct netif_extra_info *) - RING_GET_REQUEST(&netif->tx, cons); - if (unlikely(!extra->type || - extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { + memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons), + sizeof(extra)); + if (unlikely(!extra.type || + extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) { netif->tx.req_cons = ++cons; - DPRINTK("Invalid extra type: %d\n", extra->type); + DPRINTK("Invalid extra type: %d\n", extra.type); return -EINVAL; } - memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); + memcpy(&extras[extra.type - 1], &extra, sizeof(extra)); netif->tx.req_cons = ++cons; - } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); + } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE); return work_to_do; } @@ -1092,6 +1106,7 @@ static void net_tx_action(unsigned long unused) struct sk_buff *skb; netif_t *netif; netif_tx_request_t txreq; + netif_tx_request_t txfrags[MAX_SKB_FRAGS]; struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; u16 pending_idx; RING_IDX i; @@ -1168,19 +1183,13 @@ static void net_tx_action(unsigned long unused) } } - ret = netbk_count_requests(netif, &txreq, work_to_do); + ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do); if (unlikely(ret < 0)) { netbk_tx_err(netif, &txreq, i - ret); continue; } i += ret; - if (unlikely(ret > MAX_SKB_FRAGS)) { - DPRINTK("Too many frags\n"); - netbk_tx_err(netif, &txreq, i); - continue; - } - if (unlikely(txreq.size < ETH_HLEN)) { DPRINTK("Bad packet size: %d\n", txreq.size); netbk_tx_err(netif, &txreq, i); @@ -1249,7 +1258,7 @@ static void net_tx_action(unsigned long unused) pending_cons++; - mop = netbk_get_requests(netif, skb, mop); + mop = netbk_get_requests(netif, skb, txfrags, mop); netif->tx.req_cons = i; netif_schedule_work(netif); @@ -1339,6 +1348,7 @@ static void netif_page_release(struct page *page) { /* Ready for next use. */ init_page_count(page); + netif_idx_release(page->index); } diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c index 8592ab4cb..c61821c8f 100644 --- a/drivers/xen/netback/xenbus.c +++ b/drivers/xen/netback/xenbus.c @@ -28,29 +28,20 @@ printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) #endif -struct backend_info -{ +struct backend_info { struct xenbus_device *dev; netif_t *netif; - struct xenbus_watch backend_watch; enum xenbus_state frontend_state; }; static int connect_rings(struct backend_info *); static void connect(struct backend_info *); -static void maybe_connect(struct backend_info *); -static void backend_changed(struct xenbus_watch *, const char **, - unsigned int); +static void backend_create_netif(struct backend_info *be); static int netback_remove(struct xenbus_device *dev) { struct backend_info *be = dev->dev.driver_data; - if (be->backend_watch.node) { - unregister_xenbus_watch(&be->backend_watch); - kfree(be->backend_watch.node); - be->backend_watch.node = NULL; - } if (be->netif) { netif_disconnect(be->netif); be->netif = NULL; @@ -63,8 +54,7 @@ static int netback_remove(struct xenbus_device *dev) /** * Entry point to this code when a new device is created. Allocate the basic - * structures, and watch the store waiting for the hotplug scripts to tell us - * the device's handle. Switch to InitWait. + * structures and switch to InitWait. */ static int netback_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) @@ -83,11 +73,6 @@ static int netback_probe(struct xenbus_device *dev, be->dev = dev; dev->dev.driver_data = be; - err = xenbus_watch_path2(dev, dev->nodename, "handle", - &be->backend_watch, backend_changed); - if (err) - goto fail; - do { err = xenbus_transaction_start(&xbt); if (err) { @@ -108,7 +93,8 @@ static int netback_probe(struct xenbus_device *dev, goto abort_transaction; } - err = xenbus_printf(xbt, dev->nodename, "feature-rx-copy", "%d", 1); + err = xenbus_printf(xbt, dev->nodename, + "feature-rx-copy", "%d", 1); if (err) { message = "writing feature-copying"; goto abort_transaction; @@ -123,9 +109,11 @@ static int netback_probe(struct xenbus_device *dev, } err = xenbus_switch_state(dev, XenbusStateInitWait); - if (err) { + if (err) goto fail; - } + + /* This kicks hotplug scripts, so do it immediately. */ + backend_create_netif(be); return 0; @@ -175,48 +163,30 @@ static int netback_uevent(struct xenbus_device *xdev, char **envp, } -/** - * Callback received when the hotplug scripts have placed the handle node. - * Read it, and create a netif structure. If the frontend is ready, connect. - */ -static void backend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) +static void backend_create_netif(struct backend_info *be) { int err; long handle; - struct backend_info *be - = container_of(watch, struct backend_info, backend_watch); struct xenbus_device *dev = be->dev; - DPRINTK(""); + if (be->netif != NULL) + return; err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle); - if (XENBUS_EXIST_ERR(err)) { - /* Since this watch will fire once immediately after it is - registered, we expect this. Ignore it, and wait for the - hotplug scripts. */ - return; - } if (err != 1) { xenbus_dev_fatal(dev, err, "reading handle"); return; } - if (be->netif == NULL) { - u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - - be->netif = netif_alloc(dev->otherend_id, handle, be_mac); - if (IS_ERR(be->netif)) { - err = PTR_ERR(be->netif); - be->netif = NULL; - xenbus_dev_fatal(dev, err, "creating interface"); - return; - } - - kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); - - maybe_connect(be); + be->netif = netif_alloc(dev->otherend_id, handle); + if (IS_ERR(be->netif)) { + err = PTR_ERR(be->netif); + be->netif = NULL; + xenbus_dev_fatal(dev, err, "creating interface"); + return; } + + kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); } @@ -249,11 +219,9 @@ static void frontend_changed(struct xenbus_device *dev, break; case XenbusStateConnected: - if (!be->netif) { - /* reconnect: setup be->netif */ - backend_changed(&be->backend_watch, NULL, 0); - } - maybe_connect(be); + backend_create_netif(be); + if (be->netif) + connect(be); break; case XenbusStateClosing: @@ -279,15 +247,6 @@ static void frontend_changed(struct xenbus_device *dev, } -/* ** Connection ** */ - - -static void maybe_connect(struct backend_info *be) -{ - if (be->netif && (be->frontend_state == XenbusStateConnected)) - connect(be); -} - static void xen_net_read_rate(struct xenbus_device *dev, unsigned long *bytes, unsigned long *usec) { diff --git a/drivers/xen/netfront/netfront.c b/drivers/xen/netfront/netfront.c index 8e5f622a3..5dc55e833 100644 --- a/drivers/xen/netfront/netfront.c +++ b/drivers/xen/netfront/netfront.c @@ -141,7 +141,6 @@ struct netfront_info { spinlock_t tx_lock; spinlock_t rx_lock; - unsigned int handle; unsigned int evtchn, irq; unsigned int copying_receiver; @@ -230,9 +229,8 @@ static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np, #define WPRINTK(fmt, args...) \ printk(KERN_WARNING "netfront: " fmt, ##args) -static int talk_to_backend(struct xenbus_device *, struct netfront_info *); static int setup_device(struct xenbus_device *, struct netfront_info *); -static struct net_device *create_netdev(int, int, struct xenbus_device *); +static struct net_device *create_netdev(struct xenbus_device *); static void netfront_closing(struct xenbus_device *); @@ -242,7 +240,7 @@ static int open_netdev(struct netfront_info *); static void close_netdev(struct netfront_info *); static void netif_free(struct netfront_info *); -static void network_connect(struct net_device *); +static int network_connect(struct net_device *); static void network_tx_buf_gc(struct net_device *); static void network_alloc_rx_buffers(struct net_device *); static int send_fake_arp(struct net_device *); @@ -265,8 +263,7 @@ static inline int xennet_can_sg(struct net_device *dev) /** * Entry point to this code when a new device is created. Allocate the basic * structures and the ring buffers for communication with the backend, and - * inform the backend of the appropriate details for those. Switch to - * Connected state. + * inform the backend of the appropriate details for those. */ static int __devinit netfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) @@ -274,32 +271,8 @@ static int __devinit netfront_probe(struct xenbus_device *dev, int err; struct net_device *netdev; struct netfront_info *info; - unsigned int handle, feature_rx_copy, feature_rx_flip, use_copy; - err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%u", &handle); - if (err != 1) { - xenbus_dev_fatal(dev, err, "reading handle"); - return err; - } - - err = xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-copy", "%u", - &feature_rx_copy); - if (err != 1) - feature_rx_copy = 0; - err = xenbus_scanf(XBT_NIL, dev->otherend, "feature-rx-flip", "%u", - &feature_rx_flip); - if (err != 1) - feature_rx_flip = 1; - - /* - * Copy packets on receive path if: - * (a) This was requested by user, and the backend supports it; or - * (b) Flipping was requested, but this is unsupported by the backend. - */ - use_copy = (MODPARM_rx_copy && feature_rx_copy) || - (MODPARM_rx_flip && !feature_rx_flip); - - netdev = create_netdev(handle, use_copy, dev); + netdev = create_netdev(dev); if (IS_ERR(netdev)) { err = PTR_ERR(netdev); xenbus_dev_fatal(dev, err, "creating netdev"); @@ -309,23 +282,13 @@ static int __devinit netfront_probe(struct xenbus_device *dev, info = netdev_priv(netdev); dev->dev.driver_data = info; - err = talk_to_backend(dev, info); - if (err) - goto fail_backend; - err = open_netdev(info); if (err) - goto fail_open; - - IPRINTK("Created netdev %s with %sing receive path.\n", - netdev->name, info->copying_receiver ? "copy" : "flipp"); + goto fail; return 0; - fail_open: - xennet_sysfs_delif(info->netdev); - unregister_netdev(netdev); - fail_backend: + fail: free_netdev(netdev); dev->dev.driver_data = NULL; return err; @@ -345,7 +308,7 @@ static int netfront_resume(struct xenbus_device *dev) DPRINTK("%s\n", dev->nodename); netif_disconnect_backend(info); - return talk_to_backend(dev, info); + return 0; } static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[]) @@ -456,7 +419,7 @@ again: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, err, "%s", message); destroy_ring: - netif_free(info); + netif_disconnect_backend(info); out: return err; } @@ -546,7 +509,10 @@ static void backend_changed(struct xenbus_device *dev, break; case XenbusStateInitWait: - network_connect(netdev); + if (network_connect(netdev) != 0) { + netif_free(np); + break; + } xenbus_switch_state(dev, XenbusStateConnected); (void)send_fake_arp(netdev); break; @@ -1120,6 +1086,7 @@ static int xennet_get_responses(struct netfront_info *np, if (net_ratelimit()) WPRINTK("rx->offset: %x, size: %u\n", rx->offset, rx->status); + xennet_move_rx_slot(np, skb, ref); err = -EINVAL; goto next; } @@ -1130,7 +1097,8 @@ static int xennet_get_responses(struct netfront_info *np, * situation to the system controller to reboot the backed. */ if (ref == GRANT_INVALID_REF) { - WPRINTK("Bad rx response id %d.\n", rx->id); + if (net_ratelimit()) + WPRINTK("Bad rx response id %d.\n", rx->id); err = -EINVAL; goto next; } @@ -1202,6 +1170,9 @@ next: err = -E2BIG; } + if (unlikely(err)) + np->rx.rsp_cons = cons + frags; + *pages_flipped_p = pages_flipped; return err; @@ -1306,9 +1277,9 @@ static int netif_poll(struct net_device *dev, int *pbudget) rp = np->rx.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - for (i = np->rx.rsp_cons, work_done = 0; - (i != rp) && (work_done < budget); - np->rx.rsp_cons = ++i, work_done++) { + i = np->rx.rsp_cons; + work_done = 0; + while ((i != rp) && (work_done < budget)) { memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); memset(extras, 0, sizeof(extras)); @@ -1316,12 +1287,11 @@ static int netif_poll(struct net_device *dev, int *pbudget) &pages_flipped); if (unlikely(err)) { -err: - i = np->rx.rsp_cons + skb_queue_len(&tmpq) - 1; - work_done--; +err: while ((skb = __skb_dequeue(&tmpq))) __skb_queue_tail(&errq, skb); np->stats.rx_errors++; + i = np->rx.rsp_cons; continue; } @@ -1333,6 +1303,7 @@ err: if (unlikely(xennet_set_skb_gso(skb, gso))) { __skb_queue_head(&tmpq, skb); + np->rx.rsp_cons += skb_queue_len(&tmpq); goto err; } } @@ -1396,6 +1367,9 @@ err: np->stats.rx_bytes += skb->len; __skb_queue_tail(&rxq, skb); + + np->rx.rsp_cons = ++i; + work_done++; } if (pages_flipped) { @@ -1643,16 +1617,41 @@ static void xennet_set_features(struct net_device *dev) xennet_set_tso(dev, 1); } -static void network_connect(struct net_device *dev) +static int network_connect(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); - int i, requeue_idx; + int i, requeue_idx, err; struct sk_buff *skb; grant_ref_t ref; netif_rx_request_t *req; + unsigned int feature_rx_copy, feature_rx_flip; + + err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-rx-copy", "%u", &feature_rx_copy); + if (err != 1) + feature_rx_copy = 0; + err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, + "feature-rx-flip", "%u", &feature_rx_flip); + if (err != 1) + feature_rx_flip = 1; + + /* + * Copy packets on receive path if: + * (a) This was requested by user, and the backend supports it; or + * (b) Flipping was requested, but this is unsupported by the backend. + */ + np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) || + (MODPARM_rx_flip && !feature_rx_flip)); + + err = talk_to_backend(np->xbdev, np); + if (err) + return err; xennet_set_features(dev); + IPRINTK("device %s has %sing receive path.\n", + dev->name, np->copying_receiver ? "copy" : "flipp"); + spin_lock_irq(&np->tx_lock); spin_lock(&np->rx_lock); @@ -1708,6 +1707,8 @@ static void network_connect(struct net_device *dev) spin_unlock(&np->rx_lock); spin_unlock_irq(&np->tx_lock); + + return 0; } static void netif_uninit(struct net_device *dev) @@ -1873,8 +1874,7 @@ static void network_set_multicast_list(struct net_device *dev) { } -static struct net_device * __devinit -create_netdev(int handle, int copying_receiver, struct xenbus_device *dev) +static struct net_device * __devinit create_netdev(struct xenbus_device *dev) { int i, err = 0; struct net_device *netdev = NULL; @@ -1888,9 +1888,7 @@ create_netdev(int handle, int copying_receiver, struct xenbus_device *dev) } np = netdev_priv(netdev); - np->handle = handle; np->xbdev = dev; - np->copying_receiver = copying_receiver; netif_carrier_off(netdev); @@ -2021,10 +2019,12 @@ static int open_netdev(struct netfront_info *info) err = xennet_sysfs_addif(info->netdev); if (err) { - /* This can be non-fatal: it only means no tuning parameters */ + unregister_netdev(info->netdev); printk(KERN_WARNING "%s: add sysfs failed err=%d\n", __FUNCTION__, err); + return err; } + return 0; } diff --git a/drivers/xen/privcmd/privcmd.c b/drivers/xen/privcmd/privcmd.c index 501aa5fe3..af9e13cee 100644 --- a/drivers/xen/privcmd/privcmd.c +++ b/drivers/xen/privcmd/privcmd.c @@ -34,6 +34,10 @@ static struct proc_dir_entry *privcmd_intf; static struct proc_dir_entry *capabilities_intf; +#ifndef HAVE_ARCH_PRIVCMD_MMAP +static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); +#endif + static int privcmd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { @@ -121,12 +125,10 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, vma = find_vma(mm, msg.va); rc = -EINVAL; - if (!vma || (msg.va != vma->vm_start) || vma->vm_private_data) + if (!vma || (msg.va != vma->vm_start) || + !privcmd_enforce_singleshot_mapping(vma)) goto mmap_out; - /* Mapping is a one-shot operation per vma. */ - vma->vm_private_data = (void *)1; - va = vma->vm_start; for (i = 0; i < mmapcmd.num; i++) { @@ -136,7 +138,7 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, /* Do not allow range to wrap the address space. */ rc = -EINVAL; - if ((msg.npages > (INT_MAX >> PAGE_SHIFT)) || + if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) || ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va)) goto mmap_out; @@ -180,7 +182,7 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&m, udata, sizeof(m))) return -EFAULT; - if ((m.num <= 0) || (m.num > (INT_MAX >> PAGE_SHIFT))) + if ((m.num <= 0) || (m.num > (LONG_MAX >> PAGE_SHIFT))) return -EINVAL; down_read(&mm->mmap_sem); @@ -188,15 +190,13 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, vma = find_vma(mm, m.addr); if (!vma || (m.addr != vma->vm_start) || - ((m.addr + (m.num<vm_end) || - vma->vm_private_data) { + ((m.addr + ((unsigned long)m.num<vm_end) || + !privcmd_enforce_singleshot_mapping(vma)) { up_read(&mm->mmap_sem); return -EINVAL; } - /* Mapping is a one-shot operation per vma. */ - vma->vm_private_data = (void *)1; - p = m.arr; addr = m.addr; for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) { @@ -250,6 +250,11 @@ static int privcmd_mmap(struct file * file, struct vm_area_struct * vma) return 0; } + +static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) +{ + return (xchg(&vma->vm_private_data, (void *)1) == NULL); +} #endif static struct file_operations privcmd_file_ops = { diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 2ae941fa1..733c5d976 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index d1fe43b01..0cfa5a655 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -446,6 +446,12 @@ beyond_if: regs->gp = ex.a_gpvalue; #endif start_thread(regs, ex.a_entry, current->mm->start_stack); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } return 0; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 8f2bd09a8..43700dc14 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1091,6 +1091,12 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) #endif start_thread(regs, elf_entry, bprm->p); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } retval = 0; out: kfree(loc); diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index e16f42d73..44728778f 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -422,6 +422,13 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, entryaddr = interp_params.entry_addr ?: exec_params.entry_addr; start_thread(regs, entryaddr, current->mm->start_stack); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } + retval = 0; error: diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index a37a000d6..561c313ff 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -898,6 +898,9 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) start_thread(regs, start_addr, current->mm->start_stack); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; } diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index c927dc56f..2d7e18688 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c @@ -272,6 +272,8 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) map_hpux_gateway_page(current,current->mm); start_thread_som(regs, som_entry, bprm->p); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); return 0; /* error cleanup */ diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 0feb3bd49..77a2fbb15 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -6,7 +6,11 @@ on requests on other threads. Improve POSIX locking emulation, (lock cancel now works, and unlock of merged range works even to Windows servers now). Fix oops on mount to lanman servers (win9x, os/2 etc.) when null password. Do not send listxattr -(SMB to query all EAs) if nouser_xattr specified. +(SMB to query all EAs) if nouser_xattr specified. Return error +in rename 2nd attempt retry (ie report if rename by handle also +fails, after rename by path fails, we were not reporting whether +the retry worked or not). + Version 1.44 ------------ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e9c5ba908..ddb012a68 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -752,6 +752,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) int stored_rc = 0; struct cifsLockInfo *li, *tmp; + rc = 0; down(&fid->lock_sem); list_for_each_entry_safe(li, tmp, &fid->llist, llist) { if (pfLock->fl_start <= li->offset && @@ -766,7 +767,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) kfree(li); } } - up(&fid->lock_sem); + up(&fid->lock_sem); } } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 36e069f81..d558c304b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -880,10 +880,14 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); if (info_buf_source != NULL) { info_buf_target = info_buf_source + 1; - rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, - info_buf_source, cifs_sb_source->local_nls, - cifs_sb_source->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (pTcon->ses->capabilities & CAP_UNIX) + rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, + info_buf_source, + cifs_sb_source->local_nls, + cifs_sb_source->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + /* else rc is still EEXIST so will fall through to + unlink the target and retry rename */ if (rc == 0) { rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName, info_buf_target, @@ -932,7 +936,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, cifs_sb_source->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { - CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, + rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, cifs_sb_source->local_nls, cifs_sb_source->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d1705ab81..d6d3efcbc 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -90,7 +90,9 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, } */ /* copy user */ if(ses->userName == NULL) { - /* BB what about null user mounts - check that we do this BB */ + /* null user mount */ + *bcc_ptr = 0; + *(bcc_ptr+1) = 0; } else { /* 300 should be long enough for any conceivable user name */ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, 300, nls_cp); @@ -98,10 +100,13 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ /* copy domain */ - if(ses->domainName == NULL) - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, - "CIFS_LINUX_DOM", 32, nls_cp); - else + if(ses->domainName == NULL) { + /* Sending null domain better than using a bogus domain name (as + we did briefly in 2.6.18) since server will use its default */ + *bcc_ptr = 0; + *(bcc_ptr+1) = 0; + bytes_ret = 0; + } else bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 256, nls_cp); bcc_ptr += 2 * bytes_ret; @@ -144,13 +149,11 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, /* copy domain */ - if(ses->domainName == NULL) { - strcpy(bcc_ptr, "CIFS_LINUX_DOM"); - bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */ - } else { + if(ses->domainName != NULL) { strncpy(bcc_ptr, ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, 256); - } + } /* else we will send a null domain name + so the server will default to its own domain */ *bcc_ptr = 0; bcc_ptr++; diff --git a/fs/exec.c b/fs/exec.c index c567e1a20..92805ece1 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -961,7 +961,13 @@ EXPORT_SYMBOL(prepare_binprm); static int unsafe_exec(struct task_struct *p) { - int unsafe = tracehook_unsafe_exec(p); + int unsafe = 0; + if (p->ptrace & PT_PTRACED) { + if (p->ptrace & PT_PTRACE_CAP) + unsafe |= LSM_UNSAFE_PTRACE_CAP; + else + unsafe |= LSM_UNSAFE_PTRACE; + } if (atomic_read(&p->fs->count) > 1 || atomic_read(&p->files->count) > 1 || atomic_read(&p->sighand->count) > 1) @@ -1086,7 +1092,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) bprm->file = NULL; current->did_exec = 1; proc_exec_connector(current); - tracehook_report_exec(bprm, regs); return retval; } read_lock(&binfmt_lock); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 5d7c726be..f75deebbf 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -138,6 +138,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) struct fuse_entry_out outarg; struct fuse_conn *fc; struct fuse_req *req; + struct fuse_req *forget_req; /* Doesn't hurt to "reset" the validity timeout */ fuse_invalidate_entry_cache(entry); @@ -151,21 +152,29 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) if (IS_ERR(req)) return 0; + forget_req = fuse_get_req(fc); + if (IS_ERR(forget_req)) { + fuse_put_request(fc, req); + return 0; + } + fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); request_send(fc, req); err = req->out.h.error; + fuse_put_request(fc, req); /* Zero nodeid is same as -ENOENT */ if (!err && !outarg.nodeid) err = -ENOENT; if (!err) { struct fuse_inode *fi = get_fuse_inode(inode); if (outarg.nodeid != get_node_id(inode)) { - fuse_send_forget(fc, req, outarg.nodeid, 1); + fuse_send_forget(fc, forget_req, + outarg.nodeid, 1); return 0; } fi->nlookup ++; } - fuse_put_request(fc, req); + fuse_put_request(fc, forget_req); if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) return 0; @@ -214,6 +223,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, struct inode *inode = NULL; struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req; + struct fuse_req *forget_req; if (entry->d_name.len > FUSE_NAME_MAX) return ERR_PTR(-ENAMETOOLONG); @@ -222,9 +232,16 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, if (IS_ERR(req)) return ERR_PTR(PTR_ERR(req)); + forget_req = fuse_get_req(fc); + if (IS_ERR(forget_req)) { + fuse_put_request(fc, req); + return ERR_PTR(PTR_ERR(forget_req)); + } + fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); err = req->out.h.error; + fuse_put_request(fc, req); /* Zero nodeid is same as -ENOENT, but with valid timeout */ if (!err && outarg.nodeid && (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) @@ -233,11 +250,11 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr); if (!inode) { - fuse_send_forget(fc, req, outarg.nodeid, 1); + fuse_send_forget(fc, forget_req, outarg.nodeid, 1); return ERR_PTR(-ENOMEM); } } - fuse_put_request(fc, req); + fuse_put_request(fc, forget_req); if (err && err != -ENOENT) return ERR_PTR(err); @@ -375,6 +392,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, struct fuse_entry_out outarg; struct inode *inode; int err; + struct fuse_req *forget_req; + + forget_req = fuse_get_req(fc); + if (IS_ERR(forget_req)) { + fuse_put_request(fc, req); + return PTR_ERR(forget_req); + } req->in.h.nodeid = get_node_id(dir); req->out.numargs = 1; @@ -382,24 +406,24 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; - if (err) { - fuse_put_request(fc, req); - return err; - } + fuse_put_request(fc, req); + if (err) + goto out_put_forget_req; + err = -EIO; if (invalid_nodeid(outarg.nodeid)) - goto out_put_request; + goto out_put_forget_req; if ((outarg.attr.mode ^ mode) & S_IFMT) - goto out_put_request; + goto out_put_forget_req; inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr); if (!inode) { - fuse_send_forget(fc, req, outarg.nodeid, 1); + fuse_send_forget(fc, forget_req, outarg.nodeid, 1); return -ENOMEM; } - fuse_put_request(fc, req); + fuse_put_request(fc, forget_req); if (dir_alias(inode)) { iput(inode); @@ -411,8 +435,8 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, fuse_invalidate_attr(dir); return 0; - out_put_request: - fuse_put_request(fc, req); + out_put_forget_req: + fuse_put_request(fc, forget_req); return err; } diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 34937ee83..4af327a89 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -391,6 +391,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) hfs_find_exit(&fd); goto bail_no_root; } + res = -EINVAL; root_inode = hfs_iget(sb, &fd.search_key->cat, &rec); hfs_find_exit(&fd); if (!root_inode) diff --git a/fs/namei.c b/fs/namei.c index 805a35e97..b9d0804bb 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -230,7 +230,7 @@ int generic_permission(struct inode *inode, int mask, static inline int vx_barrier(struct inode *inode) { - if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN)) { + if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN|VX_WATCH)) { vxwprintk(1, "xid=%d did hit the barrier.", vx_current_xid()); return 1; @@ -807,9 +807,10 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, goto need_lookup; if (dentry->d_op && dentry->d_op->d_revalidate) goto need_revalidate; +done: inode = dentry->d_inode; if (!inode) - goto done; + goto no_inode; if (!vx_check(inode->i_xid, VX_WATCH|VX_ADMIN|VX_HOSTID|VX_IDENT)) goto hidden; if (inode->i_sb->s_magic == PROC_SUPER_MAGIC) { @@ -818,7 +819,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, if (de && !vx_hide_check(0, de->vx_flags)) goto hidden; } -done: +no_inode: path->mnt = mnt; path->dentry = dentry; __follow_mount(path); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 8b454d67b..d424d082d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -931,6 +931,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru if (IS_ERR(res)) goto out_unlock; vx_propagate_xid(nd, inode); + no_entry: res = d_materialise_unique(dentry, inode); if (res != NULL) diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 445abb4d4..ed88119e5 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -91,6 +91,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, clnt->cl_softrtry = 1; clnt->cl_oneshot = 1; clnt->cl_intr = 1; + clnt->cl_tagxid = 1; } return clnt; } diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 62e627b47..97a93752d 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -287,7 +287,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, { NFS_MOUNT_NONLM, ",nolock", "" }, { NFS_MOUNT_NOACL, ",noacl", "" }, { NFS_MOUNT_FSCACHE, ",fsc", "" }, - { NFS_MOUNT_TAGXID, ",tagxid", "" }, + { NFS_MOUNT_TAGXID, ",tagxid", ""}, { 0, NULL, NULL } }; const struct proc_nfs_info *nfs_infop; @@ -527,6 +527,7 @@ static inline void nfs_initialise_sb(struct super_block *sb) if (server->flags & NFS_MOUNT_NOAC) sb->s_flags |= MS_SYNCHRONOUS; + if (server->flags & NFS_MOUNT_TAGXID) sb->s_flags |= MS_TAGXID; diff --git a/fs/proc/array.c b/fs/proc/array.c index 765cc2994..9b31fb457 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include @@ -164,21 +163,16 @@ static inline const char * get_task_state(struct task_struct *tsk) static inline char * task_state(struct task_struct *p, char *buffer) { - struct task_struct *tracer; - pid_t tracer_pid, pid, ptgid, tgid; struct group_info *group_info; int g; struct fdtable *fdt = NULL; - - rcu_read_lock(); - tracer = tracehook_tracer_task(p); - tracer_pid = tracer == NULL ? 0 : vx_map_pid(tracer->pid); - rcu_read_unlock(); + pid_t pid, ptgid, tppid, tgid; read_lock(&tasklist_lock); tgid = vx_map_tgid(p->tgid); pid = vx_map_pid(p->pid); - ptgid = vx_map_pid(p->group_leader->parent->tgid); + ptgid = vx_map_pid(p->group_leader->real_parent->tgid); + tppid = vx_map_pid(p->parent->pid); buffer += sprintf(buffer, "State:\t%s\n" "SleepAVG:\t%lu%%\n" @@ -191,7 +185,7 @@ static inline char * task_state(struct task_struct *p, char *buffer) get_task_state(p), (p->sleep_avg/1024)*100/(1020000000/1024), tgid, pid, (pid > 1) ? ptgid : 0, - tracer_pid, + pid_alive(p) && p->ptrace ? tppid : 0, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); @@ -451,7 +445,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) } pid = vx_info_map_pid(task->vx_info, pid_alive(task) ? task->pid : 0); ppid = (!(pid > 1)) ? 0 : vx_info_map_tgid(task->vx_info, - task->group_leader->parent->tgid); + task->group_leader->real_parent->tgid); pgid = vx_info_map_pid(task->vx_info, pgid); read_unlock(&tasklist_lock); diff --git a/fs/proc/base.c b/fs/proc/base.c index b7a5972f6..ea545e55e 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -67,7 +67,6 @@ #include #include #include -#include #include #include #include @@ -417,6 +416,13 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf return result; } +#define MAY_PTRACE(task) \ + (task == current || \ + (task->parent == current && \ + (task->ptrace & PT_PTRACED) && \ + (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ + security_ptrace(current,task) == 0)) + struct mm_struct *mm_for_maps(struct task_struct *task) { struct mm_struct *mm = get_task_mm(task); @@ -761,8 +767,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, if (!task) goto out_no_task; - if (!tracehook_allow_access_process_vm(task) - || !ptrace_may_attach(task)) + if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) goto out; ret = -ENOMEM; @@ -788,8 +793,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; retval = access_process_vm(task, src, page, this_len, 0); - if (!retval || !tracehook_allow_access_process_vm(task) - || !ptrace_may_attach(task)) { + if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) { if (!ret) ret = -EIO; break; @@ -833,8 +837,7 @@ static ssize_t mem_write(struct file * file, const char * buf, if (!task) goto out_no_task; - if (!tracehook_allow_access_process_vm(task) - || !ptrace_may_attach(task)) + if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) goto out; copied = -ENOMEM; diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 2348368d5..9e8ae2607 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -173,14 +173,15 @@ out: SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, long long index, unsigned int length, - long long *next_index) + long long *next_index, int srclength) { struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >> msblk->devblksize_log2) + 2]; unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1); unsigned int cur_index = index >> msblk->devblksize_log2; - int bytes, avail_bytes, b = 0, k; + int bytes, avail_bytes, b = 0, k = 0; char *c_buffer; unsigned int compressed; unsigned int c_byte = length; @@ -191,8 +192,11 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, c_buffer = compressed ? msblk->read_data : buffer; c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); - TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed - ? "" : "un", (unsigned int) c_byte); + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed + ? "" : "un", (unsigned int) c_byte, srclength); + + if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used) + goto read_failure; if (!(bh[0] = sb_getblk(s, cur_index))) goto block_release; @@ -204,6 +208,9 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, } ll_rw_block(READ, b, bh); } else { + if (index < 0 || (index + 2) > sblk->bytes_used) + goto read_failure; + if (!(bh[0] = get_block_length(s, &cur_index, &offset, &c_byte))) goto read_failure; @@ -216,6 +223,9 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed ? "" : "un", (unsigned int) c_byte); + if (c_byte > srclength || (index + c_byte) > sblk->bytes_used) + goto read_failure; + for (b = 1; bytes < c_byte; b++) { if (!(bh[b] = sb_getblk(s, ++cur_index))) goto block_release; @@ -227,7 +237,7 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, if (compressed) down(&msblk->read_data_mutex); - for (bytes = 0, k = 0; k < b; k++) { + for (bytes = 0; k < b; k++) { avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ? msblk->devblksize - offset : c_byte - bytes; @@ -249,7 +259,7 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, msblk->stream.next_in = c_buffer; msblk->stream.avail_in = c_byte; msblk->stream.next_out = buffer; - msblk->stream.avail_out = msblk->read_size; + msblk->stream.avail_out = srclength; if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) || ((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH)) @@ -271,8 +281,8 @@ SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer, return bytes; block_release: - while (--b >= 0) - brelse(bh[b]); + for (; k < b; k++) + brelse(bh[k]); read_failure: ERROR("sb_bread failed reading block 0x%x\n", cur_index); @@ -336,14 +346,20 @@ SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, msblk->block_cache[i].block = SQUASHFS_USED_BLK; up(&msblk->block_cache_mutex); - if (!(msblk->block_cache[i].length = - squashfs_read_data(s, - msblk->block_cache[i].data, - block, 0, &next_index))) { - ERROR("Unable to read cache block [%llx:%x]\n", - block, offset); - goto out; - } + msblk->block_cache[i].length = squashfs_read_data(s, + msblk->block_cache[i].data, block, 0, &next_index, + SQUASHFS_METADATA_SIZE); + + if (msblk->block_cache[i].length == 0) { + ERROR("Unable to read cache block [%llx:%x]\n", + block, offset); + down(&msblk->block_cache_mutex); + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK; + kfree(msblk->block_cache[i].data); + wake_up(&msblk->waitq); + up(&msblk->block_cache_mutex); + goto out; + } down(&msblk->block_cache_mutex); wake_up(&msblk->waitq); @@ -357,7 +373,11 @@ SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer, continue; } - if ((bytes = msblk->block_cache[i].length - offset) >= length) { + bytes = msblk->block_cache[i].length - offset; + + if (bytes < 1) + goto out; + else if (bytes >= length) { if (buffer) memcpy(buffer, msblk->block_cache[i].data + offset, length); @@ -442,6 +462,7 @@ SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_blo { int i, n; struct squashfs_sb_info *msblk = s->s_fs_info; + struct squashfs_super_block *sblk = &msblk->sblk; while ( 1 ) { down(&msblk->fragment_mutex); @@ -487,7 +508,8 @@ SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_blo if (!(msblk->fragment[i].length = squashfs_read_data(s, msblk->fragment[i].data, - start_block, length, NULL))) { + start_block, length, NULL, + sblk->block_size))) { ERROR("Unable to read fragment cache block " "[%llx]\n", start_block); msblk->fragment[i].locked = 0; @@ -874,6 +896,10 @@ static int read_fragment_index_table(struct super_block *s) { struct squashfs_sb_info *msblk = s->s_fs_info; struct squashfs_super_block *sblk = &msblk->sblk; + unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments); + + if (length == 0) + return 1; /* Allocate fragment index table */ if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES @@ -882,13 +908,9 @@ static int read_fragment_index_table(struct super_block *s) return 0; } - if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) && - !squashfs_read_data(s, (char *) - msblk->fragment_index, - sblk->fragment_table_start, - SQUASHFS_FRAGMENT_INDEX_BYTES - (sblk->fragments) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + if (!squashfs_read_data(s, (char *) msblk->fragment_index, + sblk->fragment_table_start, length | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) { ERROR("unable to read fragment index table\n"); return 0; } @@ -980,9 +1002,11 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) init_waitqueue_head(&msblk->waitq); init_waitqueue_head(&msblk->fragment_wait_queue); + sblk->bytes_used = sizeof(struct squashfs_super_block); if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, sizeof(struct squashfs_super_block) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, + sizeof(struct squashfs_super_block))) { SERROR("unable to read superblock\n"); goto failed_mount; } @@ -1010,6 +1034,15 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) if(!supported_squashfs_filesystem(msblk, silent)) goto failed_mount; + /* Check the filesystem does not extend beyond the end of the + block device */ + if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode)) + goto failed_mount; + + /* Check the root inode for sanity */ + if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE) + goto failed_mount; + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES @@ -1079,7 +1112,9 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start, ((sblk->no_uids + sblk->no_guids) * sizeof(unsigned int)) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, + (sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int))) { ERROR("unable to read uid/gid table\n"); goto failed_mount; } @@ -1090,7 +1125,9 @@ static int squashfs_fill_super(struct super_block *s, void *data, int silent) if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start, ((sblk->no_uids + sblk->no_guids) * sizeof(unsigned int)) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, + (sblk->no_uids + sblk->no_guids) * + sizeof(unsigned int))) { ERROR("unable to read uid/gid table\n"); goto failed_mount; } @@ -1516,7 +1553,8 @@ static int squashfs_readpage(struct file *file, struct page *page) down(&msblk->read_page_mutex); if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page, - block, bsize, NULL))) { + block, bsize, NULL, + msblk->read_size))) { ERROR("Unable to read page, block %llx, size %x\n", block, bsize); up(&msblk->read_page_mutex); @@ -1616,15 +1654,12 @@ static int squashfs_readpage4K(struct file *file, struct page *page) if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { - pageaddr = kmap_atomic(page, KM_USER0); block_list = NULL; goto skip_read; } if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) { ERROR("Failed to allocate block_list\n"); - pageaddr = kmap_atomic(page, KM_USER0); - block_list = NULL; goto skip_read; } @@ -1636,11 +1671,12 @@ static int squashfs_readpage4K(struct file *file, struct page *page) down(&msblk->read_page_mutex); bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block, - bsize, NULL); - pageaddr = kmap_atomic(page, KM_USER0); - if (bytes) + bsize, NULL, msblk->read_size); + if (bytes) { + pageaddr = kmap_atomic(page, KM_USER0); memcpy(pageaddr, msblk->read_page, bytes); - else + kunmap_atomic(pageaddr, KM_USER0); + } else ERROR("Unable to read page, block %llx, size %x\n", block, bsize); up(&msblk->read_page_mutex); @@ -1650,11 +1686,12 @@ static int squashfs_readpage4K(struct file *file, struct page *page) SQUASHFS_I(inode)-> u.s1.fragment_start_block, SQUASHFS_I(inode)-> u.s1.fragment_size); - pageaddr = kmap_atomic(page, KM_USER0); if (fragment) { bytes = i_size_read(inode) & (sblk->block_size - 1); + pageaddr = kmap_atomic(page, KM_USER0); memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)-> u.s1.fragment_offset, bytes); + kunmap_atomic(pageaddr, KM_USER0); release_cached_fragment(msblk, fragment); } else ERROR("Unable to read page, block %llx, size %x\n", @@ -1664,6 +1701,7 @@ static int squashfs_readpage4K(struct file *file, struct page *page) } skip_read: + pageaddr = kmap_atomic(page, KM_USER0); memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); kunmap_atomic(pageaddr, KM_USER0); flush_dcache_page(page); diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index dcbef0d11..170e568c4 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h @@ -49,7 +49,7 @@ static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode) #define SQSH_EXTERN extern unsigned int squashfs_read_data(struct super_block *s, char *buffer, long long index, unsigned int length, - long long *next_index); + long long *next_index, int srclength); extern int squashfs_get_cached_block(struct super_block *s, char *buffer, long long block, unsigned int offset, int length, long long *next_block, diff --git a/fs/squashfs/squashfs2_0.c b/fs/squashfs/squashfs2_0.c index 53ce95e26..f163523a4 100644 --- a/fs/squashfs/squashfs2_0.c +++ b/fs/squashfs/squashfs2_0.c @@ -73,12 +73,13 @@ static int read_fragment_index_table_2(struct super_block *s) } if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && - !squashfs_read_data(s, (char *) - msblk->fragment_index_2, - sblk->fragment_table_start, - SQUASHFS_FRAGMENT_INDEX_BYTES_2 - (sblk->fragments) | - SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) { + !squashfs_read_data(s, (char *) + msblk->fragment_index_2, + sblk->fragment_table_start, + SQUASHFS_FRAGMENT_INDEX_BYTES_2 + (sblk->fragments) | + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, + SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { ERROR("unable to read fragment index table\n"); return 0; } diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index cc5419495..906dc53d5 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -128,8 +128,6 @@ void switch_ipi_to_APIC_timer(void *cpumask); extern int timer_over_8254; -extern void dmi_check_apic(void); - #else /* !CONFIG_X86_LOCAL_APIC */ static inline void lapic_shutdown(void) { } diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h index 6838ce6c8..bc1d6edae 100644 --- a/include/asm-i386/i387.h +++ b/include/asm-i386/i387.h @@ -126,12 +126,17 @@ extern int save_i387( struct _fpstate __user *buf ); extern int restore_i387( struct _fpstate __user *buf ); /* - * ptrace request handlers... + * ptrace request handers... */ -extern int get_fpregs(struct user_i387_struct *, struct task_struct *); -extern int set_fpregs(struct task_struct *, const struct user_i387_struct *); -extern void updated_fpxregs(struct task_struct *tsk); - +extern int get_fpregs( struct user_i387_struct __user *buf, + struct task_struct *tsk ); +extern int set_fpregs( struct task_struct *tsk, + struct user_i387_struct __user *buf ); + +extern int get_fpxregs( struct user_fxsr_struct __user *buf, + struct task_struct *tsk ); +extern int set_fpxregs( struct task_struct *tsk, + struct user_fxsr_struct __user *buf ); /* * FPU state for core dumps... diff --git a/include/asm-i386/mach-xen/asm/system.h b/include/asm-i386/mach-xen/asm/system.h index d8ca39352..b126e233e 100644 --- a/include/asm-i386/mach-xen/asm/system.h +++ b/include/asm-i386/mach-xen/asm/system.h @@ -19,6 +19,10 @@ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); +/* + * Saving eflags is important. It switches not only IOPL between tasks, + * it also protects other tasks from NT leaking through sysenter etc. + */ #define switch_to(prev,next,last) do { \ unsigned long esi,edi; \ asm volatile("pushfl\n\t" /* Save flags */ \ diff --git a/include/asm-i386/signal.h b/include/asm-i386/signal.h index 53945c95a..c3e8adec5 100644 --- a/include/asm-i386/signal.h +++ b/include/asm-i386/signal.h @@ -221,8 +221,10 @@ struct pt_regs; #define ptrace_signal_deliver(regs, cookie) \ do { \ - if (test_and_clear_thread_flag(TIF_FORCED_TF)) \ + if (current->ptrace & PT_DTRACE) { \ + current->ptrace &= ~PT_DTRACE; \ (regs)->eflags &= ~TF_MASK; \ + } \ } while (0) #endif /* __KERNEL__ */ diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h index b3fa512b7..54d6d7aea 100644 --- a/include/asm-i386/thread_info.h +++ b/include/asm-i386/thread_info.h @@ -135,13 +135,13 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_IRET 5 /* return with iret */ +#define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_SECCOMP 8 /* secure computing */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ #define TIF_MEMDIE 16 #define TIF_DEBUG 17 /* uses debug registers */ #define TIF_IO_BITMAP 18 /* uses I/O bitmap */ -#define TIF_FORCED_TF 19 /* true if TF in eflags artificially */ #define _TIF_SYSCALL_TRACE (1< static inline char* alloc_gatt_pages(unsigned int order) @@ -52,16 +57,6 @@ free_gatt_pages(void* table, unsigned int order) xen_destroy_contiguous_region((unsigned long)table, order); free_pages((unsigned long)table, order); } -#else /* CONFIG_XEN */ -/* Convert a physical address to an address suitable for the GART. */ -#define phys_to_gart(x) (x) -#define gart_to_phys(x) (x) - -/* GATT allocation. Returns/accepts GATT kernel virtual address. */ -#define alloc_gatt_pages(order) \ - ((char *)__get_free_pages(GFP_KERNEL, (order))) -#define free_gatt_pages(table, order) \ - free_pages((unsigned long)(table), (order)) -#endif /* CONFIG_XEN */ +#endif /* CONFIG_XEN */ #endif /* _ASM_IA64_AGP_H */ diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h index a527db735..abe230e4e 100644 --- a/include/asm-ia64/dma-mapping.h +++ b/include/asm-ia64/dma-mapping.h @@ -6,7 +6,6 @@ * David Mosberger-Tang */ #include - #ifndef CONFIG_XEN #define dma_alloc_coherent platform_dma_alloc_coherent @@ -23,7 +22,6 @@ #define dma_sync_sg_for_device platform_dma_sync_sg_for_device #define dma_mapping_error platform_dma_mapping_error - #else /* CONFIG_XEN */ /* Needed for arch/i386/kernel/swiotlb.c and arch/i386/kernel/pci-dma-xen.c */ #include diff --git a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h index d96b5ebab..25f9835d5 100644 --- a/include/asm-ia64/elf.h +++ b/include/asm-ia64/elf.h @@ -154,30 +154,6 @@ extern void ia64_init_addr_space (void); #define ELF_NGREG 128 /* we really need just 72 but let's leave some headroom... */ #define ELF_NFPREG 128 /* f0 and f1 could be omitted, but so what... */ -/* elf_gregset_t register offsets */ -#define ELF_GR_0_OFFSET 0 -#define ELF_NAT_OFFSET (32 * sizeof(elf_greg_t)) -#define ELF_PR_OFFSET (33 * sizeof(elf_greg_t)) -#define ELF_BR_0_OFFSET (34 * sizeof(elf_greg_t)) -#define ELF_CR_IIP_OFFSET (42 * sizeof(elf_greg_t)) -#define ELF_CFM_OFFSET (43 * sizeof(elf_greg_t)) -#define ELF_CR_IPSR_OFFSET (44 * sizeof(elf_greg_t)) -#define ELF_GR_OFFSET(i) (ELF_GR_0_OFFSET + i * sizeof(elf_greg_t)) -#define ELF_BR_OFFSET(i) (ELF_BR_0_OFFSET + i * sizeof(elf_greg_t)) -#define ELF_AR_RSC_OFFSET (45 * sizeof(elf_greg_t)) -#define ELF_AR_BSP_OFFSET (46 * sizeof(elf_greg_t)) -#define ELF_AR_BSPSTORE_OFFSET (47 * sizeof(elf_greg_t)) -#define ELF_AR_RNAT_OFFSET (48 * sizeof(elf_greg_t)) -#define ELF_AR_CCV_OFFSET (49 * sizeof(elf_greg_t)) -#define ELF_AR_UNAT_OFFSET (50 * sizeof(elf_greg_t)) -#define ELF_AR_FPSR_OFFSET (51 * sizeof(elf_greg_t)) -#define ELF_AR_PFS_OFFSET (52 * sizeof(elf_greg_t)) -#define ELF_AR_LC_OFFSET (53 * sizeof(elf_greg_t)) -#define ELF_AR_EC_OFFSET (54 * sizeof(elf_greg_t)) -#define ELF_AR_CSD_OFFSET (55 * sizeof(elf_greg_t)) -#define ELF_AR_SSD_OFFSET (56 * sizeof(elf_greg_t)) -#define ELF_AR_END_OFFSET (57 * sizeof(elf_greg_t)) - typedef unsigned long elf_fpxregset_t; typedef unsigned long elf_greg_t; diff --git a/include/asm-ia64/hypervisor.h b/include/asm-ia64/hypervisor.h index 3c190aea3..3ba9bcb0b 100644 --- a/include/asm-ia64/hypervisor.h +++ b/include/asm-ia64/hypervisor.h @@ -139,6 +139,7 @@ int direct_remap_pfn_range(struct vm_area_struct *vma, pgprot_t prot, domid_t domid); struct file; +int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); int privcmd_mmap(struct file * file, struct vm_area_struct * vma); #define HAVE_ARCH_PRIVCMD_MMAP diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index 6b342519a..1b6fde4eb 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -278,5 +278,5 @@ extern struct address_space xen_ia64_foreign_dummy_mapping; #endif /* CONFIG_XEN */ #endif /* __ASSEMBLY__ */ #define devmem_is_allowed(x) 1 -# endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_IA64_PAGE_H */ diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index 896550bad..c906f35aa 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -10,6 +10,7 @@ #define _ASM_IRQ_H #include +#include #include diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index ec8bf1e71..a701504f9 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -319,6 +319,8 @@ #define __NR_set_robust_list 300 #define __NR_get_robust_list 301 +#define NR_SYSCALLS 302 + #ifdef __KERNEL__ /* WARNING: You MAY NOT add syscall numbers larger than 301, since * all of the syscall tables in the Sparc kernel are diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h index dee40206b..7392fc4a9 100644 --- a/include/asm-sparc64/futex.h +++ b/include/asm-sparc64/futex.h @@ -87,24 +87,22 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) { __asm__ __volatile__( - "\n1: lduwa [%2] %%asi, %0\n" - "2: casa [%2] %%asi, %0, %1\n" - "3:\n" + "\n1: casa [%3] %%asi, %2, %0\n" + "2:\n" " .section .fixup,#alloc,#execinstr\n" " .align 4\n" - "4: ba 3b\n" - " mov %3, %0\n" + "3: ba 2b\n" + " mov %4, %0\n" " .previous\n" " .section __ex_table,\"a\"\n" " .align 4\n" - " .word 1b, 4b\n" - " .word 2b, 4b\n" + " .word 1b, 3b\n" " .previous\n" - : "=&r" (oldval) - : "r" (newval), "r" (uaddr), "i" (-EFAULT) + : "=r" (newval) + : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT) : "memory"); - return oldval; + return newval; } #endif /* !(_SPARC64_FUTEX_H) */ diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index fc28b349e..7c980092d 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -321,6 +321,8 @@ #define __NR_set_robust_list 300 #define __NR_get_robust_list 301 +#define NR_SYSCALLS 302 + #ifdef __KERNEL__ /* WARNING: You MAY NOT add syscall numbers larger than 301, since * all of the syscall tables in the Sparc kernel are diff --git a/include/asm-x86_64/fpu32.h b/include/asm-x86_64/fpu32.h index dce9f6f4b..4153db5c0 100644 --- a/include/asm-x86_64/fpu32.h +++ b/include/asm-x86_64/fpu32.h @@ -7,7 +7,4 @@ int restore_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, int save_i387_ia32(struct task_struct *tsk, struct _fpstate_ia32 __user *buf, struct pt_regs *regs, int fsave); -int get_fpregs32(struct user_i387_ia32_struct *, struct task_struct *); -int set_fpregs32(struct task_struct *, const struct user_i387_ia32_struct *); - #endif diff --git a/include/asm-x86_64/mach-xen/asm/dma-mapping.h b/include/asm-x86_64/mach-xen/asm/dma-mapping.h index 0c37aabdf..843deaba1 100644 --- a/include/asm-x86_64/mach-xen/asm/dma-mapping.h +++ b/include/asm-x86_64/mach-xen/asm/dma-mapping.h @@ -200,7 +200,6 @@ dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction dir) extern struct device fallback_dev; #endif - extern int panic_on_overflow; #endif /* _X8664_DMA_MAPPING_H */ diff --git a/include/asm-x86_64/mach-xen/asm/processor.h b/include/asm-x86_64/mach-xen/asm/processor.h index 2ca8c14fa..be43d34cf 100644 --- a/include/asm-x86_64/mach-xen/asm/processor.h +++ b/include/asm-x86_64/mach-xen/asm/processor.h @@ -242,11 +242,10 @@ struct tss_struct { } __attribute__((packed)) ____cacheline_aligned; DECLARE_PER_CPU(struct tss_struct,init_tss); +/* Save the original ist values for checking stack pointers during debugging */ #endif - extern struct cpuinfo_x86 boot_cpu_data; -/* Save the original ist values for checking stack pointers during debugging */ struct orig_ist { unsigned long ist[7]; }; diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h index 3363f7b3b..790c512a4 100644 --- a/include/asm-x86_64/thread_info.h +++ b/include/asm-x86_64/thread_info.h @@ -120,7 +120,6 @@ static inline struct thread_info *stack_thread_info(void) #define TIF_FORK 18 /* ret_from_fork */ #define TIF_ABI_PENDING 19 #define TIF_MEMDIE 20 -#define TIF_FORCED_TF 21 /* true if TF in eflags artificially */ #define _TIF_SYSCALL_TRACE (1< #ifdef __KERNEL__ -#include -#include -struct task_struct; -struct siginfo; -struct rusage; - - -extern int ptrace_may_attach(struct task_struct *task); -extern int __ptrace_may_attach(struct task_struct *task); - - -#ifdef CONFIG_PTRACE -#include -struct utrace_attached_engine; -struct utrace_regset_view; - /* - * These must be defined by arch code to handle machine-specific ptrace - * requests such as PTRACE_PEEKUSR and PTRACE_GETREGS. Returns -ENOSYS for - * any request it does not handle, then handled by machine-independent code. - * This can change *request and then return -ENOSYS to handle a - * machine-specific alias for a generic request. - * - * This code should NOT access task machine state directly. Instead it - * should use the utrace_regset accessors. The functions below make this easy. + * Ptrace flags * - * Any nonzero return value should be for an error. If the return value of - * the ptrace syscall should be a nonzero success value, this returns zero - * and sets *retval to the value--which might have any bit pattern at all, - * including one that looks like -ENOSYS or another error code. - */ -extern fastcall int arch_ptrace(long *request, struct task_struct *child, - struct utrace_attached_engine *engine, - unsigned long addr, unsigned long data, - long *retval); -#ifdef CONFIG_COMPAT -#include - -extern fastcall int arch_compat_ptrace(compat_long_t *request, - struct task_struct *child, - struct utrace_attached_engine *engine, - compat_ulong_t a, compat_ulong_t d, - compat_long_t *retval); -#endif - -/* - * Convenience function doing access to a single utrace_regset for ptrace. - * The offset and size are in bytes, giving the location in the regset data. + * The owner ship rules for task->ptrace which holds the ptrace + * flags is simple. When a task is running it owns it's task->ptrace + * flags. When the a task is stopped the ptracer owns task->ptrace. */ -extern fastcall int ptrace_regset_access(struct task_struct *child, - struct utrace_attached_engine *engine, - const struct utrace_regset_view *view, - int setno, unsigned long offset, - unsigned int size, void __user *data, - int write); -/* - * Convenience wrapper for doing access to a whole utrace_regset for ptrace. - */ -static inline int ptrace_whole_regset(struct task_struct *child, - struct utrace_attached_engine *engine, - long data, int setno, int write) -{ - return ptrace_regset_access(child, engine, utrace_native_view(current), - setno, 0, -1, (void __user *)data, write); -} - -/* - * Convenience function doing access to a single slot in a utrace_regset. - * The regno value gives a slot number plus regset->bias. - * The value accessed is regset->size bytes long. - */ -extern fastcall int ptrace_onereg_access(struct task_struct *child, - struct utrace_attached_engine *engine, - const struct utrace_regset_view *view, - int setno, unsigned long regno, - void __user *data, int write); - - -/* - * An array of these describes the layout of the virtual struct user - * accessed by PEEKUSR/POKEUSR, or the structure used by GETREGS et al. - * The array is terminated by an element with .end of zero. - * An element describes the range [.start, .end) of struct user offsets, - * measured in bytes; it maps to the regset in the view's regsets array - * at the index given by .regset, at .offset bytes into that regset's data. - * If .regset is -1, then the [.start, .end) range reads as zero. - */ -struct ptrace_layout_segment { - unsigned int start, end, regset, offset; -}; - -/* - * Convenience function for doing access to a ptrace compatibility layout. - * The offset and size are in bytes. - */ -extern fastcall int ptrace_layout_access( - struct task_struct *child, struct utrace_attached_engine *engine, - const struct utrace_regset_view *view, - const struct ptrace_layout_segment layout[], - unsigned long offset, unsigned int size, - void __user *data, void *kdata, int write); - - -/* Convenience wrapper for the common PTRACE_PEEKUSR implementation. */ -static inline int ptrace_peekusr(struct task_struct *child, - struct utrace_attached_engine *engine, - const struct ptrace_layout_segment layout[], - unsigned long addr, long data) -{ - return ptrace_layout_access(child, engine, utrace_native_view(current), - layout, addr, sizeof(long), - (unsigned long __user *)data, NULL, 0); -} - -/* Convenience wrapper for the common PTRACE_PEEKUSR implementation. */ -static inline int ptrace_pokeusr(struct task_struct *child, - struct utrace_attached_engine *engine, - const struct ptrace_layout_segment layout[], - unsigned long addr, long data) -{ - return ptrace_layout_access(child, engine, utrace_native_view(current), - layout, addr, sizeof(long), - NULL, &data, 1); -} - -#ifdef CONFIG_COMPAT -/* Convenience wrapper for the common PTRACE_PEEKUSR implementation. */ -static inline int ptrace_compat_peekusr( - struct task_struct *child, struct utrace_attached_engine *engine, - const struct ptrace_layout_segment layout[], - compat_ulong_t addr, compat_ulong_t data) -{ - compat_ulong_t *udata = (compat_ulong_t __user *) (unsigned long) data; - return ptrace_layout_access(child, engine, utrace_native_view(current), - layout, addr, sizeof(compat_ulong_t), - udata, NULL, 0); -} +#define PT_PTRACED 0x00000001 +#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ +#define PT_TRACESYSGOOD 0x00000004 +#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ +#define PT_TRACE_FORK 0x00000010 +#define PT_TRACE_VFORK 0x00000020 +#define PT_TRACE_CLONE 0x00000040 +#define PT_TRACE_EXEC 0x00000080 +#define PT_TRACE_VFORK_DONE 0x00000100 +#define PT_TRACE_EXIT 0x00000200 +#define PT_ATTACHED 0x00000400 /* parent != real_parent */ + +#define PT_TRACE_MASK 0x000003f4 + +/* single stepping state bits (used on ARM and PA-RISC) */ +#define PT_SINGLESTEP_BIT 31 +#define PT_SINGLESTEP (1< /* For unlikely. */ +#include /* For struct task_struct. */ + + +extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); +extern struct task_struct *ptrace_get_task_struct(pid_t pid); +extern int ptrace_traceme(void); +extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); +extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); +extern int ptrace_attach(struct task_struct *tsk); +extern int ptrace_detach(struct task_struct *, unsigned int); +extern void ptrace_disable(struct task_struct *); +extern int ptrace_check_attach(struct task_struct *task, int kill); +extern int ptrace_request(struct task_struct *child, long request, long addr, long data); +extern void ptrace_notify(int exit_code); +extern void __ptrace_link(struct task_struct *child, + struct task_struct *new_parent); +extern void __ptrace_unlink(struct task_struct *child); +extern void ptrace_untrace(struct task_struct *child); +extern int ptrace_may_attach(struct task_struct *task); +extern int __ptrace_may_attach(struct task_struct *task); -/* Convenience wrapper for the common PTRACE_PEEKUSR implementation. */ -static inline int ptrace_compat_pokeusr( - struct task_struct *child, struct utrace_attached_engine *engine, - const struct ptrace_layout_segment layout[], - compat_ulong_t addr, compat_ulong_t data) +static inline void ptrace_link(struct task_struct *child, + struct task_struct *new_parent) { - return ptrace_layout_access(child, engine, utrace_native_view(current), - layout, addr, sizeof(compat_ulong_t), - NULL, &data, 1); + if (unlikely(child->ptrace)) + __ptrace_link(child, new_parent); } -#endif - - -/* - * Called in do_exit, after setting PF_EXITING, no locks are held. - */ -void ptrace_exit(struct task_struct *tsk); - -/* - * Called in do_wait, with tasklist_lock held for reading. - * This reports any ptrace-child that is ready as do_wait would a normal child. - * If there are no ptrace children, returns -ECHILD. - * If there are some ptrace children but none reporting now, returns 0. - * In those cases the tasklist_lock is still held so next_thread(tsk) works. - * For any other return value, tasklist_lock is released before return. - */ -int ptrace_do_wait(struct task_struct *tsk, - pid_t pid, int options, struct siginfo __user *infop, - int __user *stat_addr, struct rusage __user *rusagep); -#else -static inline void ptrace_exit(struct task_struct *tsk) { } -static inline int ptrace_do_wait(struct task_struct *tsk, - pid_t pid, int options, - struct siginfo __user *infop, - int __user *stat_addr, - struct rusage __user *rusagep) +static inline void ptrace_unlink(struct task_struct *child) { - return -ECHILD; + if (unlikely(child->ptrace)) + __ptrace_unlink(child); } -#endif #ifndef force_successful_syscall_return diff --git a/include/linux/sched.h b/include/linux/sched.h index bd6c826f9..45a8e67e9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -785,6 +785,7 @@ struct task_struct { struct thread_info *thread_info; atomic_t usage; unsigned long flags; /* per process flags, defined below */ + unsigned long ptrace; int lock_depth; /* BKL lock depth */ @@ -815,6 +816,12 @@ struct task_struct { #endif struct list_head tasks; + /* + * ptrace_list/ptrace_children forms the list of my children + * that were stolen by a ptracer. + */ + struct list_head ptrace_children; + struct list_head ptrace_list; struct mm_struct *mm, *active_mm; @@ -829,13 +836,15 @@ struct task_struct { pid_t pid; pid_t tgid; /* - * pointers to parent process, youngest child, younger sibling, + * pointers to (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->parent->pid) */ + struct task_struct *real_parent; /* real parent process (when being debugged) */ struct task_struct *parent; /* parent process */ /* - * children/sibling forms the list of my children + * children/sibling forms the list of my children plus the + * tasks I'm ptracing. */ struct list_head children; /* list of my children */ struct list_head sibling; /* linkage in my parent's children list */ @@ -920,11 +929,6 @@ struct task_struct { seccomp_t seccomp; -#ifdef CONFIG_UTRACE - struct utrace *utrace; - unsigned long utrace_flags; -#endif - /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; @@ -978,6 +982,8 @@ struct task_struct { struct io_context *io_context; + unsigned long ptrace_message; + siginfo_t *last_siginfo; /* For ptrace use. */ /* * current io wait handle: wait queue entry to use for io waits * If this thread is processing aio, this points at the waitqueue @@ -1012,10 +1018,6 @@ struct task_struct { atomic_t fs_excl; /* holding fs exclusive resources */ struct rcu_head rcu; -#ifdef CONFIG_PTRACE - struct list_head ptracees; -#endif - /* * cache last used pipe for splice */ @@ -1258,7 +1260,6 @@ extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t, u32); extern void do_notify_parent(struct task_struct *, int); -extern void do_notify_parent_cldstop(struct task_struct *, int); extern void force_sig(int, struct task_struct *); extern void force_sig_specific(int, struct task_struct *); extern int send_sig(int, struct task_struct *, int); diff --git a/include/linux/vs_base.h b/include/linux/vs_base.h index b2dfad6a5..c49e62c01 100644 --- a/include/linux/vs_base.h +++ b/include/linux/vs_base.h @@ -8,6 +8,9 @@ #define vx_current_xid() vx_task_xid(current) +#define current_vx_info() (current->vx_info) + + #define vx_check(c,m) __vx_check(vx_current_xid(),c,m) #define vx_weak_check(c,m) ((m) ? vx_check(c,m) : 1) diff --git a/include/linux/vs_network.h b/include/linux/vs_network.h index 28fa78166..777481ecd 100644 --- a/include/linux/vs_network.h +++ b/include/linux/vs_network.h @@ -154,6 +154,9 @@ static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p, #define nx_current_nid() nx_task_nid(current) +#define current_nx_info() (current->nx_info) + + #define nx_check(c,m) __nx_check(nx_current_nid(),c,m) #define nx_weak_check(c,m) ((m) ? nx_check(c,m) : 1) @@ -196,6 +199,8 @@ static inline int addr_in_nx_info(struct nx_info *nxi, uint32_t addr) return 1; n = nxi->nbipv4; + if (n && (nxi->ipv4[0] == 0)) + return 1; for (i=0; iipv4[i] == addr) return 1; diff --git a/include/linux/vs_socket.h b/include/linux/vs_socket.h index 9173bfe26..c9c624442 100644 --- a/include/linux/vs_socket.h +++ b/include/linux/vs_socket.h @@ -7,16 +7,24 @@ /* socket accounting */ #include +#include static inline int vx_sock_type(int family) { - int type = 4; - - if (family > 0 && family < 3) - type = family; - else if (family == PF_INET6) - type = 3; - return type; + switch (family) { + case PF_UNSPEC: + return VXA_SOCK_UNSPEC; + case PF_UNIX: + return VXA_SOCK_UNIX; + case PF_INET: + return VXA_SOCK_INET; + case PF_INET6: + return VXA_SOCK_INET6; + case PF_PACKET: + return VXA_SOCK_PACKET; + default: + return VXA_SOCK_OTHER; + } } #define vx_acc_sock(v,f,p,s) \ diff --git a/include/linux/vserver/context.h b/include/linux/vserver/context.h index c545ea7f9..66971728e 100644 --- a/include/linux/vserver/context.h +++ b/include/linux/vserver/context.h @@ -11,7 +11,6 @@ /* context flags */ -#define VXF_INFO_LOCK 0x00000001 #define VXF_INFO_SCHED 0x00000002 #define VXF_INFO_NPROC 0x00000004 #define VXF_INFO_PRIVATE 0x00000008 diff --git a/include/linux/vserver/cvirt_def.h b/include/linux/vserver/cvirt_def.h index 5ac0c2e64..c368c2e59 100644 --- a/include/linux/vserver/cvirt_def.h +++ b/include/linux/vserver/cvirt_def.h @@ -8,6 +8,8 @@ #include #include +#include "cacct.h" + struct _vx_usage_stat { uint64_t user; @@ -69,7 +71,7 @@ struct _vx_sock_acc { struct _vx_cacct { unsigned long total_forks; - struct _vx_sock_acc sock[5][3]; + struct _vx_sock_acc sock[VXA_SOCK_SIZE][3]; }; #endif /* _VX_CVIRT_DEF_H */ diff --git a/include/linux/vserver/network.h b/include/linux/vserver/network.h index 0e0253b83..6dfbb38e9 100644 --- a/include/linux/vserver/network.h +++ b/include/linux/vserver/network.h @@ -13,6 +13,8 @@ /* network flags */ +#define NXF_INFO_PRIVATE 0x00000008 + #define NXF_STATE_SETUP (1ULL<<32) #define NXF_SC_HELPER (1ULL<<36) diff --git a/init/Kconfig b/init/Kconfig index 08350606e..0295b869b 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -528,35 +528,6 @@ config STOP_MACHINE Need stop_machine() primitive. endmenu -menu "Process debugging support" - -config UTRACE - bool "Infrastructure for tracing and debugging user processes" - default y - help - Enable the utrace process tracing interface. - This is an internal kernel interface to track events in user - threads, extract and change user thread state. This interface - is exported to kernel modules, and is also used to implement ptrace. - If you disable this, no facilities for debugging user processes - will be available, nor the facilities used by UML and other - applications. Unless you are making a specially stripped-down - kernel and are very sure you don't need these facilitiies, - say Y. - -config PTRACE - bool "Legacy ptrace system call interface" - default y - depends on UTRACE - help - Enable the ptrace system call. - This is traditionally used by debuggers like GDB, - and is used by UML and some other applications. - Unless you are very sure you won't run anything that needs it, - say Y. - -endmenu - menu "Block layer" source "block/Kconfig" endmenu diff --git a/kernel/Makefile b/kernel/Makefile index 1666d4b24..cc9166e3f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -53,7 +53,6 @@ obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o -obj-$(CONFIG_UTRACE) += utrace.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff --git a/kernel/exit.c b/kernel/exit.c index 80530fbcf..17987bc01 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -143,10 +142,10 @@ void release_task(struct task_struct * p) struct task_struct *leader; int zap_leader; repeat: - tracehook_release_task(p); atomic_dec(&p->user->processes); write_lock_irq(&tasklist_lock); - BUG_ON(tracehook_check_released(p)); + ptrace_unlink(p); + BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); __exit_signal(p); /* @@ -223,10 +222,10 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct *ignored_task) do_each_task_pid(pgrp, PIDTYPE_PGID, p) { if (p == ignored_task || p->exit_state - || p->parent->pid == 1) + || p->real_parent->pid == 1) continue; - if (process_group(p->parent) != pgrp - && p->parent->signal->session == p->signal->session) { + if (process_group(p->real_parent) != pgrp + && p->real_parent->signal->session == p->signal->session) { ret = 0; break; } @@ -254,6 +253,16 @@ static int has_stopped_jobs(int pgrp) if (p->state != TASK_STOPPED) continue; + /* If p is stopped by a debugger on a signal that won't + stop it, then don't count p as stopped. This isn't + perfect but it's a good approximation. */ + if (unlikely (p->ptrace) + && p->exit_code != SIGSTOP + && p->exit_code != SIGTSTP + && p->exit_code != SIGTTOU + && p->exit_code != SIGTTIN) + continue; + retval = 1; break; } while_each_task_pid(pgrp, PIDTYPE_PGID, p); @@ -276,9 +285,11 @@ static void reparent_to_init(void) { write_lock_irq(&tasklist_lock); + ptrace_unlink(current); /* Reparent to init */ remove_parent(current); current->parent = child_reaper; + current->real_parent = child_reaper; add_parent(current); /* Set the exit signal to SIGCHLD so we signal init on exit */ @@ -589,11 +600,11 @@ choose_new_parent(struct task_struct *p, struct task_struct *reaper) * the parent is not a zombie. */ BUG_ON(p == reaper || reaper->exit_state); - p->parent = reaper; + p->real_parent = reaper; } static void -reparent_thread(struct task_struct *p, struct task_struct *father) +reparent_thread(struct task_struct *p, struct task_struct *father, int traced) { /* We don't want people slaying init. */ if (p->exit_signal != -1) @@ -604,14 +615,35 @@ reparent_thread(struct task_struct *p, struct task_struct *father) group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p); /* Move the child from its dying parent to the new one. */ - list_move_tail(&p->sibling, &p->parent->children); + if (unlikely(traced)) { + /* Preserve ptrace links if someone else is tracing this child. */ + list_del_init(&p->ptrace_list); + if (p->parent != p->real_parent) + list_add(&p->ptrace_list, &p->real_parent->ptrace_children); + } else { + /* If this child is being traced, then we're the one tracing it + * anyway, so let go of it. + */ + p->ptrace = 0; + remove_parent(p); + p->parent = p->real_parent; + add_parent(p); - /* If we'd notified the old parent about this child's death, - * also notify the new parent. - */ - if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && - thread_group_empty(p)) - do_notify_parent(p, p->exit_signal); + /* If we'd notified the old parent about this child's death, + * also notify the new parent. + */ + if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && + thread_group_empty(p)) + do_notify_parent(p, p->exit_signal); + else if (p->state == TASK_TRACED) { + /* + * If it was at a trace stop, turn it into + * a normal stop since it's no longer being + * traced. + */ + ptrace_untrace(p); + } + } /* * process group orphan check @@ -637,7 +669,7 @@ reparent_thread(struct task_struct *p, struct task_struct *father) * the global child reaper process (ie "init") */ static void -forget_original_parent(struct task_struct *father) +forget_original_parent(struct task_struct *father, struct list_head *to_release) { struct task_struct *p, *reaper = father; struct list_head *_p, *_n; @@ -650,10 +682,48 @@ forget_original_parent(struct task_struct *father) } } while (reaper->exit_state); + /* + * There are only two places where our children can be: + * + * - in our child list + * - in our ptraced child list + * + * Search them and reparent children. + */ list_for_each_safe(_p, _n, &father->children) { + int ptrace; p = list_entry(_p, struct task_struct, sibling); - choose_new_parent(p, vx_child_reaper(p)); - reparent_thread(p, father); + + ptrace = p->ptrace; + + /* if father isn't the real parent, then ptrace must be enabled */ + BUG_ON(father != p->real_parent && !ptrace); + + if (father == p->real_parent) { + /* reparent with a reaper, real father it's us */ + choose_new_parent(p, vx_child_reaper(p)); + reparent_thread(p, father, 0); + } else { + /* reparent ptraced task to its real parent */ + __ptrace_unlink (p); + if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && + thread_group_empty(p)) + do_notify_parent(p, p->exit_signal); + } + + /* + * if the ptraced child is a zombie with exit_signal == -1 + * we must collect it before we exit, or it will remain + * zombie forever since we prevented it from self-reap itself + * while it was being traced by us, to be able to see it in wait4. + */ + if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) + list_add(&p->ptrace_list, to_release); + } + list_for_each_safe(_p, _n, &father->ptrace_children) { + p = list_entry(_p, struct task_struct, ptrace_list); + choose_new_parent(p, reaper); + reparent_thread(p, father, 1); } } @@ -665,8 +735,7 @@ static void exit_notify(struct task_struct *tsk) { int state; struct task_struct *t; - int noreap; - void *cookie; + struct list_head ptrace_dead, *_p, *_n; if (signal_pending(tsk) && !(tsk->signal->flags & SIGNAL_GROUP_EXIT) && !thread_group_empty(tsk)) { @@ -702,8 +771,10 @@ static void exit_notify(struct task_struct *tsk) * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) */ - forget_original_parent(tsk); + INIT_LIST_HEAD(&ptrace_dead); + forget_original_parent(tsk, &ptrace_dead); BUG_ON(!list_empty(&tsk->children)); + BUG_ON(!list_empty(&tsk->ptrace_children)); /* * Check to see if any process groups have become orphaned @@ -715,7 +786,7 @@ static void exit_notify(struct task_struct *tsk) * is about to become orphaned. */ - t = tsk->parent; + t = tsk->real_parent; if ((process_group(t) != process_group(tsk)) && (t->signal->session == tsk->signal->session) && @@ -747,18 +818,32 @@ static void exit_notify(struct task_struct *tsk) && !capable(CAP_KILL)) tsk->exit_signal = SIGCHLD; - if (!tracehook_notify_death(tsk, &noreap, &cookie) - && tsk->exit_signal != -1 && thread_group_empty(tsk)) - do_notify_parent(tsk, tsk->exit_signal); + + /* If something other than our normal parent is ptracing us, then + * send it a SIGCHLD instead of honoring exit_signal. exit_signal + * only has special meaning to our real parent. + */ + if (tsk->exit_signal != -1 && thread_group_empty(tsk)) { + int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD; + do_notify_parent(tsk, signal); + } else if (tsk->ptrace) { + do_notify_parent(tsk, SIGCHLD); + } state = EXIT_ZOMBIE; - if (tsk->exit_signal == -1 && !noreap) + if (tsk->exit_signal == -1 && + (likely(tsk->ptrace == 0) || + unlikely(tsk->parent->signal->flags & SIGNAL_GROUP_EXIT))) state = EXIT_DEAD; tsk->exit_state = state; write_unlock_irq(&tasklist_lock); - tracehook_report_death(tsk, state, cookie); + list_for_each_safe(_p, _n, &ptrace_dead) { + list_del_init(_p); + t = list_entry(_p, struct task_struct, ptrace_list); + release_task(t); + } /* If the process is dead, release it - nobody will wait for it */ if (state == EXIT_DEAD) @@ -783,7 +868,10 @@ fastcall NORET_TYPE void do_exit(long code) if (unlikely(tsk == child_reaper)) panic("Attempted to kill init!"); - tracehook_report_exit(&code); + if (unlikely(current->ptrace & PT_TRACE_EXIT)) { + current->ptrace_message = code; + ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP); + } /* * We're taking recursive faults here in do_exit. Safest is to just @@ -800,8 +888,6 @@ fastcall NORET_TYPE void do_exit(long code) tsk->flags |= PF_EXITING; - ptrace_exit(tsk); - if (unlikely(in_atomic())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, @@ -972,9 +1058,10 @@ static int eligible_child(pid_t pid, int options, struct task_struct *p) } /* - * Do not consider detached threads. + * Do not consider detached threads that are + * not ptraced: */ - if (p->exit_signal == -1) + if (p->exit_signal == -1 && !p->ptrace) return 0; /* Wait for all children (clone and not) if __WALL is set; @@ -1045,7 +1132,7 @@ static int wait_task_zombie(struct task_struct *p, int noreap, if (unlikely(p->exit_state != EXIT_ZOMBIE)) return 0; - if (unlikely(p->exit_signal == -1)) + if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) return 0; get_task_struct(p); read_unlock(&tasklist_lock); @@ -1069,9 +1156,15 @@ static int wait_task_zombie(struct task_struct *p, int noreap, BUG_ON(state != EXIT_DEAD); return 0; } - BUG_ON(p->exit_signal == -1); + if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) { + /* + * This can only happen in a race with a ptraced thread + * dying on another processor. + */ + return 0; + } - if (likely(p->signal)) { + if (likely(p->real_parent == p->parent) && likely(p->signal)) { struct signal_struct *psig; struct signal_struct *sig; @@ -1153,8 +1246,28 @@ static int wait_task_zombie(struct task_struct *p, int noreap, return retval; } retval = p->pid; - release_task(p); - + if (p->real_parent != p->parent) { + write_lock_irq(&tasklist_lock); + /* Double-check with lock held. */ + if (p->real_parent != p->parent) { + __ptrace_unlink(p); + // TODO: is this safe? + p->exit_state = EXIT_ZOMBIE; + /* + * If this is not a detached task, notify the parent. + * If it's still not detached after that, don't release + * it now. + */ + if (p->exit_signal != -1) { + do_notify_parent(p, p->exit_signal); + if (p->exit_signal != -1) + p = NULL; + } + } + write_unlock_irq(&tasklist_lock); + } + if (p != NULL) + release_task(p); BUG_ON(!retval); return retval; } @@ -1173,7 +1286,7 @@ static int wait_task_stopped(struct task_struct *p, int delayed_group_leader, if (!p->exit_code) return 0; - if (delayed_group_leader && + if (delayed_group_leader && !(p->ptrace & PT_PTRACED) && p->signal && p->signal->group_stop_count > 0) /* * A group stop is in progress and this is the group leader. @@ -1194,13 +1307,14 @@ static int wait_task_stopped(struct task_struct *p, int delayed_group_leader, if (unlikely(noreap)) { pid_t pid = p->pid; uid_t uid = p->uid; + int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED; exit_code = p->exit_code; if (unlikely(!exit_code) || unlikely(p->state & TASK_TRACED)) goto bail_ref; - return wait_noreap_copyout(p, pid, uid, CLD_STOPPED, - (exit_code << 8) | 0x7f, + return wait_noreap_copyout(p, pid, uid, + why, (exit_code << 8) | 0x7f, infop, ru); } @@ -1256,7 +1370,9 @@ bail_ref: if (!retval && infop) retval = put_user(0, &infop->si_errno); if (!retval && infop) - retval = put_user((short)CLD_STOPPED, &infop->si_code); + retval = put_user((short)((p->ptrace & PT_PTRACED) + ? CLD_TRAPPED : CLD_STOPPED), + &infop->si_code); if (!retval && infop) retval = put_user(exit_code, &infop->si_status); if (!retval && infop) @@ -1324,6 +1440,22 @@ static int wait_task_continued(struct task_struct *p, int noreap, } +static inline int my_ptrace_child(struct task_struct *p) +{ + if (!(p->ptrace & PT_PTRACED)) + return 0; + if (!(p->ptrace & PT_ATTACHED)) + return 1; + /* + * This child was PTRACE_ATTACH'd. We should be seeing it only if + * we are the attacher. If we are the real parent, this is a race + * inside ptrace_attach. It is waiting for the tasklist_lock, + * which we have to switch the parent links, but has already set + * the flags in p->ptrace. + */ + return (p->parent != p->real_parent); +} + static long do_wait(pid_t pid, int options, struct siginfo __user *infop, int __user *stat_addr, struct rusage __user *ru) { @@ -1355,17 +1487,26 @@ repeat: switch (p->state) { case TASK_TRACED: + /* + * When we hit the race with PTRACE_ATTACH, + * we will not report this child. But the + * race means it has not yet been moved to + * our ptrace_children list, so we need to + * set the flag here to avoid a spurious ECHILD + * when the race happens with the only child. + */ flag = 1; - continue; + if (!my_ptrace_child(p)) + continue; + /*FALLTHROUGH*/ case TASK_STOPPED: /* * It's stopped now, so it might later * continue, exit, or stop again. */ flag = 1; - if (!(options & WUNTRACED)) - continue; - if (tracehook_inhibit_wait_stopped(p)) + if (!(options & WUNTRACED) && + !my_ptrace_child(p)) continue; retval = wait_task_stopped(p, ret == 2, (options & WNOWAIT), @@ -1390,10 +1531,6 @@ repeat: goto check_continued; if (!likely(options & WEXITED)) continue; - if (tracehook_inhibit_wait_zombie(p)) { - flag = 1; - continue; - } retval = wait_task_zombie( p, (options & WNOWAIT), infop, stat_addr, ru); @@ -1410,8 +1547,6 @@ check_continued: flag = 1; if (!unlikely(options & WCONTINUED)) continue; - if (tracehook_inhibit_wait_continued(p)) - continue; retval = wait_task_continued( p, (options & WNOWAIT), infop, stat_addr, ru); @@ -1420,15 +1555,16 @@ check_continued: break; } } - - retval = ptrace_do_wait(tsk, pid, options, - infop, stat_addr, ru); - if (retval != -ECHILD) { - flag = 1; - if (retval != 0) /* He released the lock. */ - goto end; + if (!flag) { + list_for_each(_p, &tsk->ptrace_children) { + p = list_entry(_p, struct task_struct, + ptrace_list); + if (!eligible_child(pid, options, p)) + continue; + flag = 1; + break; + } } - if (options & __WNOTHREAD) break; tsk = next_thread(tsk); @@ -1452,7 +1588,7 @@ end: remove_wait_queue(¤t->signal->wait_chldexit,&wait); if (infop) { if (retval > 0) - retval = 0; + retval = 0; else { /* * For a WNOHANG return, clear out all the fields diff --git a/kernel/fork.c b/kernel/fork.c index adfa44841..f8f50bbf2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -923,7 +923,8 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE); new_flags |= PF_FORKNOEXEC; - new_flags |= PF_STARTING; + if (!(clone_flags & CLONE_PTRACE)) + p->ptrace = 0; p->flags = new_flags; } @@ -1056,9 +1057,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, INIT_LIST_HEAD(&p->sibling); p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); -#ifdef CONFIG_PTRACE - INIT_LIST_HEAD(&p->ptracees); -#endif clear_tsk_thread_flag(p, TIF_SIGPENDING); init_sigpending(&p->pending); @@ -1192,6 +1190,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, */ p->group_leader = p; INIT_LIST_HEAD(&p->thread_group); + INIT_LIST_HEAD(&p->ptrace_children); + INIT_LIST_HEAD(&p->ptrace_list); /* Perform scheduler related setup. Assign this task to a CPU. */ sched_fork(p, clone_flags); @@ -1215,9 +1215,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, /* CLONE_PARENT re-uses the old parent */ if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) - p->parent = current->parent; + p->real_parent = current->real_parent; else - p->parent = current; + p->real_parent = current; + p->parent = p->real_parent; spin_lock(¤t->sighand->siglock); @@ -1264,7 +1265,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (likely(p->pid)) { add_parent(p); - tracehook_init_task(p); + if (unlikely(p->ptrace & PT_PTRACED)) + __ptrace_link(p, current->parent); if (thread_group_leader(p)) { p->signal->tty = current->signal->tty; @@ -1363,6 +1365,22 @@ struct task_struct * __devinit fork_idle(int cpu) return task; } +static inline int fork_traceflag (unsigned clone_flags) +{ + if (clone_flags & CLONE_UNTRACED) + return 0; + else if (clone_flags & CLONE_VFORK) { + if (current->ptrace & PT_TRACE_VFORK) + return PTRACE_EVENT_VFORK; + } else if ((clone_flags & CSIGNAL) != SIGCHLD) { + if (current->ptrace & PT_TRACE_CLONE) + return PTRACE_EVENT_CLONE; + } else if (current->ptrace & PT_TRACE_FORK) + return PTRACE_EVENT_FORK; + + return 0; +} + /* * Ok, this is the main fork-routine. * @@ -1377,12 +1395,18 @@ long do_fork(unsigned long clone_flags, int __user *child_tidptr) { struct task_struct *p; + int trace = 0; struct pid *pid = alloc_pid(); long nr; if (!pid) return -EAGAIN; nr = pid->nr; + if (unlikely(current->ptrace)) { + trace = fork_traceflag (clone_flags); + if (trace) + clone_flags |= CLONE_PTRACE; + } p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr); /* @@ -1397,26 +1421,30 @@ long do_fork(unsigned long clone_flags, init_completion(&vfork); } - tracehook_report_clone(clone_flags, p); - - p->flags &= ~PF_STARTING; - - if (clone_flags & CLONE_STOPPED) { + if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { /* * We'll start up with an immediate SIGSTOP. */ sigaddset(&p->pending.signal, SIGSTOP); set_tsk_thread_flag(p, TIF_SIGPENDING); - p->state = TASK_STOPPED; } - else + + if (!(clone_flags & CLONE_STOPPED)) wake_up_new_task(p, clone_flags); + else + p->state = TASK_STOPPED; - tracehook_report_clone_complete(clone_flags, nr, p); + if (unlikely (trace)) { + current->ptrace_message = nr; + ptrace_notify ((trace << 8) | SIGTRAP); + } if (clone_flags & CLONE_VFORK) { wait_for_completion(&vfork); - tracehook_report_vfork_done(p, nr); + if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) { + current->ptrace_message = nr; + ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); + } } } else { free_pid(pid); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 553a09888..c3f765c81 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -171,7 +171,6 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) { struct irq_desc *desc = irq_desc + irq; struct irqaction *action; - struct vx_info_save vxis; unsigned int status; kstat_this_cpu.irqs[irq]++; @@ -181,17 +180,14 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) /* * No locking required for CPU-local interrupts: */ - __enter_vx_admin(&vxis); if (desc->chip->ack) desc->chip->ack(irq); action_ret = handle_IRQ_event(irq, regs, desc->action); desc->chip->end(irq); - __leave_vx_admin(&vxis); return 1; } spin_lock(&desc->lock); - __enter_vx_admin(&vxis); if (desc->chip->ack) desc->chip->ack(irq); /* @@ -254,7 +250,6 @@ out: * disabled while the handler was running. */ desc->chip->end(irq); - __leave_vx_admin(&vxis); spin_unlock(&desc->lock); return 1; diff --git a/kernel/printk.c b/kernel/printk.c index 913dca305..7d006afa9 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include @@ -542,10 +541,8 @@ asmlinkage int vprintk(const char *fmt, va_list args) char *p; static char printk_buf[1024]; static int log_level_unknown = 1; - struct vx_info_save vxis; preempt_disable(); - __enter_vx_admin(&vxis); if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) /* If a crash is occurring during printk() on this CPU, * make sure we can't deadlock */ @@ -654,7 +651,6 @@ asmlinkage int vprintk(const char *fmt, va_list args) local_irq_restore(flags); } - __leave_vx_admin(&vxis); preempt_enable(); return printed_len; } diff --git a/kernel/ptrace.c b/kernel/ptrace.c index ee0b4cb6d..7dc294410 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -22,15 +22,101 @@ #include #include -#ifdef CONFIG_PTRACE -#include -#include -#include -#endif +/* + * ptrace a task: make the debugger its new parent and + * move it to the ptrace list. + * + * Must be called with the tasklist lock write-held. + */ +void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) +{ + BUG_ON(!list_empty(&child->ptrace_list)); + if (child->parent == new_parent) + return; + list_add(&child->ptrace_list, &child->parent->ptrace_children); + remove_parent(child); + child->parent = new_parent; + add_parent(child); +} + +/* + * Turn a tracing stop into a normal stop now, since with no tracer there + * would be no way to wake it up with SIGCONT or SIGKILL. If there was a + * signal sent that would resume the child, but didn't because it was in + * TASK_TRACED, resume it now. + * Requires that irqs be disabled. + */ +void ptrace_untrace(struct task_struct *child) +{ + spin_lock(&child->sighand->siglock); + if (child->state == TASK_TRACED) { + if (child->signal->flags & SIGNAL_STOP_STOPPED) { + child->state = TASK_STOPPED; + } else { + signal_wake_up(child, 1); + } + } + spin_unlock(&child->sighand->siglock); +} + +/* + * unptrace a task: move it back to its original parent and + * remove it from the ptrace list. + * + * Must be called with the tasklist lock write-held. + */ +void __ptrace_unlink(struct task_struct *child) +{ + BUG_ON(!child->ptrace); + + child->ptrace = 0; + if (!list_empty(&child->ptrace_list)) { + list_del_init(&child->ptrace_list); + remove_parent(child); + child->parent = child->real_parent; + add_parent(child); + } + + if (child->state == TASK_TRACED) + ptrace_untrace(child); +} + +/* + * Check that we have indeed attached to the thing.. + */ +int ptrace_check_attach(struct task_struct *child, int kill) +{ + int ret = -ESRCH; + + /* + * We take the read lock around doing both checks to close a + * possible race where someone else was tracing our child and + * detached between these two checks. After this locked check, + * we are sure that this is our traced child and that can only + * be changed by us so it's not changing right after this. + */ + read_lock(&tasklist_lock); + if ((child->ptrace & PT_PTRACED) && child->parent == current && + (!(child->ptrace & PT_ATTACHED) || child->real_parent != current) + && child->signal != NULL) { + ret = 0; + spin_lock_irq(&child->sighand->siglock); + if (child->state == TASK_STOPPED) { + child->state = TASK_TRACED; + } else if (child->state != TASK_TRACED && !kill) { + ret = -ESRCH; + } + spin_unlock_irq(&child->sighand->siglock); + } + read_unlock(&tasklist_lock); -int getrusage(struct task_struct *, int, struct rusage __user *); + if (!ret && !kill) { + wait_task_inactive(child); + } -//#define PTRACE_DEBUG + /* All systems go.. */ + return ret; +} int __ptrace_may_attach(struct task_struct *task) { @@ -71,6 +157,90 @@ int ptrace_may_attach(struct task_struct *task) return !err; } +int ptrace_attach(struct task_struct *task) +{ + int retval; + + retval = -EPERM; + if (task->pid <= 1) + goto out; + if (task->tgid == current->tgid) + goto out; + +repeat: + /* + * Nasty, nasty. + * + * We want to hold both the task-lock and the + * tasklist_lock for writing at the same time. + * But that's against the rules (tasklist_lock + * is taken for reading by interrupts on other + * cpu's that may have task_lock). + */ + task_lock(task); + local_irq_disable(); + if (!write_trylock(&tasklist_lock)) { + local_irq_enable(); + task_unlock(task); + do { + cpu_relax(); + } while (!write_can_lock(&tasklist_lock)); + goto repeat; + } + + if (!task->mm) + goto bad; + /* the same process cannot be attached many times */ + if (task->ptrace & PT_PTRACED) + goto bad; + retval = __ptrace_may_attach(task); + if (retval) + goto bad; + + /* Go */ + task->ptrace |= PT_PTRACED | ((task->real_parent != current) + ? PT_ATTACHED : 0); + if (capable(CAP_SYS_PTRACE)) + task->ptrace |= PT_PTRACE_CAP; + + __ptrace_link(task, current); + + force_sig_specific(SIGSTOP, task); + +bad: + write_unlock_irq(&tasklist_lock); + task_unlock(task); +out: + return retval; +} + +static inline void __ptrace_detach(struct task_struct *child, unsigned int data) +{ + child->exit_code = data; + /* .. re-parent .. */ + __ptrace_unlink(child); + /* .. and wake it up. */ + if (child->exit_state != EXIT_ZOMBIE) + wake_up_process(child); +} + +int ptrace_detach(struct task_struct *child, unsigned int data) +{ + if (!valid_signal(data)) + return -EIO; + + /* Architecture-specific hardware disable .. */ + ptrace_disable(child); + + write_lock_irq(&tasklist_lock); + /* protect against de_thread()->release_task() */ + if (child->ptrace) + __ptrace_detach(child, data); + write_unlock_irq(&tasklist_lock); + + return 0; +} + /* * Access another process' address space. * Source/target buffer must be kernel space, @@ -125,1372 +295,253 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in return buf - old_buf; } - -#ifndef CONFIG_PTRACE - -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) -{ - return -ENOSYS; -} - -#else - -struct ptrace_state -{ - /* - * These elements are always available, even when the struct is - * awaiting destruction at the next RCU callback point. - */ - struct utrace_attached_engine *engine; - struct task_struct *task; /* Target task. */ - struct task_struct *parent; /* Whom we report to. */ - struct list_head entry; /* Entry on parent->ptracees list. */ - - union { - struct rcu_head dead; - struct { - u8 options; /* PTRACE_SETOPTIONS bits. */ - unsigned int stopped:1; /* Stopped for report. */ - unsigned int reported:1; /* wait already reported. */ - unsigned int syscall:1; /* Reporting for syscall. */ -#ifdef PTRACE_SYSEMU - unsigned int sysemu:1; /* PTRACE_SYSEMU in progress. */ -#endif - unsigned int have_eventmsg:1; /* u.eventmsg valid. */ - unsigned int cap_sys_ptrace:1; /* Tracer capable. */ - - union - { - unsigned long eventmsg; - siginfo_t *siginfo; - } u; - } live; - } u; -}; - -static const struct utrace_engine_ops ptrace_utrace_ops; /* Initialized below. */ - - -static void -ptrace_state_link(struct ptrace_state *state) -{ - task_lock(state->parent); - list_add_rcu(&state->entry, &state->parent->ptracees); - task_unlock(state->parent); -} - -static void -ptrace_state_unlink(struct ptrace_state *state) -{ - task_lock(state->parent); - list_del_rcu(&state->entry); - task_unlock(state->parent); -} - -static int -ptrace_setup(struct task_struct *target, struct utrace_attached_engine *engine, - struct task_struct *parent, u8 options, int cap_sys_ptrace) -{ - struct ptrace_state *state = kzalloc(sizeof *state, GFP_USER); - if (unlikely(state == NULL)) - return -ENOMEM; - - state->engine = engine; - state->task = target; - state->parent = parent; - state->u.live.options = options; - state->u.live.cap_sys_ptrace = cap_sys_ptrace; - ptrace_state_link(state); - - BUG_ON(engine->data != 0); - rcu_assign_pointer(engine->data, (unsigned long) state); - - return 0; -} - -static void -ptrace_state_free(struct rcu_head *rhead) -{ - struct ptrace_state *state = container_of(rhead, - struct ptrace_state, u.dead); - kfree(state); -} - -static void -ptrace_done(struct ptrace_state *state) -{ - INIT_RCU_HEAD(&state->u.dead); - call_rcu(&state->u.dead, ptrace_state_free); -} - -/* - * Update the tracing engine state to match the new ptrace state. - */ -static void -ptrace_update(struct task_struct *target, struct utrace_attached_engine *engine, - unsigned long flags) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - - /* - * These events are always reported. - */ - flags |= (UTRACE_EVENT(DEATH) | UTRACE_EVENT(EXEC) - | UTRACE_EVENT_SIGNAL_ALL); - - /* - * We always have to examine clone events to check for CLONE_PTRACE. - */ - flags |= UTRACE_EVENT(CLONE); - - /* - * PTRACE_SETOPTIONS can request more events. - */ - if (state->u.live.options & PTRACE_O_TRACEEXIT) - flags |= UTRACE_EVENT(EXIT); - if (state->u.live.options & PTRACE_O_TRACEVFORKDONE) - flags |= UTRACE_EVENT(VFORK_DONE); - - /* - * ptrace always inhibits normal parent reaping. - * But for a corner case we sometimes see the REAP event instead. - */ - flags |= UTRACE_ACTION_NOREAP | UTRACE_EVENT(REAP); - - state->u.live.stopped = (flags & UTRACE_ACTION_QUIESCE) != 0; - if (!state->u.live.stopped) { - if (!state->u.live.have_eventmsg) - state->u.live.u.siginfo = NULL; - if (!(target->flags & PF_EXITING)) - target->exit_code = 0; - } - utrace_set_flags(target, engine, flags); -} - -static int ptrace_traceme(void) -{ - struct utrace_attached_engine *engine; - int retval; - - engine = utrace_attach(current, (UTRACE_ATTACH_CREATE - | UTRACE_ATTACH_EXCLUSIVE - | UTRACE_ATTACH_MATCH_OPS), - &ptrace_utrace_ops, 0UL); - - if (IS_ERR(engine)) { - retval = PTR_ERR(engine); - if (retval == -EEXIST) - retval = -EPERM; - } - else { - task_lock(current); - retval = security_ptrace(current->parent, current); - task_unlock(current); - if (!retval) - retval = ptrace_setup(current, engine, - current->parent, 0, 0); - if (retval) - utrace_detach(current, engine); - else - ptrace_update(current, engine, 0); - } - - return retval; -} - -static int ptrace_attach(struct task_struct *task) -{ - struct utrace_attached_engine *engine; - int retval; - - retval = -EPERM; - if (task->pid <= 1) - goto bad; - if (task->tgid == current->tgid) - goto bad; - if (!task->mm) /* kernel threads */ - goto bad; - - engine = utrace_attach(task, (UTRACE_ATTACH_CREATE - | UTRACE_ATTACH_EXCLUSIVE - | UTRACE_ATTACH_MATCH_OPS), - &ptrace_utrace_ops, 0); - if (IS_ERR(engine)) { - retval = PTR_ERR(engine); - if (retval == -EEXIST) - retval = -EPERM; - goto bad; - } - - if (ptrace_may_attach(task)) - retval = ptrace_setup(task, engine, current, 0, - capable(CAP_SYS_PTRACE)); - if (retval) - utrace_detach(task, engine); - else { - int stopped; - - /* Go */ - ptrace_update(task, engine, 0); - force_sig_specific(SIGSTOP, task); - - spin_lock_irq(&task->sighand->siglock); - stopped = (task->state == TASK_STOPPED); - spin_unlock_irq(&task->sighand->siglock); - - if (stopped) { - /* - * Do now the regset 0 writeback that we do on every - * stop, since it's never been done. On register - * window machines, this makes sure the user memory - * backing the register data is up to date. - */ - const struct utrace_regset *regset; - regset = utrace_regset(task, engine, - utrace_native_view(task), 0); - if (regset->writeback) - (*regset->writeback)(task, regset, 1); - } - } - -bad: - return retval; -} - -static int ptrace_detach(struct task_struct *task, - struct utrace_attached_engine *engine) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - /* - * Clearing ->data before detach makes sure an unrelated task - * calling into ptrace_tracer_task won't try to touch stale state. - */ - rcu_assign_pointer(engine->data, 0UL); - utrace_detach(task, engine); - ptrace_state_unlink(state); - ptrace_done(state); - return 0; -} - - -/* - * This is called when we are exiting. We must stop all our ptracing. - */ -void -ptrace_exit(struct task_struct *tsk) +int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) { - rcu_read_lock(); - if (unlikely(!list_empty(&tsk->ptracees))) { - struct ptrace_state *state, *next; + int copied = 0; - /* - * First detach the utrace layer from all the tasks. - * We don't want to hold any locks while calling utrace_detach. - */ - list_for_each_entry_rcu(state, &tsk->ptracees, entry) { - rcu_assign_pointer(state->engine->data, 0UL); - utrace_detach(state->task, state->engine); - } + while (len > 0) { + char buf[128]; + int this_len, retval; - /* - * Now clear out our list and clean up our data structures. - * The task_lock protects our list structure. - */ - task_lock(tsk); - list_for_each_entry_safe(state, next, &tsk->ptracees, entry) { - list_del_rcu(&state->entry); - ptrace_done(state); + this_len = (len > sizeof(buf)) ? sizeof(buf) : len; + retval = access_process_vm(tsk, src, buf, this_len, 0); + if (!retval) { + if (copied) + break; + return -EIO; } - task_unlock(tsk); + if (copy_to_user(dst, buf, retval)) + return -EFAULT; + copied += retval; + src += retval; + dst += retval; + len -= retval; } - rcu_read_unlock(); - - BUG_ON(!list_empty(&tsk->ptracees)); + return copied; } -static int -ptrace_induce_signal(struct task_struct *target, - struct utrace_attached_engine *engine, - long signr) +int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len) { - struct ptrace_state *state = (struct ptrace_state *) engine->data; + int copied = 0; - if (signr == 0) - return 0; + while (len > 0) { + char buf[128]; + int this_len, retval; - if (!valid_signal(signr)) - return -EIO; - - if (state->u.live.syscall) { - /* - * This is the traditional ptrace behavior when given - * a signal to resume from a syscall tracing stop. - */ - send_sig(signr, target, 1); - } - else if (!state->u.live.have_eventmsg && state->u.live.u.siginfo) { - siginfo_t *info = state->u.live.u.siginfo; - - /* Update the siginfo structure if the signal has - changed. If the debugger wanted something - specific in the siginfo structure then it should - have updated *info via PTRACE_SETSIGINFO. */ - if (signr != info->si_signo) { - info->si_signo = signr; - info->si_errno = 0; - info->si_code = SI_USER; - info->si_pid = current->pid; - info->si_uid = current->uid; + this_len = (len > sizeof(buf)) ? sizeof(buf) : len; + if (copy_from_user(buf, src, this_len)) + return -EFAULT; + retval = access_process_vm(tsk, dst, buf, this_len, 1); + if (!retval) { + if (copied) + break; + return -EIO; } - - return utrace_inject_signal(target, engine, - UTRACE_ACTION_RESUME, info, NULL); + copied += retval; + src += retval; + dst += retval; + len -= retval; } - - return 0; + return copied; } -fastcall int -ptrace_regset_access(struct task_struct *target, - struct utrace_attached_engine *engine, - const struct utrace_regset_view *view, - int setno, unsigned long offset, unsigned int size, - void __user *data, int write) +static int ptrace_setoptions(struct task_struct *child, long data) { - const struct utrace_regset *regset = utrace_regset(target, engine, - view, setno); - int ret; - - if (unlikely(regset == NULL)) - return -EIO; + child->ptrace &= ~PT_TRACE_MASK; - if (size == (unsigned int) -1) - size = regset->size * regset->n; + if (data & PTRACE_O_TRACESYSGOOD) + child->ptrace |= PT_TRACESYSGOOD; - if (write) { - if (!access_ok(VERIFY_READ, data, size)) - ret = -EIO; - else - ret = (*regset->set)(target, regset, - offset, size, NULL, data); - } - else { - if (!access_ok(VERIFY_WRITE, data, size)) - ret = -EIO; - else - ret = (*regset->get)(target, regset, - offset, size, NULL, data); - } - - return ret; -} + if (data & PTRACE_O_TRACEFORK) + child->ptrace |= PT_TRACE_FORK; -fastcall int -ptrace_onereg_access(struct task_struct *target, - struct utrace_attached_engine *engine, - const struct utrace_regset_view *view, - int setno, unsigned long regno, - void __user *data, int write) -{ - const struct utrace_regset *regset = utrace_regset(target, engine, - view, setno); - unsigned int pos; - int ret; + if (data & PTRACE_O_TRACEVFORK) + child->ptrace |= PT_TRACE_VFORK; - if (unlikely(regset == NULL)) - return -EIO; + if (data & PTRACE_O_TRACECLONE) + child->ptrace |= PT_TRACE_CLONE; - if (regno < regset->bias || regno >= regset->bias + regset->n) - return -EINVAL; + if (data & PTRACE_O_TRACEEXEC) + child->ptrace |= PT_TRACE_EXEC; - pos = (regno - regset->bias) * regset->size; + if (data & PTRACE_O_TRACEVFORKDONE) + child->ptrace |= PT_TRACE_VFORK_DONE; - if (write) { - if (!access_ok(VERIFY_READ, data, regset->size)) - ret = -EIO; - else - ret = (*regset->set)(target, regset, pos, regset->size, - NULL, data); - } - else { - if (!access_ok(VERIFY_WRITE, data, regset->size)) - ret = -EIO; - else - ret = (*regset->get)(target, regset, pos, regset->size, - NULL, data); - } + if (data & PTRACE_O_TRACEEXIT) + child->ptrace |= PT_TRACE_EXIT; - return ret; + return (data & ~PTRACE_O_MASK) ? -EINVAL : 0; } -fastcall int -ptrace_layout_access(struct task_struct *target, - struct utrace_attached_engine *engine, - const struct utrace_regset_view *view, - const struct ptrace_layout_segment layout[], - unsigned long addr, unsigned int size, - void __user *udata, void *kdata, int write) +static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data) { - const struct ptrace_layout_segment *seg; - int ret = -EIO; + siginfo_t lastinfo; + int error = -ESRCH; - if (kdata == NULL && - !access_ok(write ? VERIFY_READ : VERIFY_WRITE, udata, size)) - return -EIO; - - seg = layout; - do { - unsigned int pos, n; - - while (addr >= seg->end && seg->end != 0) - ++seg; - - if (addr < seg->start || addr >= seg->end) - return -EIO; - - pos = addr - seg->start + seg->offset; - n = min(size, seg->end - (unsigned int) addr); - - if (unlikely(seg->regset == (unsigned int) -1)) { - /* - * This is a no-op/zero-fill portion of struct user. - */ - ret = 0; - if (!write) { - if (kdata) - memset(kdata, 0, n); - else if (clear_user(udata, n)) - ret = -EFAULT; - } - } - else { - unsigned int align; - const struct utrace_regset *regset = utrace_regset( - target, engine, view, seg->regset); - if (unlikely(regset == NULL)) - return -EIO; - - /* - * A ptrace compatibility layout can do a misaligned - * regset access, e.g. word access to larger data. - * An arch's compat layout can be this way only if - * it is actually ok with the regset code despite the - * regset->align setting. - */ - align = min(regset->align, size); - if ((pos & (align - 1)) - || pos >= regset->n * regset->size) - return -EIO; - - if (write) - ret = (*regset->set)(target, regset, - pos, n, kdata, udata); - else - ret = (*regset->get)(target, regset, - pos, n, kdata, udata); + read_lock(&tasklist_lock); + if (likely(child->sighand != NULL)) { + error = -EINVAL; + spin_lock_irq(&child->sighand->siglock); + if (likely(child->last_siginfo != NULL)) { + lastinfo = *child->last_siginfo; + error = 0; } - - if (kdata) - kdata += n; - else - udata += n; - addr += n; - size -= n; - } while (ret == 0 && size > 0); - - return ret; + spin_unlock_irq(&child->sighand->siglock); + } + read_unlock(&tasklist_lock); + if (!error) + return copy_siginfo_to_user(data, &lastinfo); + return error; } - -static int -ptrace_start(long pid, long request, - struct task_struct **childp, - struct utrace_attached_engine **enginep, - struct ptrace_state **statep) - +static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data) { - struct task_struct *child; - struct utrace_attached_engine *engine; - struct ptrace_state *state; - int ret; + siginfo_t newinfo; + int error = -ESRCH; - if (request == PTRACE_TRACEME) - return ptrace_traceme(); + if (copy_from_user(&newinfo, data, sizeof (siginfo_t))) + return -EFAULT; - ret = -ESRCH; read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); -#ifdef PTRACE_DEBUG - printk("ptrace pid %ld => %p\n", pid, child); -#endif - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - engine = utrace_attach(child, UTRACE_ATTACH_MATCH_OPS, - &ptrace_utrace_ops, 0); - ret = -ESRCH; - if (IS_ERR(engine) || engine == NULL) - goto out_tsk; - rcu_read_lock(); - state = rcu_dereference((struct ptrace_state *) engine->data); - if (state == NULL || state->parent != current) { - rcu_read_unlock(); - goto out_tsk; - } - rcu_read_unlock(); - - /* - * Traditional ptrace behavior demands that the target already be - * quiescent, but not dead. - */ - if (request != PTRACE_KILL && !state->u.live.stopped) { -#ifdef PTRACE_DEBUG - printk("%d not stopped (%lx)\n", child->pid, child->state); -#endif - if (child->state != TASK_STOPPED) - goto out_tsk; - utrace_set_flags(child, engine, - engine->flags | UTRACE_ACTION_QUIESCE); + if (likely(child->sighand != NULL)) { + error = -EINVAL; + spin_lock_irq(&child->sighand->siglock); + if (likely(child->last_siginfo != NULL)) { + *child->last_siginfo = newinfo; + error = 0; + } + spin_unlock_irq(&child->sighand->siglock); } - - /* - * We do this for all requests to match traditional ptrace behavior. - * If the machine state synchronization done at context switch time - * includes e.g. writing back to user memory, we want to make sure - * that has finished before a PTRACE_PEEKDATA can fetch the results. - * On most machines, only regset data is affected by context switch - * and calling utrace_regset later on will take care of that, so - * this is superfluous. - * - * To do this purely in utrace terms, we could do: - * (void) utrace_regset(child, engine, utrace_native_view(child), 0); - */ - wait_task_inactive(child); - - if (child->exit_state) - goto out_tsk; - - *childp = child; - *enginep = engine; - *statep = state; - return -EIO; - -out_tsk: - put_task_struct(child); -out: - return ret; + read_unlock(&tasklist_lock); + return error; } -static int -ptrace_common(long request, struct task_struct *child, - struct utrace_attached_engine *engine, - struct ptrace_state *state, - unsigned long addr, long data) +int ptrace_request(struct task_struct *child, long request, + long addr, long data) { - unsigned long flags; int ret = -EIO; switch (request) { - case PTRACE_DETACH: - /* - * Detach a process that was attached. - */ - ret = ptrace_induce_signal(child, engine, data); - if (!ret) - ret = ptrace_detach(child, engine); - break; - - /* - * These are the operations that resume the child running. - */ - case PTRACE_KILL: - data = SIGKILL; - case PTRACE_CONT: - case PTRACE_SYSCALL: -#ifdef PTRACE_SYSEMU - case PTRACE_SYSEMU: - case PTRACE_SYSEMU_SINGLESTEP: -#endif -#ifdef PTRACE_SINGLEBLOCK - case PTRACE_SINGLEBLOCK: -# ifdef ARCH_HAS_BLOCK_STEP - if (! ARCH_HAS_BLOCK_STEP) -# endif - if (request == PTRACE_SINGLEBLOCK) - break; -#endif - case PTRACE_SINGLESTEP: -#ifdef ARCH_HAS_SINGLE_STEP - if (! ARCH_HAS_SINGLE_STEP) -#endif - if (request == PTRACE_SINGLESTEP -#ifdef PTRACE_SYSEMU_SINGLESTEP - || request == PTRACE_SYSEMU_SINGLESTEP -#endif - ) - break; - - ret = ptrace_induce_signal(child, engine, data); - if (ret) - break; - - - /* - * Reset the action flags without QUIESCE, so it resumes. - */ - flags = 0; -#ifdef PTRACE_SYSEMU - state->u.live.sysemu = (request == PTRACE_SYSEMU_SINGLESTEP - || request == PTRACE_SYSEMU); -#endif - if (request == PTRACE_SINGLESTEP -#ifdef PTRACE_SYSEMU - || request == PTRACE_SYSEMU_SINGLESTEP -#endif - ) - flags |= UTRACE_ACTION_SINGLESTEP; -#ifdef PTRACE_SINGLEBLOCK - else if (request == PTRACE_SINGLEBLOCK) - flags |= UTRACE_ACTION_BLOCKSTEP; -#endif - if (request == PTRACE_SYSCALL) - flags |= UTRACE_EVENT_SYSCALL; -#ifdef PTRACE_SYSEMU - else if (request == PTRACE_SYSEMU - || request == PTRACE_SYSEMU_SINGLESTEP) - flags |= UTRACE_EVENT(SYSCALL_ENTRY); -#endif - ptrace_update(child, engine, flags); - ret = 0; - break; - #ifdef PTRACE_OLDSETOPTIONS case PTRACE_OLDSETOPTIONS: #endif case PTRACE_SETOPTIONS: - ret = -EINVAL; - if (data & ~PTRACE_O_MASK) - break; - state->u.live.options = data; - ptrace_update(child, engine, UTRACE_ACTION_QUIESCE); - ret = 0; - break; - } - - return ret; -} - - -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) -{ - struct task_struct *child; - struct utrace_attached_engine *engine; - struct ptrace_state *state; - long ret, val; - -#ifdef PTRACE_DEBUG - printk("%d sys_ptrace(%ld, %ld, %lx, %lx)\n", - current->pid, request, pid, addr, data); -#endif - - ret = ptrace_start(pid, request, &child, &engine, &state); - if (ret != -EIO) - goto out; - - val = 0; - ret = arch_ptrace(&request, child, engine, addr, data, &val); - if (ret != -ENOSYS) { - if (ret == 0) { - ret = val; - force_successful_syscall_return(); - } - goto out_tsk; - } - - switch (request) { - default: - ret = ptrace_common(request, child, engine, state, addr, data); + ret = ptrace_setoptions(child, data); break; - - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (unsigned long __user *) data); - break; - } - - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) - break; - ret = -EIO; - break; - case PTRACE_GETEVENTMSG: - ret = put_user(state->u.live.have_eventmsg - ? state->u.live.u.eventmsg : 0L, - (unsigned long __user *) data); + ret = put_user(child->ptrace_message, (unsigned long __user *) data); break; case PTRACE_GETSIGINFO: - ret = -EINVAL; - if (!state->u.live.have_eventmsg && state->u.live.u.siginfo) - ret = copy_siginfo_to_user((siginfo_t __user *) data, - state->u.live.u.siginfo); + ret = ptrace_getsiginfo(child, (siginfo_t __user *) data); break; case PTRACE_SETSIGINFO: - ret = -EINVAL; - if (!state->u.live.have_eventmsg && state->u.live.u.siginfo - && copy_from_user(state->u.live.u.siginfo, - (siginfo_t __user *) data, - sizeof(siginfo_t))) - ret = -EFAULT; + ret = ptrace_setsiginfo(child, (siginfo_t __user *) data); break; - } - -out_tsk: - put_task_struct(child); -out: -#ifdef PTRACE_DEBUG - printk("%d ptrace -> %x\n", current->pid, ret); -#endif - return ret; -} - - -#ifdef CONFIG_COMPAT -#include - -asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, - compat_ulong_t addr, compat_long_t cdata) -{ - const unsigned long data = (unsigned long) (compat_ulong_t) cdata; - struct task_struct *child; - struct utrace_attached_engine *engine; - struct ptrace_state *state; - compat_long_t ret, val; - -#ifdef PTRACE_DEBUG - printk("%d compat_sys_ptrace(%d, %d, %x, %x)\n", - current->pid, request, pid, addr, cdata); -#endif - ret = ptrace_start(pid, request, &child, &engine, &state); - if (ret != -EIO) - goto out; - - val = 0; - ret = arch_compat_ptrace(&request, child, engine, addr, cdata, &val); - if (ret != -ENOSYS) { - if (ret == 0) { - ret = val; - force_successful_syscall_return(); - } - goto out_tsk; - } - - switch (request) { default: - ret = ptrace_common(request, child, engine, state, addr, data); - break; - - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - compat_ulong_t tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (compat_ulong_t __user *) data); break; } - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &cdata, sizeof(cdata), 1) == sizeof(cdata)) - break; - ret = -EIO; - break; - - case PTRACE_GETEVENTMSG: - ret = put_user(state->u.live.have_eventmsg - ? state->u.live.u.eventmsg : 0L, - (compat_long_t __user *) data); - break; - case PTRACE_GETSIGINFO: - ret = -EINVAL; - if (!state->u.live.have_eventmsg && state->u.live.u.siginfo) - ret = copy_siginfo_to_user32( - (struct compat_siginfo __user *) data, - state->u.live.u.siginfo); - break; - case PTRACE_SETSIGINFO: - ret = -EINVAL; - if (!state->u.live.have_eventmsg && state->u.live.u.siginfo - && copy_siginfo_from_user32( - state->u.live.u.siginfo, - (struct compat_siginfo __user *) data)) - ret = -EFAULT; - break; - } - -out_tsk: - put_task_struct(child); -out: -#ifdef PTRACE_DEBUG - printk("%d ptrace -> %x\n", current->pid, ret); -#endif return ret; } -#endif - -/* - * We're called with tasklist_lock held for reading. - * If we return -ECHILD or zero, next_thread(tsk) must still be valid to use. - * If we return another error code, or a successful PID value, we - * release tasklist_lock first. +/** + * ptrace_traceme -- helper for PTRACE_TRACEME + * + * Performs checks and sets PT_PTRACED. + * Should be used by all ptrace implementations for PTRACE_TRACEME. */ -int -ptrace_do_wait(struct task_struct *tsk, - pid_t pid, int options, struct siginfo __user *infop, - int __user *stat_addr, struct rusage __user *rusagep) +int ptrace_traceme(void) { - struct ptrace_state *state; - struct task_struct *p; - int err = -ECHILD; - int why, status; - - rcu_read_lock(); - list_for_each_entry_rcu(state, &tsk->ptracees, entry) { - p = state->task; - - if (pid > 0) { - if (p->pid != pid) - continue; - } else if (!pid) { - if (process_group(p) != process_group(current)) - continue; - } else if (pid != -1) { - if (process_group(p) != -pid) - continue; - } - if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) - && !(options & __WALL)) - continue; - if (security_task_wait(p)) - continue; - - err = 0; - if (state->u.live.reported) - continue; - - if (state->u.live.stopped) - goto found; - if ((p->state & (TASK_TRACED | TASK_STOPPED)) - && (p->signal->flags & SIGNAL_STOP_STOPPED)) - goto found; - if (p->exit_state == EXIT_ZOMBIE) { - if (!likely(options & WEXITED)) - continue; - if (delay_group_leader(p)) - continue; - goto found; - } - // XXX should handle WCONTINUED - } - rcu_read_unlock(); - return err; - -found: - rcu_read_unlock(); - - BUG_ON(state->parent != tsk); - - if (p->exit_state) { - if (unlikely(p->parent == state->parent)) - /* - * This is our natural child we were ptracing. - * When it dies it detaches (see ptrace_report_death). - * So we're seeing it here in a race. When it - * finishes detaching it will become reapable in - * the normal wait_task_zombie path instead. - */ - return 0; - if ((p->exit_code & 0x7f) == 0) { - why = CLD_EXITED; - status = p->exit_code >> 8; - } else { - why = (p->exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED; - status = p->exit_code & 0xff; - } - } - else { - why = CLD_TRAPPED; - status = (p->exit_code << 8) | 0x7f; - } + int ret = -EPERM; /* - * At this point we are committed to a successful return - * or a user error return. Release the tasklist_lock. + * Are we already being traced? */ - read_unlock(&tasklist_lock); - - if (rusagep) - err = getrusage(p, RUSAGE_BOTH, rusagep); - if (infop) { - if (!err) - err = put_user(SIGCHLD, &infop->si_signo); - if (!err) - err = put_user(0, &infop->si_errno); - if (!err) - err = put_user((short)why, &infop->si_code); - if (!err) - err = put_user(p->pid, &infop->si_pid); - if (!err) - err = put_user(p->uid, &infop->si_uid); - if (!err) - err = put_user(status, &infop->si_status); - } - if (!err && stat_addr) - err = put_user(status, stat_addr); - - if (!err) { - struct utrace *utrace; - - err = p->pid; - + task_lock(current); + if (!(current->ptrace & PT_PTRACED)) { + ret = security_ptrace(current->parent, current); /* - * If this was a non-death report, the child might now be - * detaching on death in the same race possible in the - * p->exit_state check above. So check for p->utrace being - * NULL, then we don't need to update the state any more. + * Set the ptrace bit in the process ptrace flags. */ - rcu_read_lock(); - utrace = rcu_dereference(p->utrace); - if (likely(utrace != NULL)) { - utrace_lock(utrace); - if (unlikely(state->u.live.reported)) - /* - * Another thread in the group got here - * first and reaped it before we locked. - */ - err = -ERESTARTNOINTR; - state->u.live.reported = 1; - utrace_unlock(utrace); - } - rcu_read_unlock(); - - if (err > 0 && why != CLD_TRAPPED) - ptrace_detach(p, state->engine); + if (!ret) + current->ptrace |= PT_PTRACED; } - - return err; + task_unlock(current); + return ret; } -static void -do_notify(struct task_struct *tsk, struct task_struct *parent, int why) +/** + * ptrace_get_task_struct -- grab a task struct reference for ptrace + * @pid: process id to grab a task_struct reference of + * + * This function is a helper for ptrace implementations. It checks + * permissions and then grabs a task struct for use of the actual + * ptrace implementation. + * + * Returns the task_struct for @pid or an ERR_PTR() on failure. + */ +struct task_struct *ptrace_get_task_struct(pid_t pid) { - struct siginfo info; - unsigned long flags; - struct sighand_struct *sighand; - int sa_mask; - - info.si_signo = SIGCHLD; - info.si_errno = 0; - info.si_pid = tsk->pid; - info.si_uid = tsk->uid; - - /* FIXME: find out whether or not this is supposed to be c*time. */ - info.si_utime = cputime_to_jiffies(tsk->utime); - info.si_stime = cputime_to_jiffies(tsk->stime); - - sa_mask = SA_NOCLDSTOP; - info.si_code = why; - info.si_status = tsk->exit_code & 0x7f; - if (why == CLD_CONTINUED) - info.si_status = SIGCONT; - else if (why == CLD_STOPPED) - info.si_status = tsk->signal->group_exit_code & 0x7f; - else if (why == CLD_EXITED) { - sa_mask = SA_NOCLDWAIT; - if (tsk->exit_code & 0x80) - info.si_code = CLD_DUMPED; - else if (tsk->exit_code & 0x7f) - info.si_code = CLD_KILLED; - else { - info.si_code = CLD_EXITED; - info.si_status = tsk->exit_code >> 8; - } - } + struct task_struct *child; - sighand = parent->sighand; - spin_lock_irqsave(&sighand->siglock, flags); - if (sighand->action[SIGCHLD-1].sa.sa_handler != SIG_IGN && - !(sighand->action[SIGCHLD-1].sa.sa_flags & sa_mask)) - __group_send_sig_info(SIGCHLD, &info, parent); /* - * Even if SIGCHLD is not generated, we must wake up wait4 calls. + * Tracing init is not allowed. */ - wake_up_interruptible_sync(&parent->signal->wait_chldexit); - spin_unlock_irqrestore(&sighand->siglock, flags); + if (pid == 1) + return ERR_PTR(-EPERM); + + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + return ERR_PTR(-ESRCH); + return child; } -static u32 -ptrace_report(struct utrace_attached_engine *engine, struct task_struct *tsk, - int code) +#ifndef __ARCH_SYS_PTRACE +asmlinkage long sys_ptrace(long request, long pid, long addr, long data) { - struct ptrace_state *state = (struct ptrace_state *) engine->data; - const struct utrace_regset *regset; - -#ifdef PTRACE_DEBUG - printk("%d ptrace_report %d engine %p state %p code %x parent %d (%p)\n", - current->pid, tsk->pid, engine, state, code, - state->parent->pid, state->parent); - if (!state->u.live.have_eventmsg && state->u.live.u.siginfo) { - const siginfo_t *si = state->u.live.u.siginfo; - printk(" si %d code %x errno %d addr %p\n", - si->si_signo, si->si_code, si->si_errno, - si->si_addr); - } -#endif - - /* - * Set our QUIESCE flag right now, before notifying the tracer. - * We do this before setting state->u.live.stopped rather than - * by using UTRACE_ACTION_NEWSTATE in our return value, to - * ensure that the tracer can't get the notification and then - * try to resume us with PTRACE_CONT before we set the flag. - */ - utrace_set_flags(tsk, engine, engine->flags | UTRACE_ACTION_QUIESCE); + struct task_struct *child; + long ret; /* - * If regset 0 has a writeback call, do it now. On register window - * machines, this makes sure the user memory backing the register - * data is up to date by the time wait_task_inactive returns to - * ptrace_start in our tracer doing a PTRACE_PEEKDATA or the like. + * This lock_kernel fixes a subtle race with suid exec */ - regset = utrace_regset(tsk, engine, utrace_native_view(tsk), 0); - if (regset->writeback) - (*regset->writeback)(tsk, regset, 0); - - state->u.live.stopped = 1; - state->u.live.reported = 0; - tsk->exit_code = code; - do_notify(tsk, state->parent, CLD_TRAPPED); - -#ifdef PTRACE_DEBUG - printk("%d ptrace_report quiescing exit_code %x\n", - current->pid, current->exit_code); -#endif - - return UTRACE_ACTION_RESUME; -} - -static inline u32 -ptrace_event(struct utrace_attached_engine *engine, struct task_struct *tsk, - int event) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - state->u.live.syscall = 0; - return ptrace_report(engine, tsk, (event << 8) | SIGTRAP); -} - - -static u32 -ptrace_report_death(struct utrace_attached_engine *engine, - struct task_struct *tsk) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - - if (tsk->parent == state->parent) { - /* - * This is a natural child, so we detach and let the normal - * reporting happen once our NOREAP action is gone. But - * first, generate a SIGCHLD for those cases where normal - * behavior won't. A ptrace'd child always generates SIGCHLD. - */ - if (tsk->exit_signal == -1 || !thread_group_empty(tsk)) - do_notify(tsk, state->parent, CLD_EXITED); - ptrace_state_unlink(state); - rcu_assign_pointer(engine->data, 0UL); - ptrace_done(state); - return UTRACE_ACTION_DETACH; - } - - state->u.live.reported = 0; - do_notify(tsk, state->parent, CLD_EXITED); - return UTRACE_ACTION_RESUME; -} - -/* - * We get this only in the case where our UTRACE_ACTION_NOREAP was ignored. - * That happens solely when a non-leader exec reaps the old leader. - */ -static void -ptrace_report_reap(struct utrace_attached_engine *engine, - struct task_struct *tsk) -{ - struct ptrace_state *state; - rcu_read_lock(); - state = rcu_dereference((struct ptrace_state *) engine->data); - if (state != NULL) { - ptrace_state_unlink(state); - rcu_assign_pointer(engine->data, 0UL); - ptrace_done(state); - } - rcu_read_unlock(); -} - - -static u32 -ptrace_report_clone(struct utrace_attached_engine *engine, - struct task_struct *parent, - unsigned long clone_flags, struct task_struct *child) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - struct utrace_attached_engine *child_engine; - int event = PTRACE_EVENT_FORK; - int option = PTRACE_O_TRACEFORK; - -#ifdef PTRACE_DEBUG - printk("%d (%p) engine %p ptrace_report_clone child %d (%p) fl %lx\n", - parent->pid, parent, engine, child->pid, child, clone_flags); -#endif - - if (clone_flags & CLONE_UNTRACED) + lock_kernel(); + if (request == PTRACE_TRACEME) { + ret = ptrace_traceme(); goto out; - - if (clone_flags & CLONE_VFORK) { - event = PTRACE_EVENT_VFORK; - option = PTRACE_O_TRACEVFORK; - } - else if ((clone_flags & CSIGNAL) != SIGCHLD) { - event = PTRACE_EVENT_CLONE; - option = PTRACE_O_TRACECLONE; } - if (!(clone_flags & CLONE_PTRACE) && !(state->u.live.options & option)) + child = ptrace_get_task_struct(pid); + if (IS_ERR(child)) { + ret = PTR_ERR(child); goto out; - - child_engine = utrace_attach(child, (UTRACE_ATTACH_CREATE - | UTRACE_ATTACH_EXCLUSIVE - | UTRACE_ATTACH_MATCH_OPS), - &ptrace_utrace_ops, 0UL); - if (unlikely(IS_ERR(child_engine))) { - BUG_ON(PTR_ERR(child_engine) != -ENOMEM); - printk(KERN_ERR - "ptrace out of memory, lost child %d of %d", - child->pid, parent->pid); - } - else { - int ret = ptrace_setup(child, child_engine, - state->parent, - state->u.live.options, - state->u.live.cap_sys_ptrace); - if (unlikely(ret != 0)) { - BUG_ON(ret != -ENOMEM); - printk(KERN_ERR - "ptrace out of memory, lost child %d of %d", - child->pid, parent->pid); - utrace_detach(child, child_engine); - } - else { - sigaddset(&child->pending.signal, SIGSTOP); - set_tsk_thread_flag(child, TIF_SIGPENDING); - ptrace_update(child, child_engine, 0); - } - } - - if (state->u.live.options & option) { - state->u.live.have_eventmsg = 1; - state->u.live.u.eventmsg = child->pid; - return ptrace_event(engine, parent, event); } -out: - return UTRACE_ACTION_RESUME; -} - - -static u32 -ptrace_report_vfork_done(struct utrace_attached_engine *engine, - struct task_struct *parent, pid_t child_pid) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - state->u.live.have_eventmsg = 1; - state->u.live.u.eventmsg = child_pid; - return ptrace_event(engine, parent, PTRACE_EVENT_VFORK_DONE); -} - - -static u32 -ptrace_report_signal(struct utrace_attached_engine *engine, - struct task_struct *tsk, struct pt_regs *regs, - u32 action, siginfo_t *info, - const struct k_sigaction *orig_ka, - struct k_sigaction *return_ka) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - int signo = info == NULL ? SIGTRAP : info->si_signo; - state->u.live.syscall = 0; - state->u.live.have_eventmsg = 0; - state->u.live.u.siginfo = info; - return ptrace_report(engine, tsk, signo) | UTRACE_SIGNAL_IGN; -} - -static u32 -ptrace_report_jctl(struct utrace_attached_engine *engine, - struct task_struct *tsk, int type) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - do_notify(tsk, state->parent, type); - return UTRACE_JCTL_NOSIGCHLD; -} - -static u32 -ptrace_report_exec(struct utrace_attached_engine *engine, - struct task_struct *tsk, - const struct linux_binprm *bprm, - struct pt_regs *regs) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - if (state->u.live.options & PTRACE_O_TRACEEXEC) - return ptrace_event(engine, tsk, PTRACE_EVENT_EXEC); - state->u.live.syscall = 0; - return ptrace_report(engine, tsk, SIGTRAP); -} - -static u32 -ptrace_report_syscall(struct utrace_attached_engine *engine, - struct task_struct *tsk, struct pt_regs *regs, - int entry) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; -#ifdef PTRACE_SYSEMU - if (entry && state->u.live.sysemu) - tracehook_abort_syscall(regs); -#endif - state->u.live.syscall = 1; - return ptrace_report(engine, tsk, - ((state->u.live.options & PTRACE_O_TRACESYSGOOD) - ? 0x80 : 0) | SIGTRAP); -} - -static u32 -ptrace_report_syscall_entry(struct utrace_attached_engine *engine, - struct task_struct *tsk, struct pt_regs *regs) -{ - return ptrace_report_syscall(engine, tsk, regs, 1); -} - -static u32 -ptrace_report_syscall_exit(struct utrace_attached_engine *engine, - struct task_struct *tsk, struct pt_regs *regs) -{ - return ptrace_report_syscall(engine, tsk, regs, 0); -} - -static u32 -ptrace_report_exit(struct utrace_attached_engine *engine, - struct task_struct *tsk, long orig_code, long *code) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - state->u.live.have_eventmsg = 1; - state->u.live.u.eventmsg = *code; - return ptrace_event(engine, tsk, PTRACE_EVENT_EXIT); -} - -static int -ptrace_unsafe_exec(struct utrace_attached_engine *engine, - struct task_struct *tsk) -{ - struct ptrace_state *state = (struct ptrace_state *) engine->data; - int unsafe = LSM_UNSAFE_PTRACE; - if (state->u.live.cap_sys_ptrace) - unsafe = LSM_UNSAFE_PTRACE_CAP; - return unsafe; -} - -static struct task_struct * -ptrace_tracer_task(struct utrace_attached_engine *engine, - struct task_struct *target) -{ - struct ptrace_state *state; + ret = -EPERM; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_put_task_struct; - /* - * This call is not necessarily made by the target task, - * so ptrace might be getting detached while we run here. - * The state pointer will be NULL if that happens. - */ - state = rcu_dereference((struct ptrace_state *) engine->data); + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_put_task_struct; + } - return state == NULL ? NULL : state->parent; -} + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out_put_task_struct; -static int -ptrace_allow_access_process_vm(struct utrace_attached_engine *engine, - struct task_struct *target, - struct task_struct *caller) -{ - struct ptrace_state *state; - int ours; + ret = arch_ptrace(child, request, addr, data); + if (ret < 0) + goto out_put_task_struct; - /* - * This call is not necessarily made by the target task, - * so ptrace might be getting detached while we run here. - * The state pointer will be NULL if that happens. - */ - rcu_read_lock(); - state = rcu_dereference((struct ptrace_state *) engine->data); - ours = (state != NULL - && ((engine->flags & UTRACE_ACTION_QUIESCE) - || (target->state == TASK_STOPPED)) - && state->parent == caller); - rcu_read_unlock(); - - return ours && security_ptrace(caller, target) == 0; + out_put_task_struct: + put_task_struct(child); + out: + unlock_kernel(); + return ret; } - - -static const struct utrace_engine_ops ptrace_utrace_ops = -{ - .report_syscall_entry = ptrace_report_syscall_entry, - .report_syscall_exit = ptrace_report_syscall_exit, - .report_exec = ptrace_report_exec, - .report_jctl = ptrace_report_jctl, - .report_signal = ptrace_report_signal, - .report_vfork_done = ptrace_report_vfork_done, - .report_clone = ptrace_report_clone, - .report_exit = ptrace_report_exit, - .report_death = ptrace_report_death, - .report_reap = ptrace_report_reap, - .unsafe_exec = ptrace_unsafe_exec, - .tracer_task = ptrace_tracer_task, - .allow_access_process_vm = ptrace_allow_access_process_vm, -}; - -#endif +#endif /* __ARCH_SYS_PTRACE */ diff --git a/kernel/signal.c b/kernel/signal.c index b25ab79a8..fa34dee3e 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -159,6 +159,12 @@ static int sig_ignored(struct task_struct *t, int sig) { void __user * handler; + /* + * Tracers always want to know about signals.. + */ + if (t->ptrace & PT_PTRACED) + return 0; + /* * Blocked signals are never ignored, since the * signal handler may change by the time it is @@ -169,12 +175,8 @@ static int sig_ignored(struct task_struct *t, int sig) /* Is it explicitly or implicitly ignored? */ handler = t->sighand->action[sig-1].sa.sa_handler; - if (handler != SIG_IGN && - (handler != SIG_DFL || !sig_kernel_ignore(sig))) - return 0; - - /* It's ignored, we can short-circuit unless a debugger wants it. */ - return !tracehook_consider_ignored_signal(t, sig, handler); + return handler == SIG_IGN || + (handler == SIG_DFL && sig_kernel_ignore(sig)); } /* @@ -214,8 +216,7 @@ fastcall void recalc_sigpending_tsk(struct task_struct *t) if (t->signal->group_stop_count > 0 || (freezing(t)) || PENDING(&t->pending, &t->blocked) || - PENDING(&t->signal->shared_pending, &t->blocked) || - tracehook_induce_sigpending(t)) + PENDING(&t->signal->shared_pending, &t->blocked)) set_tsk_thread_flag(t, TIF_SIGPENDING); else clear_tsk_thread_flag(t, TIF_SIGPENDING); @@ -598,6 +599,8 @@ static int check_kill_permission(int sig, struct siginfo *info, return error; } +/* forward decl */ +static void do_notify_parent_cldstop(struct task_struct *tsk, int why); /* * Handle magic process-wide effects of stop/continue signals. @@ -934,7 +937,7 @@ __group_complete_signal(int sig, struct task_struct *p) */ if (sig_fatal(p, sig) && !(p->signal->flags & SIGNAL_GROUP_EXIT) && !sigismember(&t->real_blocked, sig) && - (sig == SIGKILL || !tracehook_consider_fatal_signal(t, sig))) { + (sig == SIGKILL || !(t->ptrace & PT_PTRACED))) { /* * This signal will be fatal to the whole group. */ @@ -1477,7 +1480,8 @@ void do_notify_parent(struct task_struct *tsk, int sig) /* do_notify_parent_cldstop should have been called instead. */ BUG_ON(tsk->state & (TASK_STOPPED|TASK_TRACED)); - BUG_ON(tsk->group_leader != tsk || !thread_group_empty(tsk)); + BUG_ON(!tsk->ptrace && + (tsk->group_leader != tsk || !thread_group_empty(tsk))); info.si_signo = sig; info.si_errno = 0; @@ -1502,7 +1506,7 @@ void do_notify_parent(struct task_struct *tsk, int sig) psig = tsk->parent->sighand; spin_lock_irqsave(&psig->siglock, flags); - if (sig == SIGCHLD && + if (!tsk->ptrace && sig == SIGCHLD && (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) { /* @@ -1530,13 +1534,20 @@ void do_notify_parent(struct task_struct *tsk, int sig) spin_unlock_irqrestore(&psig->siglock, flags); } -void do_notify_parent_cldstop(struct task_struct *tsk, int why) +static void do_notify_parent_cldstop(struct task_struct *tsk, int why) { struct siginfo info; unsigned long flags; struct task_struct *parent; struct sighand_struct *sighand; + if (tsk->ptrace & PT_PTRACED) + parent = tsk->parent; + else { + tsk = tsk->group_leader; + parent = tsk->real_parent; + } + info.si_signo = SIGCHLD; info.si_errno = 0; info.si_pid = tsk->pid; @@ -1561,15 +1572,6 @@ void do_notify_parent_cldstop(struct task_struct *tsk, int why) BUG(); } - /* - * Tracing can decide that we should not do the normal notification. - */ - if (tracehook_notify_cldstop(tsk, &info)) - return; - - tsk = tsk->group_leader; - parent = tsk->parent; - sighand = parent->sighand; spin_lock_irqsave(&sighand->siglock, flags); if (sighand->action[SIGCHLD-1].sa.sa_handler != SIG_IGN && @@ -1582,6 +1584,110 @@ void do_notify_parent_cldstop(struct task_struct *tsk, int why) spin_unlock_irqrestore(&sighand->siglock, flags); } +static inline int may_ptrace_stop(void) +{ + if (!likely(current->ptrace & PT_PTRACED)) + return 0; + + if (unlikely(current->parent == current->real_parent && + (current->ptrace & PT_ATTACHED))) + return 0; + + if (unlikely(current->signal == current->parent->signal) && + unlikely(current->signal->flags & SIGNAL_GROUP_EXIT)) + return 0; + + /* + * Are we in the middle of do_coredump? + * If so and our tracer is also part of the coredump stopping + * is a deadlock situation, and pointless because our tracer + * is dead so don't allow us to stop. + * If SIGKILL was already sent before the caller unlocked + * ->siglock we must see ->core_waiters != 0. Otherwise it + * is safe to enter schedule(). + */ + if (unlikely(current->mm->core_waiters) && + unlikely(current->mm == current->parent->mm)) + return 0; + + return 1; +} + +/* + * This must be called with current->sighand->siglock held. + * + * This should be the path for all ptrace stops. + * We always set current->last_siginfo while stopped here. + * That makes it a way to test a stopped process for + * being ptrace-stopped vs being job-control-stopped. + * + * If we actually decide not to stop at all because the tracer is gone, + * we leave nostop_code in current->exit_code. + */ +static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) +{ + /* + * If there is a group stop in progress, + * we must participate in the bookkeeping. + */ + if (current->signal->group_stop_count > 0) + --current->signal->group_stop_count; + + current->last_siginfo = info; + current->exit_code = exit_code; + + /* Let the debugger run. */ + set_current_state(TASK_TRACED); + spin_unlock_irq(¤t->sighand->siglock); + try_to_freeze(); + read_lock(&tasklist_lock); + if (may_ptrace_stop()) { + do_notify_parent_cldstop(current, CLD_TRAPPED); + read_unlock(&tasklist_lock); + schedule(); + } else { + /* + * By the time we got the lock, our tracer went away. + * Don't stop here. + */ + read_unlock(&tasklist_lock); + set_current_state(TASK_RUNNING); + current->exit_code = nostop_code; + } + + /* + * We are back. Now reacquire the siglock before touching + * last_siginfo, so that we are sure to have synchronized with + * any signal-sending on another CPU that wants to examine it. + */ + spin_lock_irq(¤t->sighand->siglock); + current->last_siginfo = NULL; + + /* + * Queued signals ignored us while we were stopped for tracing. + * So check for any that we should take before resuming user mode. + */ + recalc_sigpending(); +} + +void ptrace_notify(int exit_code) +{ + siginfo_t info; + + BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP); + + memset(&info, 0, sizeof info); + info.si_signo = SIGTRAP; + info.si_code = exit_code; + info.si_pid = current->pid; + info.si_uid = current->uid; + + /* Let the debugger run. */ + spin_lock_irq(¤t->sighand->siglock); + ptrace_stop(exit_code, 0, &info); + spin_unlock_irq(¤t->sighand->siglock); +} + static void finish_stop(int stop_count) { @@ -1590,7 +1696,7 @@ finish_stop(int stop_count) * a group stop in progress and we are the last to stop, * report to the parent. When ptraced, every thread reports itself. */ - if (!tracehook_finish_stop(stop_count <= 0) && stop_count <= 0) { + if (stop_count == 0 || (current->ptrace & PT_PTRACED)) { read_lock(&tasklist_lock); do_notify_parent_cldstop(current, CLD_STOPPED); read_unlock(&tasklist_lock); @@ -1715,24 +1821,44 @@ relock: handle_group_stop()) goto relock; - /* - * Tracing can induce an artifical signal and choose sigaction. - * The return value in signr determines the default action, - * but info->si_signo is the signal number we will report. - */ - signr = tracehook_get_signal(current, regs, info, return_ka); - if (unlikely(signr < 0)) - goto relock; - if (unlikely(signr != 0)) - ka = return_ka; - else { - signr = dequeue_signal(current, mask, info); - - if (!signr) - break; /* will return 0 */ - ka = ¤t->sighand->action[signr-1]; + signr = dequeue_signal(current, mask, info); + + if (!signr) + break; /* will return 0 */ + + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { + ptrace_signal_deliver(regs, cookie); + + /* Let the debugger run. */ + ptrace_stop(signr, signr, info); + + /* We're back. Did the debugger cancel the sig? */ + signr = current->exit_code; + if (signr == 0) + continue; + + current->exit_code = 0; + + /* Update the siginfo structure if the signal has + changed. If the debugger wanted something + specific in the siginfo structure then it should + have updated *info via PTRACE_SETSIGINFO. */ + if (signr != info->si_signo) { + info->si_signo = signr; + info->si_errno = 0; + info->si_code = SI_USER; + info->si_pid = current->parent->pid; + info->si_uid = current->parent->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + specific_send_sig_info(signr, info, current); + continue; + } } + ka = ¤t->sighand->action[signr-1]; if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ continue; if (ka->sa.sa_handler != SIG_DFL) { @@ -1782,7 +1908,7 @@ relock: spin_lock_irq(¤t->sighand->siglock); } - if (likely(do_signal_stop(info->si_signo))) { + if (likely(do_signal_stop(signr))) { /* It released the siglock. */ goto relock; } @@ -1811,13 +1937,13 @@ relock: * first and our do_group_exit call below will use * that value and ignore the one we pass it. */ - do_coredump(info->si_signo, info->si_signo, regs); + do_coredump((long)signr, signr, regs); } /* * Death signals, no core dump. */ - do_group_exit(info->si_signo); + do_group_exit(signr); /* NOTREACHED */ } spin_unlock_irq(¤t->sighand->siglock); @@ -1830,6 +1956,7 @@ EXPORT_SYMBOL(flush_signals); EXPORT_SYMBOL(force_sig); EXPORT_SYMBOL(kill_pg); EXPORT_SYMBOL(kill_proc); +EXPORT_SYMBOL(ptrace_notify); EXPORT_SYMBOL(send_sig); EXPORT_SYMBOL(send_sig_info); EXPORT_SYMBOL(sigprocmask); diff --git a/kernel/softirq.c b/kernel/softirq.c index 87e835b59..3789ca981 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -17,7 +17,6 @@ #include #include #include -#include #include /* @@ -206,7 +205,6 @@ EXPORT_SYMBOL(local_bh_enable_ip); asmlinkage void __do_softirq(void) { - struct vx_info_save vxis; struct softirq_action *h; __u32 pending; int max_restart = MAX_SOFTIRQ_RESTART; @@ -216,7 +214,6 @@ asmlinkage void __do_softirq(void) account_system_vtime(current); __local_bh_disable((unsigned long)__builtin_return_address(0)); - __enter_vx_admin(&vxis); trace_softirq_enter(); cpu = smp_processor_id(); @@ -248,7 +245,6 @@ restart: trace_softirq_exit(); - __leave_vx_admin(&vxis); account_system_vtime(current); _local_bh_enable(); } diff --git a/kernel/sys.c b/kernel/sys.c index a87239d9e..6195e5fe9 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1290,7 +1290,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (!thread_group_leader(p)) goto out; - if (p->parent == group_leader) { + if (p->real_parent == group_leader) { err = -EPERM; if (p->signal->session != group_leader->signal->session) goto out; diff --git a/kernel/timer.c b/kernel/timer.c index a9d5871c3..633e5dfe8 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1320,9 +1320,9 @@ asmlinkage long sys_getpid(void) } /* - * Accessing ->parent is not SMP-safe, it could + * Accessing ->real_parent is not SMP-safe, it could * change from under us. However, we can use a stale - * value of ->parent under rcu_read_lock(), see + * value of ->real_parent under rcu_read_lock(), see * release_task()->call_rcu(delayed_put_task_struct). */ asmlinkage long sys_getppid(void) @@ -1330,7 +1330,7 @@ asmlinkage long sys_getppid(void) int pid; rcu_read_lock(); - pid = rcu_dereference(current->parent)->tgid; + pid = rcu_dereference(current->real_parent)->tgid; rcu_read_unlock(); return vx_map_pid(pid); } diff --git a/kernel/vserver/context.c b/kernel/vserver/context.c index aa2b22024..e2026dfdb 100644 --- a/kernel/vserver/context.c +++ b/kernel/vserver/context.c @@ -16,6 +16,7 @@ * V0.09 revert to non RCU for now * V0.10 and back to working RCU hash * V0.11 and back to locking again + * V0.12 have __create claim() the vxi * */ @@ -195,9 +196,9 @@ static inline void __hash_vx_info(struct vx_info *vxi) static inline void __unhash_vx_info(struct vx_info *vxi) { - vxd_assert_lock(&vx_info_hash_lock); vxdprintk(VXD_CBIT(xid, 4), "__unhash_vx_info: %p[#%d]", vxi, vxi->vx_id); + spin_lock(&vx_info_hash_lock); vxh_unhash_vx_info(vxi); /* context must be hashed */ @@ -205,6 +206,7 @@ static inline void __unhash_vx_info(struct vx_info *vxi) vxi->vx_state &= ~VXS_HASHED; hlist_del(&vxi->vx_hlist); + spin_unlock(&vx_info_hash_lock); } @@ -326,7 +328,7 @@ out_unlock: /* __create_vx_info() * create the requested context - * get() and hash it */ + * get(), claim() and hash it */ static struct vx_info * __create_vx_info(int id) { @@ -371,6 +373,7 @@ static struct vx_info * __create_vx_info(int id) /* new context */ vxdprintk(VXD_CBIT(xid, 0), "create_vx_info(%d) = %p (new)", id, new); + claim_vx_info(new, NULL); __hash_vx_info(get_vx_info(new)); vxi = new, new = NULL; @@ -389,9 +392,7 @@ out_unlock: void unhash_vx_info(struct vx_info *vxi) { __shutdown_vx_info(vxi); - spin_lock(&vx_info_hash_lock); __unhash_vx_info(vxi); - spin_unlock(&vx_info_hash_lock); __wakeup_vx_info(vxi); } @@ -636,7 +637,7 @@ void vx_set_persistent(struct vx_info *vxi) "vx_set_persistent(%p[#%d])", vxi, vxi->vx_id); get_vx_info(vxi); - claim_vx_info(vxi, current); + claim_vx_info(vxi, NULL); } void vx_clear_persistent(struct vx_info *vxi) @@ -644,7 +645,7 @@ void vx_clear_persistent(struct vx_info *vxi) vxdprintk(VXD_CBIT(xid, 6), "vx_clear_persistent(%p[#%d])", vxi, vxi->vx_id); - release_vx_info(vxi, current); + release_vx_info(vxi, NULL); put_vx_info(vxi); } @@ -762,26 +763,22 @@ int vc_ctx_create(uint32_t xid, void __user *data) /* initial flags */ new_vxi->vx_flags = vc_data.flagword; - /* get a reference for persistent contexts */ - if ((vc_data.flagword & VXF_PERSISTENT)) - vx_set_persistent(new_vxi); - ret = -ENOEXEC; if (vs_state_change(new_vxi, VSC_STARTUP)) - goto out_unhash; + goto out; + ret = vx_migrate_task(current, new_vxi); - if (!ret) { - /* return context id on success */ - ret = new_vxi->vx_id; + if (ret) goto out; - } -out_unhash: - /* prepare for context disposal */ - new_vxi->vx_state |= VXS_SHUTDOWN; + + /* return context id on success */ + ret = new_vxi->vx_id; + + /* get a reference for persistent contexts */ if ((vc_data.flagword & VXF_PERSISTENT)) - vx_clear_persistent(new_vxi); - __unhash_vx_info(new_vxi); + vx_set_persistent(new_vxi); out: + release_vx_info(new_vxi, NULL); put_vx_info(new_vxi); return ret; } diff --git a/kernel/vserver/legacy.c b/kernel/vserver/legacy.c index f8a657aec..ec603ef8a 100644 --- a/kernel/vserver/legacy.c +++ b/kernel/vserver/legacy.c @@ -59,9 +59,7 @@ int vc_new_s_context(uint32_t ctx, void __user *data) return ret; } - if (!vx_check(0, VX_ADMIN) || !capable(CAP_SYS_ADMIN) - /* might make sense in the future, or not ... */ - || vx_flags(VX_INFO_LOCK, 0)) + if (!vx_check(0, VX_ADMIN) || !capable(CAP_SYS_ADMIN)) return -EPERM; /* ugly hack for Spectator */ diff --git a/kernel/vserver/legacynet.c b/kernel/vserver/legacynet.c index de64e404a..ec91d7563 100644 --- a/kernel/vserver/legacynet.c +++ b/kernel/vserver/legacynet.c @@ -77,6 +77,7 @@ int vc_set_ipv4root(uint32_t nbip, void __user *data) printk("!!! switching nx_info %p->%p\n", nxi, new_nxi); nx_migrate_task(current, new_nxi); + release_nx_info(new_nxi, NULL); put_nx_info(new_nxi); return 0; } diff --git a/kernel/vserver/limit.c b/kernel/vserver/limit.c index 18dba6c70..9f279734d 100644 --- a/kernel/vserver/limit.c +++ b/kernel/vserver/limit.c @@ -3,9 +3,10 @@ * * Virtual Server: Context Limits * - * Copyright (C) 2004-2005 Herbert Pötzl + * Copyright (C) 2004-2006 Herbert Pötzl * * V0.01 broken out from vcontext V0.05 + * V0.02 sync to valid limit check from 2.1.1 * */ @@ -40,25 +41,37 @@ const char *vlimit_name[NUM_LIMITS] = { EXPORT_SYMBOL_GPL(vlimit_name); -static int is_valid_rlimit(int id) +#define MASK_ENTRY(x) (1 << (x)) + +const struct vcmd_ctx_rlimit_mask_v0 vlimit_mask = { + /* minimum */ + 0 + , /* softlimit */ + MASK_ENTRY( RLIMIT_RSS ) | + MASK_ENTRY( VLIMIT_ANON ) | + 0 + , /* maximum */ + MASK_ENTRY( RLIMIT_RSS ) | + MASK_ENTRY( RLIMIT_NPROC ) | + MASK_ENTRY( RLIMIT_NOFILE ) | + MASK_ENTRY( RLIMIT_MEMLOCK ) | + MASK_ENTRY( RLIMIT_AS ) | + MASK_ENTRY( RLIMIT_LOCKS ) | + MASK_ENTRY( RLIMIT_MSGQUEUE ) | + + MASK_ENTRY( VLIMIT_NSOCK ) | + MASK_ENTRY( VLIMIT_OPENFD ) | + MASK_ENTRY( VLIMIT_ANON ) | + MASK_ENTRY( VLIMIT_SHMEM ) | + 0 +}; + + +static int is_valid_vlimit(int id) { - int valid = 0; - - switch (id) { - case RLIMIT_RSS: - case RLIMIT_NPROC: - case RLIMIT_NOFILE: - case RLIMIT_MEMLOCK: - case RLIMIT_AS: - - case VLIMIT_NSOCK: - case VLIMIT_OPENFD: - case VLIMIT_ANON: - case VLIMIT_SHMEM: - valid = 1; - break; - } - return valid; + uint32_t mask = vlimit_mask.minimum | + vlimit_mask.softlimit | vlimit_mask.maximum; + return mask & (1 << id); } static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id) @@ -76,7 +89,7 @@ static int do_get_rlimit(xid_t xid, uint32_t id, { struct vx_info *vxi; - if (!is_valid_rlimit(id)) + if (!is_valid_vlimit(id)) return -EINVAL; vxi = lookup_vx_info(xid); @@ -116,7 +129,7 @@ static int do_set_rlimit(xid_t xid, uint32_t id, { struct vx_info *vxi; - if (!is_valid_rlimit(id)) + if (!is_valid_vlimit(id)) return -EINVAL; vxi = lookup_vx_info(xid); @@ -181,25 +194,7 @@ int vc_get_rlimit_x32(uint32_t id, void __user *data) int vc_get_rlimit_mask(uint32_t id, void __user *data) { - static struct vcmd_ctx_rlimit_mask_v0 mask = { - /* minimum */ - 0 - , /* softlimit */ - 0 - , /* maximum */ - (1 << RLIMIT_RSS) | - (1 << RLIMIT_NPROC) | - (1 << RLIMIT_NOFILE) | - (1 << RLIMIT_MEMLOCK) | - (1 << RLIMIT_LOCKS) | - (1 << RLIMIT_AS) | - (1 << VLIMIT_ANON) | - 0 - }; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE)) - return -EPERM; - if (copy_to_user(data, &mask, sizeof(mask))) + if (copy_to_user(data, &vlimit_mask, sizeof(vlimit_mask))) return -EFAULT; return 0; } diff --git a/kernel/vserver/network.c b/kernel/vserver/network.c index 1ceb1fcb8..1a8272fdd 100644 --- a/kernel/vserver/network.c +++ b/kernel/vserver/network.c @@ -3,13 +3,14 @@ * * Virtual Server: Network Support * - * Copyright (C) 2003-2005 Herbert Pötzl + * Copyright (C) 2003-2006 Herbert Pötzl * * V0.01 broken out from vcontext V0.05 * V0.02 cleaned up implementation * V0.03 added equiv nx commands * V0.04 switch to RCU based hash * V0.05 and back to locking again + * V0.06 have __create claim() the nxi * */ @@ -139,15 +140,16 @@ static inline void __hash_nx_info(struct nx_info *nxi) static inline void __unhash_nx_info(struct nx_info *nxi) { - vxd_assert_lock(&nx_info_hash_lock); vxdprintk(VXD_CBIT(nid, 4), "__unhash_nx_info: %p[#%d]", nxi, nxi->nx_id); + spin_lock(&nx_info_hash_lock); /* context must be hashed */ BUG_ON(!nx_info_state(nxi, NXS_HASHED)); nxi->nx_state &= ~NXS_HASHED; hlist_del(&nxi->nx_hlist); + spin_unlock(&nx_info_hash_lock); } @@ -204,7 +206,7 @@ static inline nid_t __nx_dynamic_id(void) /* __create_nx_info() * create the requested context - * get() and hash it */ + * get(), claim() and hash it */ static struct nx_info * __create_nx_info(int id) { @@ -249,6 +251,7 @@ static struct nx_info * __create_nx_info(int id) /* new context */ vxdprintk(VXD_CBIT(nid, 0), "create_nx_info(%d) = %p (new)", id, new); + claim_nx_info(new, NULL); __hash_nx_info(get_nx_info(new)); nxi = new, new = NULL; @@ -267,9 +270,7 @@ out_unlock: void unhash_nx_info(struct nx_info *nxi) { __shutdown_nx_info(nxi); - spin_lock(&nx_info_hash_lock); __unhash_nx_info(nxi); - spin_unlock(&nx_info_hash_lock); } #ifdef CONFIG_VSERVER_LEGACYNET @@ -386,6 +387,7 @@ int nx_migrate_task(struct task_struct *p, struct nx_info *nxi) if (old_nxi) release_nx_info(old_nxi, p); + ret = 0; out: put_nx_info(old_nxi); return ret; @@ -488,8 +490,11 @@ int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, struct sock *sk) void nx_set_persistent(struct nx_info *nxi) { + vxdprintk(VXD_CBIT(nid, 6), + "nx_set_persistent(%p[#%d])", nxi, nxi->nx_id); + get_nx_info(nxi); - claim_nx_info(nxi, current); + claim_nx_info(nxi, NULL); } void nx_clear_persistent(struct nx_info *nxi) @@ -497,7 +502,7 @@ void nx_clear_persistent(struct nx_info *nxi) vxdprintk(VXD_CBIT(nid, 6), "nx_clear_persistent(%p[#%d])", nxi, nxi->nx_id); - release_nx_info(nxi, current); + release_nx_info(nxi, NULL); put_nx_info(nxi); } @@ -585,26 +590,22 @@ int vc_net_create(uint32_t nid, void __user *data) /* initial flags */ new_nxi->nx_flags = vc_data.flagword; - /* get a reference for persistent contexts */ - if ((vc_data.flagword & NXF_PERSISTENT)) - nx_set_persistent(new_nxi); - ret = -ENOEXEC; if (vs_net_change(new_nxi, VSC_NETUP)) - goto out_unhash; + goto out; + ret = nx_migrate_task(current, new_nxi); - if (!ret) { - /* return context id on success */ - ret = new_nxi->nx_id; + if (ret) goto out; - } -out_unhash: - /* prepare for context disposal */ - new_nxi->nx_state |= NXS_SHUTDOWN; + + /* return context id on success */ + ret = new_nxi->nx_id; + + /* get a reference for persistent contexts */ if ((vc_data.flagword & NXF_PERSISTENT)) - nx_clear_persistent(new_nxi); - __unhash_nx_info(new_nxi); + nx_set_persistent(new_nxi); out: + release_nx_info(new_nxi, NULL); put_nx_info(new_nxi); return ret; } diff --git a/kernel/vserver/proc.c b/kernel/vserver/proc.c index b16949bca..d7a5edc03 100644 --- a/kernel/vserver/proc.c +++ b/kernel/vserver/proc.c @@ -217,8 +217,10 @@ int proc_nid_status (int vid, char *buffer) length = sprintf(buffer, "UseCnt:\t%d\n" "Tasks:\t%d\n" + "Flags:\t%016llx\n" ,atomic_read(&nxi->nx_usecnt) ,atomic_read(&nxi->nx_tasks) + ,(unsigned long long)nxi->nx_flags ); put_nx_info(nxi); return length; diff --git a/mm/fremap.c b/mm/fremap.c index 7be2ae6a5..f7b6e2216 100644 --- a/mm/fremap.c +++ b/mm/fremap.c @@ -76,10 +76,9 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma, err = -ENOMEM; if (page_mapcount(page) > INT_MAX/2) goto unlock; + if (!vx_rsspages_avail(mm, 1)) + goto unlock; } - err = -ENOMEM; - if (!vx_rsspages_avail(mm, 1)) - goto unlock; if (pte_none(*pte) || !zap_pte(mm, vma, addr, pte)) inc_mm_counter(mm, file_rss); diff --git a/mm/slab.c b/mm/slab.c index 4a5634ee8..0d9cf0921 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -892,7 +892,7 @@ static void init_reap_node(int cpu) if (node == MAX_NUMNODES) node = first_node(node_online_map); - __get_cpu_var(reap_node) = node; + per_cpu(reap_node, cpu) = node; } static void next_reap_node(void) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 1a35d343e..316fa7a3e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -120,10 +120,13 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) if (!hci_test_bit(evt, &flt->event_mask)) continue; - if (flt->opcode && ((evt == HCI_EV_CMD_COMPLETE && - flt->opcode != *(__u16 *)(skb->data + 3)) || - (evt == HCI_EV_CMD_STATUS && - flt->opcode != *(__u16 *)(skb->data + 4)))) + if (flt->opcode && + ((evt == HCI_EV_CMD_COMPLETE && + flt->opcode != + get_unaligned((__u16 *)(skb->data + 3))) || + (evt == HCI_EV_CMD_STATUS && + flt->opcode != + get_unaligned((__u16 *)(skb->data + 4))))) continue; } diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 4e4119a12..4c61a7e0a 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -58,12 +58,13 @@ static int get_fdb_entries(struct net_bridge *br, void __user *userbuf, { int num; void *buf; - size_t size = maxnum * sizeof(struct __fdb_entry); + size_t size; - if (size > PAGE_SIZE) { - size = PAGE_SIZE; + /* Clamp size to PAGE_SIZE, test maxnum to avoid overflow */ + if (maxnum > PAGE_SIZE/sizeof(struct __fdb_entry)) maxnum = PAGE_SIZE/sizeof(struct __fdb_entry); - } + + size = maxnum * sizeof(struct __fdb_entry); buf = kmalloc(size, GFP_USER); if (!buf) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3ff6cb323..750ec6f8a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -657,6 +657,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) n->csum = skb->csum; n->ip_summed = skb->ip_summed; + n->truesize += skb->data_len; n->data_len = skb->data_len; n->len = skb->len; diff --git a/net/core/sock.c b/net/core/sock.c index 560cdb3a3..937a72bc1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1172,7 +1172,7 @@ static struct sk_buff *sock_alloc_send_pskb(struct sock *sk, goto failure; if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { - skb = alloc_skb(header_len, sk->sk_allocation); + skb = alloc_skb(header_len, gfp_mask); if (skb) { int npages; int i; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 610c722ac..3744c246c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -276,7 +276,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, __u64 seq; sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport, - &hdr->saddr, dh->dccph_sport, skb->dev->ifindex); + &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); if (sk == NULL) { ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c index 6ae5a1dc7..3b67d1976 100644 --- a/net/ieee80211/softmac/ieee80211softmac_io.c +++ b/net/ieee80211/softmac/ieee80211softmac_io.c @@ -304,7 +304,7 @@ ieee80211softmac_auth(struct ieee80211_auth **pkt, 2 + /* Auth Transaction Seq */ 2 + /* Status Code */ /* Challenge Text IE */ - is_shared_response ? 0 : 1 + 1 + net->challenge_len + (is_shared_response ? 1 + 1 + net->challenge_len : 0) ); if (unlikely((*pkt) == NULL)) return 0; diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 3f47ad8e1..f5946352c 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -813,6 +813,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, skb->nh.iph->saddr = cp->vaddr; ip_send_check(skb->nh.iph); + /* For policy routing, packets originating from this + * machine itself may be routed differently to packets + * passing through. We want this packet to be routed as + * if it came from this machine itself. So re-compute + * the routing information. + */ + if (ip_route_me_harder(pskb, RTN_LOCAL) != 0) + goto drop; + skb = *pskb; + IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); ip_vs_out_stats(cp, skb); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 6a9e34b79..327ba3718 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -8,7 +8,7 @@ #include /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ -int ip_route_me_harder(struct sk_buff **pskb) +int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) { struct iphdr *iph = (*pskb)->nh.iph; struct rtable *rt; @@ -16,10 +16,13 @@ int ip_route_me_harder(struct sk_buff **pskb) struct dst_entry *odst; unsigned int hh_len; + if (addr_type == RTN_UNSPEC) + addr_type = inet_addr_type(iph->saddr); + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. */ - if (inet_addr_type(iph->saddr) == RTN_LOCAL) { + if (addr_type == RTN_LOCAL) { fl.nl_u.ip4_u.daddr = iph->daddr; fl.nl_u.ip4_u.saddr = iph->saddr; fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); @@ -156,7 +159,7 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) if (!(iph->tos == rt_info->tos && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) - return ip_route_me_harder(pskb); + return ip_route_me_harder(pskb, RTN_UNSPEC); } return 0; } diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 8d1d7a6e7..8ba83e898 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -380,6 +380,13 @@ static int mark_source_chains(struct xt_table_info *newinfo, && unconditional(&e->arp)) { unsigned int oldpos, size; + if (t->verdict < -NF_MAX_VERDICT - 1) { + duprintf("mark_source_chains: bad " + "negative verdict (%i)\n", + t->verdict); + return 0; + } + /* Return: backtrack through the last * big jump. */ @@ -409,6 +416,14 @@ static int mark_source_chains(struct xt_table_info *newinfo, if (strcmp(t->target.u.user.name, ARPT_STANDARD_TARGET) == 0 && newpos >= 0) { + if (newpos > newinfo->size - + sizeof(struct arpt_entry)) { + duprintf("mark_source_chains: " + "bad verdict (%i)\n", + newpos); + return 0; + } + /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -431,8 +446,6 @@ static int mark_source_chains(struct xt_table_info *newinfo, static inline int standard_check(const struct arpt_entry_target *t, unsigned int max_offset) { - struct arpt_standard_target *targ = (void *)t; - /* Check standard info. */ if (t->u.target_size != ARPT_ALIGN(sizeof(struct arpt_standard_target))) { @@ -442,18 +455,6 @@ static inline int standard_check(const struct arpt_entry_target *t, return 0; } - if (targ->verdict >= 0 - && targ->verdict > max_offset - sizeof(struct arpt_entry)) { - duprintf("arpt_standard_check: bad verdict (%i)\n", - targ->verdict); - return 0; - } - - if (targ->verdict < -NF_MAX_VERDICT - 1) { - duprintf("arpt_standard_check: bad negative verdict (%i)\n", - targ->verdict); - return 0; - } return 1; } @@ -471,7 +472,13 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i return -EINVAL; } + if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset) + return -EINVAL; + t = arpt_get_target(e); + if (e->target_offset + t->u.target_size > e->next_offset) + return -EINVAL; + target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name, t->u.user.revision), "arpt_%s", t->u.user.name); @@ -641,7 +648,7 @@ static int translate_table(const char *name, if (ret != 0) { ARPT_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); + cleanup_entry, &i); return ret; } @@ -1204,6 +1211,8 @@ err1: static void __exit arp_tables_fini(void) { nf_unregister_sockopt(&arpt_sockopts); + xt_unregister_target(&arpt_error_target); + xt_unregister_target(&arpt_standard_target); xt_proto_fini(NF_ARP); } diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 9a39e2969..afe7039a4 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -1417,7 +1417,7 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, DEBUGP ("ip_ct_ras: set RAS connection timeout to %u seconds\n", info->timeout); - ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ); + ip_ct_refresh(ct, *pskb, info->timeout * HZ); /* Set expect timeout */ read_lock_bh(&ip_conntrack_lock); @@ -1465,7 +1465,7 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, info->sig_port[!dir] = 0; /* Give it 30 seconds for UCF or URJ */ - ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ); + ip_ct_refresh(ct, *pskb, 30 * HZ); return 0; } diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 6db485f2c..c508544d7 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -275,7 +275,8 @@ ip_nat_local_fn(unsigned int hooknum, ct->tuplehash[!dir].tuple.src.u.all #endif ) - return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; } return ret; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 048514f15..e96443699 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -404,6 +404,13 @@ mark_source_chains(struct xt_table_info *newinfo, && unconditional(&e->ip)) { unsigned int oldpos, size; + if (t->verdict < -NF_MAX_VERDICT - 1) { + duprintf("mark_source_chains: bad " + "negative verdict (%i)\n", + t->verdict); + return 0; + } + /* Return: backtrack through the last big jump. */ do { @@ -441,6 +448,13 @@ mark_source_chains(struct xt_table_info *newinfo, if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0 && newpos >= 0) { + if (newpos > newinfo->size - + sizeof(struct ipt_entry)) { + duprintf("mark_source_chains: " + "bad verdict (%i)\n", + newpos); + return 0; + } /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -473,27 +487,6 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i) return 0; } -static inline int -standard_check(const struct ipt_entry_target *t, - unsigned int max_offset) -{ - struct ipt_standard_target *targ = (void *)t; - - /* Check standard info. */ - if (targ->verdict >= 0 - && targ->verdict > max_offset - sizeof(struct ipt_entry)) { - duprintf("ipt_standard_check: bad verdict (%i)\n", - targ->verdict); - return 0; - } - if (targ->verdict < -NF_MAX_VERDICT - 1) { - duprintf("ipt_standard_check: bad negative verdict (%i)\n", - targ->verdict); - return 0; - } - return 1; -} - static inline int check_match(struct ipt_entry_match *m, const char *name, @@ -552,12 +545,18 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, return -EINVAL; } + if (e->target_offset + sizeof(struct ipt_entry_target) > e->next_offset) + return -EINVAL; + j = 0; ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip, e->comefrom, &j); if (ret != 0) goto cleanup_matches; t = ipt_get_target(e); + ret = -EINVAL; + if (e->target_offset + t->u.target_size > e->next_offset) + goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET, t->u.user.name, t->u.user.revision), @@ -575,12 +574,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, if (ret) goto err; - if (t->u.kernel.target == &ipt_standard_target) { - if (!standard_check(t, size)) { - ret = -EINVAL; - goto cleanup_matches; - } - } else if (t->u.kernel.target->checkentry + if (t->u.kernel.target->checkentry && !t->u.kernel.target->checkentry(name, e, target, t->data, t->u.target_size - sizeof(*t), @@ -730,7 +724,7 @@ translate_table(const char *name, if (ret != 0) { IPT_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); + cleanup_entry, &i); return ret; } @@ -1531,15 +1525,22 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, return -EINVAL; } + if (e->target_offset + sizeof(struct compat_xt_entry_target) > + e->next_offset) + return -EINVAL; + off = 0; entry_offset = (void *)e - (void *)base; j = 0; ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip, e->comefrom, &off, &j); if (ret != 0) - goto out; + goto cleanup_matches; t = ipt_get_target(e); + ret = -EINVAL; + if (e->target_offset + t->u.target_size > e->next_offset) + goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET, t->u.user.name, t->u.user.revision), @@ -1547,7 +1548,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, if (IS_ERR(target) || !target) { duprintf("check_entry: `%s' not found\n", t->u.user.name); ret = target ? PTR_ERR(target) : -ENOENT; - goto out; + goto cleanup_matches; } t->u.kernel.target = target; @@ -1574,7 +1575,10 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, (*i)++; return 0; + out: + module_put(t->u.kernel.target->me); +cleanup_matches: IPT_MATCH_ITERATE(e, cleanup_match, &j); return ret; } @@ -1597,18 +1601,16 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m, ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), name, hookmask, ip->proto, ip->invflags & IPT_INV_PROTO); - if (ret) - return ret; - if (m->u.kernel.match->checkentry + if (!ret && m->u.kernel.match->checkentry && !m->u.kernel.match->checkentry(name, ip, match, dm->data, dm->u.match_size - sizeof(*dm), hookmask)) { duprintf("ip_tables: check failed for `%s'.\n", m->u.kernel.match->name); - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, @@ -1630,7 +1632,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, name, &de->ip, de->comefrom); if (ret) - goto out; + goto err; de->target_offset = e->target_offset - (origsize - *size); t = ipt_get_target(e); target = t->u.kernel.target; @@ -1653,22 +1655,18 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, name, e->comefrom, e->ip.proto, e->ip.invflags & IPT_INV_PROTO); if (ret) - goto out; + goto err; - ret = -EINVAL; - if (t->u.kernel.target == &ipt_standard_target) { - if (!standard_check(t, *size)) - goto out; - } else if (t->u.kernel.target->checkentry + if (t->u.kernel.target->checkentry && !t->u.kernel.target->checkentry(name, de, target, t->data, t->u.target_size - sizeof(*t), de->comefrom)) { duprintf("ip_tables: compat: check failed for `%s'.\n", t->u.kernel.target->name); - goto out; + ret = -EINVAL; + goto err; } - ret = 0; -out: + err: return ret; } @@ -1682,7 +1680,7 @@ translate_compat_table(const char *name, unsigned int *hook_entries, unsigned int *underflows) { - unsigned int i; + unsigned int i, j; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; unsigned int size; @@ -1700,21 +1698,21 @@ translate_compat_table(const char *name, } duprintf("translate_compat_table: size %u\n", info->size); - i = 0; + j = 0; xt_compat_lock(AF_INET); /* Walk through entries, checking offsets. */ ret = IPT_ENTRY_ITERATE(entry0, total_size, check_compat_entry_size_and_hooks, info, &size, entry0, entry0 + total_size, - hook_entries, underflows, &i, name); + hook_entries, underflows, &j, name); if (ret != 0) goto out_unlock; ret = -EINVAL; - if (i != number) { + if (j != number) { duprintf("translate_compat_table: %u not %u entries\n", - i, number); + j, number); goto out_unlock; } @@ -1773,8 +1771,10 @@ translate_compat_table(const char *name, free_newinfo: xt_free_table_info(newinfo); out: + IPT_ENTRY_ITERATE(entry0, total_size, cleanup_entry, &j); return ret; out_unlock: + compat_flush_offsets(); xt_compat_unlock(AF_INET); goto out; } @@ -1994,6 +1994,9 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) { int ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch (cmd) { case IPT_SO_GET_INFO: ret = get_info(user, len, 1); diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 4e7998bed..f7b8906c3 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -157,7 +157,8 @@ ipt_local_hook(unsigned int hook, || (*pskb)->nfmark != nfmark #endif || (*pskb)->nh.iph->tos != tos)) - return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + if (ip_route_me_harder(pskb, RTN_UNSPEC)) + ret = NF_DROP; return ret; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f28f40642..b04e96e08 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2270,7 +2270,7 @@ void __init tcp_init(void) thash_entries, (num_physpages >= 128 * 1024) ? 13 : 15, - HASH_HIGHMEM, + 0, &tcp_hashinfo.ehash_size, NULL, 0); @@ -2286,7 +2286,7 @@ void __init tcp_init(void) tcp_hashinfo.ehash_size, (num_physpages >= 128 * 1024) ? 13 : 15, - HASH_HIGHMEM, + 0, &tcp_hashinfo.bhash_size, NULL, 64 * 1024); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e6aafd62f..21eff235d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -909,23 +909,32 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) return 1; #else struct udp_sock *up = udp_sk(sk); - struct udphdr *uh = skb->h.uh; + struct udphdr *uh; struct iphdr *iph; int iphlen, len; - __u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr); - __u32 *udpdata32 = (__u32 *)udpdata; + __u8 *udpdata; + __u32 *udpdata32; __u16 encap_type = up->encap_type; /* if we're overly short, let UDP handle it */ - if (udpdata > skb->tail) + len = skb->len - sizeof(struct udphdr); + if (len <= 0) return 1; /* if this is not encapsulated socket, then just return now */ if (!encap_type) return 1; - len = skb->tail - udpdata; + /* If this is a paged skb, make sure we pull up + * whatever data we need to look at. */ + if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) + return 1; + + /* Now we can get the pointers */ + uh = skb->h.uh; + udpdata = (__u8 *)uh + sizeof(struct udphdr); + udpdata32 = (__u32 *)udpdata; switch (encap_type) { default: diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index c9d6b23cd..751548a42 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -444,6 +444,13 @@ mark_source_chains(struct xt_table_info *newinfo, && unconditional(&e->ipv6)) { unsigned int oldpos, size; + if (t->verdict < -NF_MAX_VERDICT - 1) { + duprintf("mark_source_chains: bad " + "negative verdict (%i)\n", + t->verdict); + return 0; + } + /* Return: backtrack through the last big jump. */ do { @@ -481,6 +488,13 @@ mark_source_chains(struct xt_table_info *newinfo, if (strcmp(t->target.u.user.name, IP6T_STANDARD_TARGET) == 0 && newpos >= 0) { + if (newpos > newinfo->size - + sizeof(struct ip6t_entry)) { + duprintf("mark_source_chains: " + "bad verdict (%i)\n", + newpos); + return 0; + } /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -513,27 +527,6 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i) return 0; } -static inline int -standard_check(const struct ip6t_entry_target *t, - unsigned int max_offset) -{ - struct ip6t_standard_target *targ = (void *)t; - - /* Check standard info. */ - if (targ->verdict >= 0 - && targ->verdict > max_offset - sizeof(struct ip6t_entry)) { - duprintf("ip6t_standard_check: bad verdict (%i)\n", - targ->verdict); - return 0; - } - if (targ->verdict < -NF_MAX_VERDICT - 1) { - duprintf("ip6t_standard_check: bad negative verdict (%i)\n", - targ->verdict); - return 0; - } - return 1; -} - static inline int check_match(struct ip6t_entry_match *m, const char *name, @@ -592,12 +585,19 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, return -EINVAL; } + if (e->target_offset + sizeof(struct ip6t_entry_target) > + e->next_offset) + return -EINVAL; + j = 0; ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j); if (ret != 0) goto cleanup_matches; t = ip6t_get_target(e); + ret = -EINVAL; + if (e->target_offset + t->u.target_size > e->next_offset) + goto cleanup_matches; target = try_then_request_module(xt_find_target(AF_INET6, t->u.user.name, t->u.user.revision), @@ -615,12 +615,7 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, if (ret) goto err; - if (t->u.kernel.target == &ip6t_standard_target) { - if (!standard_check(t, size)) { - ret = -EINVAL; - goto cleanup_matches; - } - } else if (t->u.kernel.target->checkentry + if (t->u.kernel.target->checkentry && !t->u.kernel.target->checkentry(name, e, target, t->data, t->u.target_size - sizeof(*t), @@ -770,7 +765,7 @@ translate_table(const char *name, if (ret != 0) { IP6T_ENTRY_ITERATE(entry0, newinfo->size, - cleanup_entry, &i); + cleanup_entry, &i); return ret; } @@ -780,7 +775,7 @@ translate_table(const char *name, memcpy(newinfo->entries[i], entry0, newinfo->size); } - return ret; + return 0; } /* Gets counters. */ diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3d54f2464..7ecfe82e1 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -314,14 +314,13 @@ static void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, { struct ipv6_pinfo *np; struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; - struct net_device *dev = skb->dev; struct in6_addr *saddr = &hdr->saddr; struct in6_addr *daddr = &hdr->daddr; struct udphdr *uh = (struct udphdr*)(skb->data+offset); struct sock *sk; int err; - sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex); + sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, inet6_iif(skb)); if (sk == NULL) return; @@ -415,7 +414,7 @@ static void udpv6_mcast_deliver(struct udphdr *uh, read_lock(&udp_hash_lock); sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = skb->dev->ifindex; + dif = inet6_iif(skb); sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { kfree_skb(skb); @@ -496,7 +495,7 @@ static int udpv6_rcv(struct sk_buff **pskb) * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex); + sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, inet6_iif(skb)); if (sk == NULL) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index a9894ddfd..e1c27b7c4 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -197,7 +197,9 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_CONNSECMARK tristate '"CONNSECMARK" target support' - depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK) + depends on NETFILTER_XTABLES && \ + ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \ + (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK)) help The CONNSECMARK target copies security markings from packets to connections, and restores security markings from connections @@ -342,7 +344,7 @@ config NETFILTER_XT_MATCH_MULTIPORT config NETFILTER_XT_MATCH_PHYSDEV tristate '"physdev" match support' - depends on NETFILTER_XTABLES && BRIDGE_NETFILTER + depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER help Physdev packet matching matches against the physical bridge ports the IP packet arrived on or will leave by. diff --git a/scripts/basic/.docproc.cmd b/scripts/basic/.docproc.cmd index c9f4521be..53cdd464c 100644 --- a/scripts/basic/.docproc.cmd +++ b/scripts/basic/.docproc.cmd @@ -6,16 +6,17 @@ deps_scripts/basic/docproc := \ /usr/include/features.h \ /usr/include/sys/cdefs.h \ /usr/include/gnu/stubs.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \ - /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs-32.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stddef.h \ + /usr/include/bits/types.h \ /usr/include/bits/typesizes.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ /usr/include/wchar.h \ /usr/include/bits/wchar.h \ /usr/include/gconv.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/include/bits/stdio.h \ @@ -30,7 +31,6 @@ deps_scripts/basic/docproc := \ /usr/include/bits/time.h \ /usr/include/sys/sysmacros.h \ /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/sched.h \ /usr/include/alloca.h \ /usr/include/string.h \ /usr/include/bits/string.h \ @@ -40,8 +40,8 @@ deps_scripts/basic/docproc := \ /usr/include/bits/posix_opt.h \ /usr/include/bits/confname.h \ /usr/include/getopt.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/limits.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/syslimits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/limits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/syslimits.h \ /usr/include/limits.h \ /usr/include/bits/posix1_lim.h \ /usr/include/bits/local_lim.h \ diff --git a/scripts/basic/.fixdep.cmd b/scripts/basic/.fixdep.cmd index daa513c3c..d8cd332f8 100644 --- a/scripts/basic/.fixdep.cmd +++ b/scripts/basic/.fixdep.cmd @@ -11,9 +11,10 @@ deps_scripts/basic/fixdep := \ /usr/include/features.h \ /usr/include/sys/cdefs.h \ /usr/include/gnu/stubs.h \ - /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stddef.h \ /usr/include/bits/typesizes.h \ /usr/include/time.h \ /usr/include/endian.h \ @@ -24,7 +25,6 @@ deps_scripts/basic/fixdep := \ /usr/include/bits/time.h \ /usr/include/sys/sysmacros.h \ /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/sched.h \ /usr/include/sys/stat.h \ /usr/include/bits/stat.h \ /usr/include/sys/mman.h \ @@ -46,12 +46,12 @@ deps_scripts/basic/fixdep := \ /usr/include/wchar.h \ /usr/include/bits/wchar.h \ /usr/include/gconv.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/include/bits/stdio.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/limits.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/syslimits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/limits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/syslimits.h \ /usr/include/limits.h \ /usr/include/bits/posix1_lim.h \ /usr/include/bits/local_lim.h \ diff --git a/scripts/basic/docproc b/scripts/basic/docproc index 52174fb221045b4f2990ad4010b27b0e04135917..939288420f5423503829a9e2f93da5b135ade1f3 100755 GIT binary patch literal 13404 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 D2rT18 delta 5150 zcmcgwdvH|M89#UTCT_xp-9Q4dMzX+-AvT6Aq9&9Ak|lvoiYrSJo{2VK*NBjYtfh** ziMz4fY}W}~I?~aJp^9UxGL6B4m5B)(StHb9T4hEVtq=5s4G$rP2*~#L-Fr7=I<3<` zIz5?_bAI3X&i6XsdE7nWz2t4pNGjYWT4poGHf*0-lUR_(SV7wMmhTB`I`;Sl;RQ9< zly&b-CdMX!<)^4rrlS%L5kOgmN_Y_gl#8f@??I(<7L{;50hA~z;gtkXUQ~Z?n)#Cv z^oV*pkx;gx5-uZv@*_dVJ{_{p(b70+qtb6!c~Xa?T1gI-5|cW|JjK~zhzaOaR*9Cx z95L`w179_8hpL#frjk*_^*(C%4$&f_O=aU*FIp<=)jo5UP~SOVe$q6tTsi3WuVAFPyTKGY7F>I!FRbxELE{g-yG0B04jo7(D z?MO^HWDC5dn>NQ?%R(+G&Ap5t)tQ1W$@+rqOSk>0Hz{EQW;gXpkhHow48tQDC5E|C z9$F*WE4>27YMF=6)0A7i4ESzu5cbIY`;b_@%I)F(h^zAP6=(NrK>x^Ydtc_2aF+Hj~r zvb&9?s^GuSB;z4bqTnq2OppC~e7#e${w+hHoeTD+Wu0c3anV z`WR+h;C}{Dxg4}W;6z*3p<(e(5_qZFXD*JOh8>5^tde5Q_vpDWu!N!r`}#EdUWdyR zQ@I-kHs6b}fn1HjTF%euV*@*`?Z+gf>v3AC*`#*1#7}&q%^x@o9wSY#$sEoPgDI3M zh@!>W4~kTD1btDq9oPo)ovmiOzuUURH-fYZiSOB&j9~I}x-f+Kuq~h>SP^m8Q_vP! zAbx^IOU>r)*KroIU*3*ALK&y@D8oTff)cN#=+vVb!7XAd^ofet78IW>UWm51=+xFh zzbHZ9dl<67dr%{;HrhYT?L7tAG9Q9+@@N}8TVb3n3y9Vr6(A=m*9Pnq5$s1T1fPvu z+o)fH5lM@@_FjZE+Fbmsc4}zJOmy>3gMR!PT~G44X2#^;OVV<*5u8x8_0ifj*KvN4 z?=6d%b2!lb2Kny0B^Z$0U{+iQ?Ge{O+_sc*R-AR2Zr%qQn|jMItZffvcw3nNmi*{} zfwr!{1%+Xk8<~}HSj-<)S0cBF`GM|jVc$p5XAvVSHrXIV+sW#Xm|v=^lB}evH2Q9< zZn+i7uYBpo!6u=n?S)Fd7ID$GsV$HUR~qL^Q?*;7GM2vhWzmA6=wDiGT`oz$);0M@ z7Aarb0`fixmS_1#T)y{OTc!j)Y)IoLAt*>DYX5qD9!qyYQuI{{`AA8_ zt^ScEzBcRtecsF8F>e9p4LpntH+Y*2UU`fXXyCP=mjvlPvvnmJ+pQ#e0jW~~?S&-e zHb}v^A*kp(l$H^DqQ0$+%sMqptCWeT>4%t%6HlQN9v zjn!Fr=S3s9O4t_gU_4lE4K5TL3)lH3H*OI&`BEFVm}-3E8n>94E$||O+S-+ZHGJ(l zbgw9p3(xx=hDcqSHw`14L1aWuptX^L*lYSIPSZ{tSPWKfqBR+`Y7@0rmA;G|4D|f^bUdQ-5GI9G z2iQYF`k(u@bGYY{sp$R9HsyG0Y^U5w)RLmB^+Wna*%wAWRE)mi+8{)q8S-oMdwRYx zHTQ*n7W0kcb4XEDA1>C|PEC$-era>R?|k$mJp-5RW_X_AY4kd^4OV|t#1qgAf^TTW zYE6%aPcn?X1A3P6w-G|^k*Lm3JEo?kPffmWQ~d)hDSI=kS6%5-lh$pjsjJ^qGsn@n zF8%4`&hGSpu*2aO9n?s8y&NQGbd01Zo@VUeqqscThhyee{+)a&fMW&iP+Xk^etx{-c(h z-2cv-&JEL6n6PATN?8fCj*aSoG(Bk-db<*_qH20}Rx*9%6(YdiWOZKll%#e%;@j~( zbA!4*J1g-Z(7_36OZK$HJZ$g0H1(D2^Fp1v=ccR#H_iaJ+IN#jn5EvBGhNuB-kFml z998en$w@4miEp|DwN03$zLe9xjC9iyni(A{jFAP@n%OvN7}-FrnQ501axIQ2^B5yD zs5Rreib~#2wQa^m!L6p`Rtsy?2XpUo(uWNV32YKuf|kB&=+YI~WLA#0(NJN6iU)uX zV%81v&(RZ&{1WgfK(D!Yz6tn@+YU^Qqk$wFdj>6i80mNdqr-TsVH`>Bp#h_a?5o%j z^yx)&0Dh*zlH|ly6 z4=jpXTntR#xp7<$ER9i61*~125I_dh0#g}5B?XTdIQ}ce6TtBVCw;#Go{Joq5B-|O z&lwZqKV!UV;Li<#5ny_F#|@&NGw7C!hxCNOAOD%-4B;_LB;eghKPN2KtcVspCM1;i1Y|Kf&XDBNM-4)lq^N*KqU_=f!%O` zXcW;k#(1$YzR|$(AB$wd?V_wtz&6?e!q{Jrb{iAc8xiURrbic%$-pjj;vu&qae*)L;Q6K;S diff --git a/scripts/basic/fixdep b/scripts/basic/fixdep index 52b0b35897315e149c57a2bd0927616843e17631..942fd7c59a82fc3c3ba9ff3bbefb114ca4d1aed2 100755 GIT binary patch literal 8881 zcmds6dvILUc|Wq&W+McW!4Db)y&cv;f_Nnx*+xbN+mbCiaq!xbA7JCldiP3q)s=SH zy=%!liae6R%VrZ#$pkk;2Rr69DQyD-DJ7H&FlFm9^P#~!KK35dA{9Y}8NaKgJee-}WLMQ0YO-NAVlZ9MXBQqX+wkBE3*k9UZZ*+PRS$0FUMiUya58o>6%*a* zOrqcG78xg+B+hzq)Rdk~ExvvxgNk0<)=T-J%BoGxg8`l5+` zkxD!Lu$PIs84*jSvX1Cjw{~Tly)b;$WUh(b<2o?yGk+B_?ipXqF$NgJOcy2+2=PjB z6nU1_N<2;ch(e?$#J~&$I%8ovCdqQ}b1?YrcDM<8z{$AsEW zj>&d2IVM(|9Kr6AVO`MjPJ$9E9-z+hE?yez@NX!v%BgD%k=190(iJK(m zh`2WsTM~0*Ty|)pR$`8jn--z9U?vsyx_lg$am~YW#g|yaM))dUKv;3&@-| ze6reQVfonbk=mnU`+>`g4xm==mAw`2J8-Zx8_m8L2yxbzK0r61Q(Ip2T{gDpN&LIF zejQr>2+8n~x-t0DiRdV757nMnl0OYM&hLIk1Yex~AXK^37Xud@W*$nB@}ftPE5%Uv zFmv#M-W6t3;m|?+RlL!1?9OL~j|8`k(bYVg`te6+9dc21)0WL>vicA$emLw{AS%AG2-heAWGGpcgGX&Eit z9TNshn=poGWET2m727HzrMVat>0#w`<#}~y*$Z71 zDSZ##RbE0Lq(kF@%Br@!#KT7}+Q#vLnHQ&1fe)cqxL@3lPCWp7di>a*JtwO%FA7hF zEVBDUA+XNPrJ2yW@dk|1xqFUKL3)OfglGpu#bl@s{&sHORBD79`wH0*BAC(3Ss7#($C-~*W!r3 zh8TnmUz?>y6ct3F?!dlFPrQQoQqKUxX%&*8P{j|5TLUdW8(1>&eOQLAW$UkBy|!kA zudZdtb<~V}hgsz8nvuU#I>TeAQgc@xs8G4A4K;EvY&_7$|gwg6Qt_l`XG(kK9vL^W5`zx`ESy zj$rQO&5? zwps>T&3!M_{Pk%43pLNZ05Rv^q5TLA)%^gPAKMsl*P!QWT9$tMKQj3Fom2YD52de+ z{v-l(uvc`JI#8A$mlLUG-`AiODYl1dBb$3GOaFnYctC5U&|8ZU=oOoLr}b7udPV60 z2=imZN37xZ%ieX6VN{k!N+Ar(4O^M-EPa(K&7o2|IBX0biErDX;<%}FA#pMAiJWYkVP)UGek&)f{2J&hS%wq6A8>$D(e^mKc=!?koF5Oc4 z_6O2~{P^C{nvn>?Hb2(z;fBsF=qhGlGwRFG-+H57p?=7w&O`C)(w!=lTi)H(h4{C; z>elUEu(hgY?=LV`t6Sb3n8?4^@=?vm&o(;$F;2{Vmj)bYebB_Mv3YkvcPV-8Yr3+DPdM*t%gGruI|r z`OuV4t@O7j+;Jlc58{cSXja6%kY-lE%r@nh@}YL(HiThmH_8ja{2%1nmH$a`OS$H` zj`HciilF!A#C&M9yjyeE#o(=0&B%q|`SMer*xk|*8|bnpj$IF=&oQr6LejZL03kv zF>EsE=28Vg_iyj{f-Zl0gKF7biqX(B<7H@2^C7?HWF$VIrFSdorz0_phIZ)wWT0fC zaRwdW`?E7rxTzYiZ@m6Wn;1oR1Os?0{}A#*Ti`GUqR!OV0li*@HiHS+H3AOl_?n=*hUNL8)D-j?glxRFZe!lgYs{9fIZjrKT8t?tBN+(}!l`0Gw2oolUDe7E;F9x}1MI5vOI zwN=7G3e^uJlJQtH6Sormv1BgpG{#c>-HD#YdD*brU~R|ur!uzG$|i1gQr-3Ves8e; zVwu%!r83q)Ce`0#IsNfOwBN~Que0V|HdrOlhCMH9EnQ~K%T`qx1AXd~pDzl$Mog(S znUR|Y(^xv1$vT$YO;ibVBdZO*jr!!|~9UWzVAPnzv zGUzhgf{Chm*`?^aw%Y(7&w{0s4pTXiwVb}Rw;SWYgoj=BbLRQ+!F>YvsKLE~Aosz? z^nPs39_$5xuO7zU0K5cDQ$GW7|B8i0?ybS(p0*iL$VGJ@hxR#Ta+3}sqb61~xlX?ezdfTD5{WJ6)@#%379{-GXAA=spnC;4Q zT6=OEONCfroI;_oXXJj)^@CWQ^s9A3VbwC%1BF!!oc9W=1~|VJ zR!_^kM=SM7Gv}+4b0t#mV})h0;QUjVGg8enh1CZH=aa&mnVA3j9a$;A9@KY(lJhG< z%>#uo8ITz73iBjf#kIm5Ih-9LE*0ie!P(&?=2wG?NAgO&!ZPj@R*}N^Qdpe|GmaFV zLnh-zVgJfOdlyN$`K!cTia%9Oneo)WSU$(N?*BCOUwN!*1;m@>I%GL-SyF+>;96?> zR{`y-fldD^aFV_XSRSBB{kd|T<>4A2>dz6|!1wvuy9M}JAO2+fcR;??*Zw`g{Eh*G zy_w=ZaPvGWa5M1`u-~7@fgi;>28Ot=7B4cR6Z>}zd7d3G(&*n$wanaGoCG%CV>9u* z-qmt*ZqIwDU%~&&P<{dIe_l@vbFXnFFxOE=_DtNGEYxyy&(W@NNY)o(3vjX!2tEK# zd%Qm|<6k@N&GG>7fxGc7sN2gE-xCP_SmOi0vw+uYd=Pk_9{-us=7_%sW{QFsjsF77 zb5-`A?Y&G4edX_5@dmKFFA#h}%YO;H2KW+(QUI#*YItnR}#Hfc^IWOUuo@(p$i0{#uBy zkF?y}Gu2=T4_uA$_`S4WEgk{p*{vDxCxHF;Ue5zFnR~Av0h|8UqW{OW zoH`ch9gWR=IuC~Z?Oz7WQvuW7mB>8l!wV_U$s&(ogX_B{6S0h!^>W?a;TW!~+PcZeFxxiAa+zMum9F?n$P0Mw7Pu9=D^pK_S1> z?Rc)QZ?|b+)%ERX?HjOqsBhJlFER_`j2<9UR-jyqe7>fLGE9niOheu2Ip^cTsK02^C%n@1UF zkoy%on#n|W+cDcgR#6`RO6`bg{PF;>5TIU+q}E=>+tH=k8MY8G3}0Z>sPK=XRlwqx^q>R-L+!nx>cA> zi~=4`o$Z&;yc!qvlz865V4hT*dZ*ki@13W#Yx}zR$FIdz_{)pyvo){6gP7V&<%S6p Mbs7hyDVOU13zcfVhX4Qo literal 8848 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 diff --git a/scripts/kconfig/.conf.o.cmd b/scripts/kconfig/.conf.o.cmd index a4bd4e685..6db9a9117 100644 --- a/scripts/kconfig/.conf.o.cmd +++ b/scripts/kconfig/.conf.o.cmd @@ -9,9 +9,10 @@ deps_scripts/kconfig/conf.o := \ /usr/include/features.h \ /usr/include/sys/cdefs.h \ /usr/include/gnu/stubs.h \ - /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stddef.h \ /usr/include/bits/typesizes.h \ /usr/include/endian.h \ /usr/include/bits/endian.h \ @@ -24,7 +25,6 @@ deps_scripts/kconfig/conf.o := \ /usr/include/bits/time.h \ /usr/include/sys/sysmacros.h \ /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/sched.h \ /usr/include/alloca.h \ /usr/include/stdio.h \ /usr/include/libio.h \ @@ -32,7 +32,7 @@ deps_scripts/kconfig/conf.o := \ /usr/include/wchar.h \ /usr/include/bits/wchar.h \ /usr/include/gconv.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/include/bits/stdio.h \ @@ -48,7 +48,7 @@ deps_scripts/kconfig/conf.o := \ scripts/kconfig/lkc.h \ $(wildcard include/config/list.h) \ scripts/kconfig/expr.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdbool.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdbool.h \ /usr/include/libintl.h \ /usr/include/locale.h \ /usr/include/bits/locale.h \ diff --git a/scripts/kconfig/.kxgettext.o.cmd b/scripts/kconfig/.kxgettext.o.cmd index 69ebd9d53..27cef9a55 100644 --- a/scripts/kconfig/.kxgettext.o.cmd +++ b/scripts/kconfig/.kxgettext.o.cmd @@ -6,10 +6,11 @@ deps_scripts/kconfig/kxgettext.o := \ /usr/include/features.h \ /usr/include/sys/cdefs.h \ /usr/include/gnu/stubs.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs-32.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stddef.h \ /usr/include/sys/types.h \ /usr/include/bits/types.h \ - /usr/include/bits/wordsize.h \ /usr/include/bits/typesizes.h \ /usr/include/time.h \ /usr/include/endian.h \ @@ -20,7 +21,6 @@ deps_scripts/kconfig/kxgettext.o := \ /usr/include/bits/time.h \ /usr/include/sys/sysmacros.h \ /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/sched.h \ /usr/include/alloca.h \ /usr/include/string.h \ /usr/include/bits/string.h \ @@ -34,11 +34,11 @@ deps_scripts/kconfig/kxgettext.o := \ /usr/include/wchar.h \ /usr/include/bits/wchar.h \ /usr/include/gconv.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdarg.h \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/include/bits/stdio.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdbool.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdbool.h \ /usr/include/libintl.h \ /usr/include/locale.h \ /usr/include/bits/locale.h \ diff --git a/scripts/kconfig/.mconf.o.cmd b/scripts/kconfig/.mconf.o.cmd index 5433bc5f3..b87b8e35b 100644 --- a/scripts/kconfig/.mconf.o.cmd +++ b/scripts/kconfig/.mconf.o.cmd @@ -8,6 +8,8 @@ deps_scripts/kconfig/mconf.o := \ /usr/include/features.h \ /usr/include/sys/cdefs.h \ /usr/include/gnu/stubs.h \ + /usr/include/bits/wordsize.h \ + /usr/include/gnu/stubs-32.h \ /usr/include/bits/ioctls.h \ /usr/include/asm/ioctls.h \ /usr/include/asm/ioctl.h \ @@ -17,8 +19,7 @@ deps_scripts/kconfig/mconf.o := \ /usr/include/signal.h \ /usr/include/bits/sigset.h \ /usr/include/bits/types.h \ - /usr/include/bits/wordsize.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stddef.h \ /usr/include/bits/typesizes.h \ /usr/include/bits/signum.h \ /usr/include/time.h \ @@ -28,7 +29,6 @@ deps_scripts/kconfig/mconf.o := \ /usr/include/asm/sigcontext.h \ /usr/include/bits/sigstack.h \ /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/sched.h \ /usr/include/bits/sigthread.h \ /usr/include/sys/resource.h \ /usr/include/bits/resource.h \ @@ -48,14 +48,14 @@ deps_scripts/kconfig/mconf.o := \ /usr/include/sys/select.h \ /usr/include/bits/select.h \ /usr/include/sys/sysmacros.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/limits.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/syslimits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/limits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/syslimits.h \ /usr/include/limits.h \ /usr/include/bits/posix1_lim.h \ /usr/include/bits/local_lim.h \ /usr/include/linux/limits.h \ /usr/include/bits/posix2_lim.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdarg.h \ /usr/include/stdlib.h \ /usr/include/alloca.h \ /usr/include/string.h \ @@ -81,7 +81,7 @@ deps_scripts/kconfig/mconf.o := \ /usr/include/bits/stdio_lim.h \ /usr/include/bits/sys_errlist.h \ /usr/include/bits/stdio.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdbool.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdbool.h \ /usr/include/libintl.h \ scripts/kconfig/lkc_proto.h \ diff --git a/scripts/kconfig/.zconf.tab.o.cmd b/scripts/kconfig/.zconf.tab.o.cmd index 05d73823c..1ba1d6f45 100644 --- a/scripts/kconfig/.zconf.tab.o.cmd +++ b/scripts/kconfig/.zconf.tab.o.cmd @@ -6,13 +6,14 @@ deps_scripts/kconfig/zconf.tab.o := \ /usr/include/features.h \ /usr/include/sys/cdefs.h \ /usr/include/gnu/stubs.h \ - /usr/include/bits/types.h \ /usr/include/bits/wordsize.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stddef.h \ + /usr/include/gnu/stubs-32.h \ + /usr/include/bits/types.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stddef.h \ /usr/include/bits/typesizes.h \ /usr/include/endian.h \ /usr/include/bits/endian.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdarg.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdarg.h \ /usr/include/stdio.h \ /usr/include/libio.h \ /usr/include/_G_config.h \ @@ -31,12 +32,11 @@ deps_scripts/kconfig/zconf.tab.o := \ /usr/include/bits/time.h \ /usr/include/sys/sysmacros.h \ /usr/include/bits/pthreadtypes.h \ - /usr/include/bits/sched.h \ /usr/include/alloca.h \ /usr/include/string.h \ /usr/include/bits/string.h \ /usr/include/bits/string2.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/stdbool.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/stdbool.h \ scripts/kconfig/lkc.h \ $(wildcard include/config/list.h) \ scripts/kconfig/expr.h \ @@ -50,8 +50,8 @@ deps_scripts/kconfig/zconf.tab.o := \ /usr/include/bits/errno.h \ /usr/include/linux/errno.h \ /usr/include/asm/errno.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/limits.h \ - /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include/syslimits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/limits.h \ + /usr/lib/gcc/i386-redhat-linux/4.0.1/include/syslimits.h \ /usr/include/limits.h \ /usr/include/bits/posix1_lim.h \ /usr/include/bits/local_lim.h \ @@ -61,7 +61,9 @@ deps_scripts/kconfig/zconf.tab.o := \ /usr/include/bits/posix_opt.h \ /usr/include/bits/confname.h \ /usr/include/getopt.h \ + scripts/kconfig/lkc.h \ scripts/kconfig/util.c \ + scripts/kconfig/lkc.h \ scripts/kconfig/confdata.c \ $(wildcard include/config/config.h) \ $(wildcard include/config/.h) \ @@ -73,12 +75,16 @@ deps_scripts/kconfig/zconf.tab.o := \ /usr/include/bits/stat.h \ /usr/include/fcntl.h \ /usr/include/bits/fcntl.h \ + scripts/kconfig/lkc.h \ scripts/kconfig/expr.c \ + scripts/kconfig/lkc.h \ scripts/kconfig/symbol.c \ /usr/include/regex.h \ /usr/include/sys/utsname.h \ /usr/include/bits/utsname.h \ + scripts/kconfig/lkc.h \ scripts/kconfig/menu.c \ + scripts/kconfig/lkc.h \ scripts/kconfig/zconf.tab.o: $(deps_scripts/kconfig/zconf.tab.o) diff --git a/scripts/kconfig/conf b/scripts/kconfig/conf index ec5c1266224d24ef87b5315e51be0b8aae2b9dd9..d86cae4bdfb97be05b24d29dd9bc3ea68dcdabea 100755 GIT binary patch literal 67944 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 literal 66522 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 O!*rdVNf18p-1)x}y3Qj2 diff --git a/scripts/kconfig/conf.o b/scripts/kconfig/conf.o index 41dc5abe6cd7b472a24e556ee9c1f54c42229702..08e76d5eb2585a6234c116d5fecde355fa04ce1f 100644 GIT binary patch literal 11376 zcmcIqdwdjCmcD6%#u%o9qJpARV4^WfAPfj%lt2gsMGOIX2-r4BCEX$Ej@{LfjIU^S zi@hy^>)TNWR>yJGpE9hoiaJab1X*=gWOa3PXW9L!lm0~=Rx~_(^nTy1Q=!t1v-{81 zkE*Y}bIv{Y+;gAR;ilSov-9%ulyl{&A?heos_qn9Gf6|4`iVMTU9n{G!uV%JsqMYr zX0zGU&UA5VMM-{Nes)$#etKR>zIR(*|E!sLM(m4kx56M>*^|D$B>&524(?eO%w7mn z%Ui!7Yn2o&)DGf1ij$vPC$7sscU@i9yRAN(KBj+GJ&GS6-%+&uD&NZO>pIoWJT=$5 zZMdkcPX_bYzP`Pwe#Dd>#yFF^W5>lW;+x0Hhm-9MtwRH(t;!BLzeH*-`fG}^AC}ma zU&8F@(i@P5)b`YSsJ7mAy9-U}uemtSoA?!sb`CZ0EZjMC3_!tZpt*@2t0jGsmL4hS ztXencyZ9kb=dAdVW4wtK@b6vwDN7s~>P=h-8vm>yU_cN!9S;e-7>QwCvL*LGs9392 z2aakMyG;goPBc5T1D&(L@h-QS+32v|E#GIeD4Cs1-{MYKpc^6`j=LJ&>SO?A7iXjS zffHckDx4jf4*`yu^avd%TH%!i$}0Bz!E0%DkoVl%t6Y2S!4o$D8biFkM@m?I_Z{w~1X+S0CWu z)Cu=3&35JoIOa7?O|s_*M!39jp7vP7={Qi~m_eBOLu!BTek=tW4M?jBy~*VWJNcn? zXHE=OcV&+=rMoX;#ju?MTiB&*i?SUB0WLGnxXR3jigRpNdTCL5&W}f)uE8XCVyi#e z1PBLa-O?-V@z}atyH7_)P|JbzVjc(5EIjop{ao*$u(4}h%kUNGGnCWUFd9A}!qb1|7rrz(}_)RwZf;a+Zipq(^PPTVMh0ao zu@_$0^eXsqtTNjmO!ZfVyouW&uIjSqSyj6?si3jP3t~L*9TLMBGe5`h*l@JI%N$Rv zZ&1%A=16@Pxa*s!>th(x-C|B*P8z`N*hIQ`G^w_rCMT=A0?ac#SjIJ1yjuv6`9n(J>>-os^@&ZhwVHgg3 z(AM;6$q!=(mMy;uNj|#BCwgK<{j;lzt#{%#j_}0Z+_VuDRX@sSoiz=Xb|*br00D=* z-WG>g$M#Nxpzq;&PWqhX8fJZodhCps!Q=;9W^vz>$dA1ym8E8tjC95CO>97s^sJJi zbafGQ#py+OovG($y1D?noHr3?Acuxn*T9U5Da8Kjs$y?)GYc<5shLIb-XXMJyPnqA ziL8>5PCny$H}U9NmNG%bhzB_e4&+EY9~&RXMa~o7FwKQj?Bwy>cnwWwqyTsCM+Sd@96uf90GFAqs5 zS&HbL0|z?Un_Q3jQEp^<<_Ok$GH9JQu>gSae6+3ggBI#eCk}X@n(ipJ_YV3wFMVY} ze203Y2ezhjNS3}^`4>8MZ&+Wu-Bijr+e7hDAHb15@R zAY{Z1gBtsY%Osw~DqWAD;CV^lS(gTx7>QwpK{SkQo$j=imHgIaw+ZhUa|PbD9=OSt zBugCS0|&F~TJzxeiojM!hLEv-atw2HVNhVUZqP~M%0DP~$6^)!3gz_F{3tUWmMDl$ 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 T7Uch*qr6UVo?yM;BEkOwHi?f6 literal 10796 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 diff --git a/scripts/kconfig/kxgettext.o b/scripts/kconfig/kxgettext.o index 68539dfe857c0a7b99a68bac1c6d77b8b98d29d2..531fd720480cf020533b0b88f610cac502020982 100644 GIT binary patch literal 2416 zcma)7Yitx%6h8YvhGk$EL?yQBx=gi*Y<3CQh$yw&@`#9q(n0_`S$4N{%f7NRi`5uj zyOTH$O=_aXUncx8@duh1iGiqLrKCuVF_Nf1Fu{mOD~$n7YKZ9go!J?>>@ROJ^PTU! z?z!jQJ9DsW(>j;SMb2=Mhh`X2##^(jw4jydl0bbu<*9%^rhh*qPTVq0vwSw7RaH^n z;nfSmIm>b9uKuyn-tB!oho=^`6Tx|#6wtpO@^#Nd_}{AfKe>ME6f&66s($H@5C8gh z@a*8-rY%(X-#+oXA~dn#4+;nDI<*MX)rA%EpE z=3RrBPl2zwJ7OEzq4bkBtqPjy*KR;P?hcK2xX5@KGHIqNjqH}hk^NMj5_-(Gy22{o z!NE9)z|!UNlsFWyZ2FkBP=Dnsw!SF^+p(~TiQoS~9bBu&H{Rh5mCwv7PtJ;M zoO}$8g1v*6H`xrr{+-gi5MJ|rc=$1-0FHg+q)U?-u>$#K-W3qtP$G z_x@4ixqxk^8rY7xT=_;BycAC3-ZL|iTjrR3)8>?7_15`N-M9+BIDZ#YVLq4l2 zW1W{Psj3TL=^pgK(b7ZNZ7PDPcn9x=?wYv8W)C?YMiU2KEdAP;a>q{diNQy2yX_a) zZ@P437p{gr-K$?gK>3&J<*8<)OEe2!Yrb<{2@$oqb+2UUtXH&per#(#uLhq_#Wp6qO*#|*Ui@{I`%UK_btq!)X-`u-2xH23GM}sROkyVkl z6>Y)Rt*K;iLtL%tm#> z9Hnp~pUtLnaLMJ>R2XwESJZf7A1~~G4el+U*t=|R{`L%eYyz-9Nz?>+&WxH42}IXz z9mlgDRMdipxs&3!BS6Q)$+rwL`#Wa#b8Pi~5fIL|f|VHT_f$=^-fZJ%t&NrvudDD| z?vOg$hB}$ei|Qw>vn_z^)aLl@V8I?dCl5xqCDmRM8aWCjpX#}IIDG&Q_pUzQiP=Q_ zZF7c`&*2W%>%DZtbo7jO{ymu2&%oSE^Xve=9Bx$G3~a?Sjl|4x0) zYv3UiT{k>9HEngA*ZE8X?`q(i8hCF5-w7T>Lk-|UR8(xR9|1oO``fntjRyNW4g6RG ze;>RPZQ^sz`9El|pKRc?Z+LG?S&up8LNT8$AQf}jsRFr@ z`I1WV#uwy5Nlj3pn9ivKm@u8AL_Rkl7ve?5&dyni_>f@&e8@<|+T1vlyhm=3FMuv= z{141=Q2w;-kMP-;k2?iq`vx2TX1$+iHu}%_BqJ`$QATY3yFeE%^?Npc#EAGW8Sf_g z2IyWy^s{Zh%KRRjMVouEFC0Gy$oeMchzl`C+%nr9vF+O#?;}buE+*Q?h&l?43yJ;% Dsenp9 literal 2824 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

bqI^>M0C=wIc-DGJj4W8h5LqLG44hUu5P%z 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 return -EPERM; } /* if attempt to decrement time */ + if (tv->tv_sec > 1924988400) /* disallow dates after 2030) */ + return -EPERM; /* CVE-2005-4352 */ } /* if seclvl > 1 */ return 0; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index fc515fe86..0b32f3020 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -159,7 +159,7 @@ static int task_alloc_security(struct task_struct *task) return -ENOMEM; tsec->task = task; - tsec->osid = tsec->sid = SECINITSID_UNLABELED; + tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED; task->security = tsec; return 0; @@ -1387,13 +1387,19 @@ static int inode_security_set_sid(struct inode *inode, u32 sid) static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) { + struct task_security_struct *psec = parent->security; + struct task_security_struct *csec = child->security; int rc; rc = secondary_ops->ptrace(parent,child); if (rc) return rc; - return task_has_perm(parent, child, PROCESS__PTRACE); + rc = task_has_perm(parent, child, PROCESS__PTRACE); + /* Save the SID of the tracing process for later use in apply_creds. */ + if (!(child->ptrace & PT_PTRACED) && !rc) + csec->ptrace_sid = psec->sid; + return rc; } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, @@ -1821,24 +1827,12 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and kill. */ if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { - struct task_struct *t; - - rcu_read_lock(); - t = tracehook_tracer_task(current); - if (unlikely(t == NULL)) - rcu_read_unlock(); - else { - struct task_security_struct *sec = t->security; - u32 ptsid = sec->sid; - rcu_read_unlock(); - - rc = avc_has_perm(ptsid, sid, - SECCLASS_PROCESS, - PROCESS__PTRACE, NULL); - if (rc) { - bsec->unsafe = 1; - return; - } + rc = avc_has_perm(tsec->ptrace_sid, sid, + SECCLASS_PROCESS, PROCESS__PTRACE, + NULL); + if (rc) { + bsec->unsafe = 1; + return; } } tsec->sid = sid; @@ -2692,6 +2686,11 @@ static int selinux_task_alloc_security(struct task_struct *tsk) tsec2->keycreate_sid = tsec1->keycreate_sid; tsec2->sockcreate_sid = tsec1->sockcreate_sid; + /* Retain ptracer SID across fork, if any. + This will be reset by the ptrace hook upon any + subsequent ptrace_attach operations. */ + tsec2->ptrace_sid = tsec1->ptrace_sid; + return 0; } @@ -4296,7 +4295,6 @@ static int selinux_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { struct task_security_struct *tsec; - struct task_struct *tracer; u32 sid = 0; int error; char *str = value; @@ -4385,24 +4383,18 @@ static int selinux_setprocattr(struct task_struct *p, /* Check for ptracing, and update the task SID if ok. Otherwise, leave SID unchanged and fail. */ task_lock(p); - rcu_read_lock(); - tracer = tracehook_tracer_task(p); - if (tracer != NULL) { - struct task_security_struct *ptsec = tracer->security; - u32 ptsid = ptsec->sid; - rcu_read_unlock(); - error = avc_has_perm_noaudit(ptsid, sid, + if (p->ptrace & PT_PTRACED) { + error = avc_has_perm_noaudit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, &avd); if (!error) tsec->sid = sid; task_unlock(p); - avc_audit(ptsid, sid, SECCLASS_PROCESS, + avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, &avd, error, NULL); if (error) return error; } else { - rcu_read_unlock(); tsec->sid = sid; task_unlock(p); } diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 116b17bda..940178865 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -34,6 +34,7 @@ struct task_security_struct { u32 create_sid; /* fscreate SID */ u32 keycreate_sid; /* keycreate SID */ u32 sockcreate_sid; /* fscreate SID */ + u32 ptrace_sid; /* SID of ptrace parent */ }; struct inode_security_struct { -- 2.43.0

QvzR=_6qDN9CyAz=IX@x zuJ+=zS^0TN#(_zL2n+edh{$=%uSI_bxpkaB+sko8%CFR>oum~&B{ zOQ0j$X92RFxe@EHmilI?Zx@`uy2yS$;*Cn#QhzP$A>U1c?KR(QQ z9QeK^^-l==DeK`R&k=__%rPpKDRn~dKMGz0S{2Q>uK*<7_XwOXkhufvR|s4uaECzV z3T#ghE?4RUgzzWk2o)_#eMss*BK5aQ{pSf=F`ul5e9Q?d+HlSzT%pu=SdYIS2z*B1 zi-hR^J3#iI!ZQo{zX_22FA#W%z$UiiV7Q8K6@E>h5C`C1!uKl`1)PMr`yg@j`vl=N zIGeH_Ho8mT{j6`tZ%z|p(T%en_J5iar#JCp(pNtEZ3S5|62*~<(2&|X- zMnaEL9a6uE5c+LrJr;FP>Z1Zb$a?VGPaOO|LA+C`+lYhz!^FGr1L=g_O8t}&`o1RZ zRp%OfCLsCDCXNID6@;xyHA#C1;Re`?5d1;{V}Rt75_m1^H)5U%H!1aD)`RZHiEl2vWZx1brSbIqsbTn+0|V+##?}U`*hRgpg;y;9nB_Yl44I;A?;t z+YnE2&LyAA0lB`K3AZctenPCTb<)03@CYFe`U8ZB3!{Wy_y^!5$o@s*822FIPS~5! zr_^b-L$0^-jEwrlgguDQfaLENXtN%4_Yg<_wA9}%_4f%rF7RiB==Xxa3LLkIUjRrt z4T3Kw1fN#HuMvEw;6Z`c2^Yku!+OxUQ}BZVe<<+x zYzLil-fZZFog;*f7t+CL`v-wA%F;CBoDu)s&9{z-w)6JlR{D-MjL=LW3s zO-YxC-vL5mt7W|(DJ|pl2!gnHW1F|13 zUNqfmLeyUb$oi#H-zxZO;^4DG>iY@N-o+_6}?KG zBHX4_=Y@c~5O)c&-ot>@J5C&O?IXmxzl-&d=U<42Ku6%@x0w35fUI9BaESHbccZ|Y zSszARBo6vtCJy@F6Z}a+(EpX-zZLijA@&a@h8#Da5Om)suobYP5AlUK?6ZS7=%$II z|3?Tx_p^fky})}3LHD5GFA4kuAmiE;-1~Ced4QyMA#u=i6M}yS>#xTBqtt&u;Ee)5 z!FI&M2L(SW@W-r2Jo%~MZ@$RTy9lsiH=d~whaU5ZgYSCc;M*_ImiliHMsRP>ddT^d z)Sn=Z{-*?gRoX9jo2j1;NV*pj$GFP{HVV9k?a<3l9CWS|c$2_S6Jp#QfTZ(vsee%5 zQGt&W!cMOMavyl}bVKiAK+>Njc)P&s1f~fwZXY1m+nt2)tNWz=`vQMNh<^XdcJw zLrOhH9P&I(i1EK*J;uL49Q}Sv9Q~eTez8pH7yIL%9>@O_fbu^o@cROf34B7}Qv!b? z@L7TU9eIw=3Vc!E34wnQcv|4A0@X}2Zi>K4fmH%)1Wpq;UEmCXmO!__T7h)}=L=jY w@G60g0+$JF6}U=ZyFib?Zh@NwZWFjuU_f9(zX%G^x&QzG literal 29252 zcmeHwdwkT@nfJ*Bjbqx02yI$Xf3iUWCIJ+@V2p$$5K4fN1PCC+$;>1(VKOt${3aL6 zDl|zoon=dRZMUDdwhPtX-rCFdwe_-UQ=y{WzVF+M?YgDiS}*OyV70AMyk@`ObDrPa zfbOO5{_}nqnLOt?m*+gU^PK0L-^_ShOWUfVq9WzIid2cpVoH6o-Lx##pjx?Axf(fE zv9GzR)Dt|vL#aNMertMqdgO4$*hKPt_x+_+ceAVe{^qLUyGv0zNOWw%J^CfU)NEFb z{m9;~t4B`Ey!BjDH}b}Y+b*A8#?F1UeMLbQG-au)LEU1fZshQ+z9KVkx>V1%Z{?eM zwvof-henQ-XNPOX>{)%P&()_qdW>|eIH-AyimJa|ufDGz9rWv7F11vJp6 zKs)s=7RH`*k6ogP5Ua#{awgDy1JqSeRZvaA1C~-pX0XEnypPPNLN)6&Pe)3tZql^} zD5Nf_C8m@P6D_TJH$eI(Q?^)!_QAp&%A1-^YAM&)lgYESX2*+RqFEa~({@#*(V(8D zNYBqf;7xaYT&ZbOsTnFgG=5yu18sGXM8_*eCQ9#S>68>xv)Qxgv2hI_FLtP5icMQK zw~riKoVu~9H5IOEo=%hp-;chVG$*O1InyyKwE}<3f|ur0SBxCCpzX^?u0Gp6`Yako zj+F(MXF7CsZkkS1XcAj@2G?ZjX^W;gsm{_R$M?R8T4l$_=iHatUb;%q86)qUee1EY z6&UP*UTj^A&H#1j}&A2^}~;i z9In~EvulUZp>Z}ecrY%tq7>_6#sgju^91`cB+)$ejlDyhU%AK5gVRhd!=L>|ca_lF z;*?!gV{}GZ)5+4{06K3rTHLV$m19T8pSEZ3PpvJdBR+!G)CFTllP{-QRxFtwn;1W2 z&m8$+*;#g;wZJ1`21hwM-41q}&PnR&Ku-#ndc z(^GbC(~_I{$^IjbGO|^7@7Hr&%9c-Mhe!Qcqa>-E$GIrdqN}UBq zx@h0-sDkhh{@gp$)2Y(WP-hd#Dd=c6C%+ey)44Mi1I02>EFa%gI^M!H2DOZ* zcRW@KXDmNhiiHWnr6$&t^%dtVFoY4bQc$Yq7yGdU_8z+z_`dt9?#jrxb$eg2qpfoA zH*3pgiKCs{5UGl_dX9`%Ss3^he4}%pDet?hY7VLlpJ=~_6DfryQ{JcA`{w9zdet7$ z4cl{Cxq&0jU@$blX23u#|e}0Mi9ZmMbFs1dkVS;CFOL{=VC=p7_sFQ}h(9@^3h!!!>{jKJz8G8>OfS|CW=I5}( z58^7Sg*W&}@P`gI^?dsL*Qcj%(4>r6(PVl)0H5TRH}xgcthpx_87+2Zbk&uq+rCrp z0n^Kw_VMEgmX+y$!kiE+_#EeozcD@S>6;N81(Mll;ilVAkFitivmWJk^tq>? z&y}XnarRkg%CED0ktx5$@=TP|Tg^fno7nv!`|{T0LaqokhbAfm*|!VG9y&)GW3pXq zpmMubC%r`rG=2!?v$kz*_oP37C{nmGOW7Daf74FeutQ{zGi{>r0r5+KYa{LG1 zNtcd1Qv`w>Fu?&k%ix7v)kjm&3Mdv-m3=WrX67E9u+O<>SGjxi4)$ks{S}&1U9${r zLu`x--?Mqi#0Wx;a({fHb>x}HM<#4f@Denn?>V8Zb}7rPC}R+4WZ3r{ttt_C%BlCJ@7}(+m$Tei*ovx_ycOG(yCNv+1OG0Aq?}3=&6g-1DI^2 zmh*Gtn?gJ_8^{0Tpkrm5gV&MHeTD>;QDk35Q0yLa(Qn=?dSo3{>>hcu_>qMy&3MED z7=IC?-H$%z2{wYj|&^aNM2?IE;{ V>0baZ8EwJJq{RJAn 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%0D| diff --git a/scripts/kconfig/zconf.tab.o b/scripts/kconfig/zconf.tab.o index 245fb0b3aec5161c14bae46f97d356d4ca596e2e..9ae622f5028b1c0fadf50acc03a930f87f56b998 100644 GIT binary patch literal 70500 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 z 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