From patchwork Thu Jan 31 19:50:07 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 217249 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 9343A2C0091 for ; Fri, 1 Feb 2013 06:50:40 +1100 (EST) Received: from localhost ([::1]:46408 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U109e-00078d-EE for incoming@patchwork.ozlabs.org; Thu, 31 Jan 2013 14:50:38 -0500 Received: from eggs.gnu.org ([208.118.235.92]:44912) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U109O-000711-FD for qemu-devel@nongnu.org; Thu, 31 Jan 2013 14:50:32 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U109K-0007Us-Ky for qemu-devel@nongnu.org; Thu, 31 Jan 2013 14:50:22 -0500 Received: from smtp6-g21.free.fr ([2a01:e0c:1:1599::15]:54148) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U109K-0007T5-01 for qemu-devel@nongnu.org; Thu, 31 Jan 2013 14:50:18 -0500 Received: from localhost.localdomain (unknown [78.238.229.36]) by smtp6-g21.free.fr (Postfix) with ESMTP id B15108235A; Thu, 31 Jan 2013 20:50:10 +0100 (CET) From: Laurent Vivier To: Peter Maydell Date: Thu, 31 Jan 2013 20:50:07 +0100 Message-Id: <1359661807-9307-1-git-send-email-laurent@vivier.eu> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1358749523-20925-1-git-send-email-laurent@vivier.eu> References: <1358749523-20925-1-git-send-email-laurent@vivier.eu> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a01:e0c:1:1599::15 Cc: Riku Voipio , qemu-devel@nongnu.org, Laurent Vivier Subject: [Qemu-devel] [PATCH][v5] linux-user: correct semctl() and shmctl() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- v2: move lock_user_struct() in do_semctl() v3: correctly set the return value v3: don't duplicate unlock_user_struct(), set err to ret instead v4: replace all return by if (err) { ret = err; break; } linux-user/syscall.c | 56 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 08538fc..6610c24 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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); @@ -6933,7 +6947,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