Skip to content

Commit 80c0598

Browse files
committed
fix: inode_rename bug
SeaBee now protects correctly with inode_rename. Switched from using old_dentry to new_dentry argument for enforcement. prevent files from being overwritten using rename to new_dentry. Signed-off-by: Alan Wandke <[email protected]>
1 parent 5ded2a9 commit 80c0598

File tree

10 files changed

+58
-12
lines changed

10 files changed

+58
-12
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ zerocopy = { version = "0.8", features = ["derive"] }
2323
edition = "2021"
2424
license = "Apache-2.0"
2525
readme = "README.md"
26-
rust-version = "1.79"
26+
rust-version = "1.83"
2727
version = "1.2.0"
2828
repository = "https://github.com/NationalSecurityAgency/seabee"
2929
homepage = "https://code.nsa.gov/seabee/"

bpf/src/seabee/seabee.bpf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,15 +435,15 @@ int BPF_PROG(seabee_inode_setxattr, struct user_namespace *mnt_userns,
435435
/**
436436
* @brief prevent rename of a protected inode
437437
*
438-
@param old_dentry the old file
438+
@param new_dentry the new file which will be replaced by old file
439439
*/
440440
SEC("lsm/inode_rename")
441441
int BPF_PROG(seabee_inode_rename, struct inode *old_dir,
442442
struct dentry *old_dentry, struct inode *new_dir,
443443
struct dentry *new_dentry, unsigned int flags)
444444
{
445-
return decide_inode_access(INODE_RENAME, old_dentry->d_inode,
446-
old_dentry->d_name.name);
445+
return decide_inode_access(INODE_RENAME, new_dentry->d_inode,
446+
new_dentry->d_name.name);
447447
}
448448

449449
/**

tests/policies/test_tool_debug_audit.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ scope:
55
- ../target/debug/test_tool
66
files:
77
- /etc/seabee_test_tool
8+
- /etc/seabee_test_tempfile
89
config:
910
map_access: audit
1011
file_write_access: audit

tests/policies/test_tool_debug_block.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ scope:
55
- ../target/debug/test_tool
66
files:
77
- /etc/seabee_test_tool
8+
- /etc/seabee_test_tempfile
89
config:
910
map_access: block
1011
file_write_access: block

tests/policies/test_tool_release_audit.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ scope:
55
- ../target/release/test_tool
66
files:
77
- /etc/seabee_test_tool
8+
- /etc/seabee_test_tempfile
89
config:
910
map_access: audit
1011
file_write_access: audit

tests/policies/test_tool_release_block.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ scope:
55
- ../target/release/test_tool
66
files:
77
- /etc/seabee_test_tool
8+
- /etc/seabee_test_tempfile
89
config:
910
map_access: block
1011
file_write_access: block

tests/src/bin/test_tool.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
use std::io::Write;
43
use std::mem::MaybeUninit;
54
use std::sync::atomic::{AtomicBool, Ordering};
65
use std::sync::Arc;
@@ -12,10 +11,6 @@ use bpf::tests::test_tool::*;
1211
use tests::policy::test_constants;
1312

1413
fn main() -> Result<()> {
15-
// create file, TEST_DIR must already exist
16-
let mut file = std::fs::File::create(test_constants::TEST_TOOL_FILE)?;
17-
file.write_all(b"Hello, World!")?;
18-
1914
// load ebpf skel
2015
let skel_builder = TestToolSkelBuilder::default();
2116
let mut open_object = MaybeUninit::uninit();
@@ -48,6 +43,7 @@ fn main() -> Result<()> {
4843

4944
std::fs::remove_file(test_constants::TEST_TOOL_PIN_PATH)?;
5045
std::fs::remove_dir_all(test_constants::TEST_TOOL_DIR)?;
46+
std::fs::remove_file(test_constants::TEST_TOOL_FILE)?;
5147

5248
Ok(())
5349
}

tests/src/policy/protect_tool.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: Apache-2.0
22

33
use std::{
4-
io::ErrorKind,
4+
io::{ErrorKind, Write},
55
path::Path,
66
process::{Child, Command},
77
sync::{
@@ -65,6 +65,14 @@ pub fn start_test_tool(level: SecurityLevel) -> Result<Child> {
6565
));
6666
}
6767
}
68+
// create file
69+
let mut file = std::fs::File::create(test_constants::TEST_TOOL_FILE).map_err(|e| {
70+
anyhow!(
71+
"failed to create file {}: {e}",
72+
test_constants::TEST_TOOL_FILE
73+
)
74+
})?;
75+
file.write_all(b"Hello, World!")?;
6876

6977
// add key
7078
Command::new(SEABEECTL_EXE)
@@ -276,6 +284,10 @@ fn deny_chmod_file() -> Result<(), Failed> {
276284
test_utils::try_chmod(test_constants::TEST_TOOL_FILE, false)
277285
}
278286

287+
fn deny_rename_file() -> Result<(), Failed> {
288+
test_utils::try_rename(test_constants::TEST_TOOL_FILE, false)
289+
}
290+
279291
// check that protected directory attributes cannot be modified
280292
fn deny_chmod_dir() -> Result<(), Failed> {
281293
test_utils::try_chmod(test_constants::TEST_TOOL_DIR, false)
@@ -344,6 +356,7 @@ fn block_tests() -> Vec<Trial> {
344356
create_test!(deny_open_file),
345357
create_test!(deny_chmod_file),
346358
create_test!(deny_chmod_dir),
359+
create_test!(deny_rename_file),
347360
create_test!(deny_policy_overwrite),
348361
]
349362
}

tests/src/policy/test_constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
pub const TEST_TOOL_PIN_PATH: &str = "/sys/fs/bpf/test_tool_pin";
44
pub const TEST_TOOL_DIR: &str = "/etc/seabee_test_tool";
5-
pub const TEST_TOOL_FILE: &str = "/etc/seabee_test_tool/tempfile";
5+
pub const TEST_TOOL_FILE: &str = "/etc/seabee_test_tempfile";
66
pub const SHUTDOWN_REQUEST: &str = "shutdown_request.yaml";
77
pub const SHUTDOWN_REQUEST_SIG: &str = "crypto/sigs/shutdown-request.sign";

tests/src/test_utils.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,43 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
use std::{fs, io::ErrorKind, os::unix::fs::PermissionsExt, path::Path};
3+
use anyhow::anyhow;
4+
use std::{fs, io::ErrorKind, os::unix::fs::PermissionsExt, path::Path, process::Command};
45

56
use libtest_mimic::Failed;
67
use nix::sys::{ptrace, signal::Signal::SIGCONT};
78

9+
pub fn try_rename(target: &str, expect_success: bool) -> Result<(), Failed> {
10+
let output = Command::new("sed")
11+
.arg("-i")
12+
.arg("s/^/newtext/")
13+
.arg(target)
14+
.output()
15+
.map_err(|e| anyhow!("failed to run sed: {e}"))?;
16+
17+
let code = match output.status.code() {
18+
Some(c) => c,
19+
None => {
20+
return Err(format!(
21+
"try_rename on {target} has no return code. possibly killed by signal unexpectedly"
22+
)
23+
.into())
24+
}
25+
};
26+
27+
// Check result
28+
let stdout = String::from_utf8_lossy(&output.stdout);
29+
let stderr = String::from_utf8_lossy(&output.stderr);
30+
if code == 0 && !expect_success {
31+
return Err(format!("try_rename on {target} expected failure, but succeeded\nstdout: {stdout}\nstderr: {stderr}").into());
32+
} else if code == 4 && expect_success {
33+
// we see return code 4 on error
34+
return Err(format!("try_rename on {target} expected success, but was denied\nstdout:{stdout}\nstderr: {stderr}").into());
35+
} else if code != 0 && code != 4 {
36+
return Err(format!("try_rename on {target}: unexpected return code: {code}\nstdout: {stdout}\nstderr:{stderr}").into());
37+
}
38+
Ok(())
39+
}
40+
841
// try chmod and expect permission denied
942
pub fn try_chmod(path: &str, expect_success: bool) -> Result<(), Failed> {
1043
// Try to change permissions

0 commit comments

Comments
 (0)