diff options
author | Julian Andres Klode <jak@debian.org> | 2017-10-22 23:34:03 +0200 |
---|---|---|
committer | Julian Andres Klode <jak@debian.org> | 2017-10-22 23:38:31 +0200 |
commit | 32bcbd73e0988d2d2237690ffae33b4f5cc5ff81 (patch) | |
tree | 3234d16c59f85a84a02371e6ef2f0bc79af42738 | |
parent | 9130b5f9304b7f58273a826ff9acf04e10c6f98e (diff) |
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.
-rw-r--r-- | CMake/FindSeccomp.cmake | 25 | ||||
-rw-r--r-- | CMake/config.h.in | 3 | ||||
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | debian/NEWS | 13 | ||||
-rw-r--r-- | debian/control | 1 | ||||
-rw-r--r-- | doc/examples/configure-index | 3 | ||||
-rw-r--r-- | methods/CMakeLists.txt | 22 | ||||
-rw-r--r-- | methods/aptmethod.h | 217 | ||||
-rw-r--r-- | methods/copy.cc | 6 | ||||
-rw-r--r-- | methods/file.cc | 5 | ||||
-rw-r--r-- | methods/ftp.cc | 1 | ||||
-rw-r--r-- | methods/http.cc | 2 | ||||
-rw-r--r-- | methods/rred.cc | 5 | ||||
-rw-r--r-- | methods/store.cc | 1 | ||||
-rwxr-xr-x | prepare-release | 1 |
15 files changed, 291 insertions, 19 deletions
diff --git a/CMake/FindSeccomp.cmake b/CMake/FindSeccomp.cmake new file mode 100644 index 000000000..5cfd13a37 --- /dev/null +++ b/CMake/FindSeccomp.cmake @@ -0,0 +1,25 @@ +# - Try to find SECCOMP +# Once done, this will define +# +# SECCOMP_FOUND - system has SECCOMP +# SECCOMP_INCLUDE_DIRS - the SECCOMP include directories +# SECCOMP_LIBRARIES - the SECCOMP library +find_package(PkgConfig) + +pkg_check_modules(SECCOMP_PKGCONF libseccomp) + +find_path(SECCOMP_INCLUDE_DIRS + NAMES seccomp.h + PATHS ${SECCOMP_PKGCONF_INCLUDE_DIRS} +) + + +find_library(SECCOMP_LIBRARIES + NAMES seccomp + PATHS ${SECCOMP_PKGCONF_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SECCOMP DEFAULT_MSG SECCOMP_INCLUDE_DIRS SECCOMP_LIBRARIES) + +mark_as_advanced(SECCOMP_INCLUDE_DIRS SECCOMP_LIBRARIES) diff --git a/CMake/config.h.in b/CMake/config.h.in index e1e4f83a1..cfaa14ed1 100644 --- a/CMake/config.h.in +++ b/CMake/config.h.in @@ -20,6 +20,9 @@ /* Define if we have the udev library */ #cmakedefine HAVE_UDEV +/* Define if we have the seccomp library */ +#cmakedefine HAVE_SECCOMP + /* These two are used by the statvfs shim for glibc2.0 and bsd */ /* Define if we have sys/vfs.h */ #cmakedefine HAVE_VFS_H diff --git a/CMakeLists.txt b/CMakeLists.txt index 04a8be22a..1c703307e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,11 @@ if (UDEV_FOUND) set(HAVE_UDEV 1) endif() +find_package(Seccomp) +if (SECCOMP_FOUND) + set(HAVE_SECCOMP 1) +endif() + # Mount()ing and stat()ing and friends check_symbol_exists(statfs sys/vfs.h HAVE_VFS_H) check_include_files(sys/params.h HAVE_PARAMS_H) diff --git a/debian/NEWS b/debian/NEWS index 9a93de69e..7ad20ccd6 100644 --- a/debian/NEWS +++ b/debian/NEWS @@ -1,3 +1,16 @@ +apt (1.6~alpha1) UNRELEASED; urgency=medium + + All methods provided by apt except for cdrom, gpgv, and rsh now + use seccomp-BPF sandboxing to restrict the list of allowed system + calls, and trap all others with a SIGSYS signal. Three options + can be used to configure this further: + + APT::Sandbox::Seccomp is a boolean to turn it on/off + APT::Sandbox::Seccomp::Trap is a list of names of more syscalls to trap + APT::Sandbox::Seccomp::Allow is a list of names of more syscalls to allow + + -- Julian Andres Klode <jak@debian.org> Sun, 22 Oct 2017 22:29:58 +0200 + apt (1.5~beta1) unstable; urgency=medium [ New HTTPS method ] diff --git a/debian/control b/debian/control index 22567e193..de373a83d 100644 --- a/debian/control +++ b/debian/control @@ -20,6 +20,7 @@ Build-Depends: cmake (>= 3.4), libgnutls28-dev (>= 3.4.6), liblz4-dev (>= 0.0~r126), liblzma-dev, + libseccomp-dev [amd64 arm64 armel armhf i386 mips mips64el mipsel ppc64el s390x hppa powerpc powerpcspe ppc64 x32], libudev-dev [linux-any], pkg-config, po4a (>= 0.34-2), diff --git a/doc/examples/configure-index b/doc/examples/configure-index index 61a749495..f0d81bb7a 100644 --- a/doc/examples/configure-index +++ b/doc/examples/configure-index @@ -639,6 +639,9 @@ apt::planner "<STRING>"; apt::system "<STRING>"; apt::acquire::translation "<STRING>"; // deprecated in favor of Acquire::Languages apt::sandbox::user "<STRING>"; +apt::sandbox::seccomp "<BOOL>"; +apt::sandbox::seccomp::allow "<LIST>"; +apt::sandbox::seccomp::trap "<LIST>"; apt::color::highlight "<STRING>"; apt::color::neutral "<STRING>"; 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($<$<BOOL:${SECCOMP_FOUND}>:${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 $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(copy apt-pkg $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(store apt-pkg $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(gpgv apt-pkg $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(cdrom apt-pkg $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(http apt-pkg ${GNUTLS_LIBRARIES} $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(mirror apt-pkg ${RESOLV_LIBRARIES} ${GNUTLS_LIBRARIES} $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(ftp apt-pkg ${GNUTLS_LIBRARIES} $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(rred apt-pkg $<$<BOOL:${SECCOMP_FOUND}>:${SECCOMP_LIBRARIES}>) +target_link_libraries(rsh apt-pkg $<$<BOOL:${SECCOMP_FOUND}>:${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 <apt-pkg/acquire-method.h> #include <apt-pkg/configuration.h> #include <apt-pkg/error.h> @@ -19,6 +21,10 @@ #include <apti18n.h> +#ifdef HAVE_SECCOMP +#include <seccomp.h> +#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"); } diff --git a/prepare-release b/prepare-release index e12ca2dc9..e9e9362da 100755 --- a/prepare-release +++ b/prepare-release @@ -40,6 +40,7 @@ test_deb_control() { | sed -r -e 's#<[^,<>()@]*>##g' \ -e 's#@[^,<>()@]*@##g' \ -e 's#\[linux-any\]*##g' \ + -e 's#\[[^][]*\]*##g' \ -e 's#dpkg-dev \([^)]*\)#dpkg-dev#g' \ -e 's#debhelper \([^)]*\)#debhelper#g' \ -e 's#g\+\+ \([^)]*\)#g++#g' \ |