diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 07:21:43 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 07:21:43 -0700 | 
| commit | 08d76760832993050ad8c25e63b56773ef2ca303 (patch) | |
| tree | abdcf148dfe43cd49f30f204f1dac6978107a508 /ipc | |
| parent | 5f56886521d6ddd3648777fae44d82382dd8c87f (diff) | |
| parent | 99e621f796d7f0341a51e8cdf32b81663b10b448 (diff) | |
| download | olio-linux-3.10-08d76760832993050ad8c25e63b56773ef2ca303.tar.xz olio-linux-3.10-08d76760832993050ad8c25e63b56773ef2ca303.zip  | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull compat cleanup from Al Viro:
 "Mostly about syscall wrappers this time; there will be another pile
  with patches in the same general area from various people, but I'd
  rather push those after both that and vfs.git pile are in."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal:
  syscalls.h: slightly reduce the jungles of macros
  get rid of union semop in sys_semctl(2) arguments
  make do_mremap() static
  sparc: no need to sign-extend in sync_file_range() wrapper
  ppc compat wrappers for add_key(2) and request_key(2) are pointless
  x86: trim sys_ia32.h
  x86: sys32_kill and sys32_mprotect are pointless
  get rid of compat_sys_semctl() and friends in case of ARCH_WANT_OLD_COMPAT_IPC
  merge compat sys_ipc instances
  consolidate compat lookup_dcookie()
  convert vmsplice to COMPAT_SYSCALL_DEFINE
  switch getrusage() to COMPAT_SYSCALL_DEFINE
  switch epoll_pwait to COMPAT_SYSCALL_DEFINE
  convert sendfile{,64} to COMPAT_SYSCALL_DEFINE
  switch signalfd{,4}() to COMPAT_SYSCALL_DEFINE
  make SYSCALL_DEFINE<n>-generated wrappers do asmlinkage_protect
  make HAVE_SYSCALL_WRAPPERS unconditional
  consolidate cond_syscall and SYSCALL_ALIAS declarations
  teach SYSCALL_DEFINE<n> how to deal with long long/unsigned long long
  get rid of duplicate logics in __SC_....[1-6] definitions
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/compat.c | 172 | ||||
| -rw-r--r-- | ipc/sem.c | 123 | ||||
| -rw-r--r-- | ipc/syscall.c | 6 | 
3 files changed, 176 insertions, 125 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index 2547f29dcd1..892f6585dd6 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -240,7 +240,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s,  static long do_compat_semctl(int first, int second, int third, u32 pad)  { -	union semun fourth; +	unsigned long fourth;  	int err, err2;  	struct semid64_ds s64;  	struct semid64_ds __user *up64; @@ -249,9 +249,13 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)  	memset(&s64, 0, sizeof(s64));  	if ((third & (~IPC_64)) == SETVAL) -		fourth.val = (int) pad; +#ifdef __BIG_ENDIAN +		fourth = (unsigned long)pad << 32; +#else +		fourth = pad; +#endif  	else -		fourth.__pad = compat_ptr(pad); +		fourth = (unsigned long)compat_ptr(pad);  	switch (third & (~IPC_64)) {  	case IPC_INFO:  	case IPC_RMID: @@ -269,7 +273,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)  	case IPC_STAT:  	case SEM_STAT:  		up64 = compat_alloc_user_space(sizeof(s64)); -		fourth.__pad = up64; +		fourth = (unsigned long)up64;  		err = sys_semctl(first, second, third, fourth);  		if (err < 0)  			break; @@ -295,7 +299,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)  		if (err)  			break; -		fourth.__pad = up64; +		fourth = (unsigned long)up64;  		err = sys_semctl(first, second, third, fourth);  		break; @@ -306,7 +310,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)  	return err;  } -long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) +static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)  {  	struct compat_msgbuf __user *msgp = dest;  	size_t msgsz; @@ -320,77 +324,117 @@ long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)  	return msgsz;  } +#ifndef COMPAT_SHMLBA +#define COMPAT_SHMLBA	SHMLBA +#endif +  #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC -long compat_sys_semctl(int first, int second, int third, void __user *uptr) +COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, +	u32, third, compat_uptr_t, ptr, u32, fifth)  { +	int version;  	u32 pad; -	if (!uptr) -		return -EINVAL; -	if (get_user(pad, (u32 __user *) uptr)) -		return -EFAULT; -	return do_compat_semctl(first, second, third, pad); -} +	version = call >> 16; /* hack for backward compatibility */ +	call &= 0xffff; -long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) -{ -	struct compat_msgbuf __user *up = uptr; -	long type; +	switch (call) { +	case SEMOP: +		/* struct sembuf is the same on 32 and 64bit :)) */ +		return sys_semtimedop(first, compat_ptr(ptr), second, NULL); +	case SEMTIMEDOP: +		return compat_sys_semtimedop(first, compat_ptr(ptr), second, +						compat_ptr(fifth)); +	case SEMGET: +		return sys_semget(first, second, third); +	case SEMCTL: +		if (!ptr) +			return -EINVAL; +		if (get_user(pad, (u32 __user *) compat_ptr(ptr))) +			return -EFAULT; +		return do_compat_semctl(first, second, third, pad); -	if (first < 0) -		return -EINVAL; -	if (second < 0) -		return -EINVAL; +	case MSGSND: { +		struct compat_msgbuf __user *up = compat_ptr(ptr); +		compat_long_t type; -	if (get_user(type, &up->mtype)) -		return -EFAULT; +		if (first < 0 || second < 0) +			return -EINVAL; -	return do_msgsnd(first, type, up->mtext, second, third); -} +		if (get_user(type, &up->mtype)) +			return -EFAULT; -long compat_sys_msgrcv(int first, int second, int msgtyp, int third, -			   int version, void __user *uptr) -{ -	if (first < 0) -		return -EINVAL; -	if (second < 0) -		return -EINVAL; +		return do_msgsnd(first, type, up->mtext, second, third); +	} +	case MSGRCV: { +		void __user *uptr = compat_ptr(ptr); -	if (!version) { -		struct compat_ipc_kludge ipck; -		if (!uptr) +		if (first < 0 || second < 0)  			return -EINVAL; -		if (copy_from_user (&ipck, uptr, sizeof(ipck))) -			return -EFAULT; -		uptr = compat_ptr(ipck.msgp); -		msgtyp = ipck.msgtyp; + +		if (!version) { +			struct compat_ipc_kludge ipck; +			if (!uptr) +				return -EINVAL; +			if (copy_from_user (&ipck, uptr, sizeof(ipck))) +				return -EFAULT; +			uptr = compat_ptr(ipck.msgp); +			fifth = ipck.msgtyp; +		} +		return do_msgrcv(first, uptr, second, fifth, third, +				 compat_do_msg_fill);  	} -	return do_msgrcv(first, uptr, second, msgtyp, third, -			 compat_do_msg_fill); +	case MSGGET: +		return sys_msgget(first, second); +	case MSGCTL: +		return compat_sys_msgctl(first, second, compat_ptr(ptr)); + +	case SHMAT: { +		int err; +		unsigned long raddr; + +		if (version == 1) +			return -EINVAL; +		err = do_shmat(first, compat_ptr(ptr), second, &raddr, +			       COMPAT_SHMLBA); +		if (err < 0) +			return err; +		return put_user(raddr, (compat_ulong_t *)compat_ptr(third)); +	} +	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)); +	} + +	return -ENOSYS;  } -#else -long compat_sys_semctl(int semid, int semnum, int cmd, int arg) +#endif + +COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)  {  	return do_compat_semctl(semid, semnum, cmd, arg);  } -long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp, -		       compat_ssize_t msgsz, int msgflg) +COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, +		       compat_ssize_t, msgsz, int, msgflg)  { +	struct compat_msgbuf __user *up = compat_ptr(msgp);  	compat_long_t mtype; -	if (get_user(mtype, &msgp->mtype)) +	if (get_user(mtype, &up->mtype))  		return -EFAULT; -	return do_msgsnd(msqid, mtype, msgp->mtext, (ssize_t)msgsz, msgflg); +	return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);  } -long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp, -		       compat_ssize_t msgsz, long msgtyp, int msgflg) +COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, +		       compat_ssize_t, msgsz, long, msgtyp, int, msgflg)  { -	return do_msgrcv(msqid, msgp, (ssize_t)msgsz, msgtyp, msgflg, -			 compat_do_msg_fill); +	return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, msgtyp, +			 msgflg, compat_do_msg_fill);  } -#endif  static inline int get_compat_msqid64(struct msqid64_ds *m64,  				     struct compat_msqid64_ds __user *up64) @@ -508,28 +552,7 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)  	return err;  } -#ifndef COMPAT_SHMLBA -#define COMPAT_SHMLBA	SHMLBA -#endif - -#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC -long compat_sys_shmat(int first, int second, compat_uptr_t third, int version, -			void __user *uptr) -{ -	int err; -	unsigned long raddr; -	compat_ulong_t __user *uaddr; - -	if (version == 1) -		return -EINVAL; -	err = do_shmat(first, uptr, second, &raddr, COMPAT_SHMLBA); -	if (err < 0) -		return err; -	uaddr = compat_ptr(third); -	return put_user(raddr, uaddr); -} -#else -long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg) +COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)  {  	unsigned long ret;  	long err; @@ -540,7 +563,6 @@ long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)  	force_successful_syscall_return();  	return (long)ret;  } -#endif  static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,  					struct compat_shmid64_ds __user *up64) diff --git a/ipc/sem.c b/ipc/sem.c index 58d31f1c1eb..5b167d00efa 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -799,7 +799,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,  }  static int semctl_nolock(struct ipc_namespace *ns, int semid, -			 int cmd, int version, union semun arg) +			 int cmd, int version, void __user *p)  {  	int err;  	struct sem_array *sma; @@ -834,7 +834,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,  		}  		max_id = ipc_get_maxid(&sem_ids(ns));  		up_read(&sem_ids(ns).rw_mutex); -		if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))  +		if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))   			return -EFAULT;  		return (max_id < 0) ? 0: max_id;  	} @@ -871,7 +871,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,  		tbuf.sem_ctime  = sma->sem_ctime;  		tbuf.sem_nsems  = sma->sem_nsems;  		sem_unlock(sma); -		if (copy_semid_to_user (arg.buf, &tbuf, version)) +		if (copy_semid_to_user(p, &tbuf, version))  			return -EFAULT;  		return id;  	} @@ -883,8 +883,67 @@ out_unlock:  	return err;  } +static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum, +		unsigned long arg) +{ +	struct sem_undo *un; +	struct sem_array *sma; +	struct sem* curr; +	int err; +	int nsems; +	struct list_head tasks; +	int val; +#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN) +	/* big-endian 64bit */ +	val = arg >> 32; +#else +	/* 32bit or little-endian 64bit */ +	val = arg; +#endif + +	sma = sem_lock_check(ns, semid); +	if (IS_ERR(sma)) +		return PTR_ERR(sma); + +	INIT_LIST_HEAD(&tasks); +	nsems = sma->sem_nsems; + +	err = -EACCES; +	if (ipcperms(ns, &sma->sem_perm, S_IWUGO)) +		goto out_unlock; + +	err = security_sem_semctl(sma, SETVAL); +	if (err) +		goto out_unlock; + +	err = -EINVAL; +	if(semnum < 0 || semnum >= nsems) +		goto out_unlock; + +	curr = &sma->sem_base[semnum]; + +	err = -ERANGE; +	if (val > SEMVMX || val < 0) +		goto out_unlock; + +	assert_spin_locked(&sma->sem_perm.lock); +	list_for_each_entry(un, &sma->list_id, list_id) +		un->semadj[semnum] = 0; + +	curr->semval = val; +	curr->sempid = task_tgid_vnr(current); +	sma->sem_ctime = get_seconds(); +	/* maybe some queued-up processes were waiting for this */ +	do_smart_update(sma, NULL, 0, 0, &tasks); +	err = 0; +out_unlock: +	sem_unlock(sma); +	wake_up_sem_queue_do(&tasks); +	return err; +} +  static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, -		int cmd, int version, union semun arg) +		int cmd, void __user *p)  {  	struct sem_array *sma;  	struct sem* curr; @@ -903,7 +962,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,  	err = -EACCES;  	if (ipcperms(ns, &sma->sem_perm, -			(cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO)) +			cmd == SETALL ? S_IWUGO : S_IRUGO))  		goto out_unlock;  	err = security_sem_semctl(sma, cmd); @@ -914,7 +973,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,  	switch (cmd) {  	case GETALL:  	{ -		ushort __user *array = arg.array; +		ushort __user *array = p;  		int i;  		if(nsems > SEMMSL_FAST) { @@ -957,7 +1016,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,  			}  		} -		if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) { +		if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) {  			sem_putref(sma);  			err = -EFAULT;  			goto out_free; @@ -991,7 +1050,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,  		err = 0;  		goto out_unlock;  	} -	/* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ +	/* GETVAL, GETPID, GETNCTN, GETZCNT: fall-through */  	}  	err = -EINVAL;  	if(semnum < 0 || semnum >= nsems) @@ -1012,27 +1071,6 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,  	case GETZCNT:  		err = count_semzcnt(sma,semnum);  		goto out_unlock; -	case SETVAL: -	{ -		int val = arg.val; -		struct sem_undo *un; - -		err = -ERANGE; -		if (val > SEMVMX || val < 0) -			goto out_unlock; - -		assert_spin_locked(&sma->sem_perm.lock); -		list_for_each_entry(un, &sma->list_id, list_id) -			un->semadj[semnum] = 0; - -		curr->semval = val; -		curr->sempid = task_tgid_vnr(current); -		sma->sem_ctime = get_seconds(); -		/* maybe some queued-up processes were waiting for this */ -		do_smart_update(sma, NULL, 0, 0, &tasks); -		err = 0; -		goto out_unlock; -	}  	}  out_unlock:  	sem_unlock(sma); @@ -1076,7 +1114,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)   * NOTE: no locks must be held, the rw_mutex is taken inside this function.   */  static int semctl_down(struct ipc_namespace *ns, int semid, -		       int cmd, int version, union semun arg) +		       int cmd, int version, void __user *p)  {  	struct sem_array *sma;  	int err; @@ -1084,7 +1122,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,  	struct kern_ipc_perm *ipcp;  	if(cmd == IPC_SET) { -		if (copy_semid_from_user(&semid64, arg.buf, version)) +		if (copy_semid_from_user(&semid64, p, version))  			return -EFAULT;  	} @@ -1120,11 +1158,11 @@ out_up:  	return err;  } -SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) +SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)  { -	int err = -EINVAL;  	int version;  	struct ipc_namespace *ns; +	void __user *p = (void __user *)arg;  	if (semid < 0)  		return -EINVAL; @@ -1137,32 +1175,23 @@ SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg)  	case SEM_INFO:  	case IPC_STAT:  	case SEM_STAT: -		err = semctl_nolock(ns, semid, cmd, version, arg); -		return err; +		return semctl_nolock(ns, semid, cmd, version, p);  	case GETALL:  	case GETVAL:  	case GETPID:  	case GETNCNT:  	case GETZCNT: -	case SETVAL:  	case SETALL: -		err = semctl_main(ns,semid,semnum,cmd,version,arg); -		return err; +		return semctl_main(ns, semid, semnum, cmd, p); +	case SETVAL: +		return semctl_setval(ns, semid, semnum, arg);  	case IPC_RMID:  	case IPC_SET: -		err = semctl_down(ns, semid, cmd, version, arg); -		return err; +		return semctl_down(ns, semid, cmd, version, p);  	default:  		return -EINVAL;  	}  } -#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS -asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg) -{ -	return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg); -} -SYSCALL_ALIAS(sys_semctl, SyS_semctl); -#endif  /* If the task doesn't already have a undo_list, then allocate one   * here.  We guarantee there is only one thread using this undo list, diff --git a/ipc/syscall.c b/ipc/syscall.c index 0d1e32ce048..52429489cde 100644 --- a/ipc/syscall.c +++ b/ipc/syscall.c @@ -33,12 +33,12 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,  	case SEMGET:  		return sys_semget(first, second, third);  	case SEMCTL: { -		union semun fourth; +		unsigned long arg;  		if (!ptr)  			return -EINVAL; -		if (get_user(fourth.__pad, (void __user * __user *) ptr)) +		if (get_user(arg, (unsigned long __user *) ptr))  			return -EFAULT; -		return sys_semctl(first, second, third, fourth); +		return sys_semctl(first, second, third, arg);  	}  	case MSGSND:  |