From 6e63041962a872cdb886dd309927d65c3a941be7 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sat, 10 Oct 2026 22:23:21 +0900 Subject: [PATCH] Linux: secure NixOS helper lookup and report blocked elevation Look up NixOS helpers only when trusted system metadata identifies NixOS and each path component passes ownership and permission checks. Keep the existing helper search on other distributions. Detect NoNewPrivs before prompting for administrator credentials, with a clear error for restricted launchers. Add regression coverage to Linux CI and append the English fallback message to all language files. Refs #1911 --- .github/workflows/build-linux.yml | 5 + Tests/test_linux_privilege_helpers.py | 449 ++++++++++++++++++++++++++ Translations/Language.ar.xml | 1 + Translations/Language.be.xml | 1 + Translations/Language.bg.xml | 1 + Translations/Language.ca.xml | 1 + Translations/Language.co.xml | 1 + Translations/Language.cs.xml | 1 + Translations/Language.da.xml | 1 + Translations/Language.de.xml | 1 + Translations/Language.el.xml | 1 + Translations/Language.es.xml | 1 + Translations/Language.et.xml | 1 + Translations/Language.eu.xml | 1 + Translations/Language.fa.xml | 1 + Translations/Language.fi.xml | 1 + Translations/Language.fr.xml | 1 + Translations/Language.he.xml | 1 + Translations/Language.hu.xml | 1 + Translations/Language.id.xml | 1 + Translations/Language.it.xml | 1 + Translations/Language.ja.xml | 1 + Translations/Language.ka.xml | 1 + Translations/Language.ko.xml | 1 + Translations/Language.lv.xml | 1 + Translations/Language.my.xml | 1 + Translations/Language.nb.xml | 1 + Translations/Language.nl.xml | 1 + Translations/Language.nn.xml | 1 + Translations/Language.pl.xml | 1 + Translations/Language.pt-br.xml | 1 + Translations/Language.ro.xml | 1 + Translations/Language.ru.xml | 1 + Translations/Language.sk.xml | 1 + Translations/Language.sl.xml | 1 + Translations/Language.sv.xml | 1 + Translations/Language.th.xml | 1 + Translations/Language.tr.xml | 1 + Translations/Language.uk.xml | 1 + Translations/Language.uz.xml | 1 + Translations/Language.vi.xml | 1 + Translations/Language.zh-cn.xml | 1 + Translations/Language.zh-hk.xml | 1 + Translations/Language.zh-tw.xml | 1 + src/Common/Language.xml | 1 + src/Core/CoreException.h | 1 + src/Core/Unix/CoreService.cpp | 22 ++ src/Main/UserInterface.cpp | 1 + src/Platform/Unix/Process.cpp | 145 +++++++++ 49 files changed, 666 insertions(+) create mode 100644 Tests/test_linux_privilege_helpers.py diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 4597784a..994bfe73 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -10,6 +10,7 @@ on: - 'src/Common/*.h' - 'src/Common/*.cpp' - 'src/Common/*.c' + - 'src/Common/Language.xml' - 'src/Core/**' - 'src/Crypto/**' - 'src/Driver/Fuse/**' @@ -20,6 +21,7 @@ on: - 'src/Setup/Linux/**' - 'src/Volume/**' - 'src/Makefile' + - 'Tests/test_linux_privilege_helpers.py' - '.github/workflows/build-linux.yml' pull_request: branches: [ "master" ] @@ -30,6 +32,7 @@ on: - 'src/Common/*.h' - 'src/Common/*.cpp' - 'src/Common/*.c' + - 'src/Common/Language.xml' - 'src/Core/**' - 'src/Crypto/**' - 'src/Driver/Fuse/**' @@ -40,6 +43,7 @@ on: - 'src/Setup/Linux/**' - 'src/Volume/**' - 'src/Makefile' + - 'Tests/test_linux_privilege_helpers.py' - '.github/workflows/build-linux.yml' concurrency: @@ -128,6 +132,7 @@ jobs: - name: Install and test VeraCrypt GUI .deb packages run: | sudo apt install -y /tmp/VeraCrypt_Packaging/GUI/Packaging/veracrypt-*.deb + python3 Tests/test_linux_privilege_helpers.py --veracrypt "$(command -v veracrypt)" veracrypt --text --test && veracrypt --text --version sudo veracrypt --text --non-interactive Tests/test.sha256.hc --hash sha256 --slot 1 --password test --mount-options=ro sudo veracrypt --text --non-interactive Tests/test.sha512.hc --hash sha512 --slot 2 --password test --mount-options=ro diff --git a/Tests/test_linux_privilege_helpers.py b/Tests/test_linux_privilege_helpers.py new file mode 100644 index 00000000..e4e93baf --- /dev/null +++ b/Tests/test_linux_privilege_helpers.py @@ -0,0 +1,449 @@ +#!/usr/bin/env python3 +"""Exercise production helper lookup and the Linux elevation restriction check. + +Uses a fake filesystem to test trusted paths without changing system files. +The kernel check also runs with real NoNewPrivs in a separate process. +Pass --veracrypt to check the diagnostic in a built binary as an ordinary user. +""" +import argparse +import ctypes +import os +from pathlib import Path +import shlex +import shutil +import subprocess +import sys +import tempfile +import xml.etree.ElementTree as ET + +ROOT = Path(__file__).resolve().parents[1] + + +def between(source, start, end): + return source[source.index(start):source.index(end, source.index(start))] + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--veracrypt", type=Path) + parser.add_argument("--probe-output", type=Path, help="save the tested resolver probe for filesystem integration checks") + args = parser.parse_args() + if not sys.platform.startswith("linux"): + parser.error("these tests require Linux") + + process = (ROOT / "src/Platform/Unix/Process.cpp").read_text() + service = (ROOT / "src/Core/Unix/CoreService.cpp").read_text() + lookup = between(process, "\tbool Process::IsExecutable", "\tstring Process::Execute (") + guard_headers = between(service, "#ifdef TC_LINUX\n#include ", '#include "Platform/FileStream.h"') + guard = between(service, "\tstatic void CheckPrivilegeElevationAllowed", "\tstatic PrivilegeHelper FindPrivilegeHelper") + prelude = r''' +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef TEST_OLD_HEADERS +#undef PR_GET_NO_NEW_PRIVS +#endif + +static void Require(bool value, const char *message) { + if (!value) throw std::runtime_error(message); +} +using std::string; +using std::vector; +struct Entry { + mode_t Mode; + uid_t Owner; + string Target, Contents; + Entry(mode_t mode = 0, uid_t owner = 0, string target = "", string contents = "") + : Mode(mode), Owner(owner), Target(target), Contents(contents) {} +}; +static std::map Files; +static std::vector Probes; +static bool UseFilesystem; +static bool StoreReadOnly = true, StatvfsFails; +static string Normalize(const string &path) { + std::istringstream input(path); + vector parts; + string part, result; + while (std::getline(input, part, '/')) { + if (part.empty() || part == ".") continue; + if (part == "..") { if (!parts.empty()) parts.pop_back(); } + else parts.push_back(part); + } + for (const auto &component : parts) result += "/" + component; + return result.empty() ? "/" : result; +} +static int FakeLstat(const char *path, struct stat *result) { + if (UseFilesystem) return ::lstat(path, result); + Probes.push_back(path); + auto found = Files.find(Normalize(path)); + if (found == Files.end()) { errno = ENOENT; return -1; } + *result = {}; + result->st_mode = found->second.Mode; + result->st_uid = found->second.Owner; + return 0; +} +static int FakeStat(const char *path, struct stat *result) { + if (UseFilesystem) return ::stat(path, result); + string current = path; + for (int links = 0; links <= 40; ++links) { + if (FakeLstat(current.c_str(), result) != 0) return -1; + if (!S_ISLNK(result->st_mode)) return 0; + string target = Files.at(Normalize(current)).Target; + current = target[0] == '/' ? target : current.substr(0, current.rfind('/') + 1) + target; + } + errno = ELOOP; + return -1; +} +static ssize_t FakeReadlink(const char *path, char *buffer, size_t size) { + if (UseFilesystem) return ::readlink(path, buffer, size); + auto found = Files.find(Normalize(path)); + if (found == Files.end() || !S_ISLNK(found->second.Mode)) { errno = EINVAL; return -1; } + string target = found->second.Target; + size_t count = target.size() < size ? target.size() : size; + std::memcpy(buffer, target.data(), count); + return count; +} +static FILE *FakeFopen(const char *path, const char *mode) { + if (UseFilesystem) return ::fopen(path, mode); + auto found = Files.find(Normalize(path)); + if (found == Files.end()) { errno = ENOENT; return nullptr; } + FILE *file = tmpfile(); + Require(file != nullptr, "cannot create metadata fixture"); + const string &contents = found->second.Contents; + Require(fwrite(contents.data(), 1, contents.size(), file) == contents.size(), "cannot write metadata fixture"); + rewind(file); + return file; +} +static int FakeStatvfs(const char *path, struct statvfs *result) { + if (UseFilesystem) return ::statvfs(path, result); + if (StatvfsFails) { errno = EACCES; return -1; } + *result = {}; + result->f_flag = StoreReadOnly ? ST_RDONLY : 0; + return 0; +} +#define stat(path, result) FakeStat(path, result) +#define lstat(path, result) FakeLstat(path, result) +#define readlink(path, buffer, size) FakeReadlink(path, buffer, size) +#define fopen(path, mode) FakeFopen(path, mode) +#define statvfs(path, result) FakeStatvfs(path, result) +class Process { +public: + static bool IsExecutable(const std::string &); + static std::string FindSystemBinary(const char *, std::string &); +}; + +struct ElevationBlocked : std::runtime_error { + explicit ElevationBlocked(const char *message) : std::runtime_error(message) {} +}; +#define SRC_POS "test" +static int QueryResult, QueryError, QueryCount; +static bool UseKernel; +static int TestPrctl(int option, long a, long b, long c, long d) { + Require(option == 39 && a == 0 && b == 0 && c == 0 && d == 0, + "invalid PR_GET_NO_NEW_PRIVS query"); + ++QueryCount; + if (UseKernel) return ::prctl(option, a, b, c, d); + errno = QueryError; + return QueryResult; +} +#define prctl(option, a, b, c, d) TestPrctl(option, a, b, c, d) +''' + tests = r''' +#undef prctl +#undef stat +#undef lstat +#undef readlink +#undef fopen +#undef statvfs +static void ExpectPath(const char *name, const std::string &expected) { + std::string error; + Probes.clear(); + Require(Process::FindSystemBinary(name, error) == expected, "wrong helper selected"); + if (expected.empty()) + Require(errno == ENOENT && error.find("not found in system directories") != std::string::npos, + "missing helper lost its diagnostic"); +} +static void ExpectNoNixLookup() { + ExpectPath("sudo", "/usr/bin/sudo"); + for (const auto &path : Probes) + Require(path.find("/run/") != 0, "NixOS locations used without trusted NixOS metadata"); +} +static void NixFixture() { + Files.clear(); + StoreReadOnly = true; + StatvfsFails = false; + for (const char *path : {"/", "/etc", "/run", "/run/wrappers", "/run/wrappers/wrappers.test", + "/nix", "/nix/store", "/nix/store/system", "/nix/store/profile", "/nix/store/profile/bin", + "/nix/store/tools", "/nix/store/tools/bin"}) + Files[path] = Entry(S_IFDIR | 0755); + Files["/etc/os-release"] = Entry(S_IFLNK | 0777, 0, "../nix/store/os-release"); + Files["/nix/store/os-release"] = Entry(S_IFREG | 0444, 0, "", "NAME=NixOS\nID=nixos\n"); + Files["/run/wrappers/bin"] = Entry(S_IFLNK | 0777, 0, "wrappers.test"); + Files["/run/current-system"] = Entry(S_IFLNK | 0777, 0, "/nix/store/system"); + Files["/nix/store/system/sw"] = Entry(S_IFLNK | 0777, 0, "../profile"); + for (const char *name : {"sudo", "true", "dmsetup", "mount", "umount", "losetup", "modprobe", "fsck", "mkfs.ext4"}) { + Files[string("/nix/store/profile/bin/") + name] = Entry(S_IFLNK | 0777, 0, string("../../tools/bin/") + name); + Files[string("/nix/store/tools/bin/") + name] = Entry(S_IFREG | 0555); + Files[string("/usr/bin/") + name] = Entry(S_IFREG | 0755); + } + Files["/run/wrappers/wrappers.test/sudo"] = Entry(S_IFREG | 04511); + Files["/run/wrappers/wrappers.test/doas"] = Entry(S_IFREG | 04511); +} +static bool IsBlocked() { + try { CheckPrivilegeElevationAllowed(); } + catch (const ElevationBlocked &) { return true; } + return false; +} +int main(int argc, char **argv) { + try { +#ifdef TC_LINUX + if (argc == 3 && std::string(argv[1]) == "--resolve") { + UseFilesystem = true; + string error, path = Process::FindSystemBinary(argv[2], error); + std::cout << (path.empty() ? error : path) << std::endl; + return path.empty() ? 1 : 0; + } + if (argc == 3 && std::string(argv[1]) == "--trusted") { + UseFilesystem = true; + string path; + struct stat info; + if (!ResolveTrustedSystemPath(argv[2], path, info)) return 1; + std::cout << path << std::endl; + return 0; + } +#endif + if (argc == 2 && std::string(argv[1]) == "--kernel") { +#ifdef TC_LINUX + UseKernel = true; + int before = ::prctl(PR_GET_NO_NEW_PRIVS, 0L, 0L, 0L, 0L); + Require(before != -1, "kernel cannot query NoNewPrivs"); + Require(IsBlocked() == (before == 1), "wrong initial restriction state"); + Require(::prctl(PR_SET_NO_NEW_PRIVS, 1L, 0L, 0L, 0L) == 0, + "cannot set NoNewPrivs in test process"); + Require(IsBlocked(), "real NoNewPrivs was not detected"); +#endif + return 0; + } + const mode_t executable = S_IFREG | 0755; + setenv("PATH", "/tmp/untrusted:/home/test/.nix-profile/bin", 1); + Files["/tmp/untrusted/sudo"] = executable; + Files["/home/test/.nix-profile/bin/sudo"] = executable; + ExpectPath("sudo", ""); + + Files["/usr/bin/sudo"] = executable; + ExpectPath("sudo", "/usr/bin/sudo"); + NixFixture(); +#ifdef TC_LINUX + ExpectPath("sudo", "/run/wrappers/bin/sudo"); + ExpectPath("doas", "/run/wrappers/bin/doas"); + for (const char *name : {"true", "dmsetup", "mount", "umount", "losetup", "modprobe", "fsck", "mkfs.ext4"}) { + ExpectPath(name, string("/run/current-system/sw/bin/") + name); + } + for (mode_t mode : {S_IFREG | 0644, S_IFDIR | 0755, S_IFIFO | 0755}) { + Files["/run/wrappers/wrappers.test/sudo"].Mode = mode; + ExpectPath("sudo", "/run/current-system/sw/bin/sudo"); + } + + // Non-NixOS systems must ignore even existing, otherwise valid NixOS paths. + for (const char *text : {"ID=ubuntu\n", "ID_LIKE=nixos\n", "# ID=nixos\n", + "ID=nixos-extra\n", "ID=nixos\nID=ubuntu\n", "ID=\"nixos\" extra\n", ""}) { + NixFixture(); + Files["/nix/store/os-release"].Contents = text; + ExpectNoNixLookup(); + } + for (const char *text : {"ID=nixos\n", "ID=\"nixos\"\n", "ID='nixos'\r\n"}) { + NixFixture(); + Files["/nix/store/os-release"].Contents = text; + ExpectPath("sudo", "/run/wrappers/bin/sudo"); + } + NixFixture(); + Files.erase("/etc/os-release"); + ExpectNoNixLookup(); + NixFixture(); + Files["/etc/os-release"].Target = "/tmp/os-release"; + Files["/tmp"] = Entry(S_IFDIR | 01777); + Files["/tmp/os-release"] = Entry(S_IFREG | 0444, 0, "", "ID=nixos\n"); + ExpectNoNixLookup(); + NixFixture(); + Files["/nix/store/os-release"].Contents = "ID=nixos\n" + string(65536, 'x'); + ExpectNoNixLookup(); + + // Reject control by any non-root owner, or write access for group/other. + for (const char *path : {"/", "/etc", "/etc/os-release", "/nix", "/nix/store", "/nix/store/os-release"}) { + NixFixture(); + Files[path].Owner = 1000; + ExpectNoNixLookup(); + if (S_ISLNK(Files[path].Mode)) continue; + for (mode_t mode : {S_IWGRP, S_IWOTH}) { + NixFixture(); + Files[path].Mode |= mode; + ExpectNoNixLookup(); + } + } + for (const char *path : {"/run", "/run/wrappers", "/run/wrappers/bin", + "/run/wrappers/wrappers.test", "/run/wrappers/wrappers.test/sudo"}) { + NixFixture(); + Files.erase("/nix/store/profile/bin/sudo"); + Files[path].Owner = 1000; + ExpectPath("sudo", "/usr/bin/sudo"); + if (S_ISLNK(Files[path].Mode)) continue; + for (mode_t mode : {S_IWGRP, S_IWOTH}) { + NixFixture(); + Files.erase("/nix/store/profile/bin/sudo"); + Files[path].Mode |= mode; + ExpectPath("sudo", "/usr/bin/sudo"); + } + } + for (const char *path : {"/run/current-system", "/nix/store/system", "/nix/store/system/sw", + "/nix/store/profile", "/nix/store/profile/bin", "/nix/store/profile/bin/true", + "/nix/store/tools", "/nix/store/tools/bin", "/nix/store/tools/bin/true"}) { + NixFixture(); + Files[path].Owner = 1000; + ExpectPath("true", "/usr/bin/true"); + if (S_ISLNK(Files[path].Mode)) continue; + for (mode_t mode : {S_IWGRP, S_IWOTH}) { + NixFixture(); + Files[path].Mode |= mode; + ExpectPath("true", "/usr/bin/true"); + } + } + // A root-owned link to a root-owned file still fails through a writable parent. + for (const char *target : {"/tmp/helpers", "../../tmp/helpers", "/tmp/../nix/store/tools/bin"}) { + NixFixture(); + Files.erase("/nix/store/profile/bin/sudo"); + Files["/tmp"] = Entry(S_IFDIR | 01777); + Files["/tmp/helpers"] = Entry(S_IFDIR | 0755); + Files["/tmp/helpers/sudo"] = Entry(executable); + Files["/run/wrappers/bin"].Target = target; + ExpectPath("sudo", "/usr/bin/sudo"); + } + // Broken links and link cycles fail closed. + for (const char *target : {"missing", "bin", "/run/wrappers/bin", ""}) { + NixFixture(); + Files.erase("/nix/store/profile/bin/sudo"); + Files["/run/wrappers/bin"].Target = target; + ExpectPath("sudo", "/usr/bin/sudo"); + } + NixFixture(); + Files.erase("/run/wrappers"); + Files.erase("/run/current-system"); + ExpectPath("sudo", "/usr/bin/sudo"); + + // The real NixOS store is sticky, group-writable, and mounted read-only. + NixFixture(); + Files["/nix/store"].Mode = S_IFDIR | 01775; + ExpectPath("sudo", "/run/wrappers/bin/sudo"); + ExpectPath("true", "/run/current-system/sw/bin/true"); + StoreReadOnly = false; + ExpectNoNixLookup(); + StoreReadOnly = true; + StatvfsFails = true; + ExpectNoNixLookup(); + StatvfsFails = false; + Files["/nix/store"].Mode = S_IFDIR | 01777; + ExpectNoNixLookup(); + Files["/nix/store"].Mode = S_IFDIR | 0775; + ExpectNoNixLookup(); + Files["/nix/store"].Mode = S_IFDIR | 01775; + Files["/nix/store/tools/bin/true"].Mode |= S_IWGRP; + ExpectPath("true", "/usr/bin/true"); + Files["/nix/store/tools/bin/true"].Mode = executable; + Files["/nix/store/tools"].Mode |= S_IWGRP | S_ISVTX; + ExpectPath("true", "/usr/bin/true"); + + // Keep the invoked name when the checked target is a multicall binary. + NixFixture(); + Files["/nix/store/tools/bin/coreutils"] = Entry(S_IFREG | 0555); + Files["/nix/store/tools/bin/true"] = Entry(S_IFLNK | 0777, 0, "coreutils"); + ExpectPath("true", "/run/current-system/sw/bin/true"); +#else + ExpectNoNixLookup(); +#endif + Files["/opt/explicit/helper"] = executable; + ExpectPath("/opt/explicit/helper", "/opt/explicit/helper"); + std::string error; + Require(Process::FindSystemBinary(nullptr, error).empty() && errno == EINVAL, + "null name handling changed"); + + QueryResult = 0; + Require(!IsBlocked(), "ordinary elevation blocked"); + QueryResult = 1; +#ifdef TC_LINUX + Require(IsBlocked(), "NoNewPrivs did not block elevation"); +#else + Require(!IsBlocked() && QueryCount == 0, "Linux query used outside Linux"); +#endif + QueryResult = -1; + QueryError = EINVAL; + Require(!IsBlocked(), "unsupported query blocked older kernels"); + QueryError = EPERM; + Require(!IsBlocked(), "failed query misreported as NoNewPrivs"); + return 0; + } catch (const std::exception &error) { + std::cerr << error.what() << std::endl; + return 1; + } +} +''' + with tempfile.TemporaryDirectory(prefix="vc-linux-helpers-") as directory: + work = Path(directory) + source = work / "helpers.cpp" + source.write_text(prelude + guard_headers + lookup + guard + tests) + compiler = shlex.split(os.environ.get("CXX", "c++")) + for name, flags in [ + ("linux", ["-DTC_LINUX"]), + ("old-headers", ["-DTC_LINUX", "-DTEST_OLD_HEADERS"]), + ("other-unix", ["-DTC_MACOSX"]), + ]: + binary = work / name + subprocess.run(compiler + ["-std=c++11", *flags, str(source), "-o", str(binary)], check=True) + subprocess.run([str(binary)], check=True) + if name != "other-unix": + subprocess.run([str(binary), "--kernel"], check=True) + if name == "linux" and args.probe_output: + shutil.copyfile(binary, args.probe_output) + args.probe_output.chmod(0o755) + print(f"PASS: {name} helper lookup and elevation checks", flush=True) + + if args.veracrypt: + if os.geteuid() == 0: + parser.error("--veracrypt must be tested as an ordinary user") + binary = str(args.veracrypt.resolve()) + libc = ctypes.CDLL(None, use_errno=True) + + def restrict_privileges(): + if libc.prctl(38, ctypes.c_ulong(1), ctypes.c_ulong(0), ctypes.c_ulong(0), ctypes.c_ulong(0)) != 0: + raise OSError(ctypes.get_errno(), "PR_SET_NO_NEW_PRIVS failed") + + command = [binary, "--text", "--non-interactive"] + result = subprocess.run(command + ["--version"], preexec_fn=restrict_privileges, + capture_output=True, text=True, timeout=15) + assert result.returncode == 0, result.stderr + result = subprocess.run(command + ["--mount", str(ROOT / "Tests/test.sha256.hc"), + "--password=test", "--pim=0", "--keyfiles=", "--protect-hidden=no", + "--filesystem=none", "--mount-options=ro"], + preexec_fn=restrict_privileges, stdin=subprocess.DEVNULL, + capture_output=True, text=True, timeout=15) + output = result.stdout + result.stderr + entry = ET.parse(ROOT / "src/Common/Language.xml").find(".//entry[@key='LINUX_ELEVATION_BLOCKED']") + message = entry.text.replace("\\n", "\n") + assert result.returncode != 0 and message in output, output + assert "Enter your user password" not in output, output + print("PASS: built binary reports NoNewPrivs before authentication", flush=True) + + +if __name__ == "__main__": + main() diff --git a/Translations/Language.ar.xml b/Translations/Language.ar.xml index e3b2305b..b34c1e12 100644 --- a/Translations/Language.ar.xml +++ b/Translations/Language.ar.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.be.xml b/Translations/Language.be.xml index 2cec825b..b8d0e6ec 100644 --- a/Translations/Language.be.xml +++ b/Translations/Language.be.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.bg.xml b/Translations/Language.bg.xml index f5530538..6c1ca1f6 100644 --- a/Translations/Language.bg.xml +++ b/Translations/Language.bg.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.ca.xml b/Translations/Language.ca.xml index 0c41ab7e..34b8af18 100644 --- a/Translations/Language.ca.xml +++ b/Translations/Language.ca.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.co.xml b/Translations/Language.co.xml index 0936cfc4..c99e7501 100644 --- a/Translations/Language.co.xml +++ b/Translations/Language.co.xml @@ -1725,6 +1725,7 @@ Information about Corsican localization: Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.cs.xml b/Translations/Language.cs.xml index 255f1820..cfc47d29 100644 --- a/Translations/Language.cs.xml +++ b/Translations/Language.cs.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.da.xml b/Translations/Language.da.xml index 88d54513..3d052e37 100644 --- a/Translations/Language.da.xml +++ b/Translations/Language.da.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.de.xml b/Translations/Language.de.xml index b5502163..9d2df3ea 100644 --- a/Translations/Language.de.xml +++ b/Translations/Language.de.xml @@ -1706,6 +1706,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.el.xml b/Translations/Language.el.xml index 900e3886..9bc5ac1c 100644 --- a/Translations/Language.el.xml +++ b/Translations/Language.el.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.es.xml b/Translations/Language.es.xml index bfd12008..2783bbe9 100644 --- a/Translations/Language.es.xml +++ b/Translations/Language.es.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.et.xml b/Translations/Language.et.xml index b5b903fe..a9b884fb 100644 --- a/Translations/Language.et.xml +++ b/Translations/Language.et.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.eu.xml b/Translations/Language.eu.xml index dbdfbd8c..eff137a1 100644 --- a/Translations/Language.eu.xml +++ b/Translations/Language.eu.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.fa.xml b/Translations/Language.fa.xml index 39a3d454..73cffbc1 100644 --- a/Translations/Language.fa.xml +++ b/Translations/Language.fa.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.fi.xml b/Translations/Language.fi.xml index d3d11ed3..87083096 100644 --- a/Translations/Language.fi.xml +++ b/Translations/Language.fi.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.fr.xml b/Translations/Language.fr.xml index 02bb9263..4164e59b 100644 --- a/Translations/Language.fr.xml +++ b/Translations/Language.fr.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.he.xml b/Translations/Language.he.xml index 40cc2be5..2d86fef6 100644 --- a/Translations/Language.he.xml +++ b/Translations/Language.he.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.hu.xml b/Translations/Language.hu.xml index bb460ca3..2dc8d25a 100644 --- a/Translations/Language.hu.xml +++ b/Translations/Language.hu.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.id.xml b/Translations/Language.id.xml index 57cc15e9..89013dd8 100644 --- a/Translations/Language.id.xml +++ b/Translations/Language.id.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.it.xml b/Translations/Language.it.xml index eb92858b..380ec767 100644 --- a/Translations/Language.it.xml +++ b/Translations/Language.it.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.ja.xml b/Translations/Language.ja.xml index f39c0fa4..de586dd9 100644 --- a/Translations/Language.ja.xml +++ b/Translations/Language.ja.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.ka.xml b/Translations/Language.ka.xml index 2b2243dd..437f693b 100644 --- a/Translations/Language.ka.xml +++ b/Translations/Language.ka.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.ko.xml b/Translations/Language.ko.xml index 41702036..923bc756 100644 --- a/Translations/Language.ko.xml +++ b/Translations/Language.ko.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.lv.xml b/Translations/Language.lv.xml index eb200b9c..ffd49f13 100644 --- a/Translations/Language.lv.xml +++ b/Translations/Language.lv.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.my.xml b/Translations/Language.my.xml index f570ad70..6db882d7 100644 --- a/Translations/Language.my.xml +++ b/Translations/Language.my.xml @@ -1705,6 +1705,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.nb.xml b/Translations/Language.nb.xml index 64708fff..62ee9073 100644 --- a/Translations/Language.nb.xml +++ b/Translations/Language.nb.xml @@ -1703,6 +1703,7 @@ Oppdaterer volumstatus… Volumstatus utilgjengelig; prøver igjen… Noe voluminformasjon er utilgjengelig; prøver igjen… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.nl.xml b/Translations/Language.nl.xml index 72e14b77..b908577d 100644 --- a/Translations/Language.nl.xml +++ b/Translations/Language.nl.xml @@ -1703,6 +1703,7 @@ Volumestatus vernieuwen... Volumestatus niet beschikbaar; opnieuw proberen... Sommige volumegegevens zijn niet beschikbaar; opnieuw proberen… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.nn.xml b/Translations/Language.nn.xml index b397d223..767046c7 100644 --- a/Translations/Language.nn.xml +++ b/Translations/Language.nn.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.pl.xml b/Translations/Language.pl.xml index 99db511d..0e9b43cb 100644 --- a/Translations/Language.pl.xml +++ b/Translations/Language.pl.xml @@ -1703,6 +1703,7 @@ Odświeżanie stanu wolumenu… Stan wolumenu niedostępny; ponawianie próby… Niektóre informacje o wolumenie są niedostępne; ponawianie próby… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.pt-br.xml b/Translations/Language.pt-br.xml index 5cfdae23..8f019ea9 100644 --- a/Translations/Language.pt-br.xml +++ b/Translations/Language.pt-br.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.ro.xml b/Translations/Language.ro.xml index d6659d19..3535862d 100644 --- a/Translations/Language.ro.xml +++ b/Translations/Language.ro.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.ru.xml b/Translations/Language.ru.xml index a907d579..770a09c2 100644 --- a/Translations/Language.ru.xml +++ b/Translations/Language.ru.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.sk.xml b/Translations/Language.sk.xml index 9167dfd2..05bbe2f9 100644 --- a/Translations/Language.sk.xml +++ b/Translations/Language.sk.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.sl.xml b/Translations/Language.sl.xml index 49d17b8d..623b84db 100644 --- a/Translations/Language.sl.xml +++ b/Translations/Language.sl.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.sv.xml b/Translations/Language.sv.xml index a960e573..25a32715 100644 --- a/Translations/Language.sv.xml +++ b/Translations/Language.sv.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.th.xml b/Translations/Language.th.xml index ab0bf8ec..00cfc8b2 100644 --- a/Translations/Language.th.xml +++ b/Translations/Language.th.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.tr.xml b/Translations/Language.tr.xml index 37b3cac6..d3f0f1c0 100644 --- a/Translations/Language.tr.xml +++ b/Translations/Language.tr.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.uk.xml b/Translations/Language.uk.xml index 543293a8..93bb668a 100644 --- a/Translations/Language.uk.xml +++ b/Translations/Language.uk.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.uz.xml b/Translations/Language.uz.xml index 555ebe54..915764c7 100644 --- a/Translations/Language.uz.xml +++ b/Translations/Language.uz.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.vi.xml b/Translations/Language.vi.xml index f641fa93..c3eb7ac4 100644 --- a/Translations/Language.vi.xml +++ b/Translations/Language.vi.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.zh-cn.xml b/Translations/Language.zh-cn.xml index 718850ce..3d9cdde7 100644 --- a/Translations/Language.zh-cn.xml +++ b/Translations/Language.zh-cn.xml @@ -1704,6 +1704,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.zh-hk.xml b/Translations/Language.zh-hk.xml index 6557c948..b047d297 100644 --- a/Translations/Language.zh-hk.xml +++ b/Translations/Language.zh-hk.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/Translations/Language.zh-tw.xml b/Translations/Language.zh-tw.xml index 83322e25..860be562 100644 --- a/Translations/Language.zh-tw.xml +++ b/Translations/Language.zh-tw.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/src/Common/Language.xml b/src/Common/Language.xml index 85003b7d..c724ebaf 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -1703,6 +1703,7 @@ Refreshing volume status… Volume status unavailable; retrying… Some volume information is unavailable; retrying… + The current launcher or sandbox blocks VeraCrypt from obtaining administrator privileges (Linux NoNewPrivs).\n\nClose VeraCrypt and start it outside this restricted environment. On NixOS, use the native VeraCrypt package instead of appimage-run. diff --git a/src/Core/CoreException.h b/src/Core/CoreException.h index 9e9e01df..8c6f57f5 100644 --- a/src/Core/CoreException.h +++ b/src/Core/CoreException.h @@ -46,6 +46,7 @@ namespace VeraCrypt TC_EXCEPTION_NODECL (RootDeviceUnavailable); \ TC_EXCEPTION (DriveLetterUnavailable); \ TC_EXCEPTION (DriverError); \ + TC_EXCEPTION (ElevationBlocked); \ TC_EXCEPTION (EncryptedSystemRequired); \ TC_EXCEPTION (HigherFuseVersionRequired); \ TC_EXCEPTION (KernelCryptoServiceTestFailed); \ diff --git a/src/Core/Unix/CoreService.cpp b/src/Core/Unix/CoreService.cpp index 380de05b..8cf2f0f5 100644 --- a/src/Core/Unix/CoreService.cpp +++ b/src/Core/Unix/CoreService.cpp @@ -23,6 +23,13 @@ #include #include #include +#ifdef TC_LINUX +#include +// Allow builds with headers predating Linux 3.5. +#ifndef PR_GET_NO_NEW_PRIVS +#define PR_GET_NO_NEW_PRIVS 39 +#endif +#endif #include "Platform/FileStream.h" #include "Platform/MemoryStream.h" #include "Platform/Serializable.h" @@ -189,6 +196,17 @@ namespace VeraCrypt } #endif + static void CheckPrivilegeElevationAllowed () + { +#ifdef TC_LINUX + // NoNewPrivs is inherited across fork/exec and prevents sudo or doas + // from gaining privileges. A password cannot remove this restriction. + // Older kernels reject the query; let normal elevation handle that case. + if (prctl (PR_GET_NO_NEW_PRIVS, 0L, 0L, 0L, 0L) == 1) + throw ElevationBlocked (SRC_POS); +#endif + } + static PrivilegeHelper FindPrivilegeHelper () { std::string errorMsg; @@ -1466,6 +1484,9 @@ namespace VeraCrypt while (!ElevatedServiceAvailable) { + // Check before authentication, but allow reuse of an elevated service. + CheckPrivilegeElevationAllowed (); + // Test if the user has an active privilege helper session. bool authCheckDone = false; bool passwordCollected = false; @@ -1580,6 +1601,7 @@ namespace VeraCrypt void CoreService::StartElevated (const CoreServiceRequest &request) { + CheckPrivilegeElevationAllowed (); PrivilegeHelper privilegeHelper = FindPrivilegeHelper (); int doasAuthTerminal = -1; string doasAuthTerminalPath; diff --git a/src/Main/UserInterface.cpp b/src/Main/UserInterface.cpp index 4c8c9215..4d3fe1dc 100644 --- a/src/Main/UserInterface.cpp +++ b/src/Main/UserInterface.cpp @@ -592,6 +592,7 @@ namespace VeraCrypt #define EX2MSG(exception, message) do { if (ex == typeid (exception)) return (message); } while (false) EX2MSG (DriveLetterUnavailable, LangString["DRIVE_LETTER_UNAVAILABLE"]); EX2MSG (DeviceSectorSizeMismatch, LangString["LINUX_EX2MSG_DEVICESECTORSIZEMISMATCH"]); + EX2MSG (ElevationBlocked, LangString["LINUX_ELEVATION_BLOCKED"]); EX2MSG (EncryptedSystemRequired, LangString["LINUX_EX2MSG_ENCRYPTEDSYSTEMREQUIRED"]); EX2MSG (ExternalException, LangString["EXCEPTION_OCCURRED"]); EX2MSG (InsufficientData, LangString["LINUX_EX2MSG_INSUFFICIENTDATA"]); diff --git a/src/Platform/Unix/Process.cpp b/src/Platform/Unix/Process.cpp index 812ece6d..abf9a761 100644 --- a/src/Platform/Unix/Process.cpp +++ b/src/Platform/Unix/Process.cpp @@ -12,9 +12,15 @@ #include #include +#include +#include +#include #include #include #include +#ifdef TC_LINUX +#include +#endif #include "Process.h" #include "Platform/Exception.h" #include "Platform/Finally.h" @@ -212,6 +218,127 @@ namespace VeraCrypt return false; } +#ifdef TC_LINUX + static bool IsTrustedSystemPathEntry (const string &path, const struct stat &info) + { + if (info.st_uid != 0) + return false; + if (S_ISLNK (info.st_mode) || !(info.st_mode & (S_IWGRP | S_IWOTH))) + return true; + + // NixOS exposes its store read-only, but the directory retains group + // write permission for the build users. Its sticky bit protects existing + // root-owned entries in the daemon's writable view. All children still + // have to pass the normal ownership and permission checks below. + if (path != "/nix/store" || !S_ISDIR (info.st_mode) + || !(info.st_mode & S_ISVTX) || (info.st_mode & S_IWOTH)) + return false; + struct statvfs filesystem; + return statvfs (path.c_str(), &filesystem) == 0 && (filesystem.f_flag & ST_RDONLY); + } + + // Walk from the root before following each link. Checking only realpath's + // result would miss a writable directory containing an earlier symlink. + // Once checked, a component can only be replaced by a trusted administrator. + static bool ResolveTrustedSystemPath (const string &path, string &resolved, struct stat &info) + { + resolved.clear(); + if (path.empty() || path[0] != '/') + return false; + + if (lstat ("/", &info) != 0 || !S_ISDIR (info.st_mode) || !IsTrustedSystemPathEntry ("/", info)) + return false; + + string current = "/"; + string remaining = path.substr (1); + unsigned int links = 0; + while (!remaining.empty()) + { + size_t separator = remaining.find ('/'); + bool directoryRequired = separator != string::npos; + string component = remaining.substr (0, separator); + remaining = directoryRequired ? remaining.substr (separator + 1) : ""; + if (component.empty()) + continue; + + string candidate = current + (current == "/" ? "" : "/") + component; + if (candidate.size() >= PATH_MAX || lstat (candidate.c_str(), &info) != 0 || info.st_uid != 0) + return false; + + if (S_ISLNK (info.st_mode)) + { + if (++links > 40) + return false; + char target[PATH_MAX]; + ssize_t length = readlink (candidate.c_str(), target, sizeof (target)); + if (length <= 0 || static_cast (length) >= sizeof (target)) + return false; + remaining = string (target, length) + (directoryRequired ? "/" + remaining : ""); + if (target[0] == '/') + current = "/"; + // Symlink mode bits aren't access controls. Its owner and the + // permissions of its parent and target are checked instead. + continue; + } + + if (directoryRequired && !S_ISDIR (info.st_mode)) + return false; + if (component == "..") + { + current.erase (current.find_last_of ('/')); + if (current.empty()) + current = "/"; + } + else if (component != ".") + current = candidate; + if (!IsTrustedSystemPathEntry (current, info)) + return false; + } + + if (lstat (current.c_str(), &info) != 0 || S_ISLNK (info.st_mode) || !IsTrustedSystemPathEntry (current, info)) + return false; + resolved = current; + return true; + } + + static bool IsNixOS () + { + string path; + struct stat info; + if (!ResolveTrustedSystemPath ("/etc/os-release", path, info) || !S_ISREG (info.st_mode)) + return false; + + // Read only protected system metadata, with no shell or environment override. + vector buffer (64 * 1024 + 1); + FILE *file = fopen (path.c_str(), "r"); + if (!file) + return false; + size_t size = fread (&buffer[0], 1, buffer.size(), file); + bool readFailed = ferror (file) != 0; + fclose (file); + if (readFailed || size == buffer.size()) + return false; + + std::istringstream contents (string (&buffer[0], size)); + string line; + bool foundId = false; + bool nixos = false; + while (std::getline (contents, line)) + { + if (!line.empty() && line.back() == '\r') + line.pop_back(); + if (line.compare (0, 3, "ID=") != 0) + continue; + if (foundId) + return false; + foundId = true; + string id = line.substr (3); + nixos = id == "nixos" || id == "\"nixos\"" || id == "'nixos'"; + } + return nixos; + } +#endif + // Find executable in system paths std::string Process::FindSystemBinary(const char* name, std::string& errorMsg) { if (!name) { @@ -242,6 +369,24 @@ namespace VeraCrypt // If path doesn't start with '/', prepend default directories if (currentPath[0] != '/') { +#ifdef TC_LINUX + if (IsNixOS ()) + { + // Only NixOS enables these additional locations. The privileged + // wrapper must precede the system profile's plain sudo binary. + const char *nixDirs[] = { "/run/wrappers/bin", "/run/current-system/sw/bin" }; + for (size_t i = 0; i < sizeof (nixDirs) / sizeof (nixDirs[0]); ++i) + { + string candidate = string (nixDirs[i]) + "/" + currentPath; + string resolved; + struct stat info; + if (ResolveTrustedSystemPath (candidate, resolved, info) + && S_ISREG (info.st_mode) && (info.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + // Preserve argv[0] for helpers such as true that link to a multicall binary. + return candidate; + } + } +#endif for (size_t i = 0; i < defaultDirCount; ++i) { std::string combinedPath = std::string(defaultDirs[i]) + "/" + currentPath; if (IsExecutable(combinedPath)) {