aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/ptrace.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index d56aa18309f8..3399c1be79b8 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -636,6 +636,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
636 636
637#ifdef CONFIG_IA32_EMULATION 637#ifdef CONFIG_IA32_EMULATION
638 638
639#include <linux/compat.h>
640#include <linux/syscalls.h>
641#include <asm/ia32.h>
642#include <asm/fpu32.h>
639#include <asm/user32.h> 643#include <asm/user32.h>
640 644
641#define R32(l,q) \ 645#define R32(l,q) \
@@ -758,6 +762,216 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
758#undef R32 762#undef R32
759#undef SEG32 763#undef SEG32
760 764
765static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
766{
767 siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
768 compat_siginfo_t __user *si32 = compat_ptr(data);
769 siginfo_t ssi;
770 int ret;
771
772 if (request == PTRACE_SETSIGINFO) {
773 memset(&ssi, 0, sizeof(siginfo_t));
774 ret = copy_siginfo_from_user32(&ssi, si32);
775 if (ret)
776 return ret;
777 if (copy_to_user(si, &ssi, sizeof(siginfo_t)))
778 return -EFAULT;
779 }
780 ret = sys_ptrace(request, pid, addr, (unsigned long)si);
781 if (ret)
782 return ret;
783 if (request == PTRACE_GETSIGINFO) {
784 if (copy_from_user(&ssi, si, sizeof(siginfo_t)))
785 return -EFAULT;
786 ret = copy_siginfo_to_user32(si32, &ssi);
787 }
788 return ret;
789}
790
791asmlinkage long sys32_ptrace(long request, u32 pid, u32 addr, u32 data)
792{
793 struct task_struct *child;
794 struct pt_regs *childregs;
795 void __user *datap = compat_ptr(data);
796 int ret;
797 __u32 val;
798
799 switch (request) {
800 case PTRACE_TRACEME:
801 case PTRACE_ATTACH:
802 case PTRACE_KILL:
803 case PTRACE_CONT:
804 case PTRACE_SINGLESTEP:
805 case PTRACE_SINGLEBLOCK:
806 case PTRACE_DETACH:
807 case PTRACE_SYSCALL:
808 case PTRACE_OLDSETOPTIONS:
809 case PTRACE_SETOPTIONS:
810 case PTRACE_SET_THREAD_AREA:
811 case PTRACE_GET_THREAD_AREA:
812 return sys_ptrace(request, pid, addr, data);
813
814 default:
815 return -EINVAL;
816
817 case PTRACE_PEEKTEXT:
818 case PTRACE_PEEKDATA:
819 case PTRACE_POKEDATA:
820 case PTRACE_POKETEXT:
821 case PTRACE_POKEUSR:
822 case PTRACE_PEEKUSR:
823 case PTRACE_GETREGS:
824 case PTRACE_SETREGS:
825 case PTRACE_SETFPREGS:
826 case PTRACE_GETFPREGS:
827 case PTRACE_SETFPXREGS:
828 case PTRACE_GETFPXREGS:
829 case PTRACE_GETEVENTMSG:
830 break;
831
832 case PTRACE_SETSIGINFO:
833 case PTRACE_GETSIGINFO:
834 return ptrace32_siginfo(request, pid, addr, data);
835 }
836
837 child = ptrace_get_task_struct(pid);
838 if (IS_ERR(child))
839 return PTR_ERR(child);
840
841 ret = ptrace_check_attach(child, request == PTRACE_KILL);
842 if (ret < 0)
843 goto out;
844
845 childregs = task_pt_regs(child);
846
847 switch (request) {
848 case PTRACE_PEEKDATA:
849 case PTRACE_PEEKTEXT:
850 ret = 0;
851 if (access_process_vm(child, addr, &val, sizeof(u32), 0) !=
852 sizeof(u32))
853 ret = -EIO;
854 else
855 ret = put_user(val, (unsigned int __user *)datap);
856 break;
857
858 case PTRACE_POKEDATA:
859 case PTRACE_POKETEXT:
860 ret = 0;
861 if (access_process_vm(child, addr, &data, sizeof(u32), 1) !=
862 sizeof(u32))
863 ret = -EIO;
864 break;
865
866 case PTRACE_PEEKUSR:
867 ret = getreg32(child, addr, &val);
868 if (ret == 0)
869 ret = put_user(val, (__u32 __user *)datap);
870 break;
871
872 case PTRACE_POKEUSR:
873 ret = putreg32(child, addr, data);
874 break;
875
876 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
877 int i;
878
879 if (!access_ok(VERIFY_WRITE, datap, 16*4)) {
880 ret = -EIO;
881 break;
882 }
883 ret = 0;
884 for (i = 0; i < sizeof(struct user_regs_struct32); i += sizeof(__u32)) {
885 getreg32(child, i, &val);
886 ret |= __put_user(val, (u32 __user *)datap);
887 datap += sizeof(u32);
888 }
889 break;
890 }
891
892 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
893 unsigned long tmp;
894 int i;
895
896 if (!access_ok(VERIFY_READ, datap, 16*4)) {
897 ret = -EIO;
898 break;
899 }
900 ret = 0;
901 for (i = 0; i < sizeof(struct user_regs_struct32); i += sizeof(u32)) {
902 ret |= __get_user(tmp, (u32 __user *)datap);
903 putreg32(child, i, tmp);
904 datap += sizeof(u32);
905 }
906 break;
907 }
908
909 case PTRACE_GETFPREGS:
910 ret = -EIO;
911 if (!access_ok(VERIFY_READ, compat_ptr(data),
912 sizeof(struct user_i387_struct)))
913 break;
914 save_i387_ia32(child, datap, childregs, 1);
915 ret = 0;
916 break;
917
918 case PTRACE_SETFPREGS:
919 ret = -EIO;
920 if (!access_ok(VERIFY_WRITE, datap,
921 sizeof(struct user_i387_struct)))
922 break;
923 ret = 0;
924 /* don't check EFAULT to be bug-to-bug compatible to i386 */
925 restore_i387_ia32(child, datap, 1);
926 break;
927
928 case PTRACE_GETFPXREGS: {
929 struct user32_fxsr_struct __user *u = datap;
930
931 init_fpu(child);
932 ret = -EIO;
933 if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
934 break;
935 ret = -EFAULT;
936 if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
937 break;
938 ret = __put_user(childregs->cs, &u->fcs);
939 ret |= __put_user(child->thread.ds, &u->fos);
940 break;
941 }
942 case PTRACE_SETFPXREGS: {
943 struct user32_fxsr_struct __user *u = datap;
944
945 unlazy_fpu(child);
946 ret = -EIO;
947 if (!access_ok(VERIFY_READ, u, sizeof(*u)))
948 break;
949 /*
950 * no checking to be bug-to-bug compatible with i386.
951 * but silence warning
952 */
953 if (__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)))
954 ;
955 set_stopped_child_used_math(child);
956 child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask;
957 ret = 0;
958 break;
959 }
960
961 case PTRACE_GETEVENTMSG:
962 ret = put_user(child->ptrace_message,
963 (unsigned int __user *)compat_ptr(data));
964 break;
965
966 default:
967 BUG();
968 }
969
970 out:
971 put_task_struct(child);
972 return ret;
973}
974
761#endif /* CONFIG_IA32_EMULATION */ 975#endif /* CONFIG_IA32_EMULATION */
762 976
763#ifdef CONFIG_X86_32 977#ifdef CONFIG_X86_32