diff --git a/bsd-user/freebsd/os-proc.h b/bsd-user/freebsd/os-proc.h index 62b8afbc5e5..ed8e64482c7 100644 --- a/bsd-user/freebsd/os-proc.h +++ b/bsd-user/freebsd/os-proc.h @@ -21,6 +21,7 @@ #define __FREEBSD_PROC_H_ #include +#include #if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000 #include #include @@ -32,7 +33,9 @@ #include #include +#include "qemu.h" #include "target_arch_cpu.h" +#include "target_os_user.h" extern int __setugid(int flag); extern int pdwait4(int fd, int *status, int options, struct rusage *rusage); @@ -437,45 +440,110 @@ static inline abi_long do_freebsd_cap_getmode(abi_ulong arg1) } /* cap_rights_limit(2) */ -static inline abi_long do_freebsd_cap_rights_limit(int arg1, abi_ulong arg2) +static inline abi_long do_freebsd_cap_rights_limit(int fd, abi_ulong raddr) { + cap_rights_t rights; + target_cap_rights_t *target_rights; + int i, nrights; - qemu_log("qemu: Unsupported syscall cap_rights_limit()\n"); - return -TARGET_ENOSYS; + if (fd == STDERR_FILENO || fd == STDOUT_FILENO || fd == STDIN_FILENO) + return -TARGET_ENOSYS; + if (lock_user_struct(VERIFY_READ, target_rights, raddr, 1) == NULL) + return -TARGET_EFAULT; + + memset(&rights, 0, sizeof(rights)); + nrights = MIN(sizeof(target_rights->cr_rights), sizeof(rights.cr_rights)); + for (i = 0; i < nrights; ++i) { + rights.cr_rights[i] = tswap64(target_rights->cr_rights[i]); + } + unlock_user_struct(target_rights, raddr, 1); + + return (get_errno(cap_rights_limit(fd, &rights))); } /* cap_ioctls_limit(2) */ -static inline abi_long do_freebsd_cap_ioctls_limit(int arg1, abi_ulong arg2, - abi_ulong arg3) +static inline abi_long do_freebsd_cap_ioctls_limit(int fd, abi_ulong cmd_addr, + abi_ulong ncmds) { + abi_ulong i, *target_cmds; + unsigned long *cmds; + abi_long ret; - qemu_log("qemu: Unsupported syscall cap_ioctls_limit()\n"); - return -TARGET_ENOSYS; + if (fd == STDERR_FILENO || fd == STDOUT_FILENO || fd == STDIN_FILENO) + return -TARGET_ENOSYS; + target_cmds = lock_user(VERIFY_READ, cmd_addr, sizeof(*target_cmds) * ncmds, + 1); + if (target_cmds == NULL) + return -TARGET_EFAULT; + + cmds = malloc(sizeof(*cmds) * ncmds); + if (cmds == NULL) + return -TARGET_ENOMEM; + for (i = 0; i < ncmds; ++i) { + cmds[i] = tswapl(target_cmds[i]); + } + unlock_user(target_cmds, cmd_addr, sizeof(*target_cmds) * ncmds); + ret = cap_ioctls_limit(fd, cmds, ncmds); + free(cmds); + return (get_errno(ret)); } /* cap_ioctls_get(2) */ -static inline abi_long do_freebsd_cap_ioctls_get(int arg1, abi_ulong arg2, - abi_ulong arg3) -{ +static inline abi_long do_freebsd_cap_ioctls_get(int fd, abi_ulong cmd_addr, + abi_ulong ncmds) +{ + abi_ulong *target_cmds; + unsigned long *cmds; + ssize_t i, ret; + + cmds = malloc(sizeof(*cmds) * ncmds); + if (cmds == NULL) + return -TARGET_ENOMEM; + ret = cap_ioctls_get(fd, cmds, ncmds); + /* cap_ioctls_get will not modify buffer if all allowed */ + if (ret == CAP_IOCTLS_ALL) { + free(cmds); + return CAP_IOCTLS_ALL; + } else if (ret < 0) { + free(cmds); + return (get_errno(ret)); + } - qemu_log("qemu: Unsupported syscall cap_ioctls_limit()\n"); - return -TARGET_ENOSYS; + target_cmds = lock_user(VERIFY_WRITE, cmd_addr, + sizeof(*target_cmds) * ncmds, 1); + if (target_cmds == NULL) + return -TARGET_EFAULT; + for (i = 0; i < ret; ++i) { + target_cmds[i] = tswapl(cmds[i]); + } + free(cmds); + unlock_user(target_cmds, cmd_addr, sizeof(*target_cmds) * ncmds); + return (ret); } /* cap_fcntls_limit(2) */ -static inline abi_long do_freebsd_cap_fcntls_limit(int arg1, abi_ulong arg2) +static inline abi_long do_freebsd_cap_fcntls_limit(int fd, abi_ulong rights) { + uint32_t host_rights; - qemu_log("qemu: Unsupported syscall cap_fcntls_limit()\n"); - return -TARGET_ENOSYS; + if (fd == STDERR_FILENO || fd == STDOUT_FILENO || fd == STDIN_FILENO) + return -TARGET_ENOSYS; + host_rights = tswap32(rights); + return (get_errno(cap_fcntls_limit(fd, host_rights))); } /* cap_fcntls_get(2) */ -static inline abi_long do_freebsd_cap_fcntls_get(int arg1, abi_ulong arg2) +static inline abi_long do_freebsd_cap_fcntls_get(int fd, abi_ulong raddr) { + uint32_t host_rights; + int ret; - qemu_log("qemu: Unsupported syscall cap_fcntls_get()\n"); - return -TARGET_ENOSYS; + ret = cap_fcntls_get(fd, &host_rights); + if (ret < 0) + return (get_errno(ret)); + + put_user_u32(host_rights, raddr); + return (0); } /* audit(2) */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 69d51d6c9d5..e394df958ce 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -64,8 +64,7 @@ abi_long get_errno(abi_long ret) { if (ret == -1) { - /* XXX need to translate host -> target errnos here */ - return -(errno); + return -(host_to_target_errno(errno)); } else { return ret; }