1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//
// Syd: rock-solid application kernel
// src/utils/syd-tsc.rs: Run a command without access to the timestamp counter
//
// Copyright (c) 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0
use std::{
env,
ffi::OsString,
process::{Command, ExitCode},
};
use nix::errno::Errno;
use syd::{config::*, confine::run_cmd};
// Set global allocator to GrapheneOS allocator.
#[cfg(all(
not(coverage),
not(feature = "prof"),
not(target_os = "android"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
// Set global allocator to tcmalloc if profiling is enabled.
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;
syd::main! {
use lexopt::prelude::*;
syd::set_sigpipe_dfl()?;
// Parse CLI options.
//
// Note, option parsing is POSIXly correct:
// POSIX recommends that no more options are parsed after the first
// positional argument. The other arguments are then all treated as
// positional arguments.
// See: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
let mut opt_cmd = env::var_os(ENV_SH).unwrap_or(OsString::from(SYD_SH));
let mut opt_arg = Vec::new();
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('h') => {
help();
return Ok(ExitCode::SUCCESS);
}
Value(prog) => {
opt_cmd = prog;
opt_arg.extend(parser.raw_args()?);
}
_ => return Err(arg.unexpected().into()),
}
}
// Deny access to the timestamp counter.
//
// SAFETY: `PR_SET_TSC` with `PR_TSC_SIGSEGV` are valid
// prctl(2) constants; affects calling thread only.
Errno::result(unsafe { libc::prctl(libc::PR_SET_TSC, libc::PR_TSC_SIGSEGV) })?;
// Execute command, /bin/sh by default.
let mut cmd = Command::new(opt_cmd);
let cmd = cmd.args(opt_arg);
Ok(ExitCode::from(run_cmd(cmd)))
}
fn help() {
println!("Usage: syd-tsc [-h] {{command [args...]}}");
println!("Run a command without access to the timestamp counter.");
}