Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix rasp oom #708

Merged
merged 3 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion rasp/librasp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ libc = "0.2.80"
nix = "0.24"
anyhow = "1.0.38"
# elf
goblin = "0.8.0"
goblin = "0.3.4"
byteorder = "1.0"
# lru cache
lru_time_cache = "0.11.8"
Expand All @@ -31,6 +31,7 @@ coarsetime = "0.1"
wait-timeout = "0.2.0"
lazy_static = "1.4.0"

cgroups-rs = "0.2.6"
# plugins
plugins = { path = "../../plugins/lib/rust"}

Expand Down
4 changes: 2 additions & 2 deletions rasp/librasp/src/golang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ pub fn golang_bin_inspect(bin_file: &PathBuf, elf: &Elf) -> Result<u64> {
let shstrtab = &elf.shdr_strtab;
for section in elf.section_headers.iter() {
let offset = section.sh_name;
if let Some(name) = shstrtab.get_at(offset) {
if name == ".gopclntab" {
if let Some(name) = shstrtab.get(offset) {
if name.unwrap_or_default() == ".gopclntab" {
return Ok(size);
}
}
Expand Down
7 changes: 4 additions & 3 deletions rasp/librasp/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ impl RASPManager {
})
}
}
let mut need_write_config = true;
// issue: may case oom
let mut need_write_config = false;
for m in messages.iter() {
if m.message_type >= 12 && m.message_type <= 14 {
need_write_config = false;
Expand Down Expand Up @@ -331,9 +332,9 @@ impl RASPManager {
let runtime_info = &process_info.runtime.clone().unwrap();
let root_dir = format!("/proc/{}/root", process_info.pid);
let pid = process_info.pid;
let nspid = process_info.nspid;
// let nspid = process_info.nspid;
// delete config
self.delete_config_file(pid, nspid)?;
// self.delete_config_file(pid, nspid)?;
let attach_result = match runtime_info.name {
"JVM" => match JVMProbeState::inspect_process(process_info)? {
ProbeState::Attached => {
Expand Down
93 changes: 66 additions & 27 deletions rasp/librasp/src/nodejs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;

use anyhow::Result as Anyhow;
// cgroup
use cgroups_rs::{self, cgroup_builder::CgroupBuilder, CgroupPid, Controller};

const NODEJS_INSPECT_PORT_MIN:u16 = 19230;
const NODEJS_INSPECT_PORT_MAX:u16 = 19235;
pub struct NodeJSProbe {}
Expand Down Expand Up @@ -148,6 +152,22 @@ pub fn get_inspect_port(process_info: &ProcessInfo) -> u16 {
0
}

fn setup_cgroup(pid: u32, cg_name: &str) -> Anyhow<()> {
let hier = cgroups_rs::hierarchies::auto();
let rasp_child_cg = CgroupBuilder::new(cg_name)
.memory()
.memory_hard_limit(1024 * 1024 * 200)
.done()
.cpu()
.quota(1000 * 10).done()
.build(hier);
let mems: &cgroups_rs::memory::MemController = rasp_child_cg.controller_of().unwrap();
mems.add_task(&CgroupPid::from(pid as u64))?;
let cpus: &cgroups_rs::cpu::CpuController = rasp_child_cg.controller_of().unwrap();
cpus.add_task(&CgroupPid::from(pid as u64))?;
Ok(())
}

pub fn nodejs_run(pid: i32, node_path: &str, smith_module_path: &str, port: Option<u16>) -> Result<bool> {
let pid_string = pid.to_string();
let nsenter = settings::RASP_NS_ENTER_BIN();
Expand Down Expand Up @@ -205,6 +225,7 @@ pub fn nodejs_run(pid: i32, node_path: &str, smith_module_path: &str, port: Opti
.stdout(Stdio::piped())
.spawn()?;

setup_cgroup(child.id(), "rasp_nodejs_attach_cg")?;
let timeout = Duration::from_secs(30);

match child.wait_timeout(timeout).unwrap() {
Expand Down Expand Up @@ -261,34 +282,52 @@ pub fn nodejs_version(pid: i32, nodejs_bin_path: &String) -> Result<(u32, u32, S
nodejs_bin_path,
"-v",
];
let output = match Command::new(nsenter).args(&args).output() {
Ok(s) => s,
Err(e) => return Err(anyhow!(e.to_string())),
};
let output_string = String::from_utf8(output.stdout).unwrap_or(String::new());
if output_string.is_empty() {
return Err(anyhow!("empty stdout"));
}
// parse nodejs version
let re = Regex::new(r"v((\d+)\.(\d+)\.\d+)").unwrap();
let (major, minor, version) = match re.captures(&output_string) {
Some(c) => {
let major = c.get(2).map_or("", |m| m.as_str());
let minor = c.get(3).map_or("", |m| m.as_str());
let version = c.get(1).map_or("", |m| m.as_str());
(major, minor, version)
let mut child = Command::new(nsenter)
.args(&args)
.stderr(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;

setup_cgroup(child.id(), "rasp_nodejs_inspect_cg")?;

let timeout = Duration::from_secs(30);

match child.wait_timeout(timeout).unwrap() {
Some(_) => {
let out = child.wait_with_output()?;

let output_string = String::from_utf8(out.stdout).unwrap_or(String::new());
if output_string.is_empty() {
return Err(anyhow!("empty stdout"));
}
// parse nodejs version
let re = Regex::new(r"v((\d+)\.(\d+)\.\d+)").unwrap();
let (major, minor, version) = match re.captures(&output_string) {
Some(c) => {
let major = c.get(2).map_or("", |m| m.as_str());
let minor = c.get(3).map_or("", |m| m.as_str());
let version = c.get(1).map_or("", |m| m.as_str());
(major, minor, version)
}
None => return Err(anyhow!(String::from("can not find version"))),
};
let major_number = match major.parse::<u32>() {
Ok(n) => n,
Err(e) => return Err(anyhow!(e.to_string())),
};
let minor_number = match minor.parse::<u32>() {
Ok(n) => n,
Err(e) => return Err(anyhow!(e.to_string())),
};
return Ok((major_number, minor_number, String::from(version)));
},
None => {
// child hasn't exited yet within 30s, kill the child process
child.kill()?;
child.wait()?;
return Err(anyhow!("command execution timeout"));
}
None => return Err(anyhow!(String::from("can not find version"))),
};
let major_number = match major.parse::<u32>() {
Ok(n) => n,
Err(e) => return Err(anyhow!(e.to_string())),
};
let minor_number = match minor.parse::<u32>() {
Ok(n) => n,
Err(e) => return Err(anyhow!(e.to_string())),
};
Ok((major_number, minor_number, String::from(version)))
}
}

pub fn check_nodejs_version(ver: &String) -> Result<()> {
Expand Down
8 changes: 4 additions & 4 deletions rasp/librasp/src/parse_elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ fn read_data_at_address(mut file: &File, elf: &Elf, address: u64, size: usize) -

fn find_symbol<'a>(elf: &'a Elf<'a>, symbol_name: &str) -> Option<Sym> {
for sym in &elf.syms {
if let Some(name) = elf.strtab.get_at(sym.st_name) {
if name == symbol_name {
if let Some(name) = elf.strtab.get(sym.st_name) {
if name.unwrap_or_default() == symbol_name {
return Some(sym.clone());
}
}
Expand Down Expand Up @@ -148,8 +148,8 @@ pub fn find_by_section(elf: &Elf, file: &File, mmap: &Mmap) -> Result<String> {

// find .go.buildinfo
if let Some(go_buildinfo_section) = elf.section_headers.iter().find(|section| {
if let Some(sect_name) = elf.shdr_strtab.get_at(section.sh_name) {
sect_name == ".go.buildinfo"
if let Some(sect_name) = elf.shdr_strtab.get(section.sh_name) {
sect_name.unwrap_or_default() == ".go.buildinfo"
} else {
false
}
Expand Down
Loading