linux32.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,612 行 · 第 1/5 页

C
2,612
字号
	case IPC_STAT:	case SHM_STAT:		old_fs = get_fs();		set_fs(KERNEL_DS);		err = sys_shmctl(first, second | IPC_64, (void *) &s64);		set_fs(old_fs);		if (err < 0)			break;		if (second & IPC_64) {			if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) {				err = -EFAULT;				break;			}			err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key);			err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid);			err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid);			err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid);			err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid);			err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode);			err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq);			err2 |= __put_user(s64.shm_atime, &up64->shm_atime);			err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime);			err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime);			err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz);			err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch);			err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid);			err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid);		} else {			if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) {				err = -EFAULT;				break;			}			err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key);			err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid);			err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid);			err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid);			err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid);			err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode);			err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq);			err2 |= __put_user(s64.shm_atime, &up32->shm_atime);			err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime);			err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime);			err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz);			err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch);			err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid);			err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid);		}		if (err2)			err = -EFAULT;		break;	case SHM_INFO:		old_fs = get_fs();		set_fs(KERNEL_DS);		err = sys_shmctl(first, second, (void *)&si);		set_fs(old_fs);		if (err < 0)			break;		err2 = put_user(si.used_ids, &uip->used_ids);		err2 |= __put_user(si.shm_tot, &uip->shm_tot);		err2 |= __put_user(si.shm_rss, &uip->shm_rss);		err2 |= __put_user(si.shm_swp, &uip->shm_swp);		err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);		err2 |= __put_user (si.swap_successes, &uip->swap_successes);		if (err2)			err = -EFAULT;		break;	default:		err = -EINVAL;		break;	}	return err;}static inline void *alloc_user_space(long len){	struct pt_regs *regs = (struct pt_regs *)		((unsigned long) current + THREAD_SIZE - 32) - 1; 	return (void *) (regs->regs[29] - len);}static int sys32_semtimedop(int semid, struct sembuf *tsems, int nsems,                            const struct timespec32 *timeout32){	struct timespec32 t32;	struct timespec *t64 = alloc_user_space(sizeof(*t64));	if (copy_from_user(&t32, timeout32, sizeof(t32)))		return -EFAULT;                                                                                	if (put_user(t32.tv_sec, &t64->tv_sec) ||	    put_user(t32.tv_nsec, &t64->tv_nsec))		return -EFAULT;	return sys_semtimedop(semid, tsems, nsems, t64);}asmlinkage longsys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth){	int version, err;	version = call >> 16; /* hack for backward compatibility */	call &= 0xffff;	switch (call) {	case SEMOP:		/* struct sembuf is the same on 32 and 64bit :)) */		err = sys_semtimedop (first, (struct sembuf *)AA(ptr),		                      second, NULL);		break;	case SEMTIMEDOP:		err = sys32_semtimedop(first, (struct sembuf *)AA(ptr), second,		                       (const struct timespec32 *) AA(fifth));		break;	case SEMGET:		err = sys_semget (first, second, third);		break;	case SEMCTL:		err = do_sys32_semctl (first, second, third,				       (void *)AA(ptr));		break;	case MSGSND:		err = do_sys32_msgsnd (first, second, third,				       (void *)AA(ptr));		break;	case MSGRCV:		err = do_sys32_msgrcv (first, second, fifth, third,				       version, (void *)AA(ptr));		break;	case MSGGET:		err = sys_msgget ((key_t) first, second);		break;	case MSGCTL:		err = do_sys32_msgctl (first, second, (void *)AA(ptr));		break;	case SHMAT:		err = do_sys32_shmat (first, second, third,				      version, (void *)AA(ptr));		break;	case SHMDT:		err = sys_shmdt ((char *)A(ptr));		break;	case SHMGET:		err = sys_shmget (first, second, third);		break;	case SHMCTL:		err = do_sys32_shmctl (first, second, (void *)AA(ptr));		break;	default:		err = -EINVAL;		break;	}	return err;}struct sysctl_args32{	__kernel_caddr_t32 name;	int nlen;	__kernel_caddr_t32 oldval;	__kernel_caddr_t32 oldlenp;	__kernel_caddr_t32 newval;	__kernel_size_t32 newlen;	unsigned int __unused[4];};#ifdef CONFIG_SYSCTLasmlinkage long sys32_sysctl(struct sysctl_args32 *args){	struct sysctl_args32 tmp;	int error;	size_t oldlen, *oldlenp = NULL;	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;	if (copy_from_user(&tmp, args, sizeof(tmp)))		return -EFAULT;	if (tmp.oldval && tmp.oldlenp) {		/* Duh, this is ugly and might not work if sysctl_args		   is in read-only memory, but do_sysctl does indirectly		   a lot of uaccess in both directions and we'd have to		   basically copy the whole sysctl.c here, and		   glibc's __sysctl uses rw memory for the structure		   anyway.  */		if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||		    put_user(oldlen, (size_t *)addr))			return -EFAULT;		oldlenp = (size_t *)addr;	}	lock_kernel();	error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),			  oldlenp, (void *)A(tmp.newval), tmp.newlen);	unlock_kernel();	if (oldlenp) {		if (!error) {			if (get_user(oldlen, (size_t *)addr) ||			    put_user(oldlen, (u32 *)A(tmp.oldlenp)))				error = -EFAULT;		}		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));	}	return error;}#else /* CONFIG_SYSCTL */asmlinkage long sys32_sysctl(struct sysctl_args32 *args){	return -ENOSYS;}#endif /* CONFIG_SYSCTL */asmlinkage long sys32_newuname(struct new_utsname * name){	int ret = 0;	down_read(&uts_sem);	if (copy_to_user(name,&system_utsname,sizeof *name))		ret = -EFAULT;	up_read(&uts_sem);	if (current->personality == PER_LINUX32 && !ret)		if (copy_to_user(name->machine, "mips\0\0\0", 8))			ret = -EFAULT;	return ret;}extern asmlinkage long sys_personality(unsigned long);asmlinkage int sys32_personality(unsigned long personality){	int 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;}/* ustat compatibility */struct ustat32 {	__kernel_daddr_t32	f_tfree;	__kernel_ino_t32	f_tinode;	char			f_fname[6];	char			f_fpack[6];};extern asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf);asmlinkage int sys32_ustat(dev_t dev, struct ustat32 * ubuf32){	int err;	struct ustat tmp;	struct ustat32 tmp32;	mm_segment_t old_fs = get_fs();	set_fs(KERNEL_DS);	err = sys_ustat(dev, &tmp);	set_fs (old_fs);	if (err)		goto out;	memset(&tmp32,0,sizeof(struct ustat32));	tmp32.f_tfree = tmp.f_tfree;	tmp32.f_tinode = tmp.f_tinode;	err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;out:	return err;}/* Handle adjtimex compatability. */struct timex32 {	u32 modes;	s32 offset, freq, maxerror, esterror;	s32 status, constant, precision, tolerance;	struct timeval32 time;	s32 tick;	s32 ppsfreq, jitter, shift, stabil;	s32 jitcnt, calcnt, errcnt, stbcnt;	s32  :32; s32  :32; s32  :32; s32  :32;	s32  :32; s32  :32; s32  :32; s32  :32;	s32  :32; s32  :32; s32  :32; s32  :32;};extern int do_adjtimex(struct timex *);asmlinkage int sys32_adjtimex(struct timex32 *utp){	struct timex txc;	int ret;	memset(&txc, 0, sizeof(struct timex));	if(get_user(txc.modes, &utp->modes) ||	   __get_user(txc.offset, &utp->offset) ||	   __get_user(txc.freq, &utp->freq) ||	   __get_user(txc.maxerror, &utp->maxerror) ||	   __get_user(txc.esterror, &utp->esterror) ||	   __get_user(txc.status, &utp->status) ||	   __get_user(txc.constant, &utp->constant) ||	   __get_user(txc.precision, &utp->precision) ||	   __get_user(txc.tolerance, &utp->tolerance) ||	   __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||	   __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||	   __get_user(txc.tick, &utp->tick) ||	   __get_user(txc.ppsfreq, &utp->ppsfreq) ||	   __get_user(txc.jitter, &utp->jitter) ||	   __get_user(txc.shift, &utp->shift) ||	   __get_user(txc.stabil, &utp->stabil) ||	   __get_user(txc.jitcnt, &utp->jitcnt) ||	   __get_user(txc.calcnt, &utp->calcnt) ||	   __get_user(txc.errcnt, &utp->errcnt) ||	   __get_user(txc.stbcnt, &utp->stbcnt))		return -EFAULT;	ret = do_adjtimex(&txc);	if(put_user(txc.modes, &utp->modes) ||	   __put_user(txc.offset, &utp->offset) ||	   __put_user(txc.freq, &utp->freq) ||	   __put_user(txc.maxerror, &utp->maxerror) ||	   __put_user(txc.esterror, &utp->esterror) ||	   __put_user(txc.status, &utp->status) ||	   __put_user(txc.constant, &utp->constant) ||	   __put_user(txc.precision, &utp->precision) ||	   __put_user(txc.tolerance, &utp->tolerance) ||	   __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||	   __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||	   __put_user(txc.tick, &utp->tick) ||	   __put_user(txc.ppsfreq, &utp->ppsfreq) ||	   __put_user(txc.jitter, &utp->jitter) ||	   __put_user(txc.shift, &utp->shift) ||	   __put_user(txc.stabil, &utp->stabil) ||	   __put_user(txc.jitcnt, &utp->jitcnt) ||	   __put_user(txc.calcnt, &utp->calcnt) ||	   __put_user(txc.errcnt, &utp->errcnt) ||	   __put_user(txc.stbcnt, &utp->stbcnt))		ret = -EFAULT;	return ret;}/* *  Declare the 32-bit version of the msghdr */ struct msghdr32 {	unsigned int    msg_name;	/* Socket name			*/	int		msg_namelen;	/* Length of name		*/	unsigned int    msg_iov;	/* Data blocks			*/	unsigned int	msg_iovlen;	/* Number of blocks		*/	unsigned int    msg_control;	/* Per protocol magic (eg BSD file descriptor passing) */	unsigned int	msg_controllen;	/* Length of cmsg list */	unsigned	msg_flags;};struct cmsghdr32 {        __kernel_size_t32 cmsg_len;        int               cmsg_level;        int               cmsg_type;};/* Bleech... */#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )#define CMSG32_DATA(cmsg)	((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \				    (struct cmsghdr32 *)(ctl) : \				    (struct cmsghdr32 *)NULL)#define CMSG32_FIRSTHDR(msg)	__CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)#define CMSG32_OK(ucmlen, ucmsg, mhdr) \	((ucmlen) >= sizeof(struct cmsghdr32) && \	 (ucmlen) <= (unsigned long) \	 ((mhdr)->msg_controllen - \	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,					      struct cmsghdr32 *__cmsg, int __cmsg_len){	struct cmsghdr32 * __ptr;	__ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +				     CMSG32_ALIGN(__cmsg_len));	if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)		return NULL;	return __ptr;}__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg,					    struct cmsghdr32 *__cmsg,					    int __cmsg_len){	return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,			       __cmsg, __cmsg_len);}static inline int iov_from_user32_to_kern(struct iovec *kiov,					  struct iovec32 *uiov32,					  int niov){	int tot_len = 0;	while(niov > 0) {		u32 len, buf;		if(get_user(len, &uiov32->iov_len) ||		   get_user(buf, &uiov32->iov_base)) {			tot_len = -EFAULT;			break;		}		tot_len += len;		kiov->iov_base = (void *)AA(buf);		kiov->iov_len = (__kernel_size_t) len;		uiov32++;		kiov++;		niov--;	}	return tot_len;}static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,					     struct msghdr32 *umsg){	u32 tmp1, tmp2, tmp3;	int err;	err = get_user(tmp1, &umsg->msg_name);	err |= __get_user(tmp2, &umsg->msg_iov);	err |= __get_user(tmp3, &umsg->msg_control);	if (err)		return -EFAULT;	kmsg->msg_name = (void *)AA(tmp1);	kmsg->msg_iov = (struct iovec *)AA(tmp2);	kmsg->msg_control = (void *)AA(tmp3);	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);		return err;}/* I've named the args so it is easy to tell whose space the pointers are in. */static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,			  char *kern_address, int mode){	int tot_len;	if(kern_msg->msg_namelen) {		if(mode==VERIFY_READ) {			int err = move_addr_to_kernel(kern_msg->msg_name,						      kern_msg->msg_namelen,						      kern_address);			if(err < 0)				return err;		}		kern_msg->msg_name = kern_address;	} else		kern_msg->msg_name = NULL;	if(kern_msg->msg_iovlen > UIO_FASTIOV) {		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),				   GFP_KERNEL);		if(!kern_iov)			return -ENOMEM;	}	tot_len = iov_from_user32_to_kern(kern_iov,					  (struct iovec32 *)kern_msg->msg_iov,					  kern_msg->msg_iovlen);	if(tot_len >= 0)		kern_msg->msg_iov = kern_iov;	else if(kern_msg->msg_iovlen > UIO_FASTIOV)		kfree(kern_iov);	return tot_len;}static __inline__ voidsockfd_put(struct socket *sock){	fput(sock->file);}/* XXX This really belongs in some header file... -DaveM */#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 					   16 for IP, 16 for IPX,					   24 for IPv6,					   about 80 for AX.25 */extern struct socket *sockfd_lookup(int fd, int *err);/* There is a lot of hair here because the

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?