On Mon, Mar 17, 2014 at 12:15:35PM +0000, Peter Maydell wrote:
> 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.mayd...@linaro.org>
> ---
> Changes v1->v2: initialize target_data to NULL to suppress a gcc 4.8
> warning; roll our own capget() and capset() rather than relying on
> the sys/capability.h header that is in an optional package rather
> than libc proper.

Thanks, looks good and passes the ltp tests. Honestly, I think putting
this to 2.0 past freeze is sloppy maintainership from me - but I trust
you would fix any issues caused by this patch rapidly ;)

I've included in the to-be-pull req:

http://git.linaro.org/people/riku.voipio/qemu.git/shortlog/refs/heads/linux-user-for-upstream

If someone protests, I can replace it with nowarn version.

Riku

>  linux-user/syscall.c      | 75 
> +++++++++++++++++++++++++++++++++++++++++++++--
>  linux-user/syscall_defs.h | 11 +++++++
>  2 files changed, 84 insertions(+), 2 deletions(-)
> 
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 2a8b66c..49244f8 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,    },
> @@ -7641,9 +7646,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_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:
>  #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
>      defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA) || 
> \
> diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
> index 732c9e3..7db878a 100644
> --- a/linux-user/syscall_defs.h
> +++ b/linux-user/syscall_defs.h
> @@ -2559,3 +2559,14 @@ struct target_sigevent {
>          } _sigev_thread;
>      } _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;
> +};
> -- 
> 1.9.0

Reply via email to