From 32bcbd73e0988d2d2237690ffae33b4f5cc5ff81 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 22 Oct 2017 23:34:03 +0200 Subject: Sandbox methods with seccomp-BPF; except cdrom, gpgv, rsh This reduces the number of syscalls to about 140 from about 350 or so, significantly reducing security risks. Also change prepare-release to ignore the architecture lists in the build dependencies when generating the build-depends package for travis. We might want to clean up things a bit more and/or move it somewhere else. --- methods/CMakeLists.txt | 22 ++--- methods/aptmethod.h | 217 +++++++++++++++++++++++++++++++++++++++++++++++-- methods/copy.cc | 6 +- methods/file.cc | 5 +- methods/ftp.cc | 1 + methods/http.cc | 2 + methods/rred.cc | 5 +- methods/store.cc | 1 + 8 files changed, 240 insertions(+), 19 deletions(-) (limited to 'methods') diff --git a/methods/CMakeLists.txt b/methods/CMakeLists.txt index 72f07e87e..60c636c7b 100644 --- a/methods/CMakeLists.txt +++ b/methods/CMakeLists.txt @@ -1,4 +1,6 @@ # Create the executable targets +include_directories($<$:${SECCOMP_INCLUDE_DIR}>) + add_executable(file file.cc) add_executable(copy copy.cc) add_executable(store store.cc) @@ -14,16 +16,16 @@ target_compile_definitions(http PRIVATE ${GNUTLS_DEFINITIONS}) target_include_directories(http PRIVATE ${GNUTLS_INCLUDE_DIR}) # Link the executables against the libraries -target_link_libraries(file apt-pkg) -target_link_libraries(copy apt-pkg) -target_link_libraries(store apt-pkg) -target_link_libraries(gpgv apt-pkg) -target_link_libraries(cdrom apt-pkg) -target_link_libraries(http apt-pkg ${GNUTLS_LIBRARIES}) -target_link_libraries(mirror apt-pkg ${RESOLV_LIBRARIES} ${GNUTLS_LIBRARIES}) -target_link_libraries(ftp apt-pkg ${GNUTLS_LIBRARIES}) -target_link_libraries(rred apt-pkg) -target_link_libraries(rsh apt-pkg) +target_link_libraries(file apt-pkg $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(copy apt-pkg $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(store apt-pkg $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(gpgv apt-pkg $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(cdrom apt-pkg $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(http apt-pkg ${GNUTLS_LIBRARIES} $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(mirror apt-pkg ${RESOLV_LIBRARIES} ${GNUTLS_LIBRARIES} $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(ftp apt-pkg ${GNUTLS_LIBRARIES} $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(rred apt-pkg $<$:${SECCOMP_LIBRARIES}>) +target_link_libraries(rsh apt-pkg $<$:${SECCOMP_LIBRARIES}>) # Install the library install(TARGETS file copy store gpgv cdrom http ftp rred rsh mirror diff --git a/methods/aptmethod.h b/methods/aptmethod.h index 23fd036dd..d5d426914 100644 --- a/methods/aptmethod.h +++ b/methods/aptmethod.h @@ -1,6 +1,8 @@ #ifndef APT_APTMETHOD_H #define APT_APTMETHOD_H +#include "config.h" + #include #include #include @@ -19,6 +21,10 @@ #include +#ifdef HAVE_SECCOMP +#include +#endif + static bool hasDoubleColon(std::string const &n) { return n.find("::") != std::string::npos; @@ -28,8 +34,15 @@ class aptMethod : public pkgAcqMethod { protected: std::string const Binary; + unsigned long SeccompFlags; + enum Seccomp + { + BASE = (1 << 1), + NETWORK = (1 << 2), + DIRECTORY = (1 << 3), + }; -public: + public: virtual bool Configuration(std::string Message) APT_OVERRIDE { if (pkgAcqMethod::Configuration(Message) == false) @@ -39,7 +52,198 @@ public: _config->MoveSubTree(conf.c_str(), NULL); DropPrivsOrDie(); + if (LoadSeccomp() == false) + return false; + + return true; + } + + bool LoadSeccomp() + { +#ifdef HAVE_SECCOMP + int rc; + scmp_filter_ctx ctx = NULL; + + if (SeccompFlags == 0) + return true; + + if (_config->FindB("APT::Sandbox::Seccomp", true) == false) + return true; + + ctx = seccomp_init(SCMP_ACT_TRAP); + if (ctx == NULL) + return _error->FatalE("HttpMethod::Configuration", "Cannot init seccomp"); + +#define ALLOW(what) \ + if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(what), 0))) \ + return _error->FatalE("HttpMethod::Configuration", "Cannot allow %s: %s", #what, strerror(-rc)); + for (auto &custom : _config->FindVector("APT::Sandbox::Seccomp::Trap")) + { + if ((rc = seccomp_rule_add(ctx, SCMP_ACT_TRAP, seccomp_syscall_resolve_name(custom.c_str()), 0))) + return _error->FatalE("HttpMethod::Configuration", "Cannot trap %s: %s", custom.c_str(), strerror(-rc)); + } + + ALLOW(access); + ALLOW(arch_prctl); + ALLOW(brk); + ALLOW(chmod); + ALLOW(chown); + ALLOW(chown32); + ALLOW(clock_getres); + ALLOW(clock_gettime); + ALLOW(close); + ALLOW(creat); + ALLOW(dup); + ALLOW(dup2); + ALLOW(dup3); + ALLOW(exit); + ALLOW(exit_group); + ALLOW(faccessat); + ALLOW(fchmod); + ALLOW(fchmodat); + ALLOW(fchown); + ALLOW(fchown32); + ALLOW(fchownat); + ALLOW(fcntl); + ALLOW(fcntl64); + ALLOW(fdatasync); + ALLOW(flock); + ALLOW(fstat); + ALLOW(fstat64); + ALLOW(fstatat64); + ALLOW(fstatfs); + ALLOW(fstatfs64); + ALLOW(fsync); + ALLOW(ftime); + ALLOW(ftruncate); + ALLOW(ftruncate64); + ALLOW(futex); + ALLOW(futimesat); + ALLOW(getegid); + ALLOW(getegid32); + ALLOW(geteuid); + ALLOW(geteuid32); + ALLOW(getgid); + ALLOW(getgid32); + ALLOW(getgroups); + ALLOW(getgroups32); + ALLOW(getpeername); + ALLOW(getpgid); + ALLOW(getpgrp); + ALLOW(getpid); + ALLOW(getppid); + ALLOW(getrandom); + ALLOW(getresgid); + ALLOW(getresgid32); + ALLOW(getresuid); + ALLOW(getresuid32); + ALLOW(getrlimit); + ALLOW(get_robust_list); + ALLOW(getrusage); + ALLOW(gettid); + ALLOW(gettimeofday); + ALLOW(getuid); + ALLOW(getuid32); + ALLOW(ioctl); + ALLOW(lchown); + ALLOW(lchown32); + ALLOW(_llseek); + ALLOW(lseek); + ALLOW(lstat); + ALLOW(lstat64); + ALLOW(madvise); + ALLOW(mmap); + ALLOW(mmap2); + ALLOW(mprotect); + ALLOW(mremap); + ALLOW(msync); + ALLOW(munmap); + ALLOW(newfstatat); + ALLOW(oldfstat); + ALLOW(oldlstat); + ALLOW(oldolduname); + ALLOW(oldstat); + ALLOW(olduname); + ALLOW(open); + ALLOW(openat); + ALLOW(pipe); + ALLOW(pipe2); + ALLOW(poll); + ALLOW(ppoll); + ALLOW(prctl); + ALLOW(prlimit64); + ALLOW(pselect6); + ALLOW(read); + ALLOW(rename); + ALLOW(renameat); + ALLOW(rt_sigaction); + ALLOW(rt_sigpending); + ALLOW(rt_sigprocmask); + ALLOW(rt_sigqueueinfo); + ALLOW(rt_sigreturn); + ALLOW(rt_sigsuspend); + ALLOW(rt_sigtimedwait); + ALLOW(sched_yield); + ALLOW(select); + ALLOW(set_robust_list); + ALLOW(sigaction); + ALLOW(sigpending); + ALLOW(sigprocmask); + ALLOW(sigreturn); + ALLOW(sigsuspend); + ALLOW(stat); + ALLOW(statfs); + ALLOW(sync); + ALLOW(syscall); + ALLOW(time); + ALLOW(truncate); + ALLOW(truncate64); + ALLOW(ugetrlimit); + ALLOW(umask); + ALLOW(uname); + ALLOW(unlink); + ALLOW(unlinkat); + ALLOW(utime); + ALLOW(utimensat); + ALLOW(utimes); + ALLOW(write); + + if ((SeccompFlags & Seccomp::NETWORK) != 0) + { + ALLOW(bind); + ALLOW(connect); + ALLOW(getsockname); + ALLOW(getsockopt); + ALLOW(recv); + ALLOW(recvfrom); + ALLOW(recvmsg); + ALLOW(send); + ALLOW(sendmsg); + ALLOW(sendto); + ALLOW(setsockopt); + ALLOW(socket); + } + + if ((SeccompFlags & Seccomp::DIRECTORY) != 0) + { + ALLOW(readdir); + ALLOW(getdents); + ALLOW(getdents64); + } + + for (auto &custom : _config->FindVector("APT::Sandbox::Seccomp::Allow")) + { + if ((rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, seccomp_syscall_resolve_name(custom.c_str()), 0))) + return _error->FatalE("HttpMethod::Configuration", "Cannot allow %s: %s", custom.c_str(), strerror(-rc)); + } + +#undef ALLOW + + rc = seccomp_load(ctx); + if (rc != 0) + return _error->FatalE("HttpMethod::Configuration", "could not load seccomp policy: %s", strerror(-rc)); +#endif return true; } @@ -139,8 +343,8 @@ public: return true; } - aptMethod(std::string &&Binary, char const * const Ver, unsigned long const Flags) APT_NONNULL(3) : - pkgAcqMethod(Ver, Flags), Binary(Binary), methodNames({Binary}) + aptMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3) + : pkgAcqMethod(Ver, Flags), Binary(Binary), SeccompFlags(0), methodNames({Binary}) { try { std::locale::global(std::locale("")); @@ -172,6 +376,9 @@ public: DropPrivsOrDie(); + if (LoadSeccomp() == false) + return false; + return true; } @@ -186,7 +393,7 @@ public: return MaybeAddAuth(authconf, uri); } - aptAuthConfMethod(std::string &&Binary, char const * const Ver, unsigned long const Flags) APT_NONNULL(3) : - aptMethod(std::move(Binary), Ver, Flags) {} + aptAuthConfMethod(std::string &&Binary, char const *const Ver, unsigned long const Flags) APT_NONNULL(3) + : aptMethod(std::move(Binary), Ver, Flags) {} }; #endif diff --git a/methods/copy.cc b/methods/copy.cc index fd4786ede..cc2fe9ea4 100644 --- a/methods/copy.cc +++ b/methods/copy.cc @@ -30,8 +30,10 @@ class CopyMethod : public aptMethod virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; public: - - CopyMethod() : aptMethod("copy", "1.0",SingleInstance | SendConfig) {}; + CopyMethod() : aptMethod("copy", "1.0", SingleInstance | SendConfig) + { + SeccompFlags = aptMethod::BASE; + } }; // CopyMethod::Fetch - Fetch a file /*{{{*/ diff --git a/methods/file.cc b/methods/file.cc index 6111329d5..269fb432d 100644 --- a/methods/file.cc +++ b/methods/file.cc @@ -33,7 +33,10 @@ class FileMethod : public aptMethod virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; public: - FileMethod() : aptMethod("file", "1.0", SingleInstance | SendConfig | LocalOnly) {}; + FileMethod() : aptMethod("file", "1.0", SingleInstance | SendConfig | LocalOnly) + { + SeccompFlags = aptMethod::BASE; + } }; // FileMethod::Fetch - Fetch a file /*{{{*/ diff --git a/methods/ftp.cc b/methods/ftp.cc index 341230f69..99eebc5af 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -962,6 +962,7 @@ bool FTPConn::Get(const char *Path,FileFd &To,unsigned long long Resume, /* */ FtpMethod::FtpMethod() : aptAuthConfMethod("ftp", "1.0", SendConfig) { + SeccompFlags = aptMethod::BASE | aptMethod::NETWORK; signal(SIGTERM,SigTerm); signal(SIGINT,SigTerm); diff --git a/methods/http.cc b/methods/http.cc index cbc77f477..d939ba7b1 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -984,6 +984,8 @@ BaseHttpMethod::DealWithHeadersResult HttpMethod::DealWithHeaders(FetchResult &R /*}}}*/ HttpMethod::HttpMethod(std::string &&pProg) : BaseHttpMethod(pProg.c_str(), "1.2", Pipeline | SendConfig)/*{{{*/ { + SeccompFlags = aptMethod::BASE | aptMethod::NETWORK; + auto addName = std::inserter(methodNames, methodNames.begin()); if (Binary != "http") addName = "http"; diff --git a/methods/rred.cc b/methods/rred.cc index 3a3b20286..d4cf1050d 100644 --- a/methods/rred.cc +++ b/methods/rred.cc @@ -721,7 +721,10 @@ class RredMethod : public aptMethod { } public: - RredMethod() : aptMethod("rred", "2.0", SendConfig), Debug(false) {} + RredMethod() : aptMethod("rred", "2.0", SendConfig), Debug(false) + { + SeccompFlags = aptMethod::BASE | aptMethod::DIRECTORY; + } }; int main(int argc, char **argv) diff --git a/methods/store.cc b/methods/store.cc index d54a14397..7b9e202d9 100644 --- a/methods/store.cc +++ b/methods/store.cc @@ -38,6 +38,7 @@ class StoreMethod : public aptMethod explicit StoreMethod(std::string &&pProg) : aptMethod(std::move(pProg),"1.2",SingleInstance | SendConfig) { + SeccompFlags = aptMethod::BASE; if (Binary != "store") methodNames.insert(methodNames.begin(), "store"); } -- cgit v1.2.3