forked from mirrors/linux
		
	ipc: move compat shmctl to native
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									9ba720c186
								
							
						
					
					
						commit
						553f770ef7
					
				
					 3 changed files with 231 additions and 235 deletions
				
			
		
							
								
								
									
										233
									
								
								ipc/compat.c
									
									
									
									
									
								
							
							
						
						
									
										233
									
								
								ipc/compat.c
									
									
									
									
									
								
							|  | @ -39,16 +39,6 @@ struct compat_msgbuf { | ||||||
| 	char mtext[1]; | 	char mtext[1]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct compat_ipc_perm { |  | ||||||
| 	key_t key; |  | ||||||
| 	__compat_uid_t uid; |  | ||||||
| 	__compat_gid_t gid; |  | ||||||
| 	__compat_uid_t cuid; |  | ||||||
| 	__compat_gid_t cgid; |  | ||||||
| 	compat_mode_t mode; |  | ||||||
| 	unsigned short seq; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct compat_semid_ds { | struct compat_semid_ds { | ||||||
| 	struct compat_ipc_perm sem_perm; | 	struct compat_ipc_perm sem_perm; | ||||||
| 	compat_time_t sem_otime; | 	compat_time_t sem_otime; | ||||||
|  | @ -76,44 +66,12 @@ struct compat_msqid_ds { | ||||||
| 	compat_ipc_pid_t msg_lrpid; | 	compat_ipc_pid_t msg_lrpid; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct compat_shmid_ds { |  | ||||||
| 	struct compat_ipc_perm shm_perm; |  | ||||||
| 	int shm_segsz; |  | ||||||
| 	compat_time_t shm_atime; |  | ||||||
| 	compat_time_t shm_dtime; |  | ||||||
| 	compat_time_t shm_ctime; |  | ||||||
| 	compat_ipc_pid_t shm_cpid; |  | ||||||
| 	compat_ipc_pid_t shm_lpid; |  | ||||||
| 	unsigned short shm_nattch; |  | ||||||
| 	unsigned short shm_unused; |  | ||||||
| 	compat_uptr_t shm_unused2; |  | ||||||
| 	compat_uptr_t shm_unused3; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct compat_ipc_kludge { | struct compat_ipc_kludge { | ||||||
| 	compat_uptr_t msgp; | 	compat_uptr_t msgp; | ||||||
| 	compat_long_t msgtyp; | 	compat_long_t msgtyp; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct compat_shminfo64 { | static inline int __compat_ipc_parse_version(int *cmd) | ||||||
| 	compat_ulong_t shmmax; |  | ||||||
| 	compat_ulong_t shmmin; |  | ||||||
| 	compat_ulong_t shmmni; |  | ||||||
| 	compat_ulong_t shmseg; |  | ||||||
| 	compat_ulong_t shmall; |  | ||||||
| 	compat_ulong_t __unused1; |  | ||||||
| 	compat_ulong_t __unused2; |  | ||||||
| 	compat_ulong_t __unused3; |  | ||||||
| 	compat_ulong_t __unused4; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct compat_shm_info { |  | ||||||
| 	compat_int_t used_ids; |  | ||||||
| 	compat_ulong_t shm_tot, shm_rss, shm_swp; |  | ||||||
| 	compat_ulong_t swap_attempts, swap_successes; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static inline int compat_ipc_parse_version(int *cmd) |  | ||||||
| { | { | ||||||
| #ifdef	CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION | #ifdef	CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION | ||||||
| 	int version = *cmd & IPC_64; | 	int version = *cmd & IPC_64; | ||||||
|  | @ -241,7 +199,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) | ||||||
| 	int err, err2; | 	int err, err2; | ||||||
| 	struct semid64_ds sem64; | 	struct semid64_ds sem64; | ||||||
| 	struct semid64_ds __user *up64; | 	struct semid64_ds __user *up64; | ||||||
| 	int version = compat_ipc_parse_version(&third); | 	int version = __compat_ipc_parse_version(&third); | ||||||
| 
 | 
 | ||||||
| 	memset(&sem64, 0, sizeof(sem64)); | 	memset(&sem64, 0, sizeof(sem64)); | ||||||
| 
 | 
 | ||||||
|  | @ -499,7 +457,7 @@ COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr) | ||||||
| { | { | ||||||
| 	int err, err2; | 	int err, err2; | ||||||
| 	struct msqid64_ds m64; | 	struct msqid64_ds m64; | ||||||
| 	int version = compat_ipc_parse_version(&second); | 	int version = __compat_ipc_parse_version(&second); | ||||||
| 	void __user *p; | 	void __user *p; | ||||||
| 
 | 
 | ||||||
| 	memset(&m64, 0, sizeof(m64)); | 	memset(&m64, 0, sizeof(m64)); | ||||||
|  | @ -561,191 +519,6 @@ COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) | ||||||
| 	return (long)ret; | 	return (long)ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64, |  | ||||||
| 					struct compat_shmid64_ds __user *up64) |  | ||||||
| { |  | ||||||
| 	if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int get_compat_shmid_ds(struct shmid64_ds *s, |  | ||||||
| 				      struct compat_shmid_ds __user *up) |  | ||||||
| { |  | ||||||
| 	if (!access_ok(VERIFY_READ, up, sizeof(*up))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64, |  | ||||||
| 					struct compat_shmid64_ds __user *up64) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	err  = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); |  | ||||||
| 	err |= __put_user(sem64->shm_atime, &up64->shm_atime); |  | ||||||
| 	err |= __put_user(sem64->shm_dtime, &up64->shm_dtime); |  | ||||||
| 	err |= __put_user(sem64->shm_ctime, &up64->shm_ctime); |  | ||||||
| 	err |= __put_user(sem64->shm_segsz, &up64->shm_segsz); |  | ||||||
| 	err |= __put_user(sem64->shm_nattch, &up64->shm_nattch); |  | ||||||
| 	err |= __put_user(sem64->shm_cpid, &up64->shm_cpid); |  | ||||||
| 	err |= __put_user(sem64->shm_lpid, &up64->shm_lpid); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int put_compat_shmid_ds(struct shmid64_ds *s, |  | ||||||
| 				      struct compat_shmid_ds __user *up) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	err  = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm); |  | ||||||
| 	err |= __put_user(s->shm_atime, &up->shm_atime); |  | ||||||
| 	err |= __put_user(s->shm_dtime, &up->shm_dtime); |  | ||||||
| 	err |= __put_user(s->shm_ctime, &up->shm_ctime); |  | ||||||
| 	err |= __put_user(s->shm_segsz, &up->shm_segsz); |  | ||||||
| 	err |= __put_user(s->shm_nattch, &up->shm_nattch); |  | ||||||
| 	err |= __put_user(s->shm_cpid, &up->shm_cpid); |  | ||||||
| 	err |= __put_user(s->shm_lpid, &up->shm_lpid); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int put_compat_shminfo64(struct shminfo64 *smi, |  | ||||||
| 				       struct compat_shminfo64 __user *up64) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	if (smi->shmmax > INT_MAX) |  | ||||||
| 		smi->shmmax = INT_MAX; |  | ||||||
| 	err  = __put_user(smi->shmmax, &up64->shmmax); |  | ||||||
| 	err |= __put_user(smi->shmmin, &up64->shmmin); |  | ||||||
| 	err |= __put_user(smi->shmmni, &up64->shmmni); |  | ||||||
| 	err |= __put_user(smi->shmseg, &up64->shmseg); |  | ||||||
| 	err |= __put_user(smi->shmall, &up64->shmall); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int put_compat_shminfo(struct shminfo64 *smi, |  | ||||||
| 				     struct shminfo __user *up) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	if (smi->shmmax > INT_MAX) |  | ||||||
| 		smi->shmmax = INT_MAX; |  | ||||||
| 	err  = __put_user(smi->shmmax, &up->shmmax); |  | ||||||
| 	err |= __put_user(smi->shmmin, &up->shmmin); |  | ||||||
| 	err |= __put_user(smi->shmmni, &up->shmmni); |  | ||||||
| 	err |= __put_user(smi->shmseg, &up->shmseg); |  | ||||||
| 	err |= __put_user(smi->shmall, &up->shmall); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline int put_compat_shm_info(struct shm_info __user *ip, |  | ||||||
| 				      struct compat_shm_info __user *uip) |  | ||||||
| { |  | ||||||
| 	int err; |  | ||||||
| 	struct shm_info si; |  | ||||||
| 
 |  | ||||||
| 	if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) || |  | ||||||
| 	    copy_from_user(&si, ip, sizeof(si))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 	err  = __put_user(si.used_ids, &uip->used_ids); |  | ||||||
| 	err |= __put_user(si.shm_tot, &uip->shm_tot); |  | ||||||
| 	err |= __put_user(si.shm_rss, &uip->shm_rss); |  | ||||||
| 	err |= __put_user(si.shm_swp, &uip->shm_swp); |  | ||||||
| 	err |= __put_user(si.swap_attempts, &uip->swap_attempts); |  | ||||||
| 	err |= __put_user(si.swap_successes, &uip->swap_successes); |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) |  | ||||||
| { |  | ||||||
| 	void __user *p; |  | ||||||
| 	struct shmid64_ds sem64; |  | ||||||
| 	struct shminfo64 smi; |  | ||||||
| 	int err, err2; |  | ||||||
| 	int version = compat_ipc_parse_version(&second); |  | ||||||
| 
 |  | ||||||
| 	memset(&sem64, 0, sizeof(sem64)); |  | ||||||
| 
 |  | ||||||
| 	switch (second & (~IPC_64)) { |  | ||||||
| 	case IPC_RMID: |  | ||||||
| 	case SHM_LOCK: |  | ||||||
| 	case SHM_UNLOCK: |  | ||||||
| 		err = sys_shmctl(first, second, uptr); |  | ||||||
| 		break; |  | ||||||
| 
 |  | ||||||
| 	case IPC_INFO: |  | ||||||
| 		p = compat_alloc_user_space(sizeof(smi)); |  | ||||||
| 		err = sys_shmctl(first, second, p); |  | ||||||
| 		if (err < 0) |  | ||||||
| 			break; |  | ||||||
| 		if (copy_from_user(&smi, p, sizeof(smi))) |  | ||||||
| 			err2 = -EFAULT; |  | ||||||
| 		else if (version == IPC_64) |  | ||||||
| 			err2 = put_compat_shminfo64(&smi, uptr); |  | ||||||
| 		else |  | ||||||
| 			err2 = put_compat_shminfo(&smi, uptr); |  | ||||||
| 		if (err2) |  | ||||||
| 			err = -EFAULT; |  | ||||||
| 		break; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	case IPC_SET: |  | ||||||
| 		if (version == IPC_64) |  | ||||||
| 			err = get_compat_shmid64_ds(&sem64, uptr); |  | ||||||
| 		else |  | ||||||
| 			err = get_compat_shmid_ds(&sem64, uptr); |  | ||||||
| 
 |  | ||||||
| 		if (err) |  | ||||||
| 			break; |  | ||||||
| 		p = compat_alloc_user_space(sizeof(sem64)); |  | ||||||
| 		if (copy_to_user(p, &sem64, sizeof(sem64))) |  | ||||||
| 			err = -EFAULT; |  | ||||||
| 		else |  | ||||||
| 			err = sys_shmctl(first, second, p); |  | ||||||
| 		break; |  | ||||||
| 
 |  | ||||||
| 	case IPC_STAT: |  | ||||||
| 	case SHM_STAT: |  | ||||||
| 		p = compat_alloc_user_space(sizeof(sem64)); |  | ||||||
| 		err = sys_shmctl(first, second, p); |  | ||||||
| 		if (err < 0) |  | ||||||
| 			break; |  | ||||||
| 		if (copy_from_user(&sem64, p, sizeof(sem64))) |  | ||||||
| 			err2 = -EFAULT; |  | ||||||
| 		else if (version == IPC_64) |  | ||||||
| 			err2 = put_compat_shmid64_ds(&sem64, uptr); |  | ||||||
| 		else |  | ||||||
| 			err2 = put_compat_shmid_ds(&sem64, uptr); |  | ||||||
| 		if (err2) |  | ||||||
| 			err = -EFAULT; |  | ||||||
| 		break; |  | ||||||
| 
 |  | ||||||
| 	case SHM_INFO: |  | ||||||
| 		p = compat_alloc_user_space(sizeof(struct shm_info)); |  | ||||||
| 		err = sys_shmctl(first, second, p); |  | ||||||
| 		if (err < 0) |  | ||||||
| 			break; |  | ||||||
| 		err2 = put_compat_shm_info(p, uptr); |  | ||||||
| 		if (err2) |  | ||||||
| 			err = -EFAULT; |  | ||||||
| 		break; |  | ||||||
| 
 |  | ||||||
| 	default: |  | ||||||
| 		err = -EINVAL; |  | ||||||
| 		break; |  | ||||||
| 	} |  | ||||||
| 	return err; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, | COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, | ||||||
| 		       unsigned, nsops, | 		       unsigned, nsops, | ||||||
| 		       const struct compat_timespec __user *, timeout) | 		       const struct compat_timespec __user *, timeout) | ||||||
|  |  | ||||||
							
								
								
									
										209
									
								
								ipc/shm.c
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								ipc/shm.c
									
									
									
									
									
								
							|  | @ -1030,7 +1030,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | ||||||
| { | { | ||||||
| 	int err, version; | 	int err, version; | ||||||
| 	struct ipc_namespace *ns; | 	struct ipc_namespace *ns; | ||||||
| 	struct shmid64_ds tbuf; | 	struct shmid64_ds sem64; | ||||||
| 
 | 
 | ||||||
| 	if (cmd < 0 || shmid < 0) | 	if (cmd < 0 || shmid < 0) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  | @ -1059,18 +1059,19 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | ||||||
| 	} | 	} | ||||||
| 	case SHM_STAT: | 	case SHM_STAT: | ||||||
| 	case IPC_STAT: { | 	case IPC_STAT: { | ||||||
| 		err = shmctl_stat(ns, shmid, cmd, &tbuf); | 		err = shmctl_stat(ns, shmid, cmd, &sem64); | ||||||
| 		if (err < 0) | 		if (err < 0) | ||||||
| 			return err; | 			return err; | ||||||
| 		if (copy_shmid_to_user(buf, &tbuf, version)) | 		if (copy_shmid_to_user(buf, &sem64, version)) | ||||||
| 			err = -EFAULT; | 			err = -EFAULT; | ||||||
| 		return err; | 		return err; | ||||||
| 	} | 	} | ||||||
| 	case IPC_SET: | 	case IPC_SET: | ||||||
| 		if (copy_shmid_from_user(&tbuf, buf, version)) | 		if (copy_shmid_from_user(&sem64, buf, version)) | ||||||
| 			return -EFAULT; | 			return -EFAULT; | ||||||
|  | 		/* fallthru */ | ||||||
| 	case IPC_RMID: | 	case IPC_RMID: | ||||||
| 		return shmctl_down(ns, shmid, cmd, &tbuf); | 		return shmctl_down(ns, shmid, cmd, &sem64); | ||||||
| 	case SHM_LOCK: | 	case SHM_LOCK: | ||||||
| 	case SHM_UNLOCK: | 	case SHM_UNLOCK: | ||||||
| 		return shmctl_do_lock(ns, shmid, cmd); | 		return shmctl_do_lock(ns, shmid, cmd); | ||||||
|  | @ -1079,6 +1080,204 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_COMPAT | ||||||
|  | 
 | ||||||
|  | struct compat_shmid_ds { | ||||||
|  | 	struct compat_ipc_perm shm_perm; | ||||||
|  | 	int shm_segsz; | ||||||
|  | 	compat_time_t shm_atime; | ||||||
|  | 	compat_time_t shm_dtime; | ||||||
|  | 	compat_time_t shm_ctime; | ||||||
|  | 	compat_ipc_pid_t shm_cpid; | ||||||
|  | 	compat_ipc_pid_t shm_lpid; | ||||||
|  | 	unsigned short shm_nattch; | ||||||
|  | 	unsigned short shm_unused; | ||||||
|  | 	compat_uptr_t shm_unused2; | ||||||
|  | 	compat_uptr_t shm_unused3; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct compat_shminfo64 { | ||||||
|  | 	compat_ulong_t shmmax; | ||||||
|  | 	compat_ulong_t shmmin; | ||||||
|  | 	compat_ulong_t shmmni; | ||||||
|  | 	compat_ulong_t shmseg; | ||||||
|  | 	compat_ulong_t shmall; | ||||||
|  | 	compat_ulong_t __unused1; | ||||||
|  | 	compat_ulong_t __unused2; | ||||||
|  | 	compat_ulong_t __unused3; | ||||||
|  | 	compat_ulong_t __unused4; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct compat_shm_info { | ||||||
|  | 	compat_int_t used_ids; | ||||||
|  | 	compat_ulong_t shm_tot, shm_rss, shm_swp; | ||||||
|  | 	compat_ulong_t swap_attempts, swap_successes; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int copy_compat_shminfo_to_user(void __user *buf, struct shminfo64 *in, | ||||||
|  | 					int version) | ||||||
|  | { | ||||||
|  | 	if (in->shmmax > INT_MAX) | ||||||
|  | 		in->shmmax = INT_MAX; | ||||||
|  | 	if (version == IPC_64) { | ||||||
|  | 		struct compat_shminfo64 info; | ||||||
|  | 		memset(&info, 0, sizeof(info)); | ||||||
|  | 		info.shmmax = in->shmmax; | ||||||
|  | 		info.shmmin = in->shmmin; | ||||||
|  | 		info.shmmni = in->shmmni; | ||||||
|  | 		info.shmseg = in->shmseg; | ||||||
|  | 		info.shmall = in->shmall; | ||||||
|  | 		return copy_to_user(buf, &info, sizeof(info)); | ||||||
|  | 	} else { | ||||||
|  | 		struct shminfo info; | ||||||
|  | 		memset(&info, 0, sizeof(info)); | ||||||
|  | 		info.shmmax = in->shmmax; | ||||||
|  | 		info.shmmin = in->shmmin; | ||||||
|  | 		info.shmmni = in->shmmni; | ||||||
|  | 		info.shmseg = in->shmseg; | ||||||
|  | 		info.shmall = in->shmall; | ||||||
|  | 		return copy_to_user(buf, &info, sizeof(info)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int put_compat_shm_info(struct shm_info *ip, | ||||||
|  | 				struct compat_shm_info __user *uip) | ||||||
|  | { | ||||||
|  | 	struct compat_shm_info info; | ||||||
|  | 
 | ||||||
|  | 	memset(&info, 0, sizeof(info)); | ||||||
|  | 	info.used_ids = ip->used_ids; | ||||||
|  | 	info.shm_tot = ip->shm_tot; | ||||||
|  | 	info.shm_rss = ip->shm_rss; | ||||||
|  | 	info.shm_swp = ip->shm_swp; | ||||||
|  | 	info.swap_attempts = ip->swap_attempts; | ||||||
|  | 	info.swap_successes = ip->swap_successes; | ||||||
|  | 	return copy_to_user(up, &info, sizeof(info)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in, | ||||||
|  | 					int version) | ||||||
|  | { | ||||||
|  | 	if (version == IPC_64) { | ||||||
|  | 		struct compat_shmid64_ds v; | ||||||
|  | 		memset(&v, 0, sizeof(v)); | ||||||
|  | 		v.shm_perm.key = in->shm_perm.key; | ||||||
|  | 		v.shm_perm.uid = in->shm_perm.uid; | ||||||
|  | 		v.shm_perm.gid = in->shm_perm.gid; | ||||||
|  | 		v.shm_perm.cuid = in->shm_perm.cuid; | ||||||
|  | 		v.shm_perm.cgid = in->shm_perm.cgid; | ||||||
|  | 		v.shm_perm.mode = in->shm_perm.mode; | ||||||
|  | 		v.shm_perm.seq = in->shm_perm.seq; | ||||||
|  | 		v.shm_atime = in->shm_atime; | ||||||
|  | 		v.shm_dtime = in->shm_dtime; | ||||||
|  | 		v.shm_ctime = in->shm_ctime; | ||||||
|  | 		v.shm_segsz = in->shm_segsz; | ||||||
|  | 		v.shm_nattch = in->shm_nattch; | ||||||
|  | 		v.shm_cpid = in->shm_cpid; | ||||||
|  | 		v.shm_lpid = in->shm_lpid; | ||||||
|  | 		return copy_to_user(buf, &v, sizeof(v)); | ||||||
|  | 	} else { | ||||||
|  | 		struct compat_shmid_ds v; | ||||||
|  | 		memset(&v, 0, sizeof(v)); | ||||||
|  | 		v.shm_perm.key = in->shm_perm.key; | ||||||
|  | 		SET_UID(v.shm_perm.uid, in->shm_perm.uid); | ||||||
|  | 		SET_GID(v.shm_perm.gid, in->shm_perm.gid); | ||||||
|  | 		SET_UID(v.shm_perm.cuid, in->shm_perm.cuid); | ||||||
|  | 		SET_GID(v.shm_perm.cgid, in->shm_perm.cgid); | ||||||
|  | 		v.shm_perm.mode = in->shm_perm.mode; | ||||||
|  | 		v.shm_perm.seq = in->shm_perm.seq; | ||||||
|  | 		v.shm_atime = in->shm_atime; | ||||||
|  | 		v.shm_dtime = in->shm_dtime; | ||||||
|  | 		v.shm_ctime = in->shm_ctime; | ||||||
|  | 		v.shm_segsz = in->shm_segsz; | ||||||
|  | 		v.shm_nattch = in->shm_nattch; | ||||||
|  | 		v.shm_cpid = in->shm_cpid; | ||||||
|  | 		v.shm_lpid = in->shm_lpid; | ||||||
|  | 		return copy_to_user(buf, &v, sizeof(v)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf, | ||||||
|  | 					int version) | ||||||
|  | { | ||||||
|  | 	memset(out, 0, sizeof(*out)); | ||||||
|  | 	if (version == IPC_64) { | ||||||
|  | 		struct compat_shmid64_ds *p = buf; | ||||||
|  | 		struct compat_ipc64_perm v; | ||||||
|  | 		if (copy_from_user(&v, &p->shm_perm, sizeof(v))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 		out->shm_perm.uid = v.uid; | ||||||
|  | 		out->shm_perm.gid = v.gid; | ||||||
|  | 		out->shm_perm.mode = v.mode; | ||||||
|  | 	} else { | ||||||
|  | 		struct compat_shmid_ds *p = buf; | ||||||
|  | 		struct compat_ipc_perm v; | ||||||
|  | 		if (copy_from_user(&v, &p->shm_perm, sizeof(v))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 		out->shm_perm.uid = v.uid; | ||||||
|  | 		out->shm_perm.gid = v.gid; | ||||||
|  | 		out->shm_perm.mode = v.mode; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr) | ||||||
|  | { | ||||||
|  | 	struct ipc_namespace *ns; | ||||||
|  | 	struct shmid64_ds sem64; | ||||||
|  | 	int version = compat_ipc_parse_version(&cmd); | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	ns = current->nsproxy->ipc_ns; | ||||||
|  | 
 | ||||||
|  | 	if (cmd < 0 || shmid < 0) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	switch (cmd) { | ||||||
|  | 	case IPC_INFO: { | ||||||
|  | 		struct shminfo64 shminfo; | ||||||
|  | 		err = shmctl_ipc_info(ns, &shminfo); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 		if (copy_compat_shminfo_to_user(uptr, &shminfo, version)) | ||||||
|  | 			err = -EFAULT; | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  | 	case SHM_INFO: { | ||||||
|  | 		struct shm_info shm_info; | ||||||
|  | 		err = shmctl_shm_info(ns, &shm_info); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 		if (put_compat_shm_info(&shm_info, uptr)) | ||||||
|  | 			err = -EFAULT; | ||||||
|  | 		return err; | ||||||
|  | 	} | ||||||
|  | 	case IPC_STAT: | ||||||
|  | 	case SHM_STAT: | ||||||
|  | 		err = shmctl_stat(ns, shmid, cmd, &sem64); | ||||||
|  | 		if (err < 0) | ||||||
|  | 			return err; | ||||||
|  | 		if (copy_compat_shmid_to_user(&sem64, uptr, version)) | ||||||
|  | 			err = -EFAULT; | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	case IPC_SET: | ||||||
|  | 		if (copy_compat_shmid_from_user(&sem64, uptr, version)) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 		/* fallthru */ | ||||||
|  | 	case IPC_RMID: | ||||||
|  | 		return shmctl_down(ns, shmid, cmd, &sem64); | ||||||
|  | 	case SHM_LOCK: | ||||||
|  | 	case SHM_UNLOCK: | ||||||
|  | 		return shmctl_do_lock(ns, shmid, cmd); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. |  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. | ||||||
|  * |  * | ||||||
|  |  | ||||||
							
								
								
									
										24
									
								
								ipc/util.h
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								ipc/util.h
									
									
									
									
									
								
							|  | @ -191,4 +191,28 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, | ||||||
| 			const struct ipc_ops *ops, struct ipc_params *params); | 			const struct ipc_ops *ops, struct ipc_params *params); | ||||||
| void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, | void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, | ||||||
| 		void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)); | 		void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)); | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_COMPAT | ||||||
|  | #include <linux/compat.h> | ||||||
|  | struct compat_ipc_perm { | ||||||
|  | 	key_t key; | ||||||
|  | 	__compat_uid_t uid; | ||||||
|  | 	__compat_gid_t gid; | ||||||
|  | 	__compat_uid_t cuid; | ||||||
|  | 	__compat_gid_t cgid; | ||||||
|  | 	compat_mode_t mode; | ||||||
|  | 	unsigned short seq; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline int compat_ipc_parse_version(int *cmd) | ||||||
|  | { | ||||||
|  | #ifdef	CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION | ||||||
|  | 	int version = *cmd & IPC_64; | ||||||
|  | 	*cmd &= ~IPC_64; | ||||||
|  | 	return version; | ||||||
|  | #else | ||||||
|  | 	return IPC_64; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Al Viro
						Al Viro