@@ -2652,8 +2652,9 @@ static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
}
static inline abi_long do_semctl(int semid, int semnum, int cmd,
- union target_semun target_su)
+ abi_ulong ptr)
{
+ union target_semun *target_su;
union semun arg;
struct semid_ds dsarg;
unsigned short *array = NULL;
@@ -2662,43 +2663,55 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
abi_long err;
cmd &= 0xff;
+ if (!lock_user_struct(VERIFY_READ, target_su, ptr, 1)) {
+ return -TARGET_EFAULT;
+ }
switch( cmd ) {
case GETVAL:
case SETVAL:
- arg.val = tswap32(target_su.val);
+ arg.val = tswap32(target_su->val);
ret = get_errno(semctl(semid, semnum, cmd, arg));
- target_su.val = tswap32(arg.val);
+ target_su->val = tswap32(arg.val);
break;
case GETALL:
case SETALL:
- err = target_to_host_semarray(semid, &array, target_su.array);
- if (err)
- return err;
+ err = target_to_host_semarray(semid, &array,
+ tswapal(target_su->array));
+ if (err) {
+ ret = err;
+ break;
+ }
arg.array = array;
ret = get_errno(semctl(semid, semnum, cmd, arg));
- err = host_to_target_semarray(semid, target_su.array, &array);
- if (err)
- return err;
+ err = host_to_target_semarray(semid, tswapal(target_su->array),
+ &array);
+ if (err) {
+ ret = err;
+ }
break;
case IPC_STAT:
case IPC_SET:
case SEM_STAT:
- err = target_to_host_semid_ds(&dsarg, target_su.buf);
- if (err)
- return err;
+ err = target_to_host_semid_ds(&dsarg, tswapal(target_su->buf));
+ if (err) {
+ ret = err;
+ break;
+ }
arg.buf = &dsarg;
ret = get_errno(semctl(semid, semnum, cmd, arg));
- err = host_to_target_semid_ds(target_su.buf, &dsarg);
- if (err)
- return err;
+ err = host_to_target_semid_ds(tswapal(target_su->buf), &dsarg);
+ if (err) {
+ ret = err;
+ }
break;
case IPC_INFO:
case SEM_INFO:
arg.__buf = &seminfo;
ret = get_errno(semctl(semid, semnum, cmd, arg));
- err = host_to_target_seminfo(target_su.__buf, &seminfo);
- if (err)
- return err;
+ err = host_to_target_seminfo(tswapal(target_su->__buf), &seminfo);
+ if (err) {
+ ret = err;
+ }
break;
case IPC_RMID:
case GETPID:
@@ -2707,6 +2720,7 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
ret = get_errno(semctl(semid, semnum, cmd, NULL));
break;
}
+ unlock_user_struct(target_su, ptr, 0);
return ret;
}
@@ -3177,7 +3191,7 @@ static abi_long do_ipc(unsigned int call, int first,
break;
case IPCOP_semctl:
- ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
+ ret = do_semctl(first, second, third, ptr);
break;
case IPCOP_msgget:
@@ -3244,7 +3258,7 @@ static abi_long do_ipc(unsigned int call, int first,
/* IPC_* and SHM_* command values are the same on all linux platforms */
case IPCOP_shmctl:
- ret = do_shmctl(first, second, third);
+ ret = do_shmctl(first, second, ptr);
break;
default:
gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
@@ -6936,7 +6950,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_semctl
case TARGET_NR_semctl:
- ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
+ ret = do_semctl(arg1, arg2, arg3, arg4);
break;
#endif
#ifdef TARGET_NR_msgctl