Skip to content

Commit

Permalink
fix(event)!: use typed-path for filesystem paths
Browse files Browse the repository at this point in the history
This should make them work consistently on Windows,
where e.g. PT_FSPATH still describes a Unix-style path.

Signed-off-by: Grzegorz Nosek <[email protected]>
  • Loading branch information
gnosek committed Dec 5, 2024
1 parent 75809dc commit f943b94
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 70 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions falco_event/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ bitflags = { version = "2.4.2" }
anyhow = "1.0.81"
chrono = "0.4.38"
serde = { version = "1.0.210", features = ["derive"], optional = true }
typed-path = "0.9.3"

[target.'cfg(target_os = "linux")'.dependencies]
nix = { version = "0.29.0", features = ["signal"] }
Expand Down
4 changes: 2 additions & 2 deletions falco_event/src/fields/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ use std::ffi::CStr;
pub use std::net::IpAddr as PT_IPADDR;
pub use std::net::Ipv4Addr as PT_IPV4ADDR;
pub use std::net::Ipv6Addr as PT_IPV6ADDR;
pub use std::path::Path as PT_FSPATH;
pub use std::time::Duration as PT_RELTIME;
pub use std::time::SystemTime as PT_ABSTIME;
pub use typed_path::UnixPath as PT_FSPATH;

/// Signed 8-bit value ([i8])
pub type PT_INT8 = i8;
Expand Down Expand Up @@ -97,7 +97,7 @@ pub mod owned {
pub use crate::types::OwnedSockTuple as PT_SOCKTUPLE;
pub use std::ffi::CString as PT_CHARBUF;
use std::ffi::CString;
pub use std::path::PathBuf as PT_FSPATH;
pub use typed_path::UnixPathBuf as PT_FSPATH;

/// Arbitrary (owned) byte buffer (`Vec<u8>`)
pub type PT_BYTEBUF = Vec<u8>;
Expand Down
1 change: 1 addition & 0 deletions falco_event/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod utf_chunked;
#[cfg(feature = "serde")]
pub mod serde {
pub use super::bytebuf::serde::*;
pub use super::path::serde::*;
pub use super::string::serde::*;
}

Expand Down
24 changes: 13 additions & 11 deletions falco_event/src/types/net/sockaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL, PPM_AF_UNSPEC};
use crate::types::format::Format;
use crate::types::{Borrow, Borrowed, EndpointV4, EndpointV6};
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::ffi::OsStr;
use std::fmt::Formatter;
use std::io::Write;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};
use typed_path::{UnixPath, UnixPathBuf};

/// A socket address
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[derive(Debug)]
pub enum SockAddr<'a> {
/// Unix sockets
Unix(&'a Path),
Unix(
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))] &'a UnixPath,
),

/// IPv4 sockets
V4(EndpointV4),
Expand Down Expand Up @@ -71,9 +71,9 @@ impl<'a> FromBytes<'a> for SockAddr<'a> {
let variant = buf.read_u8()?;
match variant as u32 {
PPM_AF_LOCAL => {
let path = <OsStr as OsStrExt>::from_bytes(buf);
*buf = &[];
Ok(Self::Unix(Path::new(path)))
// TODO embedded NULs
let path = std::mem::take(buf);
Ok(Self::Unix(UnixPath::new(path)))
}
PPM_AF_INET => {
let addr = EndpointV4::from_bytes(buf)?;
Expand All @@ -97,7 +97,7 @@ where
fn format(&self, fmt: &mut Formatter) -> std::fmt::Result {
match self {
SockAddr::Unix(u) => {
let bytes = u.as_os_str().as_bytes();
let bytes = u.as_bytes();
fmt.write_str("unix://")?;
bytes.format(fmt)
}
Expand All @@ -114,7 +114,9 @@ where
#[derive(Debug)]
pub enum OwnedSockAddr {
/// Unix sockets
Unix(PathBuf),
Unix(
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))] UnixPathBuf,
),

/// IPv4 sockets
V4(EndpointV4),
Expand Down Expand Up @@ -150,11 +152,11 @@ impl Borrow for OwnedSockAddr {
mod tests {
use crate::types::{OwnedSockAddr, Port, SockAddr};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::Path;
use typed_path::UnixPath;

#[test]
fn test_serde_sockaddr_unix() {
let path = Path::new("/path/to/unix");
let path = UnixPath::new("/path/to/unix");
let sockaddr = SockAddr::Unix(path);

let json = serde_json::to_string(&sockaddr).unwrap();
Expand Down
20 changes: 9 additions & 11 deletions falco_event/src/types/net/socktuple.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::fmt::{Debug, Display, Formatter};
use std::io::Write;
use std::path::{Path, PathBuf};

use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL};
use crate::fields::{FromBytes, FromBytesResult, ToBytes};
use crate::types::format::Format;
use crate::types::net::endpoint::{EndpointV4, EndpointV6};
use crate::types::{Borrow, Borrowed};
use byteorder::{ReadBytesExt, WriteBytesExt};
use typed_path::{UnixPath, UnixPathBuf};

/// Socket tuple: describing both endpoints of a connection
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
Expand All @@ -21,7 +21,8 @@ pub enum SockTuple<'a> {
/// destination socket kernel pointer
dest_ptr: u64,
/// filesystem path to the socket
path: &'a Path,
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))]
path: &'a UnixPath,
},

/// IPv4 connection
Expand Down Expand Up @@ -146,7 +147,7 @@ impl<'a> FromBytes<'a> for SockTuple<'a> {

impl<F> Format<F> for SockTuple<'_>
where
for<'a> &'a Path: Format<F>,
for<'a> &'a UnixPath: Format<F>,
EndpointV4: Format<F>,
EndpointV6: Format<F>,
{
Expand Down Expand Up @@ -187,7 +188,8 @@ pub enum OwnedSockTuple {
/// destination socket kernel pointer
dest_ptr: u64,
/// filesystem path to the socket
path: PathBuf,
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))]
path: UnixPathBuf,
},

/// IPv4 connection
Expand Down Expand Up @@ -249,7 +251,6 @@ mod tests {
use super::*;
use crate::types::Port;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::os::unix::ffi::OsStrExt;
use std::str::FromStr;

#[test]
Expand Down Expand Up @@ -324,10 +325,7 @@ mod tests {

assert_eq!(source_addr, 0);
assert_eq!(dest_addr, 0xffff98bc4ecf2000);
assert_eq!(
path.as_os_str().as_bytes(),
b"/var/run/nscd/socket".as_slice()
);
assert_eq!(path.as_bytes(), b"/var/run/nscd/socket".as_slice());

assert_eq!(binary, binary2.as_slice(),);
}
Expand All @@ -337,12 +335,12 @@ mod tests {
mod serde_tests {
use crate::types::{OwnedSockTuple, Port, SockTuple};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::Path;
use std::str::FromStr;
use typed_path::UnixPath;

#[test]
fn test_serde_socktuple_unix() {
let path = Path::new("/path/to/unix");
let path = UnixPath::new("/path/to/unix");
let sockaddr = SockTuple::Unix {
source_ptr: 1,
dest_ptr: 2,
Expand Down
116 changes: 90 additions & 26 deletions falco_event/src/types/path/absolute_path.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
use std::ffi::{CStr, OsStr};
use std::fmt::Formatter;
use std::io::Write;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

use crate::event_derive::{FromBytes, FromBytesResult, ToBytes};
use crate::types::format::Format;
use crate::types::{Borrow, Borrowed};
use std::ffi::CStr;
use std::fmt::Formatter;
use std::io::Write;
use typed_path::{UnixPath, UnixPathBuf};

impl<'a> FromBytes<'a> for &'a Path {
impl<'a> FromBytes<'a> for &'a UnixPath {
fn from_bytes(buf: &mut &'a [u8]) -> FromBytesResult<Self> {
let buf = <&CStr>::from_bytes(buf)?;
let osstr = OsStr::from_bytes(buf.to_bytes());
Ok(Path::new(osstr))
Ok(UnixPath::new(buf.to_bytes()))
}
}

impl ToBytes for &Path {
impl ToBytes for &UnixPath {
fn binary_size(&self) -> usize {
self.as_os_str().len()
self.as_bytes().len() + 1
}

fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
self.as_os_str().as_bytes().write(&mut writer)?;
self.as_bytes().write(&mut writer)?;
0u8.write(writer)
}

Expand All @@ -31,59 +28,126 @@ impl ToBytes for &Path {
}
}

impl<F> Format<F> for &Path
impl<F> Format<F> for &UnixPath
where
for<'a> &'a [u8]: Format<F>,
{
fn format(&self, fmt: &mut Formatter) -> std::fmt::Result {
let bytes = self.as_os_str().as_bytes();
let bytes = self.as_bytes();
bytes.format(fmt)
}
}

impl Borrowed for Path {
type Owned = PathBuf;
impl Borrowed for UnixPath {
type Owned = UnixPathBuf;
}

impl Borrow for PathBuf {
type Borrowed<'a> = &'a Path;
impl Borrow for UnixPathBuf {
type Borrowed<'a> = &'a UnixPath;

fn borrow(&self) -> Self::Borrowed<'_> {
self.as_path()
}
}

#[cfg(feature = "serde")]
pub mod serde {
pub mod unix_path {
use crate::types::utf_chunked::{OwnedUtfChunked, UtfChunked};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use typed_path::{UnixPath, UnixPathBuf};

pub fn serialize<S: Serializer>(path: &UnixPath, ser: S) -> Result<S::Ok, S::Error> {
if ser.is_human_readable() {
let chunks = UtfChunked::from(path.as_bytes());
chunks.serialize(ser)
} else {
path.as_bytes().serialize(ser)
}
}

pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<UnixPathBuf, D::Error> {
let chunks: OwnedUtfChunked = Deserialize::deserialize(de)?;
Ok(UnixPathBuf::from(chunks.into_vec()))
}
}

pub mod unix_path_option {
use crate::types::utf_chunked::UtfChunked;
use serde::{Serialize, Serializer};
use typed_path::UnixPath;

pub fn serialize<S: Serializer>(
path: &Option<&UnixPath>,
ser: S,
) -> Result<S::Ok, S::Error> {
if ser.is_human_readable() {
let chunks = path.as_ref().map(|path| UtfChunked::from(path.as_bytes()));
chunks.serialize(ser)
} else {
path.map(|p| p.as_bytes()).serialize(ser)
}
}
}

pub mod unix_path_option_owned {
use crate::types::utf_chunked::{OwnedUtfChunked, UtfChunked};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use typed_path::UnixPathBuf;

pub fn serialize<S: Serializer>(
path: &Option<UnixPathBuf>,
ser: S,
) -> Result<S::Ok, S::Error> {
let chunks = path.as_ref().map(|path| UtfChunked::from(path.as_bytes()));
chunks.serialize(ser)
}

pub fn deserialize<'de, D: Deserializer<'de>>(
de: D,
) -> Result<Option<UnixPathBuf>, D::Error> {
let chunks: Option<OwnedUtfChunked> = Deserialize::deserialize(de)?;
Ok(chunks.map(|c| UnixPathBuf::from(c.into_vec())))
}
}
}

#[cfg(test)]
mod tests {
use std::path::{Path, PathBuf};
use std::str::FromStr;

use crate::event_derive::{FromBytes, ToBytes};
use std::str::FromStr;
use typed_path::{UnixPath, UnixPathBuf};

#[test]
fn test_absolute_path() {
let path = PathBuf::from_str("/foo").unwrap();
let path = UnixPathBuf::from_str("/foo").unwrap();
let mut binary = Vec::new();

assert_eq!(path.as_path().binary_size(), 5);

path.as_path().write(&mut binary).unwrap();
hexdump::hexdump(binary.as_slice());

assert_eq!(binary.as_slice(), "/foo\0".as_bytes());

let mut buf = binary.as_slice();
let path = <&Path>::from_bytes(&mut buf).unwrap();
let path = <&UnixPath>::from_bytes(&mut buf).unwrap();
assert_eq!(path.to_str().unwrap(), "/foo");
}

#[test]
fn test_serde_absolute_path() {
let path = Path::new("/foo");
#[derive(serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
struct SerPathBuf(#[serde(with = "super::serde::unix_path")] UnixPathBuf);

let path = SerPathBuf(UnixPathBuf::from("/foo"));

let json = serde_json::to_string(&path).unwrap();
assert_eq!(json, "\"/foo\"");

let path2: PathBuf = serde_json::from_str(&json).unwrap();
assert_eq!(path2, path);
let path2: SerPathBuf = serde_json::from_str(&json).unwrap();
assert_eq!(path2.0, path.0);

let json2 = serde_json::to_string(&path2).unwrap();
assert_eq!(json, json2);
Expand Down
Loading

0 comments on commit f943b94

Please sign in to comment.