Skip to content

Commit 38acc9e

Browse files
committed
fix(event)!: use typed-path for filesystem paths
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]>
1 parent 75809dc commit 38acc9e

File tree

13 files changed

+158
-70
lines changed

13 files changed

+158
-70
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

falco_event/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ bitflags = { version = "2.4.2" }
2424
anyhow = "1.0.81"
2525
chrono = "0.4.38"
2626
serde = { version = "1.0.210", features = ["derive"], optional = true }
27+
typed-path = "0.9.3"
2728

2829
[target.'cfg(target_os = "linux")'.dependencies]
2930
nix = { version = "0.29.0", features = ["signal"] }

falco_event/src/fields/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ use std::ffi::CStr;
2424
pub use std::net::IpAddr as PT_IPADDR;
2525
pub use std::net::Ipv4Addr as PT_IPV4ADDR;
2626
pub use std::net::Ipv6Addr as PT_IPV6ADDR;
27-
pub use std::path::Path as PT_FSPATH;
2827
pub use std::time::Duration as PT_RELTIME;
2928
pub use std::time::SystemTime as PT_ABSTIME;
29+
pub use typed_path::UnixPath as PT_FSPATH;
3030

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

102102
/// Arbitrary (owned) byte buffer (`Vec<u8>`)
103103
pub type PT_BYTEBUF = Vec<u8>;

falco_event/src/types/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod utf_chunked;
1212
#[cfg(feature = "serde")]
1313
pub mod serde {
1414
pub use super::bytebuf::serde::*;
15+
pub use super::path::serde::*;
1516
pub use super::string::serde::*;
1617
}
1718

falco_event/src/types/net/sockaddr.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@ use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL, PPM_AF_UNSPEC};
33
use crate::types::format::Format;
44
use crate::types::{Borrow, Borrowed, EndpointV4, EndpointV6};
55
use byteorder::{ReadBytesExt, WriteBytesExt};
6-
use std::ffi::OsStr;
76
use std::fmt::Formatter;
87
use std::io::Write;
9-
use std::os::unix::ffi::OsStrExt;
10-
use std::path::{Path, PathBuf};
8+
use typed_path::{UnixPath, UnixPathBuf};
119

1210
/// A socket address
1311
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
1412
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
1513
#[derive(Debug)]
1614
pub enum SockAddr<'a> {
1715
/// Unix sockets
18-
Unix(&'a Path),
16+
Unix(
17+
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))] &'a UnixPath,
18+
),
1919

2020
/// IPv4 sockets
2121
V4(EndpointV4),
@@ -71,9 +71,9 @@ impl<'a> FromBytes<'a> for SockAddr<'a> {
7171
let variant = buf.read_u8()?;
7272
match variant as u32 {
7373
PPM_AF_LOCAL => {
74-
let path = <OsStr as OsStrExt>::from_bytes(buf);
75-
*buf = &[];
76-
Ok(Self::Unix(Path::new(path)))
74+
// TODO embedded NULs
75+
let path = std::mem::take(buf);
76+
Ok(Self::Unix(UnixPath::new(path)))
7777
}
7878
PPM_AF_INET => {
7979
let addr = EndpointV4::from_bytes(buf)?;
@@ -97,7 +97,7 @@ where
9797
fn format(&self, fmt: &mut Formatter) -> std::fmt::Result {
9898
match self {
9999
SockAddr::Unix(u) => {
100-
let bytes = u.as_os_str().as_bytes();
100+
let bytes = u.as_bytes();
101101
fmt.write_str("unix://")?;
102102
bytes.format(fmt)
103103
}
@@ -114,7 +114,9 @@ where
114114
#[derive(Debug)]
115115
pub enum OwnedSockAddr {
116116
/// Unix sockets
117-
Unix(PathBuf),
117+
Unix(
118+
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))] UnixPathBuf,
119+
),
118120

119121
/// IPv4 sockets
120122
V4(EndpointV4),
@@ -150,11 +152,11 @@ impl Borrow for OwnedSockAddr {
150152
mod tests {
151153
use crate::types::{OwnedSockAddr, Port, SockAddr};
152154
use std::net::{Ipv4Addr, Ipv6Addr};
153-
use std::path::Path;
155+
use typed_path::UnixPath;
154156

155157
#[test]
156158
fn test_serde_sockaddr_unix() {
157-
let path = Path::new("/path/to/unix");
159+
let path = UnixPath::new("/path/to/unix");
158160
let sockaddr = SockAddr::Unix(path);
159161

160162
let json = serde_json::to_string(&sockaddr).unwrap();

falco_event/src/types/net/socktuple.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::fmt::{Debug, Display, Formatter};
22
use std::io::Write;
3-
use std::path::{Path, PathBuf};
43

54
use crate::ffi::{PPM_AF_INET, PPM_AF_INET6, PPM_AF_LOCAL};
65
use crate::fields::{FromBytes, FromBytesResult, ToBytes};
76
use crate::types::format::Format;
87
use crate::types::net::endpoint::{EndpointV4, EndpointV6};
98
use crate::types::{Borrow, Borrowed};
109
use byteorder::{ReadBytesExt, WriteBytesExt};
10+
use typed_path::{UnixPath, UnixPathBuf};
1111

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

2728
/// IPv4 connection
@@ -146,7 +147,7 @@ impl<'a> FromBytes<'a> for SockTuple<'a> {
146147

147148
impl<F> Format<F> for SockTuple<'_>
148149
where
149-
for<'a> &'a Path: Format<F>,
150+
for<'a> &'a UnixPath: Format<F>,
150151
EndpointV4: Format<F>,
151152
EndpointV6: Format<F>,
152153
{
@@ -187,7 +188,8 @@ pub enum OwnedSockTuple {
187188
/// destination socket kernel pointer
188189
dest_ptr: u64,
189190
/// filesystem path to the socket
190-
path: PathBuf,
191+
#[cfg_attr(feature = "serde", serde(with = "crate::types::serde::unix_path"))]
192+
path: UnixPathBuf,
191193
},
192194

193195
/// IPv4 connection
@@ -249,7 +251,6 @@ mod tests {
249251
use super::*;
250252
use crate::types::Port;
251253
use std::net::{Ipv4Addr, Ipv6Addr};
252-
use std::os::unix::ffi::OsStrExt;
253254
use std::str::FromStr;
254255

255256
#[test]
@@ -324,10 +325,7 @@ mod tests {
324325

325326
assert_eq!(source_addr, 0);
326327
assert_eq!(dest_addr, 0xffff98bc4ecf2000);
327-
assert_eq!(
328-
path.as_os_str().as_bytes(),
329-
b"/var/run/nscd/socket".as_slice()
330-
);
328+
assert_eq!(path.as_bytes(), b"/var/run/nscd/socket".as_slice());
331329

332330
assert_eq!(binary, binary2.as_slice(),);
333331
}
@@ -337,12 +335,12 @@ mod tests {
337335
mod serde_tests {
338336
use crate::types::{OwnedSockTuple, Port, SockTuple};
339337
use std::net::{Ipv4Addr, Ipv6Addr};
340-
use std::path::Path;
341338
use std::str::FromStr;
339+
use typed_path::UnixPath;
342340

343341
#[test]
344342
fn test_serde_socktuple_unix() {
345-
let path = Path::new("/path/to/unix");
343+
let path = UnixPath::new("/path/to/unix");
346344
let sockaddr = SockTuple::Unix {
347345
source_ptr: 1,
348346
dest_ptr: 2,

falco_event/src/types/path/absolute_path.rs

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
1-
use std::ffi::{CStr, OsStr};
2-
use std::fmt::Formatter;
3-
use std::io::Write;
4-
use std::os::unix::ffi::OsStrExt;
5-
use std::path::{Path, PathBuf};
6-
71
use crate::event_derive::{FromBytes, FromBytesResult, ToBytes};
82
use crate::types::format::Format;
93
use crate::types::{Borrow, Borrowed};
4+
use std::ffi::CStr;
5+
use std::fmt::Formatter;
6+
use std::io::Write;
7+
use typed_path::{UnixPath, UnixPathBuf};
108

11-
impl<'a> FromBytes<'a> for &'a Path {
9+
impl<'a> FromBytes<'a> for &'a UnixPath {
1210
fn from_bytes(buf: &mut &'a [u8]) -> FromBytesResult<Self> {
1311
let buf = <&CStr>::from_bytes(buf)?;
14-
let osstr = OsStr::from_bytes(buf.to_bytes());
15-
Ok(Path::new(osstr))
12+
Ok(UnixPath::new(buf.to_bytes()))
1613
}
1714
}
1815

19-
impl ToBytes for &Path {
16+
impl ToBytes for &UnixPath {
2017
fn binary_size(&self) -> usize {
21-
self.as_os_str().len()
18+
self.as_bytes().len() + 1
2219
}
2320

2421
fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
25-
self.as_os_str().as_bytes().write(&mut writer)?;
22+
self.as_bytes().write(&mut writer)?;
2623
0u8.write(writer)
2724
}
2825

@@ -31,59 +28,127 @@ impl ToBytes for &Path {
3128
}
3229
}
3330

34-
impl<F> Format<F> for &Path
31+
impl<F> Format<F> for &UnixPath
3532
where
3633
for<'a> &'a [u8]: Format<F>,
3734
{
3835
fn format(&self, fmt: &mut Formatter) -> std::fmt::Result {
39-
let bytes = self.as_os_str().as_bytes();
36+
let bytes = self.as_bytes();
4037
bytes.format(fmt)
4138
}
4239
}
4340

44-
impl Borrowed for Path {
45-
type Owned = PathBuf;
41+
impl Borrowed for UnixPath {
42+
type Owned = UnixPathBuf;
4643
}
4744

48-
impl Borrow for PathBuf {
49-
type Borrowed<'a> = &'a Path;
45+
impl Borrow for UnixPathBuf {
46+
type Borrowed<'a> = &'a UnixPath;
5047

5148
fn borrow(&self) -> Self::Borrowed<'_> {
5249
self.as_path()
5350
}
5451
}
5552

53+
#[cfg(feature = "serde")]
54+
pub mod serde {
55+
pub mod unix_path {
56+
use crate::types::utf_chunked::{OwnedUtfChunked, UtfChunked};
57+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
58+
use typed_path::{UnixPath, UnixPathBuf};
59+
60+
pub fn serialize<S: Serializer>(path: &UnixPath, ser: S) -> Result<S::Ok, S::Error> {
61+
if ser.is_human_readable() {
62+
let chunks = UtfChunked::from(path.as_bytes());
63+
chunks.serialize(ser)
64+
} else {
65+
path.as_bytes().serialize(ser)
66+
}
67+
}
68+
69+
pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<UnixPathBuf, D::Error> {
70+
let chunks: OwnedUtfChunked = Deserialize::deserialize(de)?;
71+
Ok(UnixPathBuf::from(chunks.into_vec()))
72+
}
73+
}
74+
75+
pub mod unix_path_option {
76+
use crate::types::utf_chunked::UtfChunked;
77+
use serde::{Serialize, Serializer};
78+
use typed_path::UnixPath;
79+
80+
pub fn serialize<S: Serializer>(
81+
path: &Option<&UnixPath>,
82+
ser: S,
83+
) -> Result<S::Ok, S::Error> {
84+
if ser.is_human_readable() {
85+
let chunks = path.as_ref().map(|path| UtfChunked::from(path.as_bytes()));
86+
chunks.serialize(ser)
87+
} else {
88+
path.map(|p| p.as_bytes()).serialize(ser)
89+
}
90+
}
91+
}
92+
93+
pub mod unix_path_option_owned {
94+
use crate::types::utf_chunked::{OwnedUtfChunked, UtfChunked};
95+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
96+
use typed_path::UnixPathBuf;
97+
98+
pub fn serialize<S: Serializer>(
99+
path: &Option<UnixPathBuf>,
100+
ser: S,
101+
) -> Result<S::Ok, S::Error> {
102+
let chunks = path.as_ref().map(|path| UtfChunked::from(path.as_bytes()));
103+
chunks.serialize(ser)
104+
}
105+
106+
pub fn deserialize<'de, D: Deserializer<'de>>(
107+
de: D,
108+
) -> Result<Option<UnixPathBuf>, D::Error> {
109+
let chunks: Option<OwnedUtfChunked> = Deserialize::deserialize(de)?;
110+
Ok(chunks.map(|c| UnixPathBuf::from(c.into_vec())))
111+
}
112+
}
113+
}
114+
56115
#[cfg(test)]
57116
mod tests {
58-
use std::path::{Path, PathBuf};
59-
use std::str::FromStr;
60-
61117
use crate::event_derive::{FromBytes, ToBytes};
118+
use std::str::FromStr;
119+
use typed_path::{UnixPath, UnixPathBuf};
62120

63121
#[test]
64122
fn test_absolute_path() {
65-
let path = PathBuf::from_str("/foo").unwrap();
123+
let path = UnixPathBuf::from_str("/foo").unwrap();
66124
let mut binary = Vec::new();
67125

126+
assert_eq!(path.as_path().binary_size(), 5);
127+
68128
path.as_path().write(&mut binary).unwrap();
69129
hexdump::hexdump(binary.as_slice());
70130

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

73133
let mut buf = binary.as_slice();
74-
let path = <&Path>::from_bytes(&mut buf).unwrap();
134+
let path = <&UnixPath>::from_bytes(&mut buf).unwrap();
75135
assert_eq!(path.to_str().unwrap(), "/foo");
76136
}
77137

138+
#[cfg(feature = "serde")]
78139
#[test]
79140
fn test_serde_absolute_path() {
80-
let path = Path::new("/foo");
141+
#[derive(serde::Deserialize, serde::Serialize)]
142+
#[serde(transparent)]
143+
struct SerPathBuf(#[serde(with = "super::serde::unix_path")] UnixPathBuf);
144+
145+
let path = SerPathBuf(UnixPathBuf::from("/foo"));
81146

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

85-
let path2: PathBuf = serde_json::from_str(&json).unwrap();
86-
assert_eq!(path2, path);
150+
let path2: SerPathBuf = serde_json::from_str(&json).unwrap();
151+
assert_eq!(path2.0, path.0);
87152

88153
let json2 = serde_json::to_string(&path2).unwrap();
89154
assert_eq!(json, json2);

0 commit comments

Comments
 (0)