From 2ff7bb3ae04c36ff7b1fef1c522957864f7575cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 1 Jul 2022 15:56:02 +0200 Subject: [PATCH] Add sandboxing with Landlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit p7zip handles a lot of archive formats, each bringing complexity and extending its attack surface. Landlock is a Linux security sandboxing mechanism which helps limit the impact of bug exploitation. These modifications enable to use Landlock following a best-effort appoach: if Landlock is available on the running system, then it will be used to sandbox p7zip, otherwise nothing will change. By default, all console commands (7z, 7za and 7zr) reading archives will create a sandbox which denies basic file-system accesses (e.g. read, create or write to files). All other commands (b, h, i, t) are untouched. FIXME: For now, only basic use of list (l) and extracts (e, x) commands is working and tested. The sandbox is enforced when calling COpenCallbackConsole::Open_setTotal(), which seems to be the more generic place for this purpose. When extracting an archive, a new helper called GetOutputBaseDir() is used to add security exception to the sandbox so that it will be allowed to create files in the output directory. Signed-off-by: Mickaël Salaün --- CPP/7zip/Bundles/Alone/makefile.list | 8 ++ CPP/7zip/Bundles/Alone7z/makefile.list | 8 ++ CPP/7zip/CMAKE/7z_/CMakeLists.txt | 2 + CPP/7zip/CMAKE/7za/CMakeLists.txt | 2 + CPP/7zip/CMAKE/7zr/CMakeLists.txt | 2 + CPP/7zip/PREMAKE/premake4.lua | 2 + CPP/7zip/QMAKE/7z_/7z_.pro | 2 + CPP/7zip/QMAKE/7za/7za.pro | 2 + CPP/7zip/QMAKE/7zr/7zr.pro | 2 + CPP/7zip/UI/Common/Extract.cpp | 50 +++++++ CPP/7zip/UI/Common/Extract.h | 4 + CPP/7zip/UI/Console/Main.cpp | 2 + CPP/7zip/UI/Console/OpenCallbackConsole.cpp | 6 + CPP/7zip/UI/Console/OpenCallbackConsole.h | 1 + CPP/7zip/UI/Console/Sandbox.cpp | 139 ++++++++++++++++++++ CPP/7zip/UI/Console/Sandbox.h | 21 +++ CPP/7zip/UI/Console/makefile.list | 8 ++ CPP/ANDROID/7z/jni/Android.mk | 2 + CPP/ANDROID/7za/jni/Android.mk | 2 + CPP/ANDROID/7zr/jni/Android.mk | 2 + CPP/Common/C_FileIO.cpp | 13 ++ CPP/Common/C_FileIO.h | 7 + Utils/file_7z.py | 2 + Utils/file_7za.py | 2 + Utils/file_7zr.py | 2 + 25 files changed, 293 insertions(+) create mode 100644 CPP/7zip/UI/Console/Sandbox.cpp create mode 100644 CPP/7zip/UI/Console/Sandbox.h diff --git a/CPP/7zip/Bundles/Alone/makefile.list b/CPP/7zip/Bundles/Alone/makefile.list index ee9f5fc82..343137b5c 100644 --- a/CPP/7zip/Bundles/Alone/makefile.list +++ b/CPP/7zip/Bundles/Alone/makefile.list @@ -191,11 +191,13 @@ SRCS=\ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ ../../../../CPP/Common/CrcReg.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ @@ -969,6 +971,8 @@ OpenCallbackConsole.o : ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp PercentPrinter.o : ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp +Sandbox.o : ../../../../CPP/7zip/UI/Console/Sandbox.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/Sandbox.cpp UpdateCallbackConsole.o : ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp UserInputUtils.o : ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp @@ -979,6 +983,8 @@ CommandLineParser.o : ../../../../CPP/Common/CommandLineParser.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/CommandLineParser.cpp CrcReg.o : ../../../../CPP/Common/CrcReg.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/CrcReg.cpp +C_FileIO.o : ../../../../CPP/Common/C_FileIO.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/Common/C_FileIO.cpp IntToString.o : ../../../../CPP/Common/IntToString.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/IntToString.cpp ListFileUtils.o : ../../../../CPP/Common/ListFileUtils.cpp @@ -1342,11 +1348,13 @@ OBJS=\ MainAr.o \ OpenCallbackConsole.o \ PercentPrinter.o \ + Sandbox.o \ UpdateCallbackConsole.o \ UserInputUtils.o \ CRC.o \ CommandLineParser.o \ CrcReg.o \ + C_FileIO.o \ IntToString.o \ ListFileUtils.o \ MyString.o \ diff --git a/CPP/7zip/Bundles/Alone7z/makefile.list b/CPP/7zip/Bundles/Alone7z/makefile.list index 23e0592a8..d19bac6ff 100644 --- a/CPP/7zip/Bundles/Alone7z/makefile.list +++ b/CPP/7zip/Bundles/Alone7z/makefile.list @@ -112,11 +112,13 @@ SRCS=\ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ ../../../../CPP/Common/CrcReg.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ @@ -446,6 +448,8 @@ OpenCallbackConsole.o : ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp PercentPrinter.o : ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp +Sandbox.o : ../../../../CPP/7zip/UI/Console/Sandbox.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/Sandbox.cpp UpdateCallbackConsole.o : ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp UserInputUtils.o : ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp @@ -456,6 +460,8 @@ CommandLineParser.o : ../../../../CPP/Common/CommandLineParser.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/CommandLineParser.cpp CrcReg.o : ../../../../CPP/Common/CrcReg.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/CrcReg.cpp +C_FileIO.o : ../../../../CPP/Common/C_FileIO.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/Common/C_FileIO.cpp IntToString.o : ../../../../CPP/Common/IntToString.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/IntToString.cpp ListFileUtils.o : ../../../../CPP/Common/ListFileUtils.cpp @@ -643,11 +649,13 @@ OBJS=\ MainAr.o \ OpenCallbackConsole.o \ PercentPrinter.o \ + Sandbox.o \ UpdateCallbackConsole.o \ UserInputUtils.o \ CRC.o \ CommandLineParser.o \ CrcReg.o \ + C_FileIO.o \ IntToString.o \ ListFileUtils.o \ MyString.o \ diff --git a/CPP/7zip/CMAKE/7z_/CMakeLists.txt b/CPP/7zip/CMAKE/7z_/CMakeLists.txt index 729ed4d3f..d792861c0 100644 --- a/CPP/7zip/CMAKE/7z_/CMakeLists.txt +++ b/CPP/7zip/CMAKE/7z_/CMakeLists.txt @@ -65,10 +65,12 @@ add_executable(7z_ "../../../../CPP/7zip/UI/Console/MainAr.cpp" "../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp" "../../../../CPP/7zip/UI/Console/PercentPrinter.cpp" + "../../../../CPP/7zip/UI/Console/Sandbox.cpp" "../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp" "../../../../CPP/7zip/UI/Console/UserInputUtils.cpp" "../../../../CPP/Common/CRC.cpp" "../../../../CPP/Common/CommandLineParser.cpp" + "../../../../CPP/Common/C_FileIO.cpp" "../../../../CPP/Common/IntToString.cpp" "../../../../CPP/Common/ListFileUtils.cpp" "../../../../CPP/Common/MyString.cpp" diff --git a/CPP/7zip/CMAKE/7za/CMakeLists.txt b/CPP/7zip/CMAKE/7za/CMakeLists.txt index 469e3254e..c1851196e 100644 --- a/CPP/7zip/CMAKE/7za/CMakeLists.txt +++ b/CPP/7zip/CMAKE/7za/CMakeLists.txt @@ -321,11 +321,13 @@ add_executable(7za "../../../../CPP/7zip/UI/Console/MainAr.cpp" "../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp" "../../../../CPP/7zip/UI/Console/PercentPrinter.cpp" + "../../../../CPP/7zip/UI/Console/Sandbox.cpp" "../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp" "../../../../CPP/7zip/UI/Console/UserInputUtils.cpp" "../../../../CPP/Common/CRC.cpp" "../../../../CPP/Common/CommandLineParser.cpp" "../../../../CPP/Common/CrcReg.cpp" + "../../../../CPP/Common/C_FileIO.cpp" "../../../../CPP/Common/IntToString.cpp" "../../../../CPP/Common/ListFileUtils.cpp" "../../../../CPP/Common/MyString.cpp" diff --git a/CPP/7zip/CMAKE/7zr/CMakeLists.txt b/CPP/7zip/CMAKE/7zr/CMakeLists.txt index 32e685eac..9873c3450 100644 --- a/CPP/7zip/CMAKE/7zr/CMakeLists.txt +++ b/CPP/7zip/CMAKE/7zr/CMakeLists.txt @@ -147,11 +147,13 @@ add_executable(7zr "../../../../CPP/7zip/UI/Console/MainAr.cpp" "../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp" "../../../../CPP/7zip/UI/Console/PercentPrinter.cpp" + "../../../../CPP/7zip/UI/Console/Sandbox.cpp" "../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp" "../../../../CPP/7zip/UI/Console/UserInputUtils.cpp" "../../../../CPP/Common/CRC.cpp" "../../../../CPP/Common/CommandLineParser.cpp" "../../../../CPP/Common/CrcReg.cpp" + "../../../../CPP/Common/C_FileIO.cpp" "../../../../CPP/Common/IntToString.cpp" "../../../../CPP/Common/ListFileUtils.cpp" "../../../../CPP/Common/MyString.cpp" diff --git a/CPP/7zip/PREMAKE/premake4.lua b/CPP/7zip/PREMAKE/premake4.lua index 431c6ba50..c34662eea 100644 --- a/CPP/7zip/PREMAKE/premake4.lua +++ b/CPP/7zip/PREMAKE/premake4.lua @@ -332,11 +332,13 @@ solution "p7zip" "../../../../CPP/7zip/UI/Console/MainAr.cpp", "../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp", "../../../../CPP/7zip/UI/Console/PercentPrinter.cpp", + "../../../../CPP/7zip/UI/Console/Sandbox.cpp", "../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp", "../../../../CPP/7zip/UI/Console/UserInputUtils.cpp", "../../../../CPP/Common/CRC.cpp", "../../../../CPP/Common/CommandLineParser.cpp", "../../../../CPP/Common/CrcReg.cpp", + "../../../../CPP/Common/C_FileIO.cpp", "../../../../CPP/Common/IntToString.cpp", "../../../../CPP/Common/ListFileUtils.cpp", "../../../../CPP/Common/MyString.cpp", diff --git a/CPP/7zip/QMAKE/7z_/7z_.pro b/CPP/7zip/QMAKE/7z_/7z_.pro index a09350dc3..7351d30f5 100644 --- a/CPP/7zip/QMAKE/7z_/7z_.pro +++ b/CPP/7zip/QMAKE/7z_/7z_.pro @@ -77,10 +77,12 @@ SOURCES += \ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ diff --git a/CPP/7zip/QMAKE/7za/7za.pro b/CPP/7zip/QMAKE/7za/7za.pro index 955e49b9f..47a3f9708 100644 --- a/CPP/7zip/QMAKE/7za/7za.pro +++ b/CPP/7zip/QMAKE/7za/7za.pro @@ -335,11 +335,13 @@ SOURCES += \ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ ../../../../CPP/Common/CrcReg.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ diff --git a/CPP/7zip/QMAKE/7zr/7zr.pro b/CPP/7zip/QMAKE/7zr/7zr.pro index 60023be97..e4014f9c8 100644 --- a/CPP/7zip/QMAKE/7zr/7zr.pro +++ b/CPP/7zip/QMAKE/7zr/7zr.pro @@ -161,11 +161,13 @@ SOURCES += \ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ ../../../../CPP/Common/CrcReg.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index 2d95f69bc..2f75fb27c 100644 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp @@ -19,6 +19,56 @@ using namespace NWindows; using namespace NFile; using namespace NDir; +// Base directories according to options.OutputDir examples: +// - "/f*" => / +// - "/*" => / +// - "" => ./ +// - "/f/" => /f +// - "/f/*" => /f +// - "/f/*/*" => /f +// - "/tmp/x/*/y" => /tmp +FString GetOutputBaseDir( + const CExtractOptions &options) +{ + // TODO: make -oX and -so mutually exclusive to avoid useless dir creation and then access error + if (options.StdOutMode) + return FString(); + + FString baseDir = options.OutputDir; + + // Removes everything after the first mask, if any. + int end = baseDir.Find(FSTRING_ANY_MASK); + if (end > 0) { + baseDir.ReleaseBuf_SetEnd(end); + + // Removes the left part of the mask, if any. + end = baseDir.ReverseFind(FCHAR_PATH_SEPARATOR); + if (end < 0) + baseDir = FString(); + else if (end == 0) + baseDir.ReleaseBuf_SetEnd(1); + else + baseDir.ReleaseBuf_SetEnd(end); + } + + // Looks for the deepest existing directory to sandbox as much as possible + // before trying to make directories. + NFind::CFileInfo fi; + while (!baseDir.IsEmpty() && baseDir != FCHAR_PATH_SEPARATOR && !(fi.Find(baseDir) && fi.IsDir())) + { + end = baseDir.ReverseFind(FCHAR_PATH_SEPARATOR); + if (end == -1) + baseDir = FString(); + else if (end > 0) + baseDir = baseDir.Left(end); + } + + if (baseDir.IsEmpty()) + return FTEXT(".") FSTRING_PATH_SEPARATOR; + + return baseDir; +} + static HRESULT DecompressArchive( CCodecs *codecs, const CArchiveLink &arcLink, diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h index 03ac74b2d..210d1d344 100644 --- a/CPP/7zip/UI/Common/Extract.h +++ b/CPP/7zip/UI/Common/Extract.h @@ -91,4 +91,8 @@ HRESULT Extract( UString &errorMessage, CDecompressStat &st); +// Returns the existing directory where the archive should be extracted, or an empty Fstring if stdout is used. +FString GetOutputBaseDir( + const CExtractOptions &options); + #endif diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index 4226e534f..5e0bc46a4 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -909,6 +909,8 @@ int Main2( eo.Properties = options.Properties; #endif + ecs->OutputDir = GetOutputBaseDir(eo); + UString errorMessage; CDecompressStat stat; CHashBundle hb; diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp index 9d25a729c..9da20b9e8 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp @@ -6,6 +6,7 @@ #include "ConsoleClose.h" #include "UserInputUtils.h" +#include "Sandbox.h" static HRESULT CheckBreak2() { @@ -19,6 +20,11 @@ HRESULT COpenCallbackConsole::Open_CheckBreak() HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) { + Sandbox sb; + sb.ErrorStream = _se; + sb.WritableDir = &OutputDir; + sb.Enforce(); + if (!MultiArcMode && NeedPercents()) { if (files) diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.h b/CPP/7zip/UI/Console/OpenCallbackConsole.h index 0dd4e1d1c..728c4a4d2 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.h +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h @@ -27,6 +27,7 @@ class COpenCallbackConsole: public IOpenCallbackUI public: bool MultiArcMode; + FString OutputDir; void ClosePercents() { diff --git a/CPP/7zip/UI/Console/Sandbox.cpp b/CPP/7zip/UI/Console/Sandbox.cpp new file mode 100644 index 000000000..833d01e1c --- /dev/null +++ b/CPP/7zip/UI/Console/Sandbox.cpp @@ -0,0 +1,139 @@ +// Sandbox.cpp + +#include "Sandbox.h" +#include "../../../Common/C_FileIO.h" +#include "../../../Common/StringConvert.h" + +#ifndef __linux__ + +void Sandbox::Enforce(void) {} + +#else + +// TODO: don't error out if landlock.h is missing +#include +#include +#include +#include +#include + +#ifndef landlock_create_ruleset +static inline int landlock_create_ruleset( + const struct landlock_ruleset_attr *const attr, + const size_t size, const __u32 flags) +{ + return syscall(__NR_landlock_create_ruleset, attr, size, flags); +} +#endif + +#ifndef landlock_add_rule +static inline int landlock_add_rule( + const int ruleset_fd, + const enum landlock_rule_type rule_type, + const void *const rule_attr, + const __u32 flags) +{ + return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, flags); +} +#endif + +#ifndef landlock_restrict_self +static inline int landlock_restrict_self( + const int ruleset_fd, + const __u32 flags) +{ + return syscall(__NR_landlock_restrict_self, ruleset_fd, flags); +} +#endif + +class Ruleset +{ +public: + int fd; + Ruleset(): fd(-1) {}; + ~Ruleset() + { + close(fd); + } + bool Create(const struct landlock_ruleset_attr *ruleset_attr) + { + fd = landlock_create_ruleset(ruleset_attr, sizeof(*ruleset_attr), 0); + return fd != -1; + } +}; + +void Sandbox::Enforce(void) +{ + struct landlock_path_beneath_attr path_beneath = { + .allowed_access = \ + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_MAKE_CHAR | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_MAKE_SOCK | + LANDLOCK_ACCESS_FS_MAKE_FIFO | + LANDLOCK_ACCESS_FS_MAKE_BLOCK | + LANDLOCK_ACCESS_FS_MAKE_SYM, + .parent_fd = -1, + }; + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = \ + path_beneath.allowed_access | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_READ_DIR, + }; + Ruleset ruleset = Ruleset(); + + if (!ruleset.Create(&ruleset_attr)) { + // TODO: remove status message + if (ErrorStream) + *ErrorStream << "landlock: Failed to create a ruleset: " << strerror(errno) << endl; + // Silently ignores sandboxing if Landlock is not available (i.e. best-effort security). + return; + } + + if (!WritableDir->IsEmpty()) { +#ifdef USE_UNICODE_FSTRING + AString astr = UnicodeStringToMultiByte(*WritableDir); +#else + AString astr = *WritableDir; +#endif + + NC::NFile::NIO::CPathFile path; + if (!path.Open(astr)) { + if (ErrorStream) + *ErrorStream << "landlock: Failed to open path " << astr << endl; + return; + } + + path_beneath.parent_fd = path.GetHandle(); + if (landlock_add_rule(ruleset.fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0)) { + if (ErrorStream) + *ErrorStream << "landlock: Failed to update the ruleset: " << strerror(errno) << endl; + return; + } + + // TODO: remove this status message + if (ErrorStream) + *ErrorStream << "landock: Writable directory: " << astr << endl; + } + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + if (ErrorStream) + *ErrorStream << "landlock: Failed to restrict privileges: " << strerror(errno) << endl; + return; + } + if (landlock_restrict_self(ruleset.fd, 0)) { + if (ErrorStream) + *ErrorStream << "landlock: Failed to enforce the ruleset: " << strerror(errno) << endl; + return; + } + // TODO: remove this status message + if (ErrorStream) + *ErrorStream << "landock: Successfully sandboxed!" << endl; +} + +#endif diff --git a/CPP/7zip/UI/Console/Sandbox.h b/CPP/7zip/UI/Console/Sandbox.h new file mode 100644 index 000000000..39a568c19 --- /dev/null +++ b/CPP/7zip/UI/Console/Sandbox.h @@ -0,0 +1,21 @@ +// Sandbox.h + +#ifndef __SANDBOX_H +#define __SANDBOX_H + +#include "../../../Common/StdOutStream.h" + +struct Sandbox +{ + CStdOutStream *ErrorStream; + FString *WritableDir; + + Sandbox(): + ErrorStream(NULL), + WritableDir(NULL) + {} + + void Enforce(void); +}; + +#endif diff --git a/CPP/7zip/UI/Console/makefile.list b/CPP/7zip/UI/Console/makefile.list index 9e46bf915..9e99cc9df 100644 --- a/CPP/7zip/UI/Console/makefile.list +++ b/CPP/7zip/UI/Console/makefile.list @@ -60,10 +60,12 @@ SRCS=\ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ @@ -194,6 +196,8 @@ OpenCallbackConsole.o : ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp PercentPrinter.o : ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp +Sandbox.o : ../../../../CPP/7zip/UI/Console/Sandbox.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/Sandbox.cpp UpdateCallbackConsole.o : ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp UserInputUtils.o : ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp @@ -202,6 +206,8 @@ CRC.o : ../../../../CPP/Common/CRC.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/CRC.cpp CommandLineParser.o : ../../../../CPP/Common/CommandLineParser.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/CommandLineParser.cpp +C_FileIO.o : ../../../../CPP/Common/C_FileIO.cpp + $(CXX) $(CXXFLAGS) ../../../../CPP/Common/C_FileIO.cpp IntToString.o : ../../../../CPP/Common/IntToString.cpp $(CXX) $(CXXFLAGS) ../../../../CPP/Common/IntToString.cpp ListFileUtils.o : ../../../../CPP/Common/ListFileUtils.cpp @@ -301,10 +307,12 @@ OBJS=\ MainAr.o \ OpenCallbackConsole.o \ PercentPrinter.o \ + Sandbox.o \ UpdateCallbackConsole.o \ UserInputUtils.o \ CRC.o \ CommandLineParser.o \ + C_FileIO.o \ IntToString.o \ ListFileUtils.o \ MyString.o \ diff --git a/CPP/ANDROID/7z/jni/Android.mk b/CPP/ANDROID/7z/jni/Android.mk index 7450c568c..de81d781e 100644 --- a/CPP/ANDROID/7z/jni/Android.mk +++ b/CPP/ANDROID/7z/jni/Android.mk @@ -64,10 +64,12 @@ LOCAL_SRC_FILES := \ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ diff --git a/CPP/ANDROID/7za/jni/Android.mk b/CPP/ANDROID/7za/jni/Android.mk index 16eb8fb5e..a79ed3381 100644 --- a/CPP/ANDROID/7za/jni/Android.mk +++ b/CPP/ANDROID/7za/jni/Android.mk @@ -209,11 +209,13 @@ LOCAL_SRC_FILES := \ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ ../../../../CPP/Common/CrcReg.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ diff --git a/CPP/ANDROID/7zr/jni/Android.mk b/CPP/ANDROID/7zr/jni/Android.mk index a10de7a5d..53fd6032f 100644 --- a/CPP/ANDROID/7zr/jni/Android.mk +++ b/CPP/ANDROID/7zr/jni/Android.mk @@ -130,11 +130,13 @@ LOCAL_SRC_FILES := \ ../../../../CPP/7zip/UI/Console/MainAr.cpp \ ../../../../CPP/7zip/UI/Console/OpenCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/PercentPrinter.cpp \ + ../../../../CPP/7zip/UI/Console/Sandbox.cpp \ ../../../../CPP/7zip/UI/Console/UpdateCallbackConsole.cpp \ ../../../../CPP/7zip/UI/Console/UserInputUtils.cpp \ ../../../../CPP/Common/CRC.cpp \ ../../../../CPP/Common/CommandLineParser.cpp \ ../../../../CPP/Common/CrcReg.cpp \ + ../../../../CPP/Common/C_FileIO.cpp \ ../../../../CPP/Common/IntToString.cpp \ ../../../../CPP/Common/ListFileUtils.cpp \ ../../../../CPP/Common/MyString.cpp \ diff --git a/CPP/Common/C_FileIO.cpp b/CPP/Common/C_FileIO.cpp index 7c6293902..eeeb266d8 100644 --- a/CPP/Common/C_FileIO.cpp +++ b/CPP/Common/C_FileIO.cpp @@ -89,4 +89,17 @@ ssize_t COutFile::Write(const void *data, size_t size) return write(_handle, data, size); } +///////////////////////// +// CPathFile + +bool CPathFile::Open(const char *name) +{ + return CFileBase::OpenBinary(name, O_PATH | O_CLOEXEC); +} + +int CPathFile::GetHandle() +{ + return _handle; +} + }}} diff --git a/CPP/Common/C_FileIO.h b/CPP/Common/C_FileIO.h index ff4ec162c..16efc97ca 100644 --- a/CPP/Common/C_FileIO.h +++ b/CPP/Common/C_FileIO.h @@ -48,6 +48,13 @@ class COutFile: public CFileBase ssize_t Write(const void *data, size_t size); }; +class CPathFile: public CFileBase +{ +public: + bool Open(const char *name); + int GetHandle(); +}; + }}} #endif diff --git a/Utils/file_7z.py b/Utils/file_7z.py index 51f397cfb..762e74811 100644 --- a/Utils/file_7z.py +++ b/Utils/file_7z.py @@ -50,10 +50,12 @@ 'CPP/7zip/UI/Console/MainAr.cpp', 'CPP/7zip/UI/Console/OpenCallbackConsole.cpp', 'CPP/7zip/UI/Console/PercentPrinter.cpp', + 'CPP/7zip/UI/Console/Sandbox.cpp', 'CPP/7zip/UI/Console/UpdateCallbackConsole.cpp', 'CPP/7zip/UI/Console/UserInputUtils.cpp', 'CPP/Common/CRC.cpp', 'CPP/Common/CommandLineParser.cpp', + 'CPP/Common/C_FileIO.cpp', 'CPP/Common/IntToString.cpp', 'CPP/Common/ListFileUtils.cpp', 'CPP/Common/MyString.cpp', diff --git a/Utils/file_7za.py b/Utils/file_7za.py index 2ba9e343f..9b8ca5a59 100644 --- a/Utils/file_7za.py +++ b/Utils/file_7za.py @@ -306,11 +306,13 @@ 'CPP/7zip/UI/Console/MainAr.cpp', 'CPP/7zip/UI/Console/OpenCallbackConsole.cpp', 'CPP/7zip/UI/Console/PercentPrinter.cpp', + 'CPP/7zip/UI/Console/Sandbox.cpp', 'CPP/7zip/UI/Console/UpdateCallbackConsole.cpp', 'CPP/7zip/UI/Console/UserInputUtils.cpp', 'CPP/Common/CRC.cpp', 'CPP/Common/CommandLineParser.cpp', 'CPP/Common/CrcReg.cpp', + 'CPP/Common/C_FileIO.cpp', 'CPP/Common/IntToString.cpp', 'CPP/Common/ListFileUtils.cpp', 'CPP/Common/MyString.cpp', diff --git a/Utils/file_7zr.py b/Utils/file_7zr.py index b5ae0533b..0ed3b4362 100644 --- a/Utils/file_7zr.py +++ b/Utils/file_7zr.py @@ -132,11 +132,13 @@ 'CPP/7zip/UI/Console/MainAr.cpp', 'CPP/7zip/UI/Console/OpenCallbackConsole.cpp', 'CPP/7zip/UI/Console/PercentPrinter.cpp', + 'CPP/7zip/UI/Console/Sandbox.cpp', 'CPP/7zip/UI/Console/UpdateCallbackConsole.cpp', 'CPP/7zip/UI/Console/UserInputUtils.cpp', 'CPP/Common/CRC.cpp', 'CPP/Common/CommandLineParser.cpp', 'CPP/Common/CrcReg.cpp', + 'CPP/Common/C_FileIO.cpp', 'CPP/Common/IntToString.cpp', 'CPP/Common/ListFileUtils.cpp', 'CPP/Common/MyString.cpp',