Files
cloud-hypervisor/vmm/src/landlock.rs
Philipp Schuster d7edd9d51f misc: vmm: streamline error Display::fmt()
The changes were mostly automatically applied using the following
Python script:

```python
import os, re

for root, _, files in os.walk("."):
    for f in files:
        if not f.endswith(".rs"):
            continue
        p = os.path.join(root, f)
        with open(p, "r", encoding="utf-8") as file:
            lines = file.readlines()
        changed = False
        for i in range(len(lines) - 1):
            if re.search(r'#\[error\(".*: \{0[^}]*\}"\)\]', lines[i]) and "#[source]" in lines[i + 1].strip():
                lines[i] = re.sub(r': \{0[^}]*\}"\)\]', '")]', lines[i])
                changed = True
        if changed:
            with open(p, "w", encoding="utf-8") as file:
                file.writelines(lines)
            print("Fixed:", p)
```

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com

# Conflicts:
#	vmm/src/api/http/mod.rs
2025-06-13 19:55:54 +00:00

156 lines
4.5 KiB
Rust

// Copyright © 2024 Microsoft Corporation
//
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryFrom;
use std::io::Error as IoError;
use std::path::PathBuf;
#[cfg(test)]
use landlock::make_bitflags;
use landlock::{
path_beneath_rules, Access, AccessFs, BitFlags, Ruleset, RulesetAttr, RulesetCreated,
RulesetCreatedAttr, RulesetError, ABI,
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum LandlockError {
/// All RulesetErrors from Landlock library are wrapped in this error
#[error("Error creating/adding/restricting ruleset")]
ManageRuleset(#[source] RulesetError),
/// Error opening path
#[error("Error opening path")]
OpenPath(#[source] IoError),
/// Invalid Landlock access
#[error("Invalid Landlock access: {0}")]
InvalidLandlockAccess(String),
/// Invalid Path
#[error("Invalid path")]
InvalidPath,
}
// https://docs.rs/landlock/latest/landlock/enum.ABI.html for more info on ABI
static ABI: ABI = ABI::V3;
#[derive(Debug)]
pub(crate) struct LandlockAccess {
access: BitFlags<AccessFs>,
}
impl TryFrom<&str> for LandlockAccess {
type Error = LandlockError;
fn try_from(s: &str) -> Result<LandlockAccess, LandlockError> {
if s.is_empty() {
return Err(LandlockError::InvalidLandlockAccess(
"Access cannot be empty".to_string(),
));
}
let mut access = BitFlags::<AccessFs>::empty();
for c in s.chars() {
match c {
'r' => access |= AccessFs::from_read(ABI),
'w' => access |= AccessFs::from_write(ABI),
_ => {
return Err(LandlockError::InvalidLandlockAccess(
format!("Invalid access: {c}").to_string(),
))
}
};
}
Ok(LandlockAccess { access })
}
}
pub struct Landlock {
ruleset: RulesetCreated,
}
impl Landlock {
pub fn new() -> Result<Landlock, LandlockError> {
let file_access = AccessFs::from_all(ABI);
let def_ruleset = Ruleset::default()
.handle_access(file_access)
.map_err(LandlockError::ManageRuleset)?;
// By default, rulesets are created in `BestEffort` mode. This lets Landlock
// to enable all the supported rules and silently ignore the unsupported ones.
let ruleset = def_ruleset.create().map_err(LandlockError::ManageRuleset)?;
Ok(Landlock { ruleset })
}
pub(crate) fn add_rule(
&mut self,
path: PathBuf,
access: BitFlags<AccessFs>,
) -> Result<(), LandlockError> {
// path_beneath_rules in landlock crate handles file and directory access rules.
// Incoming path/s are passed to path_beneath_rules, so that we don't
// have to worry about the type of the path.
let paths = vec![path.clone()];
let path_beneath_rules = path_beneath_rules(paths, access);
self.ruleset
.as_mut()
.add_rules(path_beneath_rules)
.map_err(LandlockError::ManageRuleset)?;
Ok(())
}
pub(crate) fn add_rule_with_access(
&mut self,
path: PathBuf,
access: &str,
) -> Result<(), LandlockError> {
self.add_rule(path, LandlockAccess::try_from(access)?.access)?;
Ok(())
}
pub fn restrict_self(self) -> Result<(), LandlockError> {
self.ruleset
.restrict_self()
.map_err(LandlockError::ManageRuleset)?;
Ok(())
}
}
#[test]
fn test_try_from_access() {
// These access rights could change in future versions of Landlock. Listing
// them here explicitly to raise their visibility during code reviews.
let read_access = make_bitflags!(AccessFs::{
Execute
| ReadFile
| ReadDir
});
let write_access = make_bitflags!(AccessFs::{
WriteFile
| RemoveDir
| RemoveFile
| MakeChar
| MakeDir
| MakeReg
| MakeSock
| MakeFifo
| MakeBlock
| MakeSym
| Refer
| Truncate
});
let landlock_access = LandlockAccess::try_from("rw").unwrap();
assert!(landlock_access.access == read_access | write_access);
let landlock_access = LandlockAccess::try_from("r").unwrap();
assert!(landlock_access.access == read_access);
let landlock_access = LandlockAccess::try_from("w").unwrap();
assert!(landlock_access.access == write_access);
LandlockAccess::try_from("").unwrap_err();
}