Commit 9d0fdecb authored by Yi Min Zhao's avatar Yi Min Zhao Committed by Eduardo Otubo
Browse files

sandbox: disable -sandbox if CONFIG_SECCOMP undefined



If CONFIG_SECCOMP is undefined, the option 'elevatedprivileges' remains
compiled. This would make libvirt set the corresponding capability and
then trigger failure during guest startup. This patch moves the code
regarding seccomp command line options to qemu-seccomp.c file and
wraps qemu_opts_foreach finding sandbox option with CONFIG_SECCOMP.
Because parse_sandbox() is moved into qemu-seccomp.c file, change
seccomp_start() to static function.

Signed-off-by: default avatarYi Min Zhao <zyimin@linux.ibm.com>
Reviewed-by: default avatarJán Tomko <jtomko@redhat.com>
Tested-by: default avatarJán Tomko <jtomko@redhat.com>
Acked-by: default avatarEduardo Otubo <otubo@redhat.com>
parent 14fc6184
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -21,5 +21,6 @@
#define QEMU_SECCOMP_SET_SPAWN       (1 << 3)
#define QEMU_SECCOMP_SET_RESOURCECTL (1 << 4)

int seccomp_start(uint32_t seccomp_opts);
int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp);

#endif
+120 −1
Original line number Diff line number Diff line
@@ -13,6 +13,11 @@
 * GNU GPL, version 2 or (at your option) any later version.
 */
#include "qemu/osdep.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include <sys/prctl.h>
#include <seccomp.h>
#include "sysemu/seccomp.h"

@@ -96,7 +101,7 @@ static const struct QemuSeccompSyscall blacklist[] = {
};


int seccomp_start(uint32_t seccomp_opts)
static int seccomp_start(uint32_t seccomp_opts)
{
    int rc = 0;
    unsigned int i = 0;
@@ -125,3 +130,117 @@ int seccomp_start(uint32_t seccomp_opts)
    seccomp_release(ctx);
    return rc;
}

#ifdef CONFIG_SECCOMP
int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp)
{
    if (qemu_opt_get_bool(opts, "enable", false)) {
        uint32_t seccomp_opts = QEMU_SECCOMP_SET_DEFAULT
                | QEMU_SECCOMP_SET_OBSOLETE;
        const char *value = NULL;

        value = qemu_opt_get(opts, "obsolete");
        if (value) {
            if (g_str_equal(value, "allow")) {
                seccomp_opts &= ~QEMU_SECCOMP_SET_OBSOLETE;
            } else if (g_str_equal(value, "deny")) {
                /* this is the default option, this if is here
                 * to provide a little bit of consistency for
                 * the command line */
            } else {
                error_report("invalid argument for obsolete");
                return -1;
            }
        }

        value = qemu_opt_get(opts, "elevateprivileges");
        if (value) {
            if (g_str_equal(value, "deny")) {
                seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
            } else if (g_str_equal(value, "children")) {
                seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;

                /* calling prctl directly because we're
                 * not sure if host has CAP_SYS_ADMIN set*/
                if (prctl(PR_SET_NO_NEW_PRIVS, 1)) {
                    error_report("failed to set no_new_privs "
                                 "aborting");
                    return -1;
                }
            } else if (g_str_equal(value, "allow")) {
                /* default value */
            } else {
                error_report("invalid argument for elevateprivileges");
                return -1;
            }
        }

        value = qemu_opt_get(opts, "spawn");
        if (value) {
            if (g_str_equal(value, "deny")) {
                seccomp_opts |= QEMU_SECCOMP_SET_SPAWN;
            } else if (g_str_equal(value, "allow")) {
                /* default value */
            } else {
                error_report("invalid argument for spawn");
                return -1;
            }
        }

        value = qemu_opt_get(opts, "resourcecontrol");
        if (value) {
            if (g_str_equal(value, "deny")) {
                seccomp_opts |= QEMU_SECCOMP_SET_RESOURCECTL;
            } else if (g_str_equal(value, "allow")) {
                /* default value */
            } else {
                error_report("invalid argument for resourcecontrol");
                return -1;
            }
        }

        if (seccomp_start(seccomp_opts) < 0) {
            error_report("failed to install seccomp syscall filter "
                         "in the kernel");
            return -1;
        }
    }

    return 0;
}

static QemuOptsList qemu_sandbox_opts = {
    .name = "sandbox",
    .implied_opt_name = "enable",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
    .desc = {
        {
            .name = "enable",
            .type = QEMU_OPT_BOOL,
        },
        {
            .name = "obsolete",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "elevateprivileges",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "spawn",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "resourcecontrol",
            .type = QEMU_OPT_STRING,
        },
        { /* end of list */ }
    },
};

static void seccomp_register(void)
{
    qemu_add_opts(&qemu_sandbox_opts);
}
opts_init(seccomp_register);
#endif
+8 −116
Original line number Diff line number Diff line
@@ -28,11 +28,7 @@
#include "qemu/cutils.h"
#include "qemu/help_option.h"
#include "qemu/uuid.h"

#ifdef CONFIG_SECCOMP
#include <sys/prctl.h>
#include "sysemu/seccomp.h"
#endif

#ifdef CONFIG_SDL
#if defined(__APPLE__) || defined(main)
@@ -259,35 +255,6 @@ static QemuOptsList qemu_rtc_opts = {
    },
};

static QemuOptsList qemu_sandbox_opts = {
    .name = "sandbox",
    .implied_opt_name = "enable",
    .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
    .desc = {
        {
            .name = "enable",
            .type = QEMU_OPT_BOOL,
        },
        {
            .name = "obsolete",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "elevateprivileges",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "spawn",
            .type = QEMU_OPT_STRING,
        },
        {
            .name = "resourcecontrol",
            .type = QEMU_OPT_STRING,
        },
        { /* end of list */ }
    },
};

static QemuOptsList qemu_option_rom_opts = {
    .name = "option-rom",
    .implied_opt_name = "romfile",
@@ -1050,88 +1017,6 @@ static int bt_parse(const char *opt)
    return 1;
}

static int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp)
{
    if (qemu_opt_get_bool(opts, "enable", false)) {
#ifdef CONFIG_SECCOMP
        uint32_t seccomp_opts = QEMU_SECCOMP_SET_DEFAULT
                | QEMU_SECCOMP_SET_OBSOLETE;
        const char *value = NULL;

        value = qemu_opt_get(opts, "obsolete");
        if (value) {
            if (g_str_equal(value, "allow")) {
                seccomp_opts &= ~QEMU_SECCOMP_SET_OBSOLETE;
            } else if (g_str_equal(value, "deny")) {
                /* this is the default option, this if is here
                 * to provide a little bit of consistency for
                 * the command line */
            } else {
                error_report("invalid argument for obsolete");
                return -1;
            }
        }

        value = qemu_opt_get(opts, "elevateprivileges");
        if (value) {
            if (g_str_equal(value, "deny")) {
                seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;
            } else if (g_str_equal(value, "children")) {
                seccomp_opts |= QEMU_SECCOMP_SET_PRIVILEGED;

                /* calling prctl directly because we're
                 * not sure if host has CAP_SYS_ADMIN set*/
                if (prctl(PR_SET_NO_NEW_PRIVS, 1)) {
                    error_report("failed to set no_new_privs "
                                 "aborting");
                    return -1;
                }
            } else if (g_str_equal(value, "allow")) {
                /* default value */
            } else {
                error_report("invalid argument for elevateprivileges");
                return -1;
            }
        }

        value = qemu_opt_get(opts, "spawn");
        if (value) {
            if (g_str_equal(value, "deny")) {
                seccomp_opts |= QEMU_SECCOMP_SET_SPAWN;
            } else if (g_str_equal(value, "allow")) {
                /* default value */
            } else {
                error_report("invalid argument for spawn");
                return -1;
            }
        }

        value = qemu_opt_get(opts, "resourcecontrol");
        if (value) {
            if (g_str_equal(value, "deny")) {
                seccomp_opts |= QEMU_SECCOMP_SET_RESOURCECTL;
            } else if (g_str_equal(value, "allow")) {
                /* default value */
            } else {
                error_report("invalid argument for resourcecontrol");
                return -1;
            }
        }

        if (seccomp_start(seccomp_opts) < 0) {
            error_report("failed to install seccomp syscall filter "
                         "in the kernel");
            return -1;
        }
#else
        error_report("seccomp support is disabled");
        return -1;
#endif
    }

    return 0;
}

static int parse_name(void *opaque, QemuOpts *opts, Error **errp)
{
    const char *proc_name;
@@ -3079,7 +2964,6 @@ int main(int argc, char **argv, char **envp)
    qemu_add_opts(&qemu_mem_opts);
    qemu_add_opts(&qemu_smp_opts);
    qemu_add_opts(&qemu_boot_opts);
    qemu_add_opts(&qemu_sandbox_opts);
    qemu_add_opts(&qemu_add_fd_opts);
    qemu_add_opts(&qemu_object_opts);
    qemu_add_opts(&qemu_tpmdev_opts);
@@ -3980,11 +3864,17 @@ int main(int argc, char **argv, char **envp)
                qtest_log = optarg;
                break;
            case QEMU_OPTION_sandbox:
#ifdef CONFIG_SECCOMP
                opts = qemu_opts_parse_noisily(qemu_find_opts("sandbox"),
                                               optarg, true);
                if (!opts) {
                    exit(1);
                }
#else
                error_report("-sandbox support is not enabled "
                             "in this QEMU binary");
                exit(1);
#endif
                break;
            case QEMU_OPTION_add_fd:
#ifndef _WIN32
@@ -4077,10 +3967,12 @@ int main(int argc, char **argv, char **envp)
        exit(1);
    }

#ifdef CONFIG_SECCOMP
    if (qemu_opts_foreach(qemu_find_opts("sandbox"),
                          parse_sandbox, NULL, NULL)) {
        exit(1);
    }
#endif

    if (qemu_opts_foreach(qemu_find_opts("name"),
                          parse_name, NULL, NULL)) {