📄 sys_ia32.c
字号:
"ia32.putreg: attempt to set invalid segment register %d = %x\n", regno, value); break; case PT_CS: if (value != __USER_CS) printk(KERN_ERR "ia32.putreg: attempt to to set invalid segment register %d = %x\n", regno, value); break; default: printk(KERN_ERR "ia32.putreg: unknown register %d\n", regno); break; }}static voidput_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos){ struct _fpreg_ia32 *f; char buf[32]; f = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15); if ((regno += tos) >= 8) regno -= 8; switch (regno) { case 0: ia64f2ia32f(f, &ptp->f8); break; case 1: ia64f2ia32f(f, &ptp->f9); break; case 2: ia64f2ia32f(f, &ptp->f10); break; case 3: ia64f2ia32f(f, &ptp->f11); break; case 4: case 5: case 6: case 7: ia64f2ia32f(f, &swp->f12 + (regno - 4)); break; } copy_to_user(reg, f, sizeof(*reg));}static voidget_fpreg (int regno, struct _fpreg_ia32 __user *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos){ if ((regno += tos) >= 8) regno -= 8; switch (regno) { case 0: copy_from_user(&ptp->f8, reg, sizeof(*reg)); break; case 1: copy_from_user(&ptp->f9, reg, sizeof(*reg)); break; case 2: copy_from_user(&ptp->f10, reg, sizeof(*reg)); break; case 3: copy_from_user(&ptp->f11, reg, sizeof(*reg)); break; case 4: case 5: case 6: case 7: copy_from_user(&swp->f12 + (regno - 4), reg, sizeof(*reg)); break; } return;}intsave_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) return -EFAULT; __put_user(tsk->thread.fcr & 0xffff, &save->cwd); __put_user(tsk->thread.fsr & 0xffff, &save->swd); __put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd); __put_user(tsk->thread.fir, &save->fip); __put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs); __put_user(tsk->thread.fdr, &save->foo); __put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos); /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = task_pt_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) put_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0;}static intrestore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct __user *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; unsigned int fsrlo, fsrhi, num32; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); __get_user(num32, (unsigned int __user *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); __get_user(fsrlo, (unsigned int __user *)&save->swd); __get_user(fsrhi, (unsigned int __user *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; __get_user(num32, (unsigned int __user *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; __get_user(num32, (unsigned int __user *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = task_pt_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) get_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0;}intsave_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; unsigned long mxcsr=0; unsigned long num128[2]; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) return -EFAULT; __put_user(tsk->thread.fcr & 0xffff, &save->cwd); __put_user(tsk->thread.fsr & 0xffff, &save->swd); __put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd); __put_user(tsk->thread.fir, &save->fip); __put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs); __put_user(tsk->thread.fdr, &save->foo); __put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos); /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = task_pt_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) put_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos); mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f); __put_user(mxcsr & 0xffff, &save->mxcsr); for (i = 0; i < 8; i++) { memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long)); memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long)); copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32)); } return 0;}static intrestore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct __user *save){ struct switch_stack *swp; struct pt_regs *ptp; int i, tos; unsigned int fsrlo, fsrhi, num32; int mxcsr; unsigned long num64; unsigned long num128[2]; if (!access_ok(VERIFY_READ, save, sizeof(*save))) return(-EFAULT); __get_user(num32, (unsigned int __user *)&save->cwd); tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f); __get_user(fsrlo, (unsigned int __user *)&save->swd); __get_user(fsrhi, (unsigned int __user *)&save->twd); num32 = (fsrhi << 16) | fsrlo; tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32; __get_user(num32, (unsigned int __user *)&save->fip); tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32; __get_user(num32, (unsigned int __user *)&save->foo); tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32; /* * Stack frames start with 16-bytes of temp space */ swp = (struct switch_stack *)(tsk->thread.ksp + 16); ptp = task_pt_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) get_fpreg(i, (struct _fpreg_ia32 __user *)&save->st_space[4*i], ptp, swp, tos); __get_user(mxcsr, (unsigned int __user *)&save->mxcsr); num64 = mxcsr & 0xff10; tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000UL)) | (num64<<32); num64 = mxcsr & 0x3f; tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000UL)) | (num64<<32); for (i = 0; i < 8; i++) { copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32)); memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long)); memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long)); } return 0;}asmlinkage longsys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data){ struct task_struct *child; unsigned int value, tmp; long i, 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 = sys_ptrace(request, pid, addr, data); goto out_tsk; } ret = ptrace_check_attach(child, request == PTRACE_KILL); if (ret < 0) goto out_tsk; switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(child, addr, &value); if (ret == 0) ret = put_user(value, (unsigned int __user *) compat_ptr(data)); else ret = -EIO; goto out_tsk; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ ret = ia32_poke(child, addr, data); goto out_tsk; case PTRACE_PEEKUSR: /* read word at addr in USER area */ ret = -EIO; if ((addr & 3) || addr > 17*sizeof(int)) break; tmp = getreg(child, addr); if (!put_user(tmp, (unsigned int __user *) compat_ptr(data))) ret = 0; break; case PTRACE_POKEUSR: /* write word at addr in USER area */ ret = -EIO; if ((addr & 3) || addr > 17*sizeof(int)) break; putreg(child, addr, data); ret = 0; break; case IA32_PTRACE_GETREGS: if (!access_ok(VERIFY_WRITE, compat_ptr(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { put_user(getreg(child, i), (unsigned int __user *) compat_ptr(data)); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: if (!access_ok(VERIFY_READ, compat_ptr(data), 17*sizeof(int))) { ret = -EIO; break; } for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { get_user(tmp, (unsigned int __user *) compat_ptr(data)); putreg(child, i, tmp); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_GETFPREGS: ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct __user *) compat_ptr(data)); break; case IA32_PTRACE_GETFPXREGS: ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *) compat_ptr(data)); break; case IA32_PTRACE_SETFPREGS: ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct __user *) compat_ptr(data)); break; case IA32_PTRACE_SETFPXREGS: ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct __user *) compat_ptr(data)); break; case PTRACE_GETEVENTMSG: ret = put_user(child->ptrace_message, (unsigned int __user *) compat_ptr(data)); break; case PTRACE_SYSCALL: /* continue, stop after next syscall */ case PTRACE_CONT: /* restart after signal. */ case PTRACE_KILL: case PTRACE_SINGLESTEP: /* execute chile for one instruction */ case PTRACE_DETACH: /* detach a process */ ret = sys_ptrace(request, pid, addr, data); break; default: ret = ptrace_request(child, request, addr, data); break; } out_tsk: put_task_struct(child); out: unlock_kernel(); return ret;}typedef struct { unsigned int ss_sp; unsigned int ss_flags; unsigned int ss_size;} ia32_stack_t;asmlinkage longsys32_sigaltstack (ia32_stack_t __user *uss32, ia32_stack_t __user *uoss32, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, struct pt_regs pt){ stack_t uss, uoss; ia32_stack_t buf32; int ret; mm_segment_t old_fs = get_fs(); if (uss32) { if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) return -EFAULT; uss.ss_sp = (void __user *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the check and set it to the user requested value later */ if ((buf32.ss_flags != SS_DISABLE) && (buf32.ss_size < MINSIGSTKSZ_IA32)) { ret = -ENOMEM; goto out; } uss.ss_size = MINSIGSTKSZ; } set_fs(KERNEL_DS); ret = do_sigaltstack(uss32 ? (stack_t __user *) &uss : NULL, (stack_t __user *) &uoss, pt.r12); current->sas_ss_size = buf32.ss_size; set_fs(old_fs);out: if (ret < 0) return(ret); if (uoss32) { buf32.ss_sp = (long __user) uoss.ss_sp; buf32.ss_flags = uoss.ss_flags; buf32.ss_size = uoss.ss_size; if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t))) return -EFAULT; } return ret;}asmlinkage intsys32_pause (void){ current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND;}asmlinkage intsys32_msync (unsigned int start, unsigned int len, int flags){ unsigned int addr; if (OFFSET4K(start)) return -EINVAL; addr = PAGE_START(start); return sys_msync(addr, len + (start - addr), flags);}struct sysctl32 { unsigned int name; int nlen; unsigned int oldval; unsigned int oldlenp; unsigned int newval; unsigned int newlen; unsigned int __unused[4];};#ifdef CONFIG_SYSCTL_SYSCALLasmlinkage longsys32_sysctl (struct sysctl32 __user *args){ struct sysctl32 a32; mm_segment_t old_fs = get_fs (); void __user *oldvalp, *newvalp; size_t oldlen; int __user *namep; long ret; if (copy_from_user(&a32, args, sizeof(a32))) return -EFAULT; /* * We need to pre-validate these because we have to disable address checking * before calling do_sysctl() because of OLDLEN but we can't run the risk of the * user specifying bad addresses here. Well, since we're dealing with 32 bit * addresses, we KNOW that access_ok() will always succeed, so this is an * expensive NOP, but so what... */ namep = (int __user *) compat_ptr(a32.name); oldvalp = compat_ptr(a32.oldval); newvalp = compat_ptr(a32.newval); if ((oldvalp && get_user(oldlen, (int __user *) compat_ptr(a32.oldlenp))) || !access_ok(VERIFY_WRITE, namep, 0) || !access_ok(VERIFY_WRITE, oldvalp, 0) || !access_ok(VERIFY_WRITE, newvalp, 0)) return -EFAULT; set_fs(KERNEL_DS); lock_kernel(); ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *) &oldlen, newvalp, (size_t) a32.newlen); unlock_kernel(); set_fs(old_fs); if (oldvalp && put_user (oldlen, (int __user *) compat_ptr(a32.oldlenp))) return -EFAULT; return ret;}#endifasmlinkage longsys32_newuname (struct new_utsname __user *name){ int ret = sys_newuname(name); if (!ret) if (copy_to_user(name->machine, "i686\0\0\0", 8)) ret = -EFAULT; return ret;}asmlinkage longsys32_getresuid16 (u16 __user *ruid, u16 __user *euid, u16 __user *suid){ uid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_getresuid((uid_t __user *) &a, (uid_t __user *) &b, (uid_t __user *) &c); set_fs(old_fs); if (put_user(a, ruid) || put_user(b, euid) || put_user(c, suid)) return -EFAULT; return ret;}asmlinkage longsys32_getresgid16 (u16 __user *rgid, u16 __user *egid, u16 __user *sgid){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -