Skip to content

Commit

Permalink
Merge branch 'dev' into uprobes_frontend
Browse files Browse the repository at this point in the history
Signed-off-by: Felix Hilgers <[email protected]>
  • Loading branch information
fhilgers committed Dec 11, 2024
2 parents b4fc5f9 + f8bcf97 commit a61d9fb
Show file tree
Hide file tree
Showing 18 changed files with 177 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class ConfigurationViewModel(
fnName = option.method,
target = option.odexFilePath,
offset = option.offset,
pid = it.toInt(),
pid = it,
)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,7 @@ class SymbolsViewModel(
}

private fun SymbolsEntry.toUprobeConfigForPid(pid: UInt) =
UprobeConfig(
fnName = this.name,
offset = this.offset,
target = this.odexFile,
pid = pid.toInt(), // TODO why is this not an uint
)
UprobeConfig(fnName = this.name, offset = this.offset, target = this.odexFile, pid = pid)

private fun GetSymbolsRequestState.toUIState(): SymbolsScreenState {
return when (this) {
Expand Down
18 changes: 16 additions & 2 deletions frontend/client/src/main/java/de/amosproj3/ziofa/client/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ data class VfsWriteConfig(val entries: Map<UInt, ULong>)

data class SysSendmsgConfig(val entries: Map<UInt, ULong>)

data class UprobeConfig(val fnName: String, val offset: ULong, var target: String, val pid: Int?)
data class UprobeConfig(val fnName: String, val offset: ULong, var target: String, val pid: UInt?)

data class JniReferencesConfig(val pids: List<UInt>)

Expand All @@ -38,9 +38,23 @@ sealed class Event {
val fd: ULong,
val durationNanoSecs: ULong,
) : Event()

data class JniReferences(
val pid: UInt,
val tid: UInt,
val beginTimeStamp: ULong,
val jniMethodName: JniMethodName?,
) : Event() {
enum class JniMethodName {
AddLocalRef,
DeleteLocalRef,
AddGlobalRef,
DeleteGlobalRef,
}
}
}

data class Process(val pid: Int, val ppid: Int, val state: String, val cmd: Command?)
data class Process(val pid: UInt, val ppid: UInt, val state: String, val cmd: Command?)

data class StringResponse(val name: String)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ object RustClient : Client {
private val processes =
alphabet.indices.map {
Process(
pid = Random.nextUInt(1000u).toInt(),
ppid = Random.nextUInt(1000u).toInt(),
pid = Random.nextUInt(1000u),
ppid = Random.nextUInt(1000u),
state = "R",
cmd = Command.Comm("/bin/sh/${alphabet.substring(it, it + 1)}"),
)
Expand Down Expand Up @@ -109,6 +109,16 @@ object RustClient : Client {
)
)
}
configuration.jniReferences?.pids?.forEach {
emit(
Event.JniReferences(
pid = it,
tid = 1234u,
beginTimeStamp = System.currentTimeMillis().toULong(),
jniMethodName = Event.JniReferences.JniMethodName.AddLocalRef,
)
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import uniffi.client.jniMethodNameFromI32
import uniffi.shared.Cmd
import uniffi.shared.EventData
import uniffi.shared.JniMethodName

private fun uniffi.shared.Process.into() =
Process(
Expand Down Expand Up @@ -45,6 +47,23 @@ private fun uniffi.shared.Event.into() =
fd = d.v1.fd,
durationNanoSecs = d.v1.durationNanoSec,
)
is EventData.JniReferences ->
Event.JniReferences(
pid = d.v1.pid,
tid = d.v1.tid,
beginTimeStamp = d.v1.beginTimeStamp,
jniMethodName =
when (jniMethodNameFromI32(d.v1.jniMethodName)) {
JniMethodName.ADD_LOCAL_REF -> Event.JniReferences.JniMethodName.AddLocalRef
JniMethodName.DELETE_LOCAL_REF ->
Event.JniReferences.JniMethodName.DeleteLocalRef
JniMethodName.ADD_GLOBAL_REF ->
Event.JniReferences.JniMethodName.AddGlobalRef
JniMethodName.DELETE_GLOBAL_REF ->
Event.JniReferences.JniMethodName.DeleteGlobalRef
JniMethodName.UNDEFINED -> null
},
)
null -> null
}

Expand Down
58 changes: 51 additions & 7 deletions rust/backend/daemon/src/collector.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-FileCopyrightText: 2024 Felix Hilgers <[email protected]>
// SPDX-FileCopyrightText: 2024 Benedikt Zinn <[email protected]>
// SPDX-FileCopyrightText: 2024 Robin Seidl <[email protected]>
//
// SPDX-License-Identifier: MIT

Expand All @@ -12,9 +14,10 @@ use tokio::io::unix::AsyncFd;
use tokio::{join, select};
use tonic::Status;
use tracing::error;
use backend_common::{SysSendmsgCall, VfsWriteCall};
use shared::ziofa::{Event, SysSendmsgEvent, VfsWriteEvent};
use backend_common::{JNICall, JNIMethodName, SysSendmsgCall, VfsWriteCall};
use shared::ziofa::{Event, JniReferencesEvent, SysSendmsgEvent, VfsWriteEvent};
use shared::ziofa::event::{EventData};
use shared::ziofa::jni_references_event;

pub trait CollectFromMap {
const MAP_NAME: &'static str;
Expand All @@ -23,6 +26,8 @@ pub trait CollectFromMap {
}

struct VfsWriteCollect;
struct JNICollect;
struct SysSendmsgCollect;

impl CollectFromMap for VfsWriteCollect {
const MAP_NAME: &'static str = "VFS_WRITE_EVENTS";
Expand All @@ -41,7 +46,31 @@ impl CollectFromMap for VfsWriteCollect {
}
}

struct SysSendmsgCollect;
impl CollectFromMap for JNICollect {
const MAP_NAME: &'static str = "JNI_REF_CALLS";

fn convert(item: RingBufItem<'_>) -> Result<Event, Status> {
let data = unsafe { &*(item.as_ptr() as *const JNICall) };

// manual cast from the ebpf (c rep.) typ to protobuf (rust rep.) type
let jni_method_name = match data.method_name {
JNIMethodName::AddLocalRef => jni_references_event::JniMethodName::AddLocalRef,
JNIMethodName::DeleteLocalRef => jni_references_event::JniMethodName::DeleteLocalRef,
JNIMethodName::AddGlobalRef => jni_references_event::JniMethodName::AddGlobalRef,
JNIMethodName::DeleteGlobalRef => jni_references_event::JniMethodName::DeleteGlobalRef,
};

Ok(Event {
event_data: Some(EventData::JniReferences(JniReferencesEvent {
pid: data.pid,
tid: data.tid,
begin_time_stamp: data.begin_time_stamp,
jni_method_name: i32::from(jni_method_name),
}))
})
}
}


impl CollectFromMap for SysSendmsgCollect {
const MAP_NAME: &'static str = "SYS_SENDMSG_EVENTS";
Expand All @@ -63,19 +92,22 @@ impl CollectFromMap for SysSendmsgCollect {
pub struct MultiCollector {
vfs_write: Option<Collector<VfsWriteCollect>>,
sys_sendmsg: Option<Collector<SysSendmsgCollect>>,
jni_event: Option<Collector<JNICollect>>,
}

impl MultiCollector {
pub fn from_ebpf(ebpf: &mut Ebpf) -> Result<Self, MapError> {
let vfs_write = Collector::<VfsWriteCollect>::from_ebpf(ebpf)?;
let sys_sendmsg = Collector::<SysSendmsgCollect>::from_ebpf(ebpf)?;
Ok(Self { vfs_write: Some(vfs_write), sys_sendmsg: Some(sys_sendmsg) })
let jni_collect = Collector::<JNICollect>::from_ebpf(ebpf)?;
Ok(Self { vfs_write: Some(vfs_write), sys_sendmsg: Some(sys_sendmsg), jni_event: Some(jni_collect) })
}

pub async fn collect(&mut self, tx: Sender<Result<Event, Status>>, shutdown: tokio::sync::oneshot::Receiver<()>) -> Result<(), std::io::Error> {

let (vfs_write_shutdown_tx, vfs_write_shutdown_rx) = tokio::sync::oneshot::channel();
let (sys_sendmsg_shutdown_tx, sys_sendmsg_shutdown_rx) = tokio::sync::oneshot::channel();
let (jni_event_shutdown_tx, jni_event_shutdown_rx) = tokio::sync::oneshot::channel();

let cancellation_task = async move {
if shutdown.await.is_err() {
Expand All @@ -87,6 +119,9 @@ impl MultiCollector {
if sys_sendmsg_shutdown_tx.send(()).is_err() {
error!("Error while cancelling sys_sendmsg collector");
}
if jni_event_shutdown_tx.send(()).is_err() {
error!("Error while cancelling sys_sendmsg collector");
}
};

let vfs_write_tx = tx.clone();
Expand All @@ -96,22 +131,31 @@ impl MultiCollector {
Ok::<(), std::io::Error>(())
};

let sys_sendmsg_tx = tx;
let sys_sendmsg_tx = tx.clone();
let mut sys_sendmsg = self.sys_sendmsg.take().expect("sys_sendmsg should be initialized");
let sys_sendmsg_task = async {
sys_sendmsg.collect(sys_sendmsg_tx, sys_sendmsg_shutdown_rx).await?;
Ok::<(), std::io::Error>(())
};

let jni_event_tx = tx;
let mut jni_event = self.jni_event.take().expect("jni_event should be initialized");
let jni_event_task = async {
jni_event.collect(jni_event_tx, jni_event_shutdown_rx).await?;
Ok::<(), std::io::Error>(())
};

let (_, vfs_write_result, sys_sendmsg_result) = join!(cancellation_task, vfs_write_task, sys_sendmsg_task);
let (_, vfs_write_result, sys_sendmsg_result, jni_event_result) = join!(cancellation_task, vfs_write_task, sys_sendmsg_task, jni_event_task);

self.vfs_write = Some(vfs_write);
self.sys_sendmsg = Some(sys_sendmsg);
self.jni_event = Some(jni_event);

// TODO: multiple errors
vfs_write_result?;
sys_sendmsg_result?;

jni_event_result?;

Ok(())
}
}
Expand Down
5 changes: 0 additions & 5 deletions rust/backend/daemon/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,3 @@ pub fn save_to_file(config: &Configuration, path: &str) -> io::Result<()> {
serde_json::to_writer(writer, config)?;
Ok(())
}

pub fn validate(_config: &Configuration) -> Result<(), io::Error> {
//TODO: Implement this function
Ok(())
}
4 changes: 1 addition & 3 deletions rust/backend/daemon/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ use std::net::SocketAddr;
pub(crate) const DEV_DEFAULT_FILE_PATH: &str = "./ziofa.json";

pub fn sock_addr() -> SocketAddr {
// "learn rust" they said, "it's a great language" they said
"[::1]:50051".parse().expect("is valid address")
}

// TODO: custom error type for file
pub const OATDUMP_PATH: &str = "/data/local/tmp/dump.json";
pub const OATDUMP_PATH: &str = "/data/local/tmp/dump.json";
8 changes: 4 additions & 4 deletions rust/backend/daemon/src/procfs_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ pub fn list_processes() -> Result<ProcessList, ProcError> {
let cmdline = process.cmdline();
match cmdline {
Ok(c) if !c.is_empty() => Some(ziofa::Process {
pid: stat.pid,
ppid: stat.ppid,
pid: u32::try_from(stat.pid).unwrap(),
ppid: u32::try_from(stat.ppid).unwrap(),
cmd: Some(Cmd::Cmdline(CmdlineData { args: c })),
state: stat.state.to_string(),
}),
// fallback to stat.comm if cmdline is empty
_ => Some(ziofa::Process {
pid: stat.pid,
ppid: stat.ppid,
pid: u32::try_from(stat.pid).unwrap(),
ppid: u32::try_from(stat.ppid).unwrap(),
cmd: Some(Cmd::Comm(stat.comm)),
state: stat.state.to_string(),
}),
Expand Down
18 changes: 6 additions & 12 deletions rust/backend/daemon/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ use crate::{
use async_broadcast::{broadcast, Receiver, Sender};
use aya::Ebpf;
use aya_log::EbpfLogger;
use shared::ziofa::{
Event, GetSymbolsRequest,
PidMessage, StringResponse, Symbol,
};
use shared::ziofa::{Event, GetSymbolsRequest, PidMessage, StringResponse, Symbol};
use shared::{
config::Configuration,
counter::counter_server::CounterServer,
Expand Down Expand Up @@ -97,9 +94,6 @@ impl Ziofa for ZiofaImpl {
) -> Result<Response<()>, Status> {
let config = request.into_inner();

// TODO: Implement function 'validate'
// TODO: if ? fails needs valid return value for the function so that the server doesn't fail
configuration::validate(&config)?;
configuration::save_to_file(&config, constants::DEV_DEFAULT_FILE_PATH)?;

let mut ebpf_guard = self.ebpf.lock().await;
Expand Down Expand Up @@ -171,13 +165,13 @@ impl Ziofa for ZiofaImpl {
let odex_file_path = PathBuf::from(odex_file_path_string);

let (tx, rx) = mpsc::channel(4);

let symbol_handler = self.symbol_handler.clone();

tokio::spawn(async move {
let mut symbol_handler_guard = symbol_handler.lock().await;

let symbol = match symbol_handler_guard.get_symbols(&odex_file_path).await{
let symbol = match symbol_handler_guard.get_symbols(&odex_file_path).await {
Ok(symbol) => symbol,
Err(e) => {
tx.send(Err(Status::from(e)))
Expand All @@ -187,12 +181,12 @@ impl Ziofa for ZiofaImpl {
}
};
for (symbol, offset) in symbol.iter() {
tx.send(Ok(Symbol{
tx.send(Ok(Symbol {
method: symbol.to_string(),
offset: *offset,
}))
.await
.expect("Error sending odex file to client");
.await
.expect("Error sending odex file to client");
}
});

Expand Down
2 changes: 1 addition & 1 deletion rust/backend/ebpf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The maps `<hook-name>_PIDS` are HashMaps that store the pid as key and as value

| | type | functions to hook | map<entry-type> |
|---------------|------------|------------------------------------------------------------------------------|---------------------------------------------|
| vfs_write | KProbe | `vfs_write`, `vfs_write_ret` | `VFS_WRITE_CALLS<VfsWriteCall>` |
| vfs_write | KProbe | `vfs_write`, `vfs_write_ret` | `VFS_WRITE_EVENTS<VfsWriteCall>` |
| sendmsg | Tracepoint | `sys_enter_sendmsg`, `sys_exit_sendmsg` | `SYS_SENDMSG_CALLS<SysSendmsgCall>` |
| JNIReferences | UProbe | `trace_add_local`, `trace_del_local`, `trace_add_global`, `trace_del_global` | `JNI_REF_CALLS<JNIRefCall>`, `JNI_REF_PIDS` |
| ... | ... | ... | ... |
18 changes: 10 additions & 8 deletions rust/backend/ebpf/src/jni_references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ fn handle_trace(ctx: ProbeContext, method: JNIMethodName) -> u32 {
return 0;
}

let call = JNICall {
pid,
tid,
begin_time_stamp: time_stamp,
method_name: method,
};

let mut entry = match JNI_REF_CALLS.reserve::<JNICall>(0) {
Some(entry) => entry,
None => {
Expand All @@ -42,7 +35,16 @@ fn handle_trace(ctx: ProbeContext, method: JNIMethodName) -> u32 {
}
};

entry.write(call);
let entry_mut = entry.as_mut_ptr();

unsafe {
(&raw mut (*entry_mut).pid).write(pid);
(&raw mut (*entry_mut).pid).write(pid);
(&raw mut (*entry_mut).tid).write(tid);
(&raw mut (*entry_mut).begin_time_stamp).write(time_stamp);
(&raw mut (*entry_mut).method_name).write(method);
}

entry.submit(0);

0
Expand Down
Loading

0 comments on commit a61d9fb

Please sign in to comment.