mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-10-22 14:22:36 +00:00
Volume::Open forces read-only protection on a partially encrypted system volume, but the FUSE backend used the requested protection and attached the loop device and mounted the filesystem read-write. Copy the effective protection into the mount options before choosing the backend. Run the linked mount test in CI, check raw writes and journal recovery in the VM test, and document that a filesystem needing journal recovery may refuse a read-only mount.
71 lines
3.0 KiB
Python
71 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Test the production Linux mount commands without root or devices.
|
|
|
|
Run after a matching Linux build:
|
|
python3 Tests/test_linux_mount_read_only.py --build-dir src
|
|
|
|
Links CoreLinux/CoreUnix from that build and intercepts external commands,
|
|
path type queries and auxiliary metadata using GNU ld --wrap. The native
|
|
tests stop before device I/O; real kernel access modes and cleanup require
|
|
the separate VM integration tests.
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
from pathlib import Path
|
|
import shlex
|
|
import subprocess
|
|
import tempfile
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--build-dir", type=Path, default=ROOT / "src")
|
|
parser.add_argument("--fuse-package", choices=("fuse", "fuse3"), default="fuse3")
|
|
args = parser.parse_args()
|
|
archives = [args.build_dir.resolve() / name for name in (
|
|
"Core/Core.a", "Driver/Fuse/Driver.a", "Volume/Volume.a", "Platform/Platform.a")]
|
|
symbols = subprocess.check_output(["nm", *map(str, archives)], text=True)
|
|
wrappers = {
|
|
"Process7ExecuteE": "WrapExecute",
|
|
"Process16FindSystemBinaryE": "WrapFindBinary",
|
|
"FilesystemPath7GetTypeE": "WrapGetType",
|
|
"CoreUnix23ReadAuxiliaryVolumeInfoE": "WrapAuxInfo",
|
|
"FuseService5MountE": "WrapFuseMount",
|
|
"FuseService17SendAuxDeviceInfoE": "WrapSendAuxInfo",
|
|
}
|
|
flags = []
|
|
for fragment, wrapper in wrappers.items():
|
|
matches = [line.split()[-1] for line in symbols.splitlines()
|
|
if " T " in line and fragment in line]
|
|
if len(matches) != 1:
|
|
raise RuntimeError(f"Expected one definition for {fragment}: {matches}")
|
|
symbol = matches[0]
|
|
flags += [f"-Wl,--wrap={symbol}", f"-Wl,--defsym=__wrap_{symbol}={wrapper}"]
|
|
with tempfile.TemporaryDirectory(prefix="vc-read-only-") as directory:
|
|
work = Path(directory)
|
|
binary = work / "mount-test"
|
|
volume = work / "volume"
|
|
volume.touch()
|
|
command = shlex.split(os.environ.get("CXX", "c++")) + [
|
|
"-std=c++11", "-DTC_UNIX", "-DTC_LINUX", "-D_FILE_OFFSET_BITS=64",
|
|
"-I" + str(ROOT / "src"), "-I" + str(ROOT / "src/Core/Unix/Linux"),
|
|
"-I" + str(ROOT / "src/Crypto"), "-I" + str(ROOT / "src/Crypto/Argon2/include"),
|
|
str(ROOT / "Tests/linux_mount_read_only_test.cpp"), *flags,
|
|
"-Wl,--start-group", *map(str, archives), "-Wl,--end-group",
|
|
"-pthread", "-ldl", "-o", str(binary),
|
|
]
|
|
# WXSTATIC builds use the old libstdc++ ABI (see test_volume_read.py).
|
|
if "cxx11" not in symbols:
|
|
command.append("-D_GLIBCXX_USE_CXX11_ABI=0")
|
|
command += shlex.split(subprocess.check_output(
|
|
["pkg-config", "--libs", args.fuse_package], text=True))
|
|
subprocess.run(command, check=True, timeout=120)
|
|
subprocess.run([str(binary), str(volume)], check=True, timeout=30)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|