From aa07f5ecf9828bb2ff8d796cb0b17ad8534201c7 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 2 May 2014 11:17:07 +0300 Subject: linux-user: Add /proc/self/exe open forwarding QEMU already supports /proc/self/{maps,stat,auxv} so addition of /proc/self/exe is rather trivial. Fixes https://bugs.launchpad.net/qemu/+bug/1299190 Signed-off-by: Maxim Ostapenko Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9864813..5203cc4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5225,6 +5225,11 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { NULL, NULL, NULL } }; + if (is_proc_myself(pathname, "exe")) { + int execfd = qemu_getauxval(AT_EXECFD); + return execfd ? execfd : get_errno(open(exec_path, flags, mode)); + } + for (fake_open = fakes; fake_open->filename; fake_open++) { if (fake_open->cmp(pathname, fake_open->filename)) { break; -- cgit v1.1 From 52b6549442988e0a0819b6b7fb36ded164952a34 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 17 Apr 2014 14:02:47 +0100 Subject: linux-user: Move if-elses to a switch statement. This makes adding more message types cleaner. Signed-off-by: Huw Davies Signed-off-by: Riku Voipio --- linux-user/syscall.c | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5203cc4..52bd000 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1242,25 +1242,40 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); - if ((cmsg->cmsg_level == SOL_SOCKET) && - (cmsg->cmsg_type == SCM_RIGHTS)) { - int *fd = (int *)data; - int *target_fd = (int *)target_data; - int i, numfds = len / sizeof(int); + switch (cmsg->cmsg_level) { + case SOL_SOCKET: + switch (cmsg->cmsg_type) { + case SCM_RIGHTS: + { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); - for (i = 0; i < numfds; i++) - target_fd[i] = tswap32(fd[i]); - } else if ((cmsg->cmsg_level == SOL_SOCKET) && - (cmsg->cmsg_type == SO_TIMESTAMP) && - (len == sizeof(struct timeval))) { - /* copy struct timeval to target */ - struct timeval *tv = (struct timeval *)data; - struct target_timeval *target_tv = - (struct target_timeval *)target_data; - - target_tv->tv_sec = tswapal(tv->tv_sec); - target_tv->tv_usec = tswapal(tv->tv_usec); - } else { + for (i = 0; i < numfds; i++) + target_fd[i] = tswap32(fd[i]); + break; + } + case SO_TIMESTAMP: + { + struct timeval *tv = (struct timeval *)data; + struct target_timeval *target_tv = + (struct target_timeval *)target_data; + + if (len != sizeof(struct timeval)) + goto unimplemented; + + /* copy struct timeval to target */ + target_tv->tv_sec = tswapal(tv->tv_sec); + target_tv->tv_usec = tswapal(tv->tv_usec); + break; + } + default: + goto unimplemented; + } + break; + + default: + unimplemented: gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); memcpy(target_data, data, len); -- cgit v1.1 From 4bc2975698773afdca2f79ebcff9f3b588f646fc Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 17 Apr 2014 14:02:48 +0100 Subject: linux-user: Add support for SCM_CREDENTIALS. Signed-off-by: Huw Davies Signed-off-by: Riku Voipio --- linux-user/syscall.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 52bd000..27073b1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1269,6 +1269,17 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_tv->tv_usec = tswapal(tv->tv_usec); break; } + case SCM_CREDENTIALS: + { + struct ucred *cred = (struct ucred *)data; + struct target_ucred *target_cred = + (struct target_ucred *)target_data; + + __put_user(cred->pid, &target_cred->pid); + __put_user(cred->uid, &target_cred->uid); + __put_user(cred->gid, &target_cred->gid); + break; + } default: goto unimplemented; } -- cgit v1.1 From a29e5ba21f3dc01cd7f12aac9216e06e7bdd0e9e Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Mar 2014 21:51:08 +0000 Subject: linux-user: Handle arches with llseek instead of _llseek Recently merged kernel ports (such as OpenRISC and Meta) have an llseek system call instead of _llseek. This is handled for the host architecture by defining __NR__llseek as __NR_llseek, but not for the target architecture. Handle it in the same way for these architectures, defining TARGET_NR__llseek as TARGET_NR_llseek. Signed-off-by: James Hogan Cc: Riku Voipio Cc: Jia Liu Signed-off-by: Riku Voipio --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 27073b1..15de6f8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -198,6 +198,11 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ #define __NR__llseek __NR_lseek #endif +/* Newer kernel ports have llseek() instead of _llseek() */ +#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek) +#define TARGET_NR__llseek TARGET_NR_llseek +#endif + #ifdef __NR_gettid _syscall0(int, gettid) #else -- cgit v1.1 From 34d6086236baeb59f4b46e2380f2b271acd6f6cf Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Tue, 29 Apr 2014 13:11:20 +0200 Subject: linux-user: avoid using glibc internals in _syscall5 and in definition of target_sigevent struct Use the public sigset_t instead of the glibc specific internal __sigset_t in _syscall. Calculate the sigevent pad size is calculated in similar way as kernel does it instead of using glibc internal field _pad. This is needed for building with musl libc. Signed-off-by: Natanael Copa Signed-off-by: Riku Voipio Reviewed-by: Peter Maydell --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 15de6f8..af0bb35 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -411,7 +411,7 @@ static int sys_inotify_init1(int flags) #endif #define __NR_sys_ppoll __NR_ppoll _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, - struct timespec *, timeout, const __sigset_t *, sigmask, + struct timespec *, timeout, const sigset_t *, sigmask, size_t, sigsetsize) #endif -- cgit v1.1 From 18cb008865d078c30f8efcd28c774788ae13d6a3 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 19 Feb 2014 12:59:58 +0200 Subject: linux-user: rename cpu-uname -> uname To move more uname related functions out of syscall.c, rename cpu-uname.{c,h} to uname.{c.h} Signed-off-by: Riku Voipio --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index af0bb35..0f4a092 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -110,7 +110,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include "linux_loop.h" -#include "cpu-uname.h" +#include "uname.h" #include "qemu.h" -- cgit v1.1 From 6d30db19caab3cc71a9353cab772b258f0545503 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 19 Feb 2014 15:35:35 +0200 Subject: linux-user: move uname functions to uname.c Make syscall.c slightly smaller by moving uname-related functions to uname.c. Signed-off-by: Riku Voipio --- linux-user/syscall.c | 102 --------------------------------------------------- 1 file changed, 102 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0f4a092..9fc28bd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -60,7 +60,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include -#include //#include #include #include @@ -92,7 +91,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include -#include #include #include #include @@ -287,40 +285,6 @@ static bitmask_transtbl fcntl_flags_tbl[] = { { 0, 0, 0, 0 } }; -#define COPY_UTSNAME_FIELD(dest, src) \ - do { \ - /* __NEW_UTS_LEN doesn't include terminating null */ \ - (void) strncpy((dest), (src), __NEW_UTS_LEN); \ - (dest)[__NEW_UTS_LEN] = '\0'; \ - } while (0) - -static int sys_uname(struct new_utsname *buf) -{ - struct utsname uts_buf; - - if (uname(&uts_buf) < 0) - return (-1); - - /* - * Just in case these have some differences, we - * translate utsname to new_utsname (which is the - * struct linux kernel uses). - */ - - memset(buf, 0, sizeof(*buf)); - COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname); - COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename); - COPY_UTSNAME_FIELD(buf->release, uts_buf.release); - COPY_UTSNAME_FIELD(buf->version, uts_buf.version); - COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine); -#ifdef _GNU_SOURCE - COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname); -#endif - return (0); - -#undef COPY_UTSNAME_FIELD -} - static int sys_getcwd1(char *buf, size_t size) { if (getcwd(buf, size) == NULL) { @@ -4983,72 +4947,6 @@ int host_to_target_waitstatus(int status) return status; } -static int relstr_to_int(const char *s) -{ - /* Convert a uname release string like "2.6.18" to an integer - * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.) - */ - int i, n, tmp; - - tmp = 0; - for (i = 0; i < 3; i++) { - n = 0; - while (*s >= '0' && *s <= '9') { - n *= 10; - n += *s - '0'; - s++; - } - tmp = (tmp << 8) + n; - if (*s == '.') { - s++; - } - } - return tmp; -} - -int get_osversion(void) -{ - static int osversion; - struct new_utsname buf; - const char *s; - - if (osversion) - return osversion; - if (qemu_uname_release && *qemu_uname_release) { - s = qemu_uname_release; - } else { - if (sys_uname(&buf)) - return 0; - s = buf.release; - } - osversion = relstr_to_int(s); - return osversion; -} - -void init_qemu_uname_release(void) -{ - /* Initialize qemu_uname_release for later use. - * If the host kernel is too old and the user hasn't asked for - * a specific fake version number, we might want to fake a minimum - * target kernel version. - */ -#ifdef UNAME_MINIMUM_RELEASE - struct new_utsname buf; - - if (qemu_uname_release && *qemu_uname_release) { - return; - } - - if (sys_uname(&buf)) { - return; - } - - if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { - qemu_uname_release = UNAME_MINIMUM_RELEASE; - } -#endif -} - static int open_self_maps(void *cpu_env, int fd) { #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) -- cgit v1.1 From a39fb273bddd315b440b0617783051456a148242 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Tue, 8 Apr 2014 19:24:30 +0200 Subject: linux-user: fix getrusage and wait4 failures with invalid rusage struct Implementations of system calls getrusage and wait4 have not previously handled correctly cases when incorrect address of struct rusage is passed. This change makes sure return values are correctly set for these cases. Signed-off-by: Petar Jovanovic Signed-off-by: Riku Voipio --- linux-user/syscall.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9fc28bd..6efeeff 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6243,7 +6243,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct rusage rusage; ret = get_errno(getrusage(arg1, &rusage)); if (!is_error(ret)) { - host_to_target_rusage(arg2, &rusage); + ret = host_to_target_rusage(arg2, &rusage); } } break; @@ -6908,6 +6908,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long status_ptr = arg2; struct rusage rusage, *rusage_ptr; abi_ulong target_rusage = arg4; + abi_long rusage_err; if (target_rusage) rusage_ptr = &rusage; else @@ -6919,8 +6920,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (put_user_s32(status, status_ptr)) goto efault; } - if (target_rusage) - host_to_target_rusage(target_rusage, &rusage); + if (target_rusage) { + rusage_err = host_to_target_rusage(target_rusage, &rusage); + if (rusage_err) { + ret = rusage_err; + } + } } } break; -- cgit v1.1