implement fanotify event info
This commit is contained in:
parent
4ea80a819b
commit
bab60681b3
@ -161,117 +161,132 @@ fn main() -> Result<(), Error> {
|
||||
continue;
|
||||
}
|
||||
for event in events.iter_mut() {
|
||||
let Some(fd) = event.fd() else {
|
||||
if init_flags & (InitFlags::FAN_REPORT_FID | InitFlags::FAN_REPORT_DIR_FID)
|
||||
!= InitFlags::empty()
|
||||
{
|
||||
warn!("fid not implementd");
|
||||
} else {
|
||||
warn!("queue full");
|
||||
}
|
||||
continue;
|
||||
};
|
||||
let path = match std::fs::read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())) {
|
||||
Ok(p) => p,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to read fd link for fd {}: {:?}",
|
||||
fd.as_raw_fd(),
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let cmdline_raw = match std::fs::read(format!("/proc/{}/cmdline", event.pid())) {
|
||||
Ok(raw) => raw,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to read pid cmdline for fd {}: {:?}",
|
||||
event.pid(),
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let cmdline = if cmdline_raw.len() > 0 {
|
||||
Some(
|
||||
cmdline_raw
|
||||
.split(|&b| b == 0)
|
||||
.map(|v| String::from_utf8_lossy(v))
|
||||
.collect::<Vec<Cow<str>>>(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
trace!(
|
||||
"++++++++= {:?} {} {:?} {:?}",
|
||||
fd,
|
||||
event.pid(),
|
||||
event.mask(),
|
||||
path
|
||||
);
|
||||
let arg0 = if let Some(cmdline) = cmdline.as_ref() {
|
||||
for (idx, arg) in cmdline.iter().enumerate() {
|
||||
trace!(" - {}: {}", idx, arg);
|
||||
}
|
||||
|
||||
let arg0 = cmdline[0].to_string();
|
||||
|
||||
arg0map.insert(event.pid(), arg0.clone());
|
||||
|
||||
arg0
|
||||
} else if arg0map.contains_key(&event.pid()) {
|
||||
arg0map[&event.pid()].clone()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
match event.mask() {
|
||||
MaskFlags::FAN_ACCESS_PERM
|
||||
| MaskFlags::FAN_OPEN_PERM
|
||||
| MaskFlags::FAN_OPEN_EXEC_PERM => {
|
||||
let allowed = match std::fs::metadata(&path) {
|
||||
Ok(metadata) => {
|
||||
// is a directory or filled with content
|
||||
metadata.is_dir() || ready.contains(&path)
|
||||
}
|
||||
Err(error) => error.kind() == std::io::ErrorKind::NotFound,
|
||||
};
|
||||
if allowed || whitelist.contains(&arg0) || storage_provider.contains(&arg0) {
|
||||
info!("<<<<< {} allowed", fd.as_raw_fd());
|
||||
if let Err(err) =
|
||||
fan.write_response(FanotifyResponse::new(fd, Response::FAN_ALLOW))
|
||||
{
|
||||
warn!("write response for {} failed: {}", fd.as_raw_fd(), err);
|
||||
}
|
||||
if event.mask().is_permission_event() {
|
||||
// permission event
|
||||
let Some(fd) = event.fd() else {
|
||||
if init_flags & (InitFlags::FAN_REPORT_FID | InitFlags::FAN_REPORT_DIR_FID)
|
||||
!= InitFlags::empty()
|
||||
{
|
||||
warn!("fid not implementd");
|
||||
} else {
|
||||
let fd = event.forget_fd();
|
||||
info!("<<<<< {} defered", fd.as_raw_fd());
|
||||
if let Some(fds) = bufferdfds.get_mut(&path) {
|
||||
fds.push(fd);
|
||||
} else {
|
||||
bufferdfds.insert(path, vec![fd]);
|
||||
}
|
||||
warn!("queue full");
|
||||
}
|
||||
}
|
||||
MaskFlags::FAN_CLOSE_WRITE => {
|
||||
if storage_provider.contains(&arg0) {
|
||||
ready.insert(path.clone());
|
||||
if let Some(fds) = bufferdfds.remove(&path) {
|
||||
for fd in fds {
|
||||
if let Err(err) = fan.write_response(FanotifyResponse::new(
|
||||
fd.as_fd(),
|
||||
Response::FAN_ALLOW,
|
||||
)) {
|
||||
warn!("write response for {} failed: {}", fd.as_raw_fd(), err);
|
||||
}
|
||||
info!(">>>>> {} allowed(defer)", fd.as_raw_fd());
|
||||
continue;
|
||||
};
|
||||
let path = match std::fs::read_link(format!("/proc/self/fd/{}", fd.as_raw_fd())) {
|
||||
Ok(p) => p,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to read fd link for fd {}: {:?}",
|
||||
fd.as_raw_fd(),
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let cmdline_raw = match std::fs::read(format!("/proc/{}/cmdline", event.pid())) {
|
||||
Ok(raw) => raw,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to read pid cmdline for fd {}: {:?}",
|
||||
event.pid(),
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let cmdline = if cmdline_raw.len() > 0 {
|
||||
Some(
|
||||
cmdline_raw
|
||||
.split(|&b| b == 0)
|
||||
.map(|v| String::from_utf8_lossy(v))
|
||||
.collect::<Vec<Cow<str>>>(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
trace!(
|
||||
"++++++++ permission event:{} {:?} {:?} {:?}",
|
||||
event.pid(),
|
||||
event.mask(),
|
||||
fd,
|
||||
path
|
||||
);
|
||||
let arg0 = if let Some(cmdline) = cmdline.as_ref() {
|
||||
for (idx, arg) in cmdline.iter().enumerate() {
|
||||
trace!(" - {}: {}", idx, arg);
|
||||
}
|
||||
|
||||
let arg0 = cmdline[0].to_string();
|
||||
|
||||
arg0map.insert(event.pid(), arg0.clone());
|
||||
|
||||
arg0
|
||||
} else if arg0map.contains_key(&event.pid()) {
|
||||
arg0map[&event.pid()].clone()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
match event.mask() {
|
||||
MaskFlags::FAN_ACCESS_PERM
|
||||
| MaskFlags::FAN_OPEN_PERM
|
||||
| MaskFlags::FAN_OPEN_EXEC_PERM => {
|
||||
let allowed = match std::fs::metadata(&path) {
|
||||
Ok(metadata) => {
|
||||
// is a directory or filled with content
|
||||
metadata.is_dir() || ready.contains(&path)
|
||||
}
|
||||
Err(error) => error.kind() == std::io::ErrorKind::NotFound,
|
||||
};
|
||||
if allowed || whitelist.contains(&arg0) || storage_provider.contains(&arg0)
|
||||
{
|
||||
info!("<<<<< {} allowed", fd.as_raw_fd());
|
||||
if let Err(err) =
|
||||
fan.write_response(FanotifyResponse::new(fd, Response::FAN_ALLOW))
|
||||
{
|
||||
warn!("write response for {} failed: {}", fd.as_raw_fd(), err);
|
||||
}
|
||||
} else {
|
||||
let fd = event.forget_fd();
|
||||
info!("<<<<< {} defered", fd.as_raw_fd());
|
||||
if let Some(fds) = bufferdfds.get_mut(&path) {
|
||||
fds.push(fd);
|
||||
} else {
|
||||
bufferdfds.insert(path, vec![fd]);
|
||||
}
|
||||
}
|
||||
}
|
||||
MaskFlags::FAN_CLOSE_WRITE => {
|
||||
if storage_provider.contains(&arg0) {
|
||||
ready.insert(path.clone());
|
||||
if let Some(fds) = bufferdfds.remove(&path) {
|
||||
for fd in fds {
|
||||
if let Err(err) = fan.write_response(FanotifyResponse::new(
|
||||
fd.as_fd(),
|
||||
Response::FAN_ALLOW,
|
||||
)) {
|
||||
warn!(
|
||||
"write response for {} failed: {}",
|
||||
fd.as_raw_fd(),
|
||||
err
|
||||
);
|
||||
}
|
||||
info!(">>>>> {} allowed(defer)", fd.as_raw_fd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
trace!(
|
||||
"++++++++ notification event: {} {:?} {:?}",
|
||||
event.pid(),
|
||||
event.mask(),
|
||||
event.event_info,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,3 +114,12 @@ fa_bitflags! {
|
||||
FAN_EVENT_ON_CHILD; // enable events on direct
|
||||
}
|
||||
}
|
||||
|
||||
impl MaskFlags {
|
||||
pub fn is_permission_event(&self) -> bool {
|
||||
match self.bits() {
|
||||
FAN_OPEN_PERM | FAN_ACCESS | FAN_OPEN_EXEC_PERM => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
@ -105,6 +105,53 @@ impl Fanotify {
|
||||
);
|
||||
let event = uninited.assume_init();
|
||||
|
||||
#[repr(C)]
|
||||
union fanotify_event_info {
|
||||
header: libc::fanotify_event_info_header,
|
||||
fid: libc::fanotify_event_info_fid,
|
||||
pidfd: libc::fanotify_event_info_pidfd,
|
||||
error: libc::fanotify_event_info_error,
|
||||
}
|
||||
|
||||
let mut event_info = Vec::new();
|
||||
|
||||
const HEADER_SIZE: usize = std::mem::size_of::<libc::fanotify_event_info_header>();
|
||||
|
||||
let mut header_offset = EVENT_SIZE;
|
||||
while header_offset + HEADER_SIZE < event.event_len as usize {
|
||||
// pre-check
|
||||
let mut uninited: MaybeUninit<fanotify_event_info> = MaybeUninit::uninit();
|
||||
|
||||
std::ptr::copy(
|
||||
buffer.as_ptr().add(offset+EVENT_SIZE),
|
||||
uninited.as_mut_ptr().cast(),
|
||||
EVENT_SIZE,
|
||||
);
|
||||
std::ptr::copy(
|
||||
buffer.as_ptr().add(offset + header_offset),
|
||||
uninited.as_mut_ptr().add(header_offset).cast(),
|
||||
(*uninited.as_ptr()).header.len as usize - HEADER_SIZE,
|
||||
);
|
||||
let event_info_len = (*uninited.as_ptr()).header.len as usize;
|
||||
let event_info_type = (*uninited.as_ptr()).header.info_type;
|
||||
|
||||
match event_info_type {
|
||||
libc::FAN_EVENT_INFO_TYPE_FID | libc::FAN_EVENT_INFO_TYPE_DFID_NAME | libc::FAN_EVENT_INFO_TYPE_DFID=> {
|
||||
event_info.push(EventInfo::Fid(uninited.assume_init().fid));
|
||||
}
|
||||
libc::FAN_EVENT_INFO_TYPE_PIDFD => {
|
||||
event_info.push(EventInfo::PidFd(uninited.assume_init().pidfd));
|
||||
}
|
||||
libc::FAN_EVENT_INFO_TYPE_ERROR => {
|
||||
event_info.push(EventInfo::PidFd(uninited.assume_init().pidfd));
|
||||
}
|
||||
_ => {
|
||||
panic!("unknown fan_event_info_header.type={event_info_type}")
|
||||
}
|
||||
}
|
||||
header_offset += event_info_len;
|
||||
}
|
||||
|
||||
// #define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, (struct fanotify_event_metadata*)(((char*)(meta)) + (meta) -> event_len)
|
||||
// meta = FAN_EVENT_NEXT(meta, len) translate to:
|
||||
// len -= meta->event_len; // shrink rest length
|
||||
@ -115,7 +162,7 @@ impl Fanotify {
|
||||
// + (meta) -> event_len // add event_len to move to next
|
||||
// );
|
||||
offset += event.event_len as usize;
|
||||
result.push(Event::new(event));
|
||||
result.push(Event::new(event, event_info));
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,12 +186,17 @@ impl Fanotify {
|
||||
|
||||
pub struct Event {
|
||||
pub fanotify_event_metadata: libc::fanotify_event_metadata,
|
||||
pub event_info: Vec<EventInfo>,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
fn new(fanotify_event_metadata: libc::fanotify_event_metadata) -> Self {
|
||||
fn new(
|
||||
fanotify_event_metadata: libc::fanotify_event_metadata,
|
||||
event_info: Vec<EventInfo>,
|
||||
) -> Self {
|
||||
Self {
|
||||
fanotify_event_metadata,
|
||||
event_info,
|
||||
}
|
||||
}
|
||||
// compatible to nix::sys::fanotify::FanotifyEvent
|
||||
@ -191,6 +243,13 @@ impl Drop for Event {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EventInfo {
|
||||
Fid(libc::fanotify_event_info_fid),
|
||||
PidFd(libc::fanotify_event_info_pidfd),
|
||||
Error(libc::fanotify_event_info_error),
|
||||
}
|
||||
|
||||
pub struct Response {
|
||||
inner: libc::fanotify_response,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user