Skip to content
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
14 changes: 13 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,10 @@ impl App {

let provider = PlatformStatsProvider;
let mut previous_stats: HashMap<String, InterfaceStats> = HashMap::new();
// Warn once if stat collection ever fails so a permission/sandbox
// regression (e.g. Landlock denying /sys) is visible at the
// default log level instead of being silently swallowed.
let mut warned_collect_failure = false;

loop {
if should_stop.load(Ordering::Relaxed) {
Expand Down Expand Up @@ -1477,7 +1481,15 @@ impl App {
}
}
Err(e) => {
debug!("Failed to collect interface stats: {}", e);
if !warned_collect_failure {
warn!(
"Failed to collect interface stats: {} (interface panel will be empty; on Linux this is often a sandbox/permission issue reading /sys/class/net)",
e
);
warned_collect_failure = true;
} else {
debug!("Failed to collect interface stats: {}", e);
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/network/platform/linux/sandbox/landlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ pub fn apply_landlock(config: &SandboxConfig) -> Result<LandlockResult> {
log::warn!("Could not add /proc rule: {}", e);
}

// Add rules for sysfs (read-only). The interface-stats poller enumerates
// interfaces via read_dir("/sys/class/net") and then reads each
// /sys/class/net/<iface>/statistics/* counter. Those per-interface entries
// are symlinks into /sys/devices/.../net/<iface>, and Landlock evaluates the
// *resolved* path, so both subtrees need an allow-rule — without them the
// reads fail with EACCES and the Interfaces panel shows
// "No interface stats available". sysfs is not process-sensitive the way
// /proc is, and this is read-only, so granting the two subtrees is fine.
for sysfs_path in ["/sys/class/net", "/sys/devices"] {
if let Err(e) = add_path_rule(&mut ruleset_created, sysfs_path, read_access) {
log::warn!("Could not add {} rule: {}", sysfs_path, e);
}
}

// Add rules for read-only paths (e.g., GeoIP databases)
for path in &config.read_paths {
if path.exists()
Expand Down
Loading