📄 sys_sparc32.c
字号:
/* $Id: sys_sparc32.c,v 1.171 2000/12/13 16:34:55 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * * These routines maintain argument size conversion between 32bit and 64bit * environment. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/fs.h> #include <linux/mm.h> #include <linux/file.h> #include <linux/signal.h>#include <linux/utime.h>#include <linux/resource.h>#include <linux/times.h>#include <linux/utsname.h>#include <linux/timex.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/sem.h>#include <linux/msg.h>#include <linux/shm.h>#include <linux/malloc.h>#include <linux/uio.h>#include <linux/nfs_fs.h>#include <linux/smb_fs.h>#include <linux/smb_mount.h>#include <linux/ncp_fs.h>#include <linux/quota.h>#include <linux/module.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/cache.h>#include <linux/nfsd/xdr.h>#include <linux/nfsd/syscall.h>#include <linux/poll.h>#include <linux/personality.h>#include <linux/stat.h>#include <linux/filter.h>#include <linux/highmem.h>#include <linux/highuid.h>#include <linux/mman.h>#include <linux/ipv6.h>#include <linux/in.h>#include <linux/icmpv6.h>#include <linux/sysctl.h>#include <asm/types.h>#include <asm/ipc.h>#include <asm/uaccess.h>#include <asm/fpumacro.h>#include <asm/semaphore.h>#include <net/scm.h>/* Use this to get at 32-bit user passed pointers. *//* Things to consider: the low-level assembly stub does srl x, 0, x for first four arguments, so if you have pointer to something in the first four arguments, just declare it as a pointer, not u32. On the other side, arguments from 5th onwards should be declared as u32 for pointers, and need AA() around each usage. A() macro should be used for places where you e.g. have some internal variable u32 and just want to get rid of a compiler warning. AA() has to be used in places where you want to convert a function argument to 32bit pointer or when you e.g. access pt_regs structure and want to consider 32bit registers only. -jj */#define A(__x) ((unsigned long)(__x))#define AA(__x) \({ unsigned long __ret; \ __asm__ ("srl %0, 0, %0" \ : "=r" (__ret) \ : "0" (__x)); \ __ret; \})extern asmlinkage long sys_chown(const char *, uid_t,gid_t);extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);extern asmlinkage long sys_setregid(gid_t, gid_t);extern asmlinkage long sys_setgid(gid_t);extern asmlinkage long sys_setreuid(uid_t, uid_t);extern asmlinkage long sys_setuid(uid_t);extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t);extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t);extern asmlinkage long sys_setfsuid(uid_t);extern asmlinkage long sys_setfsgid(gid_t); /* For this source file, we want overflow handling. */#undef high2lowuid#undef high2lowgid#undef low2highuid#undef low2highgid#undef SET_UID16#undef SET_GID16#undef NEW_TO_OLD_UID#undef NEW_TO_OLD_GID#undef SET_OLDSTAT_UID#undef SET_OLDSTAT_GID#undef SET_STAT_UID#undef SET_STAT_GID#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)#define SET_UID16(var, uid) var = high2lowuid(uid)#define SET_GID16(var, gid) var = high2lowgid(gid)#define NEW_TO_OLD_UID(uid) high2lowuid(uid)#define NEW_TO_OLD_GID(gid) high2lowgid(gid)#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group){ return sys_chown(filename, low2highuid(user), low2highgid(group));}asmlinkage long sys32_lchown16(const char * filename, u16 user, u16 group){ return sys_lchown(filename, low2highuid(user), low2highgid(group));}asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group){ return sys_fchown(fd, low2highuid(user), low2highgid(group));}asmlinkage long sys32_setregid16(u16 rgid, u16 egid){ return sys_setregid(low2highgid(rgid), low2highgid(egid));}asmlinkage long sys32_setgid16(u16 gid){ return sys_setgid((gid_t)gid);}asmlinkage long sys32_setreuid16(u16 ruid, u16 euid){ return sys_setreuid(low2highuid(ruid), low2highuid(euid));}asmlinkage long sys32_setuid16(u16 uid){ return sys_setuid((uid_t)uid);}asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid){ return sys_setresuid(low2highuid(ruid), low2highuid(euid), low2highuid(suid));}asmlinkage long sys32_getresuid16(u16 *ruid, u16 *euid, u16 *suid){ int retval; if (!(retval = put_user(high2lowuid(current->uid), ruid)) && !(retval = put_user(high2lowuid(current->euid), euid))) retval = put_user(high2lowuid(current->suid), suid); return retval;}asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid){ return sys_setresgid(low2highgid(rgid), low2highgid(egid), low2highgid(sgid));}asmlinkage long sys32_getresgid16(u16 *rgid, u16 *egid, u16 *sgid){ int retval; if (!(retval = put_user(high2lowgid(current->gid), rgid)) && !(retval = put_user(high2lowgid(current->egid), egid))) retval = put_user(high2lowgid(current->sgid), sgid); return retval;}asmlinkage long sys32_setfsuid16(u16 uid){ return sys_setfsuid((uid_t)uid);}asmlinkage long sys32_setfsgid16(u16 gid){ return sys_setfsgid((gid_t)gid);}asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist){ u16 groups[NGROUPS]; int i,j; if (gidsetsize < 0) return -EINVAL; i = current->ngroups; if (gidsetsize) { if (i > gidsetsize) return -EINVAL; for(j=0;j<i;j++) groups[j] = current->groups[j]; if (copy_to_user(grouplist, groups, sizeof(u16)*i)) return -EFAULT; } return i;}asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist){ u16 groups[NGROUPS]; int i; if (!capable(CAP_SETGID)) return -EPERM; if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16))) return -EFAULT; for (i = 0 ; i < gidsetsize ; i++) current->groups[i] = (gid_t)groups[i]; current->ngroups = gidsetsize; return 0;}asmlinkage long sys32_getuid16(void){ return high2lowuid(current->uid);}asmlinkage long sys32_geteuid16(void){ return high2lowuid(current->euid);}asmlinkage long sys32_getgid16(void){ return high2lowgid(current->gid);}asmlinkage long sys32_getegid16(void){ return high2lowgid(current->egid);}/* 32-bit timeval and related flotsam. */struct timeval32{ int tv_sec, tv_usec;};struct itimerval32{ struct timeval32 it_interval; struct timeval32 it_value;};static inline long get_tv32(struct timeval *o, struct timeval32 *i){ return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec)));}static inline long put_tv32(struct timeval32 *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)));}static inline long get_it32(struct itimerval *o, struct itimerval32 *i){ return (!access_ok(VERIFY_READ, i32, sizeof(*i32)) || (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));}static inline long put_it32(struct itimerval32 *o, struct itimerval *i){ return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));}extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);asmlinkage int sys32_ioperm(u32 from, u32 num, int on){ return sys_ioperm((unsigned long)from, (unsigned long)num, on);}struct msgbuf32 { s32 mtype; char mtext[1]; };struct ipc_perm32{ key_t key; __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_uid_t32 cuid; __kernel_gid_t32 cgid; __kernel_mode_t32 mode; unsigned short seq;};struct semid_ds32 { struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ __kernel_time_t32 sem_otime; /* last semop time */ __kernel_time_t32 sem_ctime; /* last change time */ u32 sem_base; /* ptr to first semaphore in array */ u32 sem_pending; /* pending operations to be processed */ u32 sem_pending_last; /* last pending operation */ u32 undo; /* undo requests on this array */ unsigned short sem_nsems; /* no. of semaphores in array */};struct semid64_ds32 { struct ipc64_perm sem_perm; /* this structure is the same on sparc32 and sparc64 */ unsigned int __pad1; __kernel_time_t32 sem_otime; unsigned int __pad2; __kernel_time_t32 sem_ctime; u32 sem_nsems; u32 __unused1; u32 __unused2;};struct msqid_ds32{ struct ipc_perm32 msg_perm; u32 msg_first; u32 msg_last; __kernel_time_t32 msg_stime; __kernel_time_t32 msg_rtime; __kernel_time_t32 msg_ctime; u32 wwait; u32 rwait; unsigned short msg_cbytes; unsigned short msg_qnum; unsigned short msg_qbytes; __kernel_ipc_pid_t32 msg_lspid; __kernel_ipc_pid_t32 msg_lrpid;};struct msqid64_ds32 { struct ipc64_perm msg_perm; unsigned int __pad1; __kernel_time_t32 msg_stime; unsigned int __pad2; __kernel_time_t32 msg_rtime; unsigned int __pad3; __kernel_time_t32 msg_ctime; unsigned int msg_cbytes; unsigned int msg_qnum; unsigned int msg_qbytes; __kernel_pid_t32 msg_lspid; __kernel_pid_t32 msg_lrpid; unsigned int __unused1; unsigned int __unused2;};struct shmid_ds32 { struct ipc_perm32 shm_perm; int shm_segsz; __kernel_time_t32 shm_atime; __kernel_time_t32 shm_dtime; __kernel_time_t32 shm_ctime; __kernel_ipc_pid_t32 shm_cpid; __kernel_ipc_pid_t32 shm_lpid; unsigned short shm_nattch;};struct shmid64_ds32 { struct ipc64_perm shm_perm; unsigned int __pad1; __kernel_time_t32 shm_atime; unsigned int __pad2; __kernel_time_t32 shm_dtime; unsigned int __pad3; __kernel_time_t32 shm_ctime; __kernel_size_t32 shm_segsz; __kernel_pid_t32 shm_cpid; __kernel_pid_t32 shm_lpid; unsigned int shm_nattch; unsigned int __unused1; unsigned int __unused2;}; /* * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. * * This is really horribly ugly. */#define IPCOP_MASK(__x) (1UL << (__x))static int do_sys32_semctl(int first, int second, int third, void *uptr){ union semun fourth; u32 pad; int err = -EINVAL; if (!uptr) goto out; err = -EFAULT; if (get_user (pad, (u32 *)uptr)) goto out; if(third == SETVAL) fourth.val = (int)pad; else fourth.__pad = (void *)A(pad); if (IPCOP_MASK (third) & (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) | IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) | IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | IPCOP_MASK (IPC_RMID))) { err = sys_semctl (first, second, third, fourth); } else if (third & IPC_64) { struct semid64_ds s; struct semid64_ds32 *usp = (struct semid64_ds32 *)A(pad); mm_segment_t old_fs; int need_back_translation; if (third == (IPC_SET|IPC_64)) { err = get_user (s.sem_perm.uid, &usp->sem_perm.uid); err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid); err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode); if (err) goto out; fourth.__pad = &s; } need_back_translation = (IPCOP_MASK (third) & (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0; if (need_back_translation) fourth.__pad = &s; old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_semctl (first, second, third, fourth); set_fs (old_fs); if (need_back_translation) { int err2 = copy_to_user (&usp->sem_perm, &s.sem_perm, sizeof(struct ipc64_perm) + 2*sizeof(time_t)); err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); if (err2) err = -EFAULT; } } else { struct semid_ds s; struct semid_ds32 *usp = (struct semid_ds32 *)A(pad); mm_segment_t old_fs; int need_back_translation; if (third == IPC_SET) { err = get_user (s.sem_perm.uid, &usp->sem_perm.uid); err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid); err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode); if (err) goto out; fourth.__pad = &s; } need_back_translation = (IPCOP_MASK (third) & (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0; if (need_back_translation) fourth.__pad = &s; old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_semctl (first, second, third, fourth); set_fs (old_fs); if (need_back_translation) { int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key); err2 |= __put_user (high2lowuid(s.sem_perm.uid), &usp->sem_perm.uid); err2 |= __put_user (high2lowgid(s.sem_perm.gid), &usp->sem_perm.gid); err2 |= __put_user (high2lowuid(s.sem_perm.cuid), &usp->sem_perm.cuid); err2 |= __put_user (high2lowgid(s.sem_perm.cgid), &usp->sem_perm.cgid); err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode); err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); err2 |= __put_user (s.sem_otime, &usp->sem_otime); err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -