📄 sys_ia32.c
字号:
gid_t a, b, c; int ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_getresgid((gid_t __user *) &a, (gid_t __user *) &b, (gid_t __user *) &c); set_fs(old_fs); if (ret) return ret; return put_user(a, rgid) | put_user(b, egid) | put_user(c, sgid);}asmlinkage longsys32_lseek (unsigned int fd, int offset, unsigned int whence){ /* Sign-extension of "offset" is important here... */ return sys_lseek(fd, offset, whence);}static intgroups16_to_user(short __user *grouplist, struct group_info *group_info){ int i; short group; for (i = 0; i < group_info->ngroups; i++) { group = (short)GROUP_AT(group_info, i); if (put_user(group, grouplist+i)) return -EFAULT; } return 0;}static intgroups16_from_user(struct group_info *group_info, short __user *grouplist){ int i; short group; for (i = 0; i < group_info->ngroups; i++) { if (get_user(group, grouplist+i)) return -EFAULT; GROUP_AT(group_info, i) = (gid_t)group; } return 0;}asmlinkage longsys32_getgroups16 (int gidsetsize, short __user *grouplist){ int i; if (gidsetsize < 0) return -EINVAL; get_group_info(current->group_info); i = current->group_info->ngroups; if (gidsetsize) { if (i > gidsetsize) { i = -EINVAL; goto out; } if (groups16_to_user(grouplist, current->group_info)) { i = -EFAULT; goto out; } }out: put_group_info(current->group_info); return i;}asmlinkage longsys32_setgroups16 (int gidsetsize, short __user *grouplist){ struct group_info *group_info; int retval; if (!capable(CAP_SETGID)) return -EPERM; if ((unsigned)gidsetsize > NGROUPS_MAX) return -EINVAL; group_info = groups_alloc(gidsetsize); if (!group_info) return -ENOMEM; retval = groups16_from_user(group_info, grouplist); if (retval) { put_group_info(group_info); return retval; } retval = set_current_groups(group_info); put_group_info(group_info); return retval;}asmlinkage longsys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi){ return sys_truncate(compat_ptr(path), ((unsigned long) len_hi << 32) | len_lo);}asmlinkage longsys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi){ return sys_ftruncate(fd, ((unsigned long) len_hi << 32) | len_lo);}static intputstat64 (struct stat64 __user *ubuf, struct kstat *kbuf){ int err; u64 hdev; if (clear_user(ubuf, sizeof(*ubuf))) return -EFAULT; hdev = huge_encode_dev(kbuf->dev); err = __put_user(hdev, (u32 __user*)&ubuf->st_dev); err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_dev) + 1); err |= __put_user(kbuf->ino, &ubuf->__st_ino); err |= __put_user(kbuf->ino, &ubuf->st_ino_lo); err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi); err |= __put_user(kbuf->mode, &ubuf->st_mode); err |= __put_user(kbuf->nlink, &ubuf->st_nlink); err |= __put_user(kbuf->uid, &ubuf->st_uid); err |= __put_user(kbuf->gid, &ubuf->st_gid); hdev = huge_encode_dev(kbuf->rdev); err = __put_user(hdev, (u32 __user*)&ubuf->st_rdev); err |= __put_user(hdev >> 32, ((u32 __user*)&ubuf->st_rdev) + 1); err |= __put_user(kbuf->size, &ubuf->st_size_lo); err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi); err |= __put_user(kbuf->atime.tv_sec, &ubuf->st_atime); err |= __put_user(kbuf->atime.tv_nsec, &ubuf->st_atime_nsec); err |= __put_user(kbuf->mtime.tv_sec, &ubuf->st_mtime); err |= __put_user(kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec); err |= __put_user(kbuf->ctime.tv_sec, &ubuf->st_ctime); err |= __put_user(kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec); err |= __put_user(kbuf->blksize, &ubuf->st_blksize); err |= __put_user(kbuf->blocks, &ubuf->st_blocks); return err;}asmlinkage longsys32_stat64 (char __user *filename, struct stat64 __user *statbuf){ struct kstat s; long ret = vfs_stat(filename, &s); if (!ret) ret = putstat64(statbuf, &s); return ret;}asmlinkage longsys32_lstat64 (char __user *filename, struct stat64 __user *statbuf){ struct kstat s; long ret = vfs_lstat(filename, &s); if (!ret) ret = putstat64(statbuf, &s); return ret;}asmlinkage longsys32_fstat64 (unsigned int fd, struct stat64 __user *statbuf){ struct kstat s; long ret = vfs_fstat(fd, &s); if (!ret) ret = putstat64(statbuf, &s); return ret;}asmlinkage longsys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval){ mm_segment_t old_fs = get_fs(); struct timespec t; long ret; set_fs(KERNEL_DS); ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t); set_fs(old_fs); if (put_compat_timespec(&t, interval)) return -EFAULT; return ret;}asmlinkage longsys32_pread (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi){ return sys_pread64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);}asmlinkage longsys32_pwrite (unsigned int fd, void __user *buf, unsigned int count, u32 pos_lo, u32 pos_hi){ return sys_pwrite64(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo);}asmlinkage longsys32_sendfile (int out_fd, int in_fd, int __user *offset, unsigned int count){ mm_segment_t old_fs = get_fs(); long ret; off_t of; if (offset && get_user(of, offset)) return -EFAULT; set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *) &of : NULL, count); set_fs(old_fs); if (offset && put_user(of, offset)) return -EFAULT; return ret;}asmlinkage longsys32_personality (unsigned int personality){ long ret; if (current->personality == PER_LINUX32 && personality == PER_LINUX) personality = PER_LINUX32; ret = sys_personality(personality); if (ret == PER_LINUX32) ret = PER_LINUX; return ret;}asmlinkage unsigned longsys32_brk (unsigned int brk){ unsigned long ret, obrk; struct mm_struct *mm = current->mm; obrk = mm->brk; ret = sys_brk(brk); if (ret < obrk) clear_user(compat_ptr(ret), PAGE_ALIGN(ret) - ret); return ret;}/* Structure for ia32 emulation on ia64 */struct epoll_event32{ u32 events; u32 data[2];};asmlinkage longsys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 __user *event){ mm_segment_t old_fs = get_fs(); struct epoll_event event64; int error; u32 data_halfword; if (!access_ok(VERIFY_READ, event, sizeof(struct epoll_event32))) return -EFAULT; __get_user(event64.events, &event->events); __get_user(data_halfword, &event->data[0]); event64.data = data_halfword; __get_user(data_halfword, &event->data[1]); event64.data |= (u64)data_halfword << 32; set_fs(KERNEL_DS); error = sys_epoll_ctl(epfd, op, fd, (struct epoll_event __user *) &event64); set_fs(old_fs); return error;}asmlinkage longsys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents, int timeout){ struct epoll_event *events64 = NULL; mm_segment_t old_fs = get_fs(); int numevents, size; int evt_idx; int do_free_pages = 0; if (maxevents <= 0) { return -EINVAL; } /* Verify that the area passed by the user is writeable */ if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event32))) return -EFAULT; /* * Allocate space for the intermediate copy. If the space needed * is large enough to cause kmalloc to fail, then try again with * __get_free_pages. */ size = maxevents * sizeof(struct epoll_event); events64 = kmalloc(size, GFP_KERNEL); if (events64 == NULL) { events64 = (struct epoll_event *) __get_free_pages(GFP_KERNEL, get_order(size)); if (events64 == NULL) return -ENOMEM; do_free_pages = 1; } /* Do the system call */ set_fs(KERNEL_DS); /* copy_to/from_user should work on kernel mem*/ numevents = sys_epoll_wait(epfd, (struct epoll_event __user *) events64, maxevents, timeout); set_fs(old_fs); /* Don't modify userspace memory if we're returning an error */ if (numevents > 0) { /* Translate the 64-bit structures back into the 32-bit structures */ for (evt_idx = 0; evt_idx < numevents; evt_idx++) { __put_user(events64[evt_idx].events, &events[evt_idx].events); __put_user((u32)events64[evt_idx].data, &events[evt_idx].data[0]); __put_user((u32)(events64[evt_idx].data >> 32), &events[evt_idx].data[1]); } } if (do_free_pages) free_pages((unsigned long) events64, get_order(size)); else kfree(events64); return numevents;}/* * Get a yet unused TLS descriptor index. */static intget_free_idx (void){ struct thread_struct *t = ¤t->thread; int idx; for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) if (desc_empty(t->tls_array + idx)) return idx + GDT_ENTRY_TLS_MIN; return -ESRCH;}/* * Set a given TLS descriptor: */asmlinkage intsys32_set_thread_area (struct ia32_user_desc __user *u_info){ struct thread_struct *t = ¤t->thread; struct ia32_user_desc info; struct desc_struct *desc; int cpu, idx; if (copy_from_user(&info, u_info, sizeof(info))) return -EFAULT; idx = info.entry_number; /* * index -1 means the kernel should try to find and allocate an empty descriptor: */ if (idx == -1) { idx = get_free_idx(); if (idx < 0) return idx; if (put_user(idx, &u_info->entry_number)) return -EFAULT; } if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; cpu = smp_processor_id(); if (LDT_empty(&info)) { desc->a = 0; desc->b = 0; } else { desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); } load_TLS(t, cpu); return 0;}/* * Get the current Thread-Local Storage area: */#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)asmlinkage intsys32_get_thread_area (struct ia32_user_desc __user *u_info){ struct ia32_user_desc info; struct desc_struct *desc; int idx; if (get_user(idx, &u_info->entry_number)) return -EFAULT; if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; desc = current->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(u_info, &info, sizeof(info))) return -EFAULT; return 0;}long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, __u32 len_low, __u32 len_high, int advice){ return sys_fadvise64_64(fd, (((u64)offset_high)<<32) | offset_low, (((u64)len_high)<<32) | len_low, advice); } #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid){ uid_t sruid, seuid; sruid = (ruid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)ruid); seuid = (euid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)euid); return sys_setreuid(sruid, seuid);}asmlinkage longsys32_setresuid(compat_uid_t ruid, compat_uid_t euid, compat_uid_t suid){ uid_t sruid, seuid, ssuid; sruid = (ruid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)ruid); seuid = (euid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)euid); ssuid = (suid == (compat_uid_t)-1) ? ((uid_t)-1) : ((uid_t)suid); return sys_setresuid(sruid, seuid, ssuid);}asmlinkage longsys32_setregid(compat_gid_t rgid, compat_gid_t egid){ gid_t srgid, segid; srgid = (rgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)rgid); segid = (egid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)egid); return sys_setregid(srgid, segid);}asmlinkage longsys32_setresgid(compat_gid_t rgid, compat_gid_t egid, compat_gid_t sgid){ gid_t srgid, segid, ssgid; srgid = (rgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)rgid); segid = (egid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)egid); ssgid = (sgid == (compat_gid_t)-1) ? ((gid_t)-1) : ((gid_t)sgid); return sys_setresgid(srgid, segid, ssgid);}#endif /* NOTYET */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -