linux-user: Implement capget, capset

Implement the capget and capset syscalls. This is useful because
simple programs like 'ls' try to use it in AArch64, and otherwise
we emit a lot of noise about it being unimplemented.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
This commit is contained in:
Peter Maydell 2014-03-17 12:15:35 +00:00 committed by Riku Voipio
parent a7ec0f98e3
commit e0eb210ec0
2 changed files with 84 additions and 2 deletions

View File

@ -43,6 +43,7 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/swap.h> #include <sys/swap.h>
#include <linux/capability.h>
#include <signal.h> #include <signal.h>
#include <sched.h> #include <sched.h>
#ifdef __ia64__ #ifdef __ia64__
@ -243,6 +244,10 @@ _syscall3(int, sys_sched_setaffinity, pid_t, pid, unsigned int, len,
unsigned long *, user_mask_ptr); unsigned long *, user_mask_ptr);
_syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd, _syscall4(int, reboot, int, magic1, int, magic2, unsigned int, cmd,
void *, arg); 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[] = { static bitmask_transtbl fcntl_flags_tbl[] = {
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
@ -7677,9 +7682,75 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, ret); unlock_user(p, arg1, ret);
break; break;
case TARGET_NR_capget: case TARGET_NR_capget:
goto unimplemented;
case TARGET_NR_capset: 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_1) {
/* 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: case TARGET_NR_sigaltstack:
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \ #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || \

View File

@ -2566,3 +2566,14 @@ struct target_sigevent {
} _sigev_thread; } _sigev_thread;
} _sigev_un; } _sigev_un;
}; };
struct target_user_cap_header {
uint32_t version;
int pid;
};
struct target_user_cap_data {
uint32_t effective;
uint32_t permitted;
uint32_t inheritable;
};