Skip to content

Commit

Permalink
ebpf: check parents of target file
Browse files Browse the repository at this point in the history
  • Loading branch information
kckeiks committed Jun 5, 2024
1 parent 0bcbf80 commit 650afb7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 12 deletions.
6 changes: 3 additions & 3 deletions etc/ebpf/ebpf/src/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ extern "C" {
pub fn task_struct_mm(target: *const task_struct) -> *const *const mm_struct;
pub fn cred_gid_val(target: *const cred) -> c_uint;
pub fn cred_uid_val(target: *const cred) -> c_uint;
pub fn dentry_i_ino(target: *const dentry) -> c_ulong;
pub fn dentry_d_inode(target: *const dentry) -> *const *const inode;
pub fn dentry_d_parent(target: *const dentry) -> *const *const dentry;
pub fn file_inode(target: *const file) -> *const *const inode;
pub fn file_f_path_dentry_inode(target: *const file) -> c_ulong;
pub fn file_dentry(target: *const file) -> *const dentry;
pub fn file_dentry(target: *const file) -> *const *const dentry;
pub fn inode_i_ino(inode: *const inode) -> *const c_ulong;
pub fn inode_i_sb(inode: *const inode) -> *const *const super_block;
pub fn linux_binprm_argc(task: *const linux_binprm) -> c_int;
Expand Down
49 changes: 46 additions & 3 deletions etc/ebpf/ebpf/src/file_open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@ use aya_ebpf::cty::c_long;
use aya_ebpf::macros::lsm;
use aya_ebpf::programs::LsmContext;
use aya_log_ebpf::info;
use lightning_ebpf_common::{File, FileRule};
use lightning_ebpf_common::{File, FileRule, MAX_FILE_RULES};

use crate::{access, maps, vmlinux};

pub const ALLOW: i32 = 0;
pub const DENY: i32 = -1;
pub const MAX_PARENT_SEARCH_DEPTH: u8 = 2;

#[lsm(hook = "file_open")]
pub fn file_open(ctx: LsmContext) -> i32 {
unsafe { try_file_open(ctx).unwrap_or_else(|_| ALLOW) }
}

unsafe fn try_file_open(ctx: LsmContext) -> Result<i32, c_long> {
let target_file: *const vmlinux::file = ctx.arg(0);

let target_inode = {
let file: *const vmlinux::file = ctx.arg(0);
let inode = aya_ebpf::helpers::bpf_probe_read_kernel(access::file_inode(file))?;
let inode = aya_ebpf::helpers::bpf_probe_read_kernel(access::file_inode(target_file))?;
aya_ebpf::helpers::bpf_probe_read_kernel(access::inode_i_ino(inode))?
};
let task_inode = get_inode_from_current_task()?;

if let Some(rule_list) = maps::FILE_RULES.get(&File::new(task_inode)) {
info!(
&ctx,
Expand All @@ -40,6 +43,7 @@ unsafe fn try_file_open(ctx: LsmContext) -> Result<i32, c_long> {
.find(|rule| rule.inode == target_inode)
.map(|rule| rule.permissions & FileRule::OPEN_MASK > 0)
.unwrap_or(false)
|| verify_parent(target_file, &rule_list.rules, FileRule::OPEN_MASK)?
{
return Ok(ALLOW);
} else {
Expand All @@ -51,6 +55,45 @@ unsafe fn try_file_open(ctx: LsmContext) -> Result<i32, c_long> {
Ok(ALLOW)
}

/// Returns true if there is a matching rule for
/// one of the target file's parents, and false otherwise.
unsafe fn verify_parent(
file: *const vmlinux::file,
rules: &[FileRule; MAX_FILE_RULES],
mask: u32,
) -> Result<bool, c_long> {
let dentry = aya_ebpf::helpers::bpf_probe_read_kernel(access::file_dentry(file))?;
let mut next_parent_dentry =
aya_ebpf::helpers::bpf_probe_read_kernel(access::dentry_d_parent(dentry))?;

for _ in 0..MAX_PARENT_SEARCH_DEPTH {
if next_parent_dentry.is_null() {
break;
}

let parent_inode = {
let inode = aya_ebpf::helpers::bpf_probe_read_kernel(access::dentry_d_inode(
next_parent_dentry,
))?;
aya_ebpf::helpers::bpf_probe_read_kernel(access::inode_i_ino(inode))?
};

if rules
.iter()
.find(|rule| rule.inode == parent_inode)
.map(|rule| rule.permissions & mask > 0)
.unwrap_or(false)
{
return Ok(true);
}

next_parent_dentry =
aya_ebpf::helpers::bpf_probe_read_kernel(access::dentry_d_parent(next_parent_dentry))?;
}

Ok(false)
}

/// Get the inode number of the current process's binary file.
unsafe fn get_inode_from_current_task() -> Result<u64, c_long> {
let task = aya_ebpf::helpers::bpf_get_current_task() as *mut vmlinux::task_struct;
Expand Down
12 changes: 6 additions & 6 deletions etc/ebpf/ebpf/src/shim/access.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ struct inode ** file_inode(struct file *target) {
return __builtin_preserve_access_index(&target->f_inode);
}

uint64_t file_f_path_dentry_inode(struct file *target) {
return __builtin_preserve_access_index(target->f_path.dentry->d_inode->i_ino);
struct dentry ** file_dentry(struct file *target) {
return __builtin_preserve_access_index(&target->f_path.dentry);
}

struct dentry* file_dentry(struct file *target) {
return __builtin_preserve_access_index(target->f_path.dentry->d_parent);
struct dentry ** dentry_d_parent(struct dentry *target) {
return __builtin_preserve_access_index(&target->d_parent);
}

uint64_t dentry_i_ino(struct dentry *target) {
return __builtin_preserve_access_index(target->d_inode->i_ino);
struct inode ** dentry_d_inode(struct dentry *target) {
return __builtin_preserve_access_index(&target->d_inode);
}

uint64_t * inode_i_ino(struct inode *target) {
Expand Down

0 comments on commit 650afb7

Please sign in to comment.