From 5488f21affd32fdf23dcc8774dade982f61c4615 Mon Sep 17 00:00:00 2001 From: Reiner Herrmann Date: Sat, 29 Oct 2022 23:41:28 +0200 Subject: Restrict filesystem access with landlock, if it is supported --- Cargo.toml | 5 +++++ src/tftpd.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9fcd1b9..3b7a709 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,11 @@ panic = 'abort' nix = { version = "0.25.0", default-features = false, features = ["fs", "user"] } getopts = "0.2" threadpool = "1.0" +landlock = { git = "https://github.com/landlock-lsm/rust-landlock.git", optional = true } + +[features] +default = ["landlock"] +landlock = ["dep:landlock"] [[bin]] name = "rtftpd" diff --git a/src/tftpd.rs b/src/tftpd.rs index 566b10b..74b5cc0 100644 --- a/src/tftpd.rs +++ b/src/tftpd.rs @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 Reiner Herrmann + * Copyright 2019-2022 Reiner Herrmann * License: GPL-3+ */ @@ -16,6 +16,12 @@ use nix::unistd::{chroot, setresgid, setresuid, Gid, Uid, ROOT}; use getopts::Options; use threadpool::ThreadPool; +#[cfg(feature = "landlock")] +use landlock::{ + Access, AccessFs, PathBeneath, PathFd, RestrictionStatus, + RulesetError, RulesetStatus, ABI +}; + #[derive(Clone)] struct Configuration { port: u16, @@ -252,6 +258,37 @@ impl Tftpd { } } + #[cfg(feature = "landlock")] + fn restrict_filesystem(&self) { + let abi = ABI::V1; + let access_all = AccessFs::from_all(abi); + let access_read = AccessFs::from_read(abi); + let access_write = AccessFs::from_write(abi); + + let pathfd = PathFd::new(&self.conf.dir).expect("Directory can't be opened"); + + let access = if self.conf.ro { + access_read + } else if self.conf.wo { + access_write + } else { + access_all + }; + + let restrict = || -> Result { + landlock::Ruleset::new() + .handle_access(access_all)? + .create()? + .add_rule(PathBeneath::new(pathfd, access))? + .restrict_self() + }; + + let status = restrict().expect("Setting up landlock restriction failed"); + if status.ruleset != RulesetStatus::FullyEnforced { + eprintln!("Landlock restrictions not (fully) applied (maybe kernel too old?)."); + } + } + pub fn start(&mut self) { let socket = match UdpSocket::bind(format!("[::]:{}", self.conf.port)) { Ok(s) => s, @@ -260,6 +297,10 @@ impl Tftpd { return; } }; + + #[cfg(feature = "landlock")] + self.restrict_filesystem(); + match self.chroot_destdir() { Ok(_) => {}, Err(err) => { -- cgit v1.2.3