Skip to content

Commit

Permalink
Merge pull request #79 from kevans91/casper
Browse files Browse the repository at this point in the history
bsd-user: freebsd: Implement some missing cap_* syscalls
  • Loading branch information
seanbruno authored and kwitaszczyk committed Dec 3, 2021
1 parent 1163019 commit 87b15cd
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 20 deletions.
104 changes: 86 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,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) */
Expand Down
3 changes: 1 addition & 2 deletions bsd-user/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 87b15cd

Please sign in to comment.