Skip to content

Commit 6283269

Browse files
committed
Move shared macos code to talpid-macos
1 parent d06f34e commit 6283269

File tree

9 files changed

+116
-120
lines changed

9 files changed

+116
-120
lines changed

Cargo.lock

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ members = [
2929
"talpid-core",
3030
"talpid-dbus",
3131
"talpid-future",
32+
"talpid-macos",
3233
"talpid-net",
3334
"talpid-openvpn",
3435
"talpid-openvpn-plugin",

talpid-core/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ talpid-platform-metadata = { path = "../talpid-platform-metadata" }
5656
pcap = { version = "2.1", features = ["capture-stream"] }
5757
pnet_packet = "0.34"
5858
tun = { version = "0.5.5", features = ["async"] }
59-
nix = { version = "0.28", features = ["socket"] }
59+
nix = { version = "0.28", features = ["socket", "signal"] }
6060
serde = { workspace = true, features = ["derive"] }
6161
serde_json = { workspace = true }
62+
talpid-macos = { path = "../talpid-macos" }
6263
talpid-net = { path = "../talpid-net" }
6364

6465
[target.'cfg(windows)'.dependencies]

talpid-core/src/resolver.rs

+5-67
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use std::{
88
io,
99
net::{IpAddr, Ipv4Addr, SocketAddr},
10-
path::{Path, PathBuf},
1110
str::FromStr,
1211
sync::{Arc, Weak},
1312
time::{Duration, Instant},
@@ -40,7 +39,6 @@ use hickory_server::{
4039
server::{Request, RequestHandler, ResponseHandler, ResponseInfo},
4140
ServerFuture,
4241
};
43-
use libc::{c_void, kill, pid_t, proc_listallpids, proc_pidpath, SIGHUP};
4442
use std::sync::LazyLock;
4543

4644
const ALLOWED_RECORD_TYPES: &[RecordType] =
@@ -358,75 +356,15 @@ const MDNS_RESPONDER_PATH: &str = "/usr/sbin/mDNSResponder";
358356

359357
/// Find and kill mDNSResponder. The OS will restart the service.
360358
fn kill_mdnsresponder() -> io::Result<()> {
361-
if let Some(mdns_pid) = pid_of_path(MDNS_RESPONDER_PATH) {
362-
if unsafe { kill(mdns_pid as i32, SIGHUP) } != 0 {
363-
return Err(io::Error::last_os_error());
364-
}
359+
if let Some(mdns_pid) = talpid_macos::process::pid_of_path(MDNS_RESPONDER_PATH) {
360+
nix::sys::signal::kill(
361+
nix::unistd::Pid::from_raw(mdns_pid),
362+
nix::sys::signal::SIGHUP,
363+
)?;
365364
}
366365
Ok(())
367366
}
368367

369-
/// Return the first process identifier matching a specified path, if one exists.
370-
fn pid_of_path(find_path: impl AsRef<Path>) -> Option<pid_t> {
371-
match list_pids() {
372-
Ok(pids) => {
373-
for pid in pids {
374-
if let Ok(path) = process_path(pid) {
375-
if path == find_path.as_ref() {
376-
return Some(pid);
377-
}
378-
}
379-
}
380-
None
381-
}
382-
Err(error) => {
383-
log::error!("Failed to list processes: {error}");
384-
None
385-
}
386-
}
387-
}
388-
389-
/// Obtain a list of all pids
390-
fn list_pids() -> io::Result<Vec<pid_t>> {
391-
// SAFETY: Passing in null and 0 returns the number of processes
392-
let num_pids = unsafe { proc_listallpids(std::ptr::null_mut(), 0) };
393-
if num_pids <= 0 {
394-
return Err(io::Error::last_os_error());
395-
}
396-
let num_pids = usize::try_from(num_pids).unwrap();
397-
let mut pids = vec![0i32; num_pids];
398-
399-
let buf_sz = (num_pids * std::mem::size_of::<pid_t>()) as i32;
400-
// SAFETY: 'pids' is large enough to contain 'num_pids' processes
401-
let num_pids = unsafe { proc_listallpids(pids.as_mut_ptr() as *mut c_void, buf_sz) };
402-
if num_pids == -1 {
403-
return Err(io::Error::last_os_error());
404-
}
405-
406-
pids.resize(usize::try_from(num_pids).unwrap(), 0);
407-
408-
Ok(pids)
409-
}
410-
411-
fn process_path(pid: pid_t) -> io::Result<PathBuf> {
412-
let mut buffer = [0u8; libc::MAXPATHLEN as usize];
413-
// SAFETY: `proc_pidpath` returns at most `buffer.len()` bytes
414-
let buf_len = unsafe {
415-
proc_pidpath(
416-
pid,
417-
buffer.as_mut_ptr() as *mut c_void,
418-
u32::try_from(buffer.len()).unwrap(),
419-
)
420-
};
421-
if buf_len == -1 {
422-
return Err(io::Error::last_os_error());
423-
}
424-
Ok(PathBuf::from(
425-
std::str::from_utf8(&buffer[0..buf_len as usize])
426-
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid process path"))?,
427-
))
428-
}
429-
430368
type LookupResponse<'a> = MessageResponse<
431369
'a,
432370
'a,

talpid-core/src/split_tunnel/macos/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ impl State {
614614
Some(vpn_interface.clone()),
615615
route_manager.clone(),
616616
Box::new(move |packet| {
617-
match states.get_process_status(packet.header.pth_pid as u32) {
617+
match states.get_process_status(packet.header.pth_pid) {
618618
ExclusionStatus::Excluded => tun::RoutingDecision::DefaultInterface,
619619
ExclusionStatus::Included => tun::RoutingDecision::VpnTunnel,
620620
ExclusionStatus::Unknown => {

talpid-core/src/split_tunnel/macos/process.rs

+9-51
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@
66
//! Endpoint Security framework.
77
88
use futures::channel::oneshot;
9-
use libc::{proc_listallpids, proc_pidpath};
9+
use libc::pid_t;
1010
use serde::Deserialize;
1111
use std::{
1212
collections::{HashMap, HashSet},
13-
ffi::c_void,
1413
io,
1514
path::PathBuf,
1615
process::Stdio,
17-
ptr,
1816
sync::{Arc, LazyLock, Mutex},
1917
time::Duration,
2018
};
19+
use talpid_macos::process::{list_pids, process_path};
2120
use talpid_platform_metadata::MacosVersion;
2221
use talpid_types::tunnel::ErrorStateCause;
2322
use tokio::io::{AsyncBufReadExt, BufReader};
@@ -52,7 +51,7 @@ pub enum Error {
5251
InitializePids(#[source] io::Error),
5352
/// Failed to find path for a process
5453
#[error("Failed to find path for a process: {}", _0)]
55-
FindProcessPath(#[source] io::Error, u32),
54+
FindProcessPath(#[source] io::Error, pid_t),
5655
}
5756

5857
impl From<&Error> for ErrorStateCause {
@@ -231,7 +230,7 @@ pub enum ExclusionStatus {
231230

232231
#[derive(Debug)]
233232
struct InnerProcessStates {
234-
processes: HashMap<u32, ProcessInfo>,
233+
processes: HashMap<pid_t, ProcessInfo>,
235234
exclude_paths: HashSet<PathBuf>,
236235
}
237236

@@ -277,7 +276,7 @@ impl ProcessStates {
277276
inner.exclude_paths = paths;
278277
}
279278

280-
pub fn get_process_status(&self, pid: u32) -> ExclusionStatus {
279+
pub fn get_process_status(&self, pid: pid_t) -> ExclusionStatus {
281280
let inner = self.inner.lock().unwrap();
282281
match inner.processes.get(&pid) {
283282
Some(val) if val.is_excluded() => ExclusionStatus::Excluded,
@@ -300,7 +299,7 @@ impl InnerProcessStates {
300299

301300
// For new processes, inherit all exclusion state from the parent, if there is one.
302301
// Otherwise, look up excluded paths
303-
fn handle_fork(&mut self, parent_pid: u32, exec_path: PathBuf, msg: ESForkEvent) {
302+
fn handle_fork(&mut self, parent_pid: pid_t, exec_path: PathBuf, msg: ESForkEvent) {
304303
let pid = msg.child.audit_token.pid;
305304

306305
if self.processes.contains_key(&pid) {
@@ -327,7 +326,7 @@ impl InnerProcessStates {
327326
self.processes.insert(pid, base_info);
328327
}
329328

330-
fn handle_exec(&mut self, pid: u32, msg: ESExecEvent) {
329+
fn handle_exec(&mut self, pid: pid_t, msg: ESExecEvent) {
331330
let Some(info) = self.processes.get_mut(&pid) else {
332331
log::error!("exec received for unknown pid {pid}");
333332
return;
@@ -354,54 +353,13 @@ impl InnerProcessStates {
354353
}
355354
}
356355

357-
fn handle_exit(&mut self, pid: u32) {
356+
fn handle_exit(&mut self, pid: pid_t) {
358357
if self.processes.remove(&pid).is_none() {
359358
log::error!("exit syscall for unknown pid {pid}");
360359
}
361360
}
362361
}
363362

364-
/// Obtain a list of all pids
365-
fn list_pids() -> io::Result<Vec<u32>> {
366-
// SAFETY: Passing in null and 0 returns the number of processes
367-
let num_pids = unsafe { proc_listallpids(ptr::null_mut(), 0) };
368-
if num_pids <= 0 {
369-
return Err(io::Error::last_os_error());
370-
}
371-
let num_pids = usize::try_from(num_pids).unwrap();
372-
let mut pids = vec![0u32; num_pids];
373-
374-
let buf_sz = (num_pids * std::mem::size_of::<u32>()) as i32;
375-
// SAFETY: 'pids' is large enough to contain 'num_pids' processes
376-
let num_pids = unsafe { proc_listallpids(pids.as_mut_ptr() as *mut c_void, buf_sz) };
377-
if num_pids == -1 {
378-
return Err(io::Error::last_os_error());
379-
}
380-
381-
pids.resize(usize::try_from(num_pids).unwrap(), 0);
382-
383-
Ok(pids)
384-
}
385-
386-
fn process_path(pid: u32) -> io::Result<PathBuf> {
387-
let mut buffer = [0u8; libc::MAXPATHLEN as usize];
388-
// SAFETY: `proc_pidpath` returns at most `buffer.len()` bytes
389-
let buf_len = unsafe {
390-
proc_pidpath(
391-
pid as i32,
392-
buffer.as_mut_ptr() as *mut c_void,
393-
buffer.len() as u32,
394-
)
395-
};
396-
if buf_len == -1 {
397-
return Err(io::Error::last_os_error());
398-
}
399-
Ok(PathBuf::from(
400-
std::str::from_utf8(&buffer[0..buf_len as usize])
401-
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid process path"))?,
402-
))
403-
}
404-
405363
#[derive(Debug, Clone)]
406364
struct ProcessInfo {
407365
exec_path: PathBuf,
@@ -480,7 +438,7 @@ struct ESExecutable {
480438
/// https://developer.apple.com/documentation/endpointsecurity/es_process_t/3228975-audit_token?language=objc
481439
#[derive(Debug, Deserialize)]
482440
struct ESAuditToken {
483-
pid: u32,
441+
pid: pid_t,
484442
}
485443

486444
/// Process information for the message returned by `eslogger`.

talpid-macos/Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "talpid-macos"
3+
description = "Abstractions for macOS"
4+
authors.workspace = true
5+
repository.workspace = true
6+
license.workspace = true
7+
edition.workspace = true
8+
rust-version.workspace = true
9+
10+
[lints]
11+
workspace = true
12+
13+
[target.'cfg(target_os="macos")'.dependencies]
14+
libc = "0.2"
15+
log = { workspace = true }

talpid-macos/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//! Interface with macOS-specific bits.
2+
3+
#![deny(missing_docs)]
4+
#![cfg(target_os = "macos")]
5+
6+
/// Processes
7+
pub mod process;

talpid-macos/src/process.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use libc::{c_void, pid_t, proc_listallpids, proc_pidpath};
2+
use std::{
3+
io,
4+
path::{Path, PathBuf},
5+
};
6+
7+
/// Return the first process identifier matching a specified path, if one exists.
8+
pub fn pid_of_path(find_path: impl AsRef<Path>) -> Option<pid_t> {
9+
match list_pids() {
10+
Ok(pids) => {
11+
for pid in pids {
12+
if let Ok(path) = process_path(pid) {
13+
if path == find_path.as_ref() {
14+
return Some(pid);
15+
}
16+
}
17+
}
18+
None
19+
}
20+
Err(error) => {
21+
log::error!("Failed to list processes: {error}");
22+
None
23+
}
24+
}
25+
}
26+
27+
/// Obtain a list of all process identifiers
28+
pub fn list_pids() -> io::Result<Vec<pid_t>> {
29+
// SAFETY: Passing in null and 0 returns the number of processes
30+
let num_pids = unsafe { proc_listallpids(std::ptr::null_mut(), 0) };
31+
if num_pids <= 0 {
32+
return Err(io::Error::last_os_error());
33+
}
34+
let num_pids = usize::try_from(num_pids).unwrap();
35+
let mut pids = vec![0i32; num_pids];
36+
37+
let buf_sz = (num_pids * std::mem::size_of::<pid_t>()) as i32;
38+
// SAFETY: 'pids' is large enough to contain 'num_pids' processes
39+
let num_pids = unsafe { proc_listallpids(pids.as_mut_ptr() as *mut c_void, buf_sz) };
40+
if num_pids == -1 {
41+
return Err(io::Error::last_os_error());
42+
}
43+
44+
pids.resize(usize::try_from(num_pids).unwrap(), 0);
45+
46+
Ok(pids)
47+
}
48+
49+
/// Return the path of the process `pid`
50+
pub fn process_path(pid: pid_t) -> io::Result<PathBuf> {
51+
let mut buffer = [0u8; libc::MAXPATHLEN as usize];
52+
// SAFETY: `proc_pidpath` returns at most `buffer.len()` bytes
53+
let buf_len = unsafe {
54+
proc_pidpath(
55+
pid,
56+
buffer.as_mut_ptr() as *mut c_void,
57+
u32::try_from(buffer.len()).unwrap(),
58+
)
59+
};
60+
if buf_len == -1 {
61+
return Err(io::Error::last_os_error());
62+
}
63+
Ok(PathBuf::from(
64+
std::str::from_utf8(&buffer[0..buf_len as usize])
65+
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid process path"))?,
66+
))
67+
}

0 commit comments

Comments
 (0)