Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db929bf9 authored by Paul Lawrence's avatar Paul Lawrence
Browse files

Enable seccomp in init with generated policy

Test: Ran script to test performance - https://b.corp.google.com/issues/32313202#comment3
      Saw no significant regression with this change on or off
      Removed chroot from SYSCALLS.TXT - chroot blocked
      Boot time appears reasonable
      Device boots with no SECCOMP blockings
      Measured per syscall time of 100ns
      Empirically counted <100,000 syscalls a second under heavy load

Bug: 32313202
Change-Id: Icfcfbcb72b2de1b38f1ad6a82e8ece3bd1c9e7ec
parent d5583867
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ LOCAL_SRC_FILES:= \
    init.cpp \
    keychords.cpp \
    property_service.cpp \
    seccomp.cpp \
    signal_handler.cpp \
    ueventd.cpp \
    ueventd_parser.cpp \
@@ -96,6 +97,7 @@ LOCAL_STATIC_LIBRARIES := \
    libbase \
    libc \
    libselinux \
    libseccomp_policy \
    liblog \
    libcrypto_utils \
    libcrypto \
+7 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@
#include "keychords.h"
#include "log.h"
#include "property_service.h"
#include "seccomp.h"
#include "service.h"
#include "signal_handler.h"
#include "ueventd.h"
@@ -763,6 +764,12 @@ int main(int argc, char** argv) {

        // Now set up SELinux for second stage.
        selinux_initialize(false);

        // Install system-wide seccomp filter
        if (!set_seccomp_filter()) {
            LOG(ERROR) << "Failed to set seccomp policy";
            security_failure();
        }
    }

    // These directories were necessarily created before initial policy load

init/seccomp.cpp

0 → 100644
+213 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "seccomp.h"

#include <vector>

#include <sys/prctl.h>

#include <linux/unistd.h>
#include <linux/audit.h>
#include <linux/filter.h>
#include <linux/seccomp.h>

#include "log.h"
#include "seccomp_policy.h"

#define syscall_nr (offsetof(struct seccomp_data, nr))
#define arch_nr (offsetof(struct seccomp_data, arch))

#if   defined __arm__
#define AUDIT_ARCH_NR AUDIT_ARCH_ARM
#elif defined __aarch64__
#define AUDIT_ARCH_NR AUDIT_ARCH_AARCH64
#define AUDIT_ARCH_NR32 AUDIT_ARCH_ARM
#elif defined __i386__
#define AUDIT_ARCH_NR AUDIT_ARCH_I386
#elif defined __x86_64__
#define AUDIT_ARCH_NR AUDIT_ARCH_X86_64
#define AUDIT_ARCH_NR32 AUDIT_ARCH_I386
#elif defined __mips64__
#define AUDIT_ARCH_NR AUDIT_ARCH_MIPS64
#define AUDIT_ARCH_NR32 AUDIT_ARCH_MIPS
#elif defined __mips__ && !defined __mips64__
#define AUDIT_ARCH_NR AUDIT_ARCH_MIPS
#else
#error "Could not determine AUDIT_ARCH_NR for this architecture"
#endif

typedef std::vector<sock_filter> filter;

// We want to keep the below inline functions for debugging and future
// development even though they are not used currently.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"

static inline void Kill(filter& f) {
    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL));
}

static inline void Trap(filter& f) {
    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
}

static inline void Error(filter& f, __u16 retcode) {
    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode));
}

inline static void Trace(filter& f) {
    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE));
}

inline static void Allow(filter& f) {
    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
}

inline static void AllowSyscall(filter& f, __u32 num) {
    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1));
    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
}

inline static void ExamineSyscall(filter& f) {
    f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
}

#ifdef AUDIT_ARCH_NR32
inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
    auto jump_length = f.size() - offset - 1;
    auto u8_jump_length = (__u8) jump_length;
    if (u8_jump_length != jump_length) {
        LOG(ERROR) << "Can't set jump greater than 255 - actual jump is " << jump_length;
        return -1;
    }
    f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, u8_jump_length, 0);
    return 0;
}
#endif

inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
    f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));

#ifdef AUDIT_ARCH_NR32
    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 2, 0));
    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, 1, 0));
    Kill(f);
    return f.size() - 2;
#else
    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 1, 0));
    Kill(f);
    return 0;
#endif
}

#pragma clang diagnostic pop

static bool install_filter(filter const& f) {
    struct sock_fprog prog = {
        (unsigned short) f.size(),
        (struct sock_filter*) &f[0],
    };

    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
        PLOG(ERROR) << "SECCOMP: Could not set seccomp filter";
        return false;
    }

    LOG(INFO) << "SECCOMP: Global filter installed";
    return true;
}

bool set_seccomp_filter() {
    filter f;

    // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
    // jump that must be changed to point to the start of the 32-bit policy
    // 32 bit syscalls will not hit the policy between here and the call to SetJump
#ifdef AUDIT_ARCH_NR32
    auto offset_to_32bit_filter =
#endif
        ValidateArchitectureAndJumpIfNeeded(f);

    // Native filter
    ExamineSyscall(f);

#ifdef __aarch64__
    // Syscalls needed to boot Android
    AllowSyscall(f, __NR_pivot_root);
    AllowSyscall(f, __NR_ioprio_get);
    AllowSyscall(f, __NR_ioprio_set);
    AllowSyscall(f, __NR_gettid);
    AllowSyscall(f, __NR_futex);
    AllowSyscall(f, __NR_clone);
    AllowSyscall(f, __NR_rt_sigreturn);
    AllowSyscall(f, __NR_rt_tgsigqueueinfo);
    AllowSyscall(f, __NR_add_key);
    AllowSyscall(f, __NR_request_key);
    AllowSyscall(f, __NR_keyctl);
    AllowSyscall(f, __NR_restart_syscall);
    AllowSyscall(f, __NR_getrandom);

    // Needed for performance tools
    AllowSyscall(f, __NR_perf_event_open);

    // Needed for treble
    AllowSyscall(f, __NR_finit_module);

    // Needed for trusty
    AllowSyscall(f, __NR_syncfs);

     // arm64-only filter - autogenerated from bionic syscall usage
    for (size_t i = 0; i < arm64_filter_size; ++i)
        f.push_back(arm64_filter[i]);
#else
    // Generic policy
    Allow(f);
#endif

#ifdef AUDIT_ARCH_NR32
    if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0)
        return -1;

    // 32-bit filter for 64-bit platforms
    ExamineSyscall(f);

#ifdef __aarch64__
    // Syscalls needed to boot android
    AllowSyscall(f, 120); // __NR_clone
    AllowSyscall(f, 240); // __NR_futex
    AllowSyscall(f, 119); // __NR_sigreturn
    AllowSyscall(f, 173); // __NR_rt_sigreturn
    AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo
    AllowSyscall(f, 224); // __NR_gettid

    // Syscalls needed to run Chrome
    AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome
    AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome

    // Syscalls needed to run GFXBenchmark
    AllowSyscall(f, 190); // __NR_vfork

    // arm32-on-arm64 only filter - autogenerated from bionic syscall usage
    for (size_t i = 0; i < arm_filter_size; ++i)
        f.push_back(arm_filter[i]);
#else
    // Generic policy
    Allow(f);
#endif
#endif
    return install_filter(f);
}

init/seccomp.h

0 → 100644
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SECCOMP_H
#define SECCOMP_H

bool set_seccomp_filter();

#endif