Message ID | 1356037136-19479-1-git-send-email-laurent@vivier.eu |
---|---|
State | New |
Headers | show |
Ping ! Le jeudi 20 décembre 2012 à 21:58 +0100, Laurent Vivier a écrit : > The parameter "union semun" of semctl() is not a value > but a pointer to the value. > > Moreover, all fields of target_su must be swapped (if needed). > > The third argument of shmctl is a pointer. > > WITHOUT this patch: > > $ ipcs > > kernel not configured for shared memory > > qemu: uncaught target signal 11 (Segmentation fault) - core dumped > > WITH this patch: > > $ ipcs > > ------ Shared Memory Segments -------- > key shmid owner perms bytes nattch status > 0x4e545030 0 root 600 96 1 > 0x4e545031 32769 root 600 96 1 > 0x4e545032 65538 root 666 96 1 > 0x4e545033 98307 root 666 96 1 > 0x47505344 131076 root 666 8240 1 > 0x3c81b7f5 163845 laurent 666 4096 0 > 0x00000000 729513990 laurent 600 393216 2 dest > 0x00000000 729546759 laurent 600 393216 2 dest > 0x00000000 1879179273 laurent 600 393216 2 dest > > ------ Semaphore Arrays -------- > key semid owner perms nsems > 0x3c81b7f6 32768 laurent 666 1 > 0x1c44ac47 6586369 laurent 600 1 > > ------ Message Queues -------- > key msqid owner perms used-bytes messages > 0x1c44ac45 458752 laurent 600 0 0 > 0x1c44ac46 491521 laurent 600 0 0 > > Signed-off-by: Laurent Vivier <laurent@vivier.eu> > --- > linux-user/syscall.c | 37 ++++++++++++++++++++++++++----------- > 1 file changed, 26 insertions(+), 11 deletions(-) > > diff --git a/linux-user/syscall.c b/linux-user/syscall.c > index c2a2343..7bab006 100644 > --- a/linux-user/syscall.c > +++ b/linux-user/syscall.c > @@ -2656,24 +2656,26 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd, > break; > case GETALL: > case SETALL: > - err = target_to_host_semarray(semid, &array, target_su.array); > + err = target_to_host_semarray(semid, &array, > + tswapal(target_su.array)); > if (err) > return err; > arg.array = array; > ret = get_errno(semctl(semid, semnum, cmd, arg)); > - err = host_to_target_semarray(semid, target_su.array, &array); > + err = host_to_target_semarray(semid, tswapal(target_su.array), > + &array); > if (err) > return err; > break; > case IPC_STAT: > case IPC_SET: > case SEM_STAT: > - err = target_to_host_semid_ds(&dsarg, target_su.buf); > + err = target_to_host_semid_ds(&dsarg, tswapal(target_su.buf)); > if (err) > return err; > arg.buf = &dsarg; > ret = get_errno(semctl(semid, semnum, cmd, arg)); > - err = host_to_target_semid_ds(target_su.buf, &dsarg); > + err = host_to_target_semid_ds(tswapal(target_su.buf), &dsarg); > if (err) > return err; > break; > @@ -2681,7 +2683,7 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd, > case SEM_INFO: > arg.__buf = &seminfo; > ret = get_errno(semctl(semid, semnum, cmd, arg)); > - err = host_to_target_seminfo(target_su.__buf, &seminfo); > + err = host_to_target_seminfo(tswapal(target_su.__buf), &seminfo); > if (err) > return err; > break; > @@ -3161,10 +3163,16 @@ static abi_long do_ipc(unsigned int call, int first, > ret = get_errno(semget(first, second, third)); > break; > > - case IPCOP_semctl: > - ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr); > + case IPCOP_semctl: { > + union target_semun *target_su; > + if (!lock_user_struct(VERIFY_READ, target_su, ptr, 1)) { > + ret = -TARGET_EFAULT; > + break; > + } > + ret = do_semctl(first, second, third, *target_su); > + unlock_user_struct(target_su, ptr, 0); > break; > - > + } > case IPCOP_msgget: > ret = get_errno(msgget(first, second)); > break; > @@ -3229,7 +3237,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); > @@ -6996,9 +7004,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, > break; > #endif > #ifdef TARGET_NR_semctl > - case TARGET_NR_semctl: > - ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4); > + case TARGET_NR_semctl: { > + union target_semun *target_su; > + if (!lock_user_struct(VERIFY_READ, target_su, arg4, 1)) { > + ret = -TARGET_EFAULT; > + break; > + } > + ret = do_semctl(arg1, arg2, arg3, *target_su); > + unlock_user_struct(target_su, ptr, 0); > break; > + } > #endif > #ifdef TARGET_NR_msgctl > case TARGET_NR_msgctl:
On 20 December 2012 20:58, Laurent Vivier <laurent@vivier.eu> wrote: > The parameter "union semun" of semctl() is not a value > but a pointer to the value. > @@ -3161,10 +3163,16 @@ static abi_long do_ipc(unsigned int call, int first, > ret = get_errno(semget(first, second, third)); > break; > > - case IPCOP_semctl: > - ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr); > + case IPCOP_semctl: { > + union target_semun *target_su; > + if (!lock_user_struct(VERIFY_READ, target_su, ptr, 1)) { > + ret = -TARGET_EFAULT; > + break; > + } > + ret = do_semctl(first, second, third, *target_su); > + unlock_user_struct(target_su, ptr, 0); Rather than doing the lock/unlock in both callers to do_semctl, just pass do_semctl an abi_long and have it do the lock/unlock. Rest of patch looks ok. -- PMM
diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c2a2343..7bab006 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2656,24 +2656,26 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd, break; case GETALL: case SETALL: - err = target_to_host_semarray(semid, &array, target_su.array); + err = target_to_host_semarray(semid, &array, + tswapal(target_su.array)); if (err) return err; arg.array = array; ret = get_errno(semctl(semid, semnum, cmd, arg)); - err = host_to_target_semarray(semid, target_su.array, &array); + err = host_to_target_semarray(semid, tswapal(target_su.array), + &array); if (err) return err; break; case IPC_STAT: case IPC_SET: case SEM_STAT: - err = target_to_host_semid_ds(&dsarg, target_su.buf); + err = target_to_host_semid_ds(&dsarg, tswapal(target_su.buf)); if (err) return err; arg.buf = &dsarg; ret = get_errno(semctl(semid, semnum, cmd, arg)); - err = host_to_target_semid_ds(target_su.buf, &dsarg); + err = host_to_target_semid_ds(tswapal(target_su.buf), &dsarg); if (err) return err; break; @@ -2681,7 +2683,7 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd, case SEM_INFO: arg.__buf = &seminfo; ret = get_errno(semctl(semid, semnum, cmd, arg)); - err = host_to_target_seminfo(target_su.__buf, &seminfo); + err = host_to_target_seminfo(tswapal(target_su.__buf), &seminfo); if (err) return err; break; @@ -3161,10 +3163,16 @@ static abi_long do_ipc(unsigned int call, int first, ret = get_errno(semget(first, second, third)); break; - case IPCOP_semctl: - ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr); + case IPCOP_semctl: { + union target_semun *target_su; + if (!lock_user_struct(VERIFY_READ, target_su, ptr, 1)) { + ret = -TARGET_EFAULT; + break; + } + ret = do_semctl(first, second, third, *target_su); + unlock_user_struct(target_su, ptr, 0); break; - + } case IPCOP_msgget: ret = get_errno(msgget(first, second)); break; @@ -3229,7 +3237,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); @@ -6996,9 +7004,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif #ifdef TARGET_NR_semctl - case TARGET_NR_semctl: - ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4); + case TARGET_NR_semctl: { + union target_semun *target_su; + if (!lock_user_struct(VERIFY_READ, target_su, arg4, 1)) { + ret = -TARGET_EFAULT; + break; + } + ret = do_semctl(arg1, arg2, arg3, *target_su); + unlock_user_struct(target_su, ptr, 0); break; + } #endif #ifdef TARGET_NR_msgctl case TARGET_NR_msgctl:
The parameter "union semun" of semctl() is not a value but a pointer to the value. Moreover, all fields of target_su must be swapped (if needed). The third argument of shmctl is a pointer. WITHOUT this patch: $ ipcs kernel not configured for shared memory qemu: uncaught target signal 11 (Segmentation fault) - core dumped WITH this patch: $ ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x4e545030 0 root 600 96 1 0x4e545031 32769 root 600 96 1 0x4e545032 65538 root 666 96 1 0x4e545033 98307 root 666 96 1 0x47505344 131076 root 666 8240 1 0x3c81b7f5 163845 laurent 666 4096 0 0x00000000 729513990 laurent 600 393216 2 dest 0x00000000 729546759 laurent 600 393216 2 dest 0x00000000 1879179273 laurent 600 393216 2 dest ------ Semaphore Arrays -------- key semid owner perms nsems 0x3c81b7f6 32768 laurent 666 1 0x1c44ac47 6586369 laurent 600 1 ------ Message Queues -------- key msqid owner perms used-bytes messages 0x1c44ac45 458752 laurent 600 0 0 0x1c44ac46 491521 laurent 600 0 0 Signed-off-by: Laurent Vivier <laurent@vivier.eu> --- linux-user/syscall.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-)