Blame linux_priv.c

Packit Service 584ef9
#include "config.h"
Packit Service 584ef9
#include <seccomp.h>
Packit Service 584ef9
#include <termios.h>
Packit Service 584ef9
#include <errno.h>
Packit Service 584ef9
#include <stdlib.h>
Packit Service 584ef9
#include <sys/ioctl.h>
Packit Service 584ef9
#include <signal.h>
Packit Service 584ef9
#include <string.h>
Packit Service 584ef9
#include "memcached.h"
Packit Service 584ef9
Packit Service 584ef9
static char *kill_msg;
Packit Service 584ef9
// Make sure to preserve the ??? position in the string, or correct the offsets
Packit Service 584ef9
// in the syssig handler.
Packit Service 584ef9
#define KILL_MSG_STR "Seccomp policy failure. Caught syscall ???. This is " \
Packit Service 584ef9
    "either an exploit attempt, or your system is not supported yet.\n"
Packit Service 584ef9
Packit Service 584ef9
static void handle_syssig(int signum, siginfo_t *si, void *thread_context) {
Packit Service 584ef9
#if defined(si_syscall)
Packit Service 584ef9
    int syscall_no = si->si_syscall;
Packit Service 584ef9
#else
Packit Service 584ef9
    // If system has no support for si_syscal, the information may not be
Packit Service 584ef9
    // precise.
Packit Service 584ef9
    int syscall_no = si->si_value.sival_int;
Packit Service 584ef9
#endif
Packit Service 584ef9
Packit Service 584ef9
    // Replace the characters in the kill message with the syscall number. We
Packit Service 584ef9
    // can't safely printf (even write is not really valid, but we're crashing
Packit Service 584ef9
    // anyway).
Packit Service 584ef9
Packit Service 584ef9
    kill_msg[39] = (syscall_no / 100) % 10 + '0';
Packit Service 584ef9
    kill_msg[40] = (syscall_no / 10) % 10 + '0';
Packit Service 584ef9
    kill_msg[41] = syscall_no % 10 + '0';
Packit Service 584ef9
    if (write(2, kill_msg, strlen(kill_msg)) == -1) {
Packit Service 584ef9
        // An error occurred, but we can't do anything about it here. This check
Packit Service 584ef9
        // is mostly to avoid the "ignoring return value of 'write'" error on
Packit Service 584ef9
        // distributions with broken gcc (no "ignore via cast to void" support).
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    // We can't use the nice exit() version because it causes at_exit handlers
Packit Service 584ef9
    // to be looked up and run. We can't take any locks while handling the
Packit Service 584ef9
    // signal, so _exit() is the only thing to do safely.
Packit Service 584ef9
    _exit(EXIT_FAILURE);
Packit Service 584ef9
}
Packit Service 584ef9
Packit Service 584ef9
static const struct sigaction act = {
Packit Service 584ef9
    .sa_sigaction = handle_syssig,
Packit Service 584ef9
    .sa_flags = SA_SIGINFO,
Packit Service 584ef9
};
Packit Service 584ef9
Packit Service 584ef9
void setup_privilege_violations_handler(void) {
Packit Service 584ef9
    kill_msg = malloc(strlen(KILL_MSG_STR)+1);
Packit Service 584ef9
    strcpy(kill_msg, KILL_MSG_STR);
Packit Service 584ef9
Packit Service 584ef9
    sigaction(SIGSYS, &act, NULL);
Packit Service 584ef9
}
Packit Service 584ef9
Packit Service 584ef9
// If anything crosses the policy, kill the process.
Packit Service 584ef9
#define DENY_ACTION SCMP_ACT_TRAP
Packit Service 584ef9
Packit Service 584ef9
void drop_privileges(void) {
Packit Service 584ef9
    scmp_filter_ctx ctx = seccomp_init(DENY_ACTION);
Packit Service 584ef9
    if (ctx == NULL) {
Packit Service 584ef9
        return;
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    int rc = 0;
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_wait), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_pwait), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(shmctl), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TIOCGWINSZ));
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TCGETS));
Packit Service 584ef9
Packit Service 584ef9
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clock_gettime), 0);
Packit Service 584ef9
#endif
Packit Service 584ef9
Packit Service 584ef9
#ifdef MEMCACHED_DEBUG
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readv), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0);
Packit Service 584ef9
Packit Service 584ef9
    if (settings.relaxed_privileges) {
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mkdir), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0);
Packit Service 584ef9
    }
Packit Service 584ef9
#endif
Packit Service 584ef9
Packit Service 584ef9
    if (rc != 0) {
Packit Service 584ef9
        goto fail;
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    rc = seccomp_load(ctx);
Packit Service 584ef9
    if (rc < 0) {
Packit Service 584ef9
        goto fail;
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    seccomp_release(ctx);
Packit Service 584ef9
    return;
Packit Service 584ef9
Packit Service 584ef9
fail:
Packit Service 584ef9
    seccomp_release(ctx);
Packit Service 584ef9
    fprintf(stderr, "Failed to set a seccomp profile on the main thread\n");
Packit Service 584ef9
    exit(EXIT_FAILURE);
Packit Service 584ef9
}
Packit Service 584ef9
Packit Service 584ef9
void drop_worker_privileges(void) {
Packit Service 584ef9
    scmp_filter_ctx ctx = seccomp_init(DENY_ACTION);
Packit Service 584ef9
    if (ctx == NULL) {
Packit Service 584ef9
        return;
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    int rc = 0;
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigreturn), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_wait), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_pwait), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readv), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpeername), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendmsg), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrusage), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mremap), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, SCMP_A1(SCMP_CMP_EQ, TIOCGWINSZ));
Packit Service 584ef9
Packit Service 584ef9
    // for spawning the LRU crawler
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(madvise), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
Packit Service 584ef9
Packit Service 584ef9
    // stat
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockname), 0);
Packit Service 584ef9
    rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0);
Packit Service 584ef9
Packit Service 584ef9
    if (settings.shutdown_command) {
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tgkill), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tkill), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettid), 0);
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    if (settings.relaxed_privileges) {
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mkdir), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 0);
Packit Service 584ef9
    } else {
Packit Service 584ef9
        // stdout
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, 1));
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 1, SCMP_A0(SCMP_CMP_EQ, 1));
Packit Service 584ef9
        // stderr
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ, 2));
Packit Service 584ef9
        rc |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(writev), 1, SCMP_A0(SCMP_CMP_EQ, 2));
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    if (rc != 0) {
Packit Service 584ef9
        goto fail;
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    rc = seccomp_load(ctx);
Packit Service 584ef9
    if (rc < 0) {
Packit Service 584ef9
        goto fail;
Packit Service 584ef9
    }
Packit Service 584ef9
Packit Service 584ef9
    seccomp_release(ctx);
Packit Service 584ef9
    return;
Packit Service 584ef9
Packit Service 584ef9
fail:
Packit Service 584ef9
    seccomp_release(ctx);
Packit Service 584ef9
    fprintf(stderr, "Failed to set a seccomp profile on a worker thread\n");
Packit Service 584ef9
    exit(EXIT_FAILURE);
Packit Service 584ef9
}