summaryrefslogtreecommitdiffstats
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c163
1 files changed, 140 insertions, 23 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e2c10cc0bd..9864813b7a 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -43,6 +43,7 @@
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/swap.h>
+#include <linux/capability.h>
#include <signal.h>
#include <sched.h>
#ifdef __ia64__
@@ -243,6 +244,10 @@ _syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr);
_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
void *, arg);
+_syscall2(int, capget, struct __user_cap_header_struct *, header,
+ struct __user_cap_data_struct *, data);
+_syscall2(int, capset, struct __user_cap_header_struct *, header,
+ struct __user_cap_data_struct *, data);
static bitmask_transtbl fcntl_flags_tbl[] = {
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
@@ -2057,9 +2062,12 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
socklen_t addrlen;
void *addr;
abi_long ret;
+ int host_flags;
+
+ host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
if (target_addr == 0) {
- return get_errno(accept4(fd, NULL, NULL, flags));
+ return get_errno(accept4(fd, NULL, NULL, host_flags));
}
/* linux returns EINVAL if addrlen pointer is invalid */
@@ -2075,7 +2083,7 @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
addr = alloca(addrlen);
- ret = get_errno(accept4(fd, addr, &addrlen, flags));
+ ret = get_errno(accept4(fd, addr, &addrlen, host_flags));
if (!is_error(ret)) {
host_to_target_sockaddr(target_addr, addr, addrlen);
if (put_user_u32(addrlen, target_addrlen_addr))
@@ -4243,7 +4251,7 @@ static void *clone_func(void *arg)
env = info->env;
cpu = ENV_GET_CPU(env);
thread_cpu = cpu;
- ts = (TaskState *)env->opaque;
+ ts = (TaskState *)cpu->opaque;
info->tid = gettid();
cpu->host_tid = info->tid;
task_settid(ts);
@@ -4271,8 +4279,10 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
abi_ulong parent_tidptr, target_ulong newtls,
abi_ulong child_tidptr)
{
+ CPUState *cpu = ENV_GET_CPU(env);
int ret;
TaskState *ts;
+ CPUState *new_cpu;
CPUArchState *new_env;
unsigned int nptl_flags;
sigset_t sigmask;
@@ -4282,7 +4292,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
flags &= ~(CLONE_VFORK | CLONE_VM);
if (flags & CLONE_VM) {
- TaskState *parent_ts = (TaskState *)env->opaque;
+ TaskState *parent_ts = (TaskState *)cpu->opaque;
new_thread_info info;
pthread_attr_t attr;
@@ -4292,7 +4302,8 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
new_env = cpu_copy(env);
/* Init regs that differ from the parent. */
cpu_clone_regs(new_env, newsp);
- new_env->opaque = ts;
+ new_cpu = ENV_GET_CPU(new_env);
+ new_cpu->opaque = ts;
ts->bprm = parent_ts->bprm;
ts->info = parent_ts->info;
nptl_flags = flags;
@@ -4364,7 +4375,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
put_user_u32(gettid(), child_tidptr);
if (flags & CLONE_PARENT_SETTID)
put_user_u32(gettid(), parent_tidptr);
- ts = (TaskState *)env->opaque;
+ ts = (TaskState *)cpu->opaque;
if (flags & CLONE_SETTLS)
cpu_set_tls (env, newtls);
if (flags & CLONE_CHILD_CLEARTID)
@@ -4418,6 +4429,14 @@ static int target_to_host_fcntl_cmd(int cmd)
#endif
case TARGET_F_NOTIFY:
return F_NOTIFY;
+#ifdef F_GETOWN_EX
+ case TARGET_F_GETOWN_EX:
+ return F_GETOWN_EX;
+#endif
+#ifdef F_SETOWN_EX
+ case TARGET_F_SETOWN_EX:
+ return F_SETOWN_EX;
+#endif
default:
return -TARGET_EINVAL;
}
@@ -4440,6 +4459,10 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
struct target_flock *target_fl;
struct flock64 fl64;
struct target_flock64 *target_fl64;
+#ifdef F_GETOWN_EX
+ struct f_owner_ex fox;
+ struct target_f_owner_ex *target_fox;
+#endif
abi_long ret;
int host_cmd = target_to_host_fcntl_cmd(cmd);
@@ -4533,6 +4556,30 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
ret = get_errno(fcntl(fd, host_cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)));
break;
+#ifdef F_GETOWN_EX
+ case TARGET_F_GETOWN_EX:
+ ret = get_errno(fcntl(fd, host_cmd, &fox));
+ if (ret >= 0) {
+ if (!lock_user_struct(VERIFY_WRITE, target_fox, arg, 0))
+ return -TARGET_EFAULT;
+ target_fox->type = tswap32(fox.type);
+ target_fox->pid = tswap32(fox.pid);
+ unlock_user_struct(target_fox, arg, 1);
+ }
+ break;
+#endif
+
+#ifdef F_SETOWN_EX
+ case TARGET_F_SETOWN_EX:
+ if (!lock_user_struct(VERIFY_READ, target_fox, arg, 1))
+ return -TARGET_EFAULT;
+ fox.type = tswap32(target_fox->type);
+ fox.pid = tswap32(target_fox->pid);
+ unlock_user_struct(target_fox, arg, 0);
+ ret = get_errno(fcntl(fd, host_cmd, &fox));
+ break;
+#endif
+
case TARGET_F_SETOWN:
case TARGET_F_GETOWN:
case TARGET_F_SETSIG:
@@ -4974,7 +5021,8 @@ void init_qemu_uname_release(void)
static int open_self_maps(void *cpu_env, int fd)
{
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
- TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+ TaskState *ts = cpu->opaque;
#endif
FILE *fp;
char *line = NULL;
@@ -5026,7 +5074,8 @@ static int open_self_maps(void *cpu_env, int fd)
static int open_self_stat(void *cpu_env, int fd)
{
- TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+ TaskState *ts = cpu->opaque;
abi_ulong start_stack = ts->info->start_stack;
int i;
@@ -5062,7 +5111,8 @@ static int open_self_stat(void *cpu_env, int fd)
static int open_self_auxv(void *cpu_env, int fd)
{
- TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
+ TaskState *ts = cpu->opaque;
abi_ulong auxv = ts->info->saved_auxv;
abi_ulong len = ts->info->auxv_len;
char *ptr;
@@ -5244,14 +5294,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
/* Remove the CPU from the list. */
QTAILQ_REMOVE(&cpus, cpu, node);
cpu_list_unlock();
- ts = ((CPUArchState *)cpu_env)->opaque;
+ ts = cpu->opaque;
if (ts->child_tidptr) {
put_user_u32(0, ts->child_tidptr);
sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
NULL, NULL, 0);
}
thread_cpu = NULL;
- object_unref(OBJECT(ENV_GET_CPU(cpu_env)));
+ object_unref(OBJECT(cpu));
g_free(ts);
pthread_exit(NULL);
}
@@ -5987,7 +6037,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
sigset_t cur_set;
abi_ulong target_set;
- sigprocmask(0, NULL, &cur_set);
+ do_sigprocmask(0, NULL, &cur_set);
host_to_target_old_sigset(&target_set, &cur_set);
ret = target_set;
}
@@ -5998,10 +6048,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
sigset_t set, oset, cur_set;
abi_ulong target_set = arg1;
- sigprocmask(0, NULL, &cur_set);
+ do_sigprocmask(0, NULL, &cur_set);
target_to_host_old_sigset(&set, &target_set);
sigorset(&set, &set, &cur_set);
- sigprocmask(SIG_SETMASK, &set, &oset);
+ do_sigprocmask(SIG_SETMASK, &set, &oset);
host_to_target_old_sigset(&target_set, &oset);
ret = target_set;
}
@@ -6032,7 +6082,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- ret = get_errno(sigprocmask(how, &set, &oldset));
+ ret = get_errno(do_sigprocmask(how, &set, &oldset));
if (!is_error(ret)) {
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
@@ -6066,7 +6116,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = 0;
set_ptr = NULL;
}
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+ ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
goto efault;
@@ -6106,7 +6156,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
how = 0;
set_ptr = NULL;
}
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
+ ret = get_errno(do_sigprocmask(how, set_ptr, &oldset));
if (!is_error(ret) && arg3) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0)))
goto efault;
@@ -6555,7 +6605,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
case TARGET_NR_mprotect:
{
- TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ TaskState *ts = cpu->opaque;
/* Special hack to detect libc making the stack executable. */
if ((arg3 & PROT_GROWSDOWN)
&& arg1 >= ts->info->stack_limit
@@ -7635,9 +7685,75 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, ret);
break;
case TARGET_NR_capget:
- goto unimplemented;
case TARGET_NR_capset:
- goto unimplemented;
+ {
+ struct target_user_cap_header *target_header;
+ struct target_user_cap_data *target_data = NULL;
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct data[2];
+ struct __user_cap_data_struct *dataptr = NULL;
+ int i, target_datalen;
+ int data_items = 1;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_header, arg1, 1)) {
+ goto efault;
+ }
+ header.version = tswap32(target_header->version);
+ header.pid = tswap32(target_header->pid);
+
+ if (header.version != _LINUX_CAPABILITY_VERSION) {
+ /* Version 2 and up takes pointer to two user_data structs */
+ data_items = 2;
+ }
+
+ target_datalen = sizeof(*target_data) * data_items;
+
+ if (arg2) {
+ if (num == TARGET_NR_capget) {
+ target_data = lock_user(VERIFY_WRITE, arg2, target_datalen, 0);
+ } else {
+ target_data = lock_user(VERIFY_READ, arg2, target_datalen, 1);
+ }
+ if (!target_data) {
+ unlock_user_struct(target_header, arg1, 0);
+ goto efault;
+ }
+
+ if (num == TARGET_NR_capset) {
+ for (i = 0; i < data_items; i++) {
+ data[i].effective = tswap32(target_data[i].effective);
+ data[i].permitted = tswap32(target_data[i].permitted);
+ data[i].inheritable = tswap32(target_data[i].inheritable);
+ }
+ }
+
+ dataptr = data;
+ }
+
+ if (num == TARGET_NR_capget) {
+ ret = get_errno(capget(&header, dataptr));
+ } else {
+ ret = get_errno(capset(&header, dataptr));
+ }
+
+ /* The kernel always updates version for both capget and capset */
+ target_header->version = tswap32(header.version);
+ unlock_user_struct(target_header, arg1, 1);
+
+ if (arg2) {
+ if (num == TARGET_NR_capget) {
+ for (i = 0; i < data_items; i++) {
+ target_data[i].effective = tswap32(data[i].effective);
+ target_data[i].permitted = tswap32(data[i].permitted);
+ target_data[i].inheritable = tswap32(data[i].inheritable);
+ }
+ unlock_user(target_data, arg2, target_datalen);
+ } else {
+ unlock_user(target_data, arg2, 0);
+ }
+ }
+ break;
+ }
case TARGET_NR_sigaltstack:
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
@@ -8119,7 +8235,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
}
mask = arg2;
target_to_host_old_sigset(&set, &mask);
- sigprocmask(how, &set, &oldset);
+ do_sigprocmask(how, &set, &oldset);
host_to_target_old_sigset(&mask, &oldset);
ret = mask;
}
@@ -8647,7 +8763,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
#elif defined(TARGET_M68K)
{
- TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ TaskState *ts = cpu->opaque;
ts->tp_value = arg1;
ret = 0;
break;
@@ -8663,7 +8779,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
#elif defined(TARGET_M68K)
{
- TaskState *ts = ((CPUArchState *)cpu_env)->opaque;
+ TaskState *ts = cpu->opaque;
ret = ts->tp_value;
break;
}
@@ -9142,6 +9258,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_atomic_barrier:
{
/* Like the kernel implementation and the qemu arm barrier, no-op this? */
+ ret = 0;
break;
}
#endif