Browse Source

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.
tags/debian/1.6_alpha1
Julian Andres Klode 3 years ago
parent
commit
32bcbd73e0
15 changed files with 291 additions and 19 deletions
  1. +25
    -0
      CMake/FindSeccomp.cmake
  2. +3
    -0
      CMake/config.h.in
  3. +5
    -0
      CMakeLists.txt
  4. +13
    -0
      debian/NEWS
  5. +1
    -0
      debian/control
  6. +3
    -0
      doc/examples/configure-index
  7. +12
    -10
      methods/CMakeLists.txt
  8. +212
    -5
      methods/aptmethod.h
  9. +4
    -2
      methods/copy.cc
  10. +4
    -1
      methods/file.cc
  11. +1
    -0
      methods/ftp.cc
  12. +2
    -0
      methods/http.cc
  13. +4
    -1
      methods/rred.cc
  14. +1
    -0
      methods/store.cc
  15. +1
    -0
      prepare-release

+ 25
- 0
CMake/FindSeccomp.cmake View File

@@ -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)

+ 3
- 0
CMake/config.h.in View File

@@ -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


+ 5
- 0
CMakeLists.txt View File

@@ -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)


+ 13
- 0
debian/NEWS View File

@@ -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 ]


+ 1
- 0
debian/control View File

@@ -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),


+ 3
- 0
doc/examples/configure-index View File

@@ -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>";



+ 12
- 10
methods/CMakeLists.txt View File

@@ -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


+ 212
- 5
methods/aptmethod.h View File

@@ -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

+ 4
- 2
methods/copy.cc View File

@@ -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 /*{{{*/


+ 4
- 1
methods/file.cc View File

@@ -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 /*{{{*/


+ 1
- 0
methods/ftp.cc View File

@@ -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);


+ 2
- 0
methods/http.cc View File

@@ -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";


+ 4
- 1
methods/rred.cc View File

@@ -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)


+ 1
- 0
methods/store.cc View File

@@ -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");
}


+ 1
- 0
prepare-release View File

@@ -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' \


Loading…
Cancel
Save