Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Needs Q/A] bsd-user: freebsd: implement some cap_* syscalls #86

Open
wants to merge 4 commits into
base: bsd-user
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 79 additions & 18 deletions bsd-user/freebsd/os-proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define __FREEBSD_PROC_H_

#include <sys/param.h>
#include <sys/capsicum.h>
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1000000
#include <sys/procctl.h>
#include <sys/signal.h>
Expand All @@ -32,7 +33,9 @@
#include <sys/wait.h>
#include <unistd.h>

#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);
Expand Down Expand Up @@ -437,45 +440,103 @@ 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 (lock_user_struct(VERIFY_READ, target_rights, raddr, 1) == NULL)
return -TARGET_EFAULT;

memset(&rights, 0, sizeof(rights));
nrights = MIN(nitems(target_rights->cr_rights), nitems(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;
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)
{

qemu_log("qemu: Unsupported syscall cap_fcntls_limit()\n");
return -TARGET_ENOSYS;
return (get_errno(cap_fcntls_limit(fd, target_to_host_bitmask(rights,
cap_fcntl_flags_tbl))));
}

/* 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) */
Expand Down
3 changes: 1 addition & 2 deletions bsd-user/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,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;
}
Expand Down