📄 sys_ia32.c
字号:
*/static longmprotect_subpage (unsigned long address, int new_prot){ int old_prot; struct vm_area_struct *vma; if (new_prot == PROT_NONE) return 0; /* optimize case where nothing changes... */ vma = find_vma(current->mm, address); old_prot = get_page_prot(vma, address); return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot);}#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */asmlinkage longsys32_mprotect (unsigned int start, unsigned int len, int prot){ unsigned int end = start + len;#if PAGE_SHIFT > IA32_PAGE_SHIFT long retval = 0;#endif prot = get_prot32(prot);#if PAGE_SHIFT <= IA32_PAGE_SHIFT return sys_mprotect(start, end - start, prot);#else if (OFFSET4K(start)) return -EINVAL; end = IA32_PAGE_ALIGN(end); if (end < start) return -EINVAL; retval = ia32_compare_pp(&start, &end); if (retval < 0) return retval; mutex_lock(&ia32_mmap_mutex); { if (offset_in_page(start)) { /* start address is 4KB aligned but not page aligned. */ retval = mprotect_subpage(PAGE_START(start), prot); if (retval < 0) goto out; start = PAGE_ALIGN(start); if (start >= end) goto out; /* retval is already zero... */ } if (offset_in_page(end)) { /* end address is 4KB aligned but not page aligned. */ retval = mprotect_subpage(PAGE_START(end), prot); if (retval < 0) goto out; end = PAGE_START(end); } retval = sys_mprotect(start, end - start, prot); } out: mutex_unlock(&ia32_mmap_mutex); return retval;#endif}asmlinkage longsys32_mremap (unsigned int addr, unsigned int old_len, unsigned int new_len, unsigned int flags, unsigned int new_addr){ long ret;#if PAGE_SHIFT <= IA32_PAGE_SHIFT ret = sys_mremap(addr, old_len, new_len, flags, new_addr);#else unsigned int old_end, new_end; if (OFFSET4K(addr)) return -EINVAL; old_len = IA32_PAGE_ALIGN(old_len); new_len = IA32_PAGE_ALIGN(new_len); old_end = addr + old_len; new_end = addr + new_len; if (!new_len) return -EINVAL; if ((flags & MREMAP_FIXED) && (OFFSET4K(new_addr))) return -EINVAL; if (old_len >= new_len) { ret = sys32_munmap(addr + new_len, old_len - new_len); if (ret && old_len != new_len) return ret; ret = addr; if (!(flags & MREMAP_FIXED) || (new_addr == addr)) return ret; old_len = new_len; } addr = PAGE_START(addr); old_len = PAGE_ALIGN(old_end) - addr; new_len = PAGE_ALIGN(new_end) - addr; mutex_lock(&ia32_mmap_mutex); ret = sys_mremap(addr, old_len, new_len, flags, new_addr); mutex_unlock(&ia32_mmap_mutex); if ((ret >= 0) && (old_len < new_len)) { /* mremap expanded successfully */ ia32_set_pp(old_end, new_end, flags); }#endif return ret;}asmlinkage longsys32_pipe (int __user *fd){ int retval; int fds[2]; retval = do_pipe(fds); if (retval) goto out; if (copy_to_user(fd, fds, sizeof(fds))) retval = -EFAULT; out: return retval;}static inline longget_tv32 (struct timeval *o, struct compat_timeval __user *i){ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec)));}static inline longput_tv32 (struct compat_timeval __user *o, struct timeval *i){ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec)));}asmlinkage unsigned longsys32_alarm (unsigned int seconds){ return alarm_setitimer(seconds);}/* Translations due to time_t size differences. Which affects all sorts of things, like timeval and itimerval. */extern struct timezone sys_tz;asmlinkage longsys32_gettimeofday (struct compat_timeval __user *tv, struct timezone __user *tz){ if (tv) { struct timeval ktv; do_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;}asmlinkage longsys32_settimeofday (struct compat_timeval __user *tv, struct timezone __user *tz){ struct timeval ktv; struct timespec kts; struct timezone ktz; if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; kts.tv_sec = ktv.tv_sec; kts.tv_nsec = ktv.tv_usec * 1000; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);}struct getdents32_callback { struct compat_dirent __user *current_dir; struct compat_dirent __user *previous; int count; int error;};struct readdir32_callback { struct old_linux32_dirent __user * dirent; int count;};static intfilldir32 (void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type){ struct compat_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4); u32 d_ino; buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; d_ino = ino; if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) return -EOVERFLOW; buf->error = -EFAULT; /* only used if we fail.. */ dirent = buf->previous; if (dirent) if (put_user(offset, &dirent->d_off)) return -EFAULT; dirent = buf->current_dir; buf->previous = dirent; if (put_user(d_ino, &dirent->d_ino) || put_user(reclen, &dirent->d_reclen) || copy_to_user(dirent->d_name, name, namlen) || put_user(0, dirent->d_name + namlen)) return -EFAULT; dirent = (struct compat_dirent __user *) ((char __user *) dirent + reclen); buf->current_dir = dirent; buf->count -= reclen; return 0;}asmlinkage longsys32_getdents (unsigned int fd, struct compat_dirent __user *dirent, unsigned int count){ struct file * file; struct compat_dirent __user * lastdirent; struct getdents32_callback buf; int error; error = -EFAULT; if (!access_ok(VERIFY_WRITE, dirent, count)) goto out; error = -EBADF; file = fget(fd); if (!file) goto out; buf.current_dir = dirent; buf.previous = NULL; buf.count = count; buf.error = 0; error = vfs_readdir(file, filldir32, &buf); if (error < 0) goto out_putf; error = buf.error; lastdirent = buf.previous; if (lastdirent) { if (put_user(file->f_pos, &lastdirent->d_off)) error = -EFAULT; else error = count - buf.count; }out_putf: fput(file);out: return error;}static intfillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, u64 ino, unsigned int d_type){ struct readdir32_callback * buf = (struct readdir32_callback *) __buf; struct old_linux32_dirent __user * dirent; u32 d_ino; if (buf->count) return -EINVAL; d_ino = ino; if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) return -EOVERFLOW; buf->count++; dirent = buf->dirent; if (put_user(d_ino, &dirent->d_ino) || put_user(offset, &dirent->d_offset) || put_user(namlen, &dirent->d_namlen) || copy_to_user(dirent->d_name, name, namlen) || put_user(0, dirent->d_name + namlen)) return -EFAULT; return 0;}asmlinkage longsys32_readdir (unsigned int fd, void __user *dirent, unsigned int count){ int error; struct file * file; struct readdir32_callback buf; error = -EBADF; file = fget(fd); if (!file) goto out; buf.count = 0; buf.dirent = dirent; error = vfs_readdir(file, fillonedir32, &buf); if (error >= 0) error = buf.count; fput(file);out: return error;}struct sel_arg_struct { unsigned int n; unsigned int inp; unsigned int outp; unsigned int exp; unsigned int tvp;};asmlinkage longsys32_old_select (struct sel_arg_struct __user *arg){ struct sel_arg_struct a; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp), compat_ptr(a.exp), compat_ptr(a.tvp));}#define SEMOP 1#define SEMGET 2#define SEMCTL 3#define SEMTIMEDOP 4#define MSGSND 11#define MSGRCV 12#define MSGGET 13#define MSGCTL 14#define SHMAT 21#define SHMDT 22#define SHMGET 23#define SHMCTL 24asmlinkage longsys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth){ int version; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; switch (call) { case SEMTIMEDOP: if (fifth) return compat_sys_semtimedop(first, compat_ptr(ptr), second, compat_ptr(fifth)); /* else fall through for normal semop() */ case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ return sys_semtimedop(first, compat_ptr(ptr), second, NULL); case SEMGET: return sys_semget(first, second, third); case SEMCTL: return compat_sys_semctl(first, second, third, compat_ptr(ptr)); case MSGSND: return compat_sys_msgsnd(first, second, third, compat_ptr(ptr)); case MSGRCV: return compat_sys_msgrcv(first, second, fifth, third, version, compat_ptr(ptr)); case MSGGET: return sys_msgget((key_t) first, second); case MSGCTL: return compat_sys_msgctl(first, second, compat_ptr(ptr)); case SHMAT: return compat_sys_shmat(first, second, third, version, compat_ptr(ptr)); break; case SHMDT: return sys_shmdt(compat_ptr(ptr)); case SHMGET: return sys_shmget(first, (unsigned)second, third); case SHMCTL: return compat_sys_shmctl(first, second, compat_ptr(ptr)); default: return -ENOSYS; } return -EINVAL;}asmlinkage longcompat_sys_wait4 (compat_pid_t pid, compat_uint_t * stat_addr, int options, struct compat_rusage *ru);asmlinkage longsys32_waitpid (int pid, unsigned int *stat_addr, int options){ return compat_sys_wait4(pid, stat_addr, options, NULL);}static unsigned intia32_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 intia32_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 */#define PT_EBX 0#define PT_ECX 1#define PT_EDX 2#define PT_ESI 3#define PT_EDI 4#define PT_EBP 5#define PT_EAX 6#define PT_DS 7#define PT_ES 8#define PT_FS 9#define PT_GS 10#define PT_ORIG_EAX 11#define PT_EIP 12#define PT_CS 13#define PT_EFL 14#define PT_UESP 15#define PT_SS 16static unsigned intgetreg (struct task_struct *child, int regno){ struct pt_regs *child_regs; child_regs = task_pt_regs(child); switch (regno / sizeof(int)) { case PT_EBX: return child_regs->r11; case PT_ECX: return child_regs->r9; case PT_EDX: return child_regs->r10; case PT_ESI: return child_regs->r14; case PT_EDI: return child_regs->r15; case PT_EBP: return child_regs->r13; case PT_EAX: return child_regs->r8; case PT_ORIG_EAX: return child_regs->r1; /* see dispatch_to_ia32_handler() */ case PT_EIP: return child_regs->cr_iip; case PT_UESP: return child_regs->r12; case PT_EFL: return child->thread.eflag; case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: return __USER_DS; case PT_CS: return __USER_CS; default: printk(KERN_ERR "ia32.getreg(): unknown register %d\n", regno); break; } return 0;}static voidputreg (struct task_struct *child, int regno, unsigned int value){ struct pt_regs *child_regs; child_regs = task_pt_regs(child); switch (regno / sizeof(int)) { case PT_EBX: child_regs->r11 = value; break; case PT_ECX: child_regs->r9 = value; break; case PT_EDX: child_regs->r10 = value; break; case PT_ESI: child_regs->r14 = value; break; case PT_EDI: child_regs->r15 = value; break; case PT_EBP: child_regs->r13 = value; break; case PT_EAX: child_regs->r8 = value; break; case PT_ORIG_EAX: child_regs->r1 = value; break; case PT_EIP: child_regs->cr_iip = value; break; case PT_UESP: child_regs->r12 = value; break; case PT_EFL: child->thread.eflag = value; break; case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: if (value != __USER_DS) printk(KERN_ERR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -