1
#[cfg(target_os = "linux")]
2
use std::path::Path;
3

            
4
#[cfg(target_os = "linux")]
5
pub fn landlock_restrict_server(config_path: Option<&Path>) -> anyhow::Result<()> {
6
    use crate::{core::common::DEFAULT_CONFIG_PATH, server::config::ServerConfig};
7
    use anyhow::Context;
8
    use landlock::{
9
        ABI, Access, AccessFs, AccessNet, NetPort, Ruleset, RulesetAttr, RulesetCreatedAttr,
10
        path_beneath_rules,
11
    };
12

            
13
    let config_path = config_path.unwrap_or(Path::new(DEFAULT_CONFIG_PATH));
14

            
15
    let config = ServerConfig::read_config_from_path(config_path)?;
16

            
17
    let abi = ABI::V4;
18
    let mut ruleset = Ruleset::default()
19
        .handle_access(AccessFs::from_all(abi))?
20
        .handle_access(AccessNet::from_all(abi))?
21
        .create()
22
        .context("Failed to create Landlock ruleset")?
23
        .add_rules(path_beneath_rules(
24
            &["/run/muscl"],
25
            AccessFs::from_read(abi),
26
        ))
27
        .context("Failed to add Landlock rules for /run/muscl")?
28
        // Needs read access to /etc to access unix user/group info
29
        .add_rules(path_beneath_rules(&["/etc"], AccessFs::from_read(abi)))
30
        .context("Failed to add Landlock rules for /etc")?
31
        .add_rules(path_beneath_rules(&[config_path], AccessFs::from_read(abi)))
32
        .context(format!(
33
            "Failed to add Landlock rules for server config path at {}",
34
            config_path.display()
35
        ))?;
36

            
37
    if let Some(socket_path) = &config.socket_path {
38
        ruleset = ruleset
39
            .add_rules(path_beneath_rules(&[socket_path], AccessFs::from_all(abi)))
40
            .context(format!(
41
                "Failed to add Landlock rules for server socket path at {}",
42
                socket_path.display()
43
            ))?;
44
    }
45

            
46
    if let Some(mysql_socket_path) = &config.mysql.socket_path {
47
        ruleset = ruleset
48
            .add_rules(path_beneath_rules(
49
                &[mysql_socket_path],
50
                AccessFs::from_all(abi),
51
            ))
52
            .context(format!(
53
                "Failed to add Landlock rules for MySQL socket path at {}",
54
                mysql_socket_path.display()
55
            ))?;
56
    }
57

            
58
    if let Some(mysql_host) = &config.mysql.host {
59
        ruleset = ruleset
60
            .add_rule(NetPort::new(config.mysql.port, AccessNet::ConnectTcp))
61
            .context(format!(
62
                "Failed to add Landlock rules for MySQL host at {}:{}",
63
                mysql_host, config.mysql.port
64
            ))?;
65
    }
66

            
67
    if let Some(mysql_passwd_file) = &config.mysql.password_file {
68
        ruleset = ruleset
69
            .add_rules(path_beneath_rules(
70
                &[mysql_passwd_file],
71
                AccessFs::from_read(abi),
72
            ))
73
            .context(format!(
74
                "Failed to add Landlock rules for MySQL password file at {}",
75
                mysql_passwd_file.display()
76
            ))?;
77
    }
78

            
79
    ruleset
80
        .restrict_self()
81
        .context("Failed to apply Landlock restrictions to the server process")?;
82

            
83
    Ok(())
84
}
85

            
86
#[cfg(not(target_os = "linux"))]
87
pub fn landlock_restrict_server() -> anyhow::Result<()> {
88
    Ok(())
89
}