summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2017-10-22 23:34:03 +0200
committerJulian Andres Klode <jak@debian.org>2017-10-22 23:38:31 +0200
commit32bcbd73e0988d2d2237690ffae33b4f5cc5ff81 (patch)
tree3234d16c59f85a84a02371e6ef2f0bc79af42738
parent9130b5f9304b7f58273a826ff9acf04e10c6f98e (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.cmake25
-rw-r--r--CMake/config.h.in3
-rw-r--r--CMakeLists.txt5
-rw-r--r--debian/NEWS13
-rw-r--r--debian/control1
-rw-r--r--doc/examples/configure-index3
-rw-r--r--methods/CMakeLists.txt22
-rw-r--r--methods/aptmethod.h217
-rw-r--r--methods/copy.cc6
-rw-r--r--methods/file.cc5
-rw-r--r--methods/ftp.cc1
-rw-r--r--methods/http.cc2
-rw-r--r--methods/rred.cc5
-rw-r--r--methods/store.cc1
-rwxr-xr-xprepare-release1
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' \