Add SELinux support (#465)
* Add SELinux support * Nits * Fix spellcheck * Don't store mod, use locked shell * Unwhoops a stale comment * Speeling: Myy aarch neemesis * Fix lost code: * Add method note
This commit is contained in:
parent
10732cef68
commit
e3a5ffc8f7
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
.ci-store
|
.ci-store
|
||||||
.direnv
|
.direnv
|
||||||
result*
|
result*
|
||||||
|
src/action/linux/selinux/nix.mod
|
17
flake.lock
17
flake.lock
|
@ -21,6 +21,22 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1673956053,
|
||||||
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lowdown-src": {
|
"lowdown-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
|
@ -129,6 +145,7 @@
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"fenix": "fenix",
|
"fenix": "fenix",
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
"naersk": "naersk",
|
"naersk": "naersk",
|
||||||
"nix": "nix",
|
"nix": "nix",
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
# Omitting `inputs.nixpkgs.follows = "nixpkgs";` on purpose
|
# Omitting `inputs.nixpkgs.follows = "nixpkgs";` on purpose
|
||||||
};
|
};
|
||||||
|
|
||||||
|
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
@ -139,6 +140,8 @@
|
||||||
cacert
|
cacert
|
||||||
cargo-audit
|
cargo-audit
|
||||||
nixpkgs-fmt
|
nixpkgs-fmt
|
||||||
|
semodule-utils
|
||||||
|
checkpolicy
|
||||||
check.check-rustfmt
|
check.check-rustfmt
|
||||||
check.check-spelling
|
check.check-spelling
|
||||||
check.check-nixpkgs-fmt
|
check.check-nixpkgs-fmt
|
||||||
|
|
|
@ -18,8 +18,8 @@ in
|
||||||
runtimeInputs = with pkgs; [ git codespell ];
|
runtimeInputs = with pkgs; [ git codespell ];
|
||||||
text = ''
|
text = ''
|
||||||
codespell \
|
codespell \
|
||||||
--ignore-words-list ba,sur,crate,pullrequest,pullrequests,ser,distroname \
|
--ignore-words-list="ba,sur,crate,pullrequest,pullrequests,ser,distroname" \
|
||||||
--skip target,.git \
|
--skip="./target,.git,./src/action/linux/selinux" \
|
||||||
.
|
.
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
|
@ -174,7 +174,7 @@ let
|
||||||
uninstallCheck = installCases.install-default.uninstallCheck;
|
uninstallCheck = installCases.install-default.uninstallCheck;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
cureCases = {
|
cureSelfCases = {
|
||||||
cure-self-linux-working = {
|
cure-self-linux-working = {
|
||||||
preinstall = ''
|
preinstall = ''
|
||||||
${nix-installer-install-quiet}
|
${nix-installer-install-quiet}
|
||||||
|
@ -253,6 +253,8 @@ let
|
||||||
uninstall = installCases.install-default.uninstall;
|
uninstall = installCases.install-default.uninstall;
|
||||||
uninstallCheck = installCases.install-default.uninstallCheck;
|
uninstallCheck = installCases.install-default.uninstallCheck;
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
cureScriptCases = {
|
||||||
cure-script-multi-self-broken-no-nix-path = {
|
cure-script-multi-self-broken-no-nix-path = {
|
||||||
preinstall = ''
|
preinstall = ''
|
||||||
${cure-script-multi-user}
|
${cure-script-multi-user}
|
||||||
|
@ -413,7 +415,7 @@ let
|
||||||
};
|
};
|
||||||
rootDisk = "box.img";
|
rootDisk = "box.img";
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
postBoot = disableSELinux;
|
upstreamScriptsWork = false; # SELinux!
|
||||||
};
|
};
|
||||||
|
|
||||||
"fedora-v37" = {
|
"fedora-v37" = {
|
||||||
|
@ -423,7 +425,7 @@ let
|
||||||
};
|
};
|
||||||
rootDisk = "box.img";
|
rootDisk = "box.img";
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
postBoot = disableSELinux;
|
upstreamScriptsWork = false; # SELinux!
|
||||||
};
|
};
|
||||||
|
|
||||||
# Currently fails with 'error while loading shared libraries:
|
# Currently fails with 'error while loading shared libraries:
|
||||||
|
@ -435,7 +437,7 @@ let
|
||||||
hash = "sha256-QwzbvRoRRGqUCQptM7X/InRWFSP2sqwRt2HaaO6zBGM=";
|
hash = "sha256-QwzbvRoRRGqUCQptM7X/InRWFSP2sqwRt2HaaO6zBGM=";
|
||||||
};
|
};
|
||||||
rootDisk = "box.img";
|
rootDisk = "box.img";
|
||||||
postBoot = disableSELinux;
|
upstreamScriptsWork = false; # SELinux!
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
@ -446,7 +448,7 @@ let
|
||||||
hash = "sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U=";
|
hash = "sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U=";
|
||||||
};
|
};
|
||||||
rootDisk = "box.img";
|
rootDisk = "box.img";
|
||||||
postBoot = disableSELinux;
|
upstreamScriptsWork = false; # SELinux!
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -457,7 +459,7 @@ let
|
||||||
};
|
};
|
||||||
rootDisk = "box.img";
|
rootDisk = "box.img";
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
postBoot = disableSELinux;
|
upstreamScriptsWork = false; # SELinux!
|
||||||
};
|
};
|
||||||
|
|
||||||
"rhel-v9" = {
|
"rhel-v9" = {
|
||||||
|
@ -467,7 +469,7 @@ let
|
||||||
};
|
};
|
||||||
rootDisk = "box.img";
|
rootDisk = "box.img";
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
postBoot = disableSELinux;
|
upstreamScriptsWork = false; # SELinux!
|
||||||
extraQemuOpts = "-cpu Westmere-v2";
|
extraQemuOpts = "-cpu Westmere-v2";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -596,11 +598,13 @@ let
|
||||||
)
|
)
|
||||||
images;
|
images;
|
||||||
|
|
||||||
allCases = lib.recursiveUpdate (lib.recursiveUpdate installCases cureCases) uninstallCases;
|
allCases = lib.recursiveUpdate (lib.recursiveUpdate installCases (lib.recursiveUpdate cureSelfCases cureScriptCases)) uninstallCases;
|
||||||
|
|
||||||
install-tests = makeTests "install" installCases;
|
install-tests = makeTests "install" installCases;
|
||||||
|
|
||||||
cure-tests = makeTests "cure" cureCases;
|
cure-self-tests = makeTests "cure-self" cureSelfCases;
|
||||||
|
|
||||||
|
cure-script-tests = makeTests "cure-script" cureScriptCases;
|
||||||
|
|
||||||
uninstall-tests = makeTests "uninstall" uninstallCases;
|
uninstall-tests = makeTests "uninstall" uninstallCases;
|
||||||
|
|
||||||
|
@ -610,14 +614,14 @@ let
|
||||||
name = "all";
|
name = "all";
|
||||||
constituents = [
|
constituents = [
|
||||||
install-tests."${imageName}"."x86_64-linux".install
|
install-tests."${imageName}"."x86_64-linux".install
|
||||||
cure-tests."${imageName}"."x86_64-linux".cure
|
cure-self-tests."${imageName}"."x86_64-linux".cure-self
|
||||||
uninstall-tests."${imageName}"."x86_64-linux".uninstall
|
uninstall-tests."${imageName}"."x86_64-linux".uninstall
|
||||||
];
|
] ++ (lib.optional (image.upstreamScriptsWork or false) cure-script-tests."${imageName}"."x86_64-linux".cure-script);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
images;
|
images;
|
||||||
|
|
||||||
joined-tests = lib.recursiveUpdate (lib.recursiveUpdate (lib.recursiveUpdate cure-tests install-tests) uninstall-tests) all-tests;
|
joined-tests = lib.recursiveUpdate (lib.recursiveUpdate (lib.recursiveUpdate install-tests (lib.recursiveUpdate cure-self-tests cure-script-tests)) uninstall-tests) all-tests;
|
||||||
|
|
||||||
in
|
in
|
||||||
lib.recursiveUpdate joined-tests {
|
lib.recursiveUpdate joined-tests {
|
||||||
|
@ -626,5 +630,5 @@ lib.recursiveUpdate joined-tests {
|
||||||
name = caseName;
|
name = caseName;
|
||||||
constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux"."${caseName}") joined-tests;
|
constituents = pkgs.lib.mapAttrsToList (name: value: value."x86_64-linux"."${caseName}") joined-tests;
|
||||||
}
|
}
|
||||||
)) (allCases // { "cure" = { }; "install" = { }; "uninstall" = { }; "all" = { }; });
|
)) (allCases // { "cure-self" = { }; "cure-script" = { }; "install" = { }; "uninstall" = { }; "all" = { }; });
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,6 +300,12 @@ impl Action for ConfigureInitService {
|
||||||
Self::check_if_systemd_unit_exists(SERVICE_SRC, SERVICE_DEST)
|
Self::check_if_systemd_unit_exists(SERVICE_SRC, SERVICE_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::error)?;
|
.map_err(Self::error)?;
|
||||||
|
if Path::new(SERVICE_DEST).exists() {
|
||||||
|
tokio::fs::remove_file(SERVICE_DEST)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionErrorKind::Remove(SERVICE_DEST.into(), e))
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
}
|
||||||
tokio::fs::symlink(SERVICE_SRC, SERVICE_DEST)
|
tokio::fs::symlink(SERVICE_SRC, SERVICE_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
@ -310,10 +316,15 @@ impl Action for ConfigureInitService {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map_err(Self::error)?;
|
.map_err(Self::error)?;
|
||||||
|
|
||||||
Self::check_if_systemd_unit_exists(SOCKET_SRC, SOCKET_DEST)
|
Self::check_if_systemd_unit_exists(SOCKET_SRC, SOCKET_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(Self::error)?;
|
.map_err(Self::error)?;
|
||||||
|
if Path::new(SOCKET_DEST).exists() {
|
||||||
|
tokio::fs::remove_file(SOCKET_DEST)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionErrorKind::Remove(SOCKET_DEST.into(), e))
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
}
|
||||||
tokio::fs::symlink(SOCKET_SRC, SOCKET_DEST)
|
tokio::fs::symlink(SOCKET_SRC, SOCKET_DEST)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub(crate) mod provision_selinux;
|
||||||
pub(crate) mod start_systemd_unit;
|
pub(crate) mod start_systemd_unit;
|
||||||
|
|
||||||
|
pub use provision_selinux::ProvisionSelinux;
|
||||||
pub use start_systemd_unit::{StartSystemdUnit, StartSystemdUnitError};
|
pub use start_systemd_unit::{StartSystemdUnit, StartSystemdUnitError};
|
||||||
|
|
125
src/action/linux/provision_selinux.rs
Normal file
125
src/action/linux/provision_selinux.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use tokio::fs::{create_dir_all, remove_file};
|
||||||
|
use tokio::process::Command;
|
||||||
|
use tracing::{span, Span};
|
||||||
|
|
||||||
|
use crate::action::{ActionError, ActionErrorKind, ActionTag};
|
||||||
|
use crate::execute_command;
|
||||||
|
|
||||||
|
use crate::action::{Action, ActionDescription, StatefulAction};
|
||||||
|
|
||||||
|
const SE_LINUX_POLICY_PP_CONTENT: &[u8] = include_bytes!("selinux/nix.pp");
|
||||||
|
|
||||||
|
/**
|
||||||
|
Provision the selinux/nix.pp for SELinux compatibility
|
||||||
|
*/
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||||
|
pub struct ProvisionSelinux {
|
||||||
|
policy_path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvisionSelinux {
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
pub async fn plan(policy_path: PathBuf) -> Result<StatefulAction<Self>, ActionError> {
|
||||||
|
let this = Self { policy_path };
|
||||||
|
|
||||||
|
// Note: `restorecon` requires us to not just skip this, even if everything is in place.
|
||||||
|
|
||||||
|
Ok(StatefulAction::uncompleted(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
#[typetag::serde(name = "provision_selinux")]
|
||||||
|
impl Action for ProvisionSelinux {
|
||||||
|
fn action_tag() -> ActionTag {
|
||||||
|
ActionTag("provision_selinux")
|
||||||
|
}
|
||||||
|
fn tracing_synopsis(&self) -> String {
|
||||||
|
format!("Install an SELinux Policy for Nix")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tracing_span(&self) -> Span {
|
||||||
|
span!(
|
||||||
|
tracing::Level::DEBUG,
|
||||||
|
"provision_selinux",
|
||||||
|
policy_path = %self.policy_path.display()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_description(&self) -> Vec<ActionDescription> {
|
||||||
|
vec![ActionDescription::new(
|
||||||
|
self.tracing_synopsis(),
|
||||||
|
vec![format!(
|
||||||
|
"On SELinux systems (such as Fedora) a policy for Nix needs to be configured for correct operation."
|
||||||
|
)],
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
async fn execute(&mut self) -> Result<(), ActionError> {
|
||||||
|
if self.policy_path.exists() {
|
||||||
|
// Rebuild it.
|
||||||
|
remove_existing_policy(&self.policy_path)
|
||||||
|
.await
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = self.policy_path.parent() {
|
||||||
|
create_dir_all(&parent)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionErrorKind::CreateDirectory(parent.into(), e))
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokio::fs::write(&self.policy_path, SE_LINUX_POLICY_PP_CONTENT)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionErrorKind::Write(self.policy_path.clone(), e))
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
|
||||||
|
execute_command(
|
||||||
|
Command::new("semodule")
|
||||||
|
.arg("--install")
|
||||||
|
.arg(&self.policy_path),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
|
||||||
|
execute_command(Command::new("restorecon").args(["-FR", "/nix"]))
|
||||||
|
.await
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn revert_description(&self) -> Vec<ActionDescription> {
|
||||||
|
vec![ActionDescription::new(
|
||||||
|
"Remove the SELinux policy for Nix".into(),
|
||||||
|
vec![],
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
async fn revert(&mut self) -> Result<(), ActionError> {
|
||||||
|
if self.policy_path.exists() {
|
||||||
|
remove_existing_policy(&self.policy_path)
|
||||||
|
.await
|
||||||
|
.map_err(Self::error)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_existing_policy(policy_path: &Path) -> Result<(), ActionErrorKind> {
|
||||||
|
execute_command(Command::new("semodule").arg("--remove").arg("nix")).await?;
|
||||||
|
|
||||||
|
remove_file(&policy_path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ActionErrorKind::Remove(policy_path.into(), e))?;
|
||||||
|
|
||||||
|
execute_command(Command::new("restorecon").args(["-FR", "/nix"])).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
9
src/action/linux/selinux/README.md
Normal file
9
src/action/linux/selinux/README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
To refresh the output `pp` file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Method
|
||||||
|
|
||||||
|
We use the same method and definitions as https://github.com/nix-community/nix-installers/tree/master/selinux.
|
5
src/action/linux/selinux/build.sh
Executable file
5
src/action/linux/selinux/build.sh
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
#! /usr/bin/env nix-shell
|
||||||
|
#! nix-shell -i bash ../../../../shell.nix
|
||||||
|
|
||||||
|
checkmodule -M -m -c 5 -o nix.mod nix.te
|
||||||
|
semodule_package -o nix.pp -m nix.mod -f nix.fc
|
8
src/action/linux/selinux/nix.fc
Normal file
8
src/action/linux/selinux/nix.fc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/nix/store/[^/]+/s?bin(/.*)? system_u:object_r:bin_t:s0
|
||||||
|
/nix/store/[^/]+/lib/systemd/system(/.*)? system_u:object_r:systemd_unit_file_t:s0
|
||||||
|
/nix/store/[^/]+/lib(/.*)? system_u:object_r:lib_t:s0
|
||||||
|
/nix/store/[^/]+/man(/.*)? system_u:object_r:man_t:s0
|
||||||
|
/nix/store/[^/]+/etc(/.*)? system_u:object_r:etc_t:s0
|
||||||
|
/nix/store/[^/]+/share(/.*)? system_u:object_r:usr_t:s0
|
||||||
|
/nix/var/nix/daemon-socket(/.*)? system_u:object_r:var_run_t:s0
|
||||||
|
/nix/var/nix/profiles(/per-user/[^/]+)?/[^/]+ system_u:object_r:usr_t:s0
|
BIN
src/action/linux/selinux/nix.pp
Normal file
BIN
src/action/linux/selinux/nix.pp
Normal file
Binary file not shown.
11
src/action/linux/selinux/nix.te
Normal file
11
src/action/linux/selinux/nix.te
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module nix 1.0;
|
||||||
|
|
||||||
|
require {
|
||||||
|
type bin_t;
|
||||||
|
type lib_t;
|
||||||
|
type man_t;
|
||||||
|
type usr_t;
|
||||||
|
type etc_t;
|
||||||
|
type var_run_t;
|
||||||
|
type systemd_unit_file_t;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ use crate::{
|
||||||
action::{
|
action::{
|
||||||
base::{CreateDirectory, RemoveDirectory},
|
base::{CreateDirectory, RemoveDirectory},
|
||||||
common::{ConfigureInitService, ConfigureNix, ProvisionNix},
|
common::{ConfigureInitService, ConfigureNix, ProvisionNix},
|
||||||
|
linux::ProvisionSelinux,
|
||||||
StatefulAction,
|
StatefulAction,
|
||||||
},
|
},
|
||||||
error::HasExpectedErrors,
|
error::HasExpectedErrors,
|
||||||
|
@ -12,6 +13,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
use which::which;
|
||||||
|
|
||||||
use super::ShellProfileLocations;
|
use super::ShellProfileLocations;
|
||||||
|
|
||||||
|
@ -42,25 +44,44 @@ impl Planner for Linux {
|
||||||
|
|
||||||
check_not_wsl1()?;
|
check_not_wsl1()?;
|
||||||
|
|
||||||
check_not_selinux().await?;
|
let has_selinux = detect_selinux().await?;
|
||||||
|
|
||||||
if self.init.init == InitSystem::Systemd && self.init.start_daemon {
|
if self.init.init == InitSystem::Systemd && self.init.start_daemon {
|
||||||
check_systemd_active()?;
|
check_systemd_active()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(vec![
|
let mut plan = vec![];
|
||||||
|
|
||||||
|
plan.push(
|
||||||
CreateDirectory::plan("/nix", None, None, 0o0755, true)
|
CreateDirectory::plan("/nix", None, None, 0o0755, true)
|
||||||
.await
|
.await
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
);
|
||||||
|
|
||||||
|
plan.push(
|
||||||
ProvisionNix::plan(&self.settings.clone())
|
ProvisionNix::plan(&self.settings.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
);
|
||||||
|
plan.push(
|
||||||
ConfigureNix::plan(ShellProfileLocations::default(), &self.settings)
|
ConfigureNix::plan(ShellProfileLocations::default(), &self.settings)
|
||||||
.await
|
.await
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if has_selinux {
|
||||||
|
plan.push(
|
||||||
|
ProvisionSelinux::plan("/usr/share/selinux/packages/nix.pp".into())
|
||||||
|
.await
|
||||||
|
.map_err(PlannerError::Action)?
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
plan.push(
|
||||||
ConfigureInitService::plan(
|
ConfigureInitService::plan(
|
||||||
self.init.init,
|
self.init.init,
|
||||||
self.init.start_daemon,
|
self.init.start_daemon,
|
||||||
|
@ -69,11 +90,15 @@ impl Planner for Linux {
|
||||||
.await
|
.await
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
);
|
||||||
|
plan.push(
|
||||||
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
|
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
|
||||||
.await
|
.await
|
||||||
.map_err(PlannerError::Action)?
|
.map_err(PlannerError::Action)?
|
||||||
.boxed(),
|
.boxed(),
|
||||||
])
|
);
|
||||||
|
|
||||||
|
Ok(plan)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn settings(&self) -> Result<HashMap<String, serde_json::Value>, InstallSettingsError> {
|
fn settings(&self) -> Result<HashMap<String, serde_json::Value>, InstallSettingsError> {
|
||||||
|
@ -139,26 +164,19 @@ fn check_not_wsl1() -> Result<(), PlannerError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_not_selinux() -> Result<(), PlannerError> {
|
async fn detect_selinux() -> Result<bool, PlannerError> {
|
||||||
// We currently do not support SELinux
|
if Path::new("/sys/fs/selinux").exists() {
|
||||||
match Command::new("getenforce").output().await {
|
// We expect systems with SELinux to have the normal SELinux tools.
|
||||||
Ok(output) => {
|
let has_semodule = which("semodule").is_ok();
|
||||||
let stdout_string = String::from_utf8(output.stdout).map_err(PlannerError::Utf8)?;
|
let has_restorecon = which("restorecon").is_ok();
|
||||||
tracing::trace!(getenforce_stdout = stdout_string, "SELinux detected");
|
if !(has_semodule && has_restorecon) {
|
||||||
match stdout_string.trim() {
|
Err(PlannerError::SelinuxRequirements)
|
||||||
"Enforcing" => return Err(PlannerError::SelinuxEnforcing),
|
} else {
|
||||||
_ => (),
|
Ok(true)
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
// The device doesn't have SELinux set up
|
Ok(false)
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
|
|
||||||
// Some unknown error
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!(error = ?e, "Got an error checking for SELinux setting, this install may fail if SELinux is set to `Enforcing`")
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_nix_not_already_installed() -> Result<(), PlannerError> {
|
async fn check_nix_not_already_installed() -> Result<(), PlannerError> {
|
||||||
|
|
|
@ -367,13 +367,8 @@ pub enum PlannerError {
|
||||||
#[error("Detected that this process is running under Rosetta, using Nix in Rosetta is not supported (Please open an issue with your use case)")]
|
#[error("Detected that this process is running under Rosetta, using Nix in Rosetta is not supported (Please open an issue with your use case)")]
|
||||||
RosettaDetected,
|
RosettaDetected,
|
||||||
/// A Linux SELinux related error
|
/// A Linux SELinux related error
|
||||||
#[error("\
|
#[error("Unable to install on an SELinux system without common SELinux tooling, the binaries `restorecon`, and `semodule` are required")]
|
||||||
This installer doesn't yet support SELinux in `Enforcing` mode.\n
|
SelinuxRequirements,
|
||||||
\n\
|
|
||||||
If desirable, consider setting SELinux to `Permissive` mode with `setenforce Permissive`.\n\
|
|
||||||
\n\
|
|
||||||
If SELinux is important to you, please see https://github.com/DeterminateSystems/nix-installer/issues/124.")]
|
|
||||||
SelinuxEnforcing,
|
|
||||||
/// A UTF-8 related error
|
/// A UTF-8 related error
|
||||||
#[error("UTF-8 error")]
|
#[error("UTF-8 error")]
|
||||||
Utf8(#[from] FromUtf8Error),
|
Utf8(#[from] FromUtf8Error),
|
||||||
|
@ -401,7 +396,7 @@ impl HasExpectedErrors for PlannerError {
|
||||||
PlannerError::Sysctl(_) => None,
|
PlannerError::Sysctl(_) => None,
|
||||||
this @ PlannerError::RosettaDetected => Some(Box::new(this)),
|
this @ PlannerError::RosettaDetected => Some(Box::new(this)),
|
||||||
PlannerError::Utf8(_) => None,
|
PlannerError::Utf8(_) => None,
|
||||||
PlannerError::SelinuxEnforcing => Some(Box::new(self)),
|
PlannerError::SelinuxRequirements => Some(Box::new(self)),
|
||||||
PlannerError::Custom(e) => {
|
PlannerError::Custom(e) => {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
if let Some(err) = e.downcast_ref::<linux::LinuxErrorKind>() {
|
if let Some(err) = e.downcast_ref::<linux::LinuxErrorKind>() {
|
||||||
|
|
Loading…
Reference in a new issue