-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
196 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,217 @@ | ||
//! Contains a [`RuleSet`] for allowing time-related syscalls, but check the comments for why you | ||
//! probably don't actually need to enable them. | ||
//! Allow various time related syscalls. | ||
use std::collections::HashSet; | ||
|
||
use syscalls::Sysno; | ||
|
||
use crate::RuleSet; | ||
use {super::YesReally, crate::RuleSet, std::collections::BTreeSet, syscalls::Sysno}; | ||
|
||
/// Allow querying and modifying time as well as sleeping. | ||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd)] | ||
#[must_use] | ||
/// Enable syscalls related to time. | ||
pub struct Time { | ||
/// Syscalls that are allowed | ||
allowed: HashSet<Sysno>, | ||
/// A set of permitted syscalls, added by various constructors and methods. | ||
syscalls: BTreeSet<Sysno>, | ||
} | ||
|
||
impl Time { | ||
/// Create a new Time [`RuleSet`] with nothing allowed by default. | ||
pub fn nothing() -> Time { | ||
Time { | ||
allowed: HashSet::new(), | ||
} | ||
/// Construct a new rule, which allows everything: | ||
/// Querying and modifying time as well as sleeping without restriction. | ||
pub fn everything() -> YesReally<Self> { | ||
Self::nothing().allow_query().allow_sleep().allow_modify() | ||
} | ||
|
||
/// Construct a new rule, which allows modifying time without restriction. | ||
pub fn modify() -> YesReally<Self> { | ||
Self::nothing().allow_modify() | ||
} | ||
|
||
/// Construct a new rule, which allows nothing. | ||
pub fn nothing() -> Self { | ||
Self::default() | ||
} | ||
|
||
/// Construct a new rule, which allows querying time without restriction. | ||
pub fn query() -> Self { | ||
Self::nothing().allow_query() | ||
} | ||
|
||
/// Construct a new rule, which allows querying and modifying time without restriction. | ||
pub fn query_and_modify() -> YesReally<Self> { | ||
Self::nothing().allow_query().allow_modify() | ||
} | ||
|
||
/// Construct a new rule, which allows querying time as well as sleeping without restriction. | ||
pub fn query_and_sleep() -> Self { | ||
Self::nothing().allow_query().allow_sleep() | ||
} | ||
|
||
/// On most 64 bit systems glibc and musl both use the | ||
/// [`vDSO`](https://man7.org/linux/man-pages/man7/vdso.7.html) to compute the time directly with | ||
/// rdtsc rather than calling the `clock_gettime` syscall, so in most cases you don't need to | ||
/// actually enable this. | ||
pub fn allow_gettime(mut self) -> Time { | ||
self.allowed | ||
.extend([Sysno::clock_gettime, Sysno::clock_getres]); | ||
/// Construct a new rule, which allows sleeping without restriction. | ||
pub fn sleep() -> Self { | ||
Self::nothing().allow_sleep() | ||
} | ||
|
||
allow! { | ||
/// Allow modifying time without restriction. | ||
pub unsafe fn allow_modify(self) { | ||
/// Allow the `adjtimex` syscall to tune a kernel clock. | ||
pub fn allow_adjtimex(adjtimex); | ||
|
||
/// Allow the `clock_adjtime` syscall to tune a kernel clock. | ||
pub fn allow_clock_adjtime(clock_adjtime); | ||
|
||
/// Allow the `clock_settime` syscall to set the time of a clock. | ||
pub fn allow_clock_settime(clock_settime); | ||
|
||
/// Allow the `settimeofday` syscall to set the time. | ||
pub fn allow_settimeofday(settimeofday); | ||
} | ||
|
||
/// Allow querying time without restriction. | ||
pub fn allow_query(self) { | ||
/// Allow the `clock_getres` syscall to get the clock resolution. | ||
pub fn allow_clock_getres(clock_getres); | ||
|
||
self | ||
/// Allow the `clock_gettime` syscall to get the time of a clock. | ||
pub fn allow_clock_gettime(clock_gettime); | ||
|
||
/// Allow the `gettimeofday` syscall to get the time. | ||
pub fn allow_gettimeofday(gettimeofday); | ||
|
||
/// Allow the `time` syscall to get the time in seconds. | ||
pub fn allow_time(time); | ||
} | ||
|
||
/// Allow sleeping without restriction. | ||
pub fn allow_sleep(self) { | ||
/// Allow the `clock_nanosleep` syscall. | ||
pub fn allow_clock_nanosleep(clock_nanosleep); | ||
|
||
/// Allow the `nanosleep` syscall. | ||
pub fn allow_nanosleep(nanosleep); | ||
} | ||
} | ||
|
||
/// On most 64 bit systems glibc and musl both use the | ||
/// [`vDSO`](https://man7.org/linux/man-pages/man7/vdso.7.html) to compute the time directly with | ||
/// rdtsc rather than calling the `clock_gettime` syscall, so in most cases you don't need to | ||
/// actually enable this. | ||
pub fn allow_gettime(self) -> Self { | ||
self.allow_clock_gettime().allow_clock_getres() | ||
} | ||
} | ||
|
||
impl RuleSet for Time { | ||
fn simple_rules(&self) -> Vec<Sysno> { | ||
self.allowed.iter().copied().collect() | ||
self.syscalls.iter().cloned().collect() | ||
} | ||
|
||
fn name(&self) -> &'static str { | ||
"Time" | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use {super::Time, crate::RuleSet as _, syscalls::Sysno}; | ||
|
||
#[test] | ||
fn everything() { | ||
let rules = Time::everything().yes_really(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert_eq!(simple_rules.len(), 10); | ||
assert!(simple_rules.contains(&Sysno::adjtimex)); | ||
assert!(simple_rules.contains(&Sysno::clock_adjtime)); | ||
assert!(simple_rules.contains(&Sysno::clock_getres)); | ||
assert!(simple_rules.contains(&Sysno::clock_gettime)); | ||
assert!(simple_rules.contains(&Sysno::clock_nanosleep)); | ||
assert!(simple_rules.contains(&Sysno::clock_settime)); | ||
assert!(simple_rules.contains(&Sysno::gettimeofday)); | ||
assert!(simple_rules.contains(&Sysno::nanosleep)); | ||
assert!(simple_rules.contains(&Sysno::settimeofday)); | ||
assert!(simple_rules.contains(&Sysno::time)); | ||
} | ||
|
||
#[test] | ||
fn modify() { | ||
let rules = Time::modify().yes_really(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert_eq!(simple_rules.len(), 4); | ||
assert!(simple_rules.contains(&Sysno::adjtimex)); | ||
assert!(simple_rules.contains(&Sysno::clock_adjtime)); | ||
assert!(simple_rules.contains(&Sysno::clock_settime)); | ||
assert!(simple_rules.contains(&Sysno::settimeofday)); | ||
} | ||
|
||
#[test] | ||
fn nothing() { | ||
let rules = Time::nothing(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert!(simple_rules.is_empty()); | ||
} | ||
|
||
#[test] | ||
fn query() { | ||
let rules = Time::query(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert_eq!(simple_rules.len(), 4); | ||
assert!(simple_rules.contains(&Sysno::clock_getres)); | ||
assert!(simple_rules.contains(&Sysno::clock_gettime)); | ||
assert!(simple_rules.contains(&Sysno::gettimeofday)); | ||
assert!(simple_rules.contains(&Sysno::time)); | ||
} | ||
|
||
#[test] | ||
fn query_and_modify() { | ||
let rules = Time::query_and_modify().yes_really(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert_eq!(simple_rules.len(), 8); | ||
assert!(simple_rules.contains(&Sysno::adjtimex)); | ||
assert!(simple_rules.contains(&Sysno::clock_adjtime)); | ||
assert!(simple_rules.contains(&Sysno::clock_getres)); | ||
assert!(simple_rules.contains(&Sysno::clock_gettime)); | ||
assert!(simple_rules.contains(&Sysno::clock_settime)); | ||
assert!(simple_rules.contains(&Sysno::gettimeofday)); | ||
assert!(simple_rules.contains(&Sysno::settimeofday)); | ||
assert!(simple_rules.contains(&Sysno::time)); | ||
} | ||
|
||
#[test] | ||
fn query_and_sleep() { | ||
let rules = Time::query_and_sleep(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert_eq!(simple_rules.len(), 6); | ||
assert!(simple_rules.contains(&Sysno::clock_getres)); | ||
assert!(simple_rules.contains(&Sysno::clock_gettime)); | ||
assert!(simple_rules.contains(&Sysno::clock_nanosleep)); | ||
assert!(simple_rules.contains(&Sysno::gettimeofday)); | ||
assert!(simple_rules.contains(&Sysno::nanosleep)); | ||
assert!(simple_rules.contains(&Sysno::time)); | ||
} | ||
|
||
#[test] | ||
fn sleep() { | ||
let rules = Time::sleep(); | ||
assert_eq!(rules.name(), "Time"); | ||
assert!(rules.conditional_rules().is_empty()); | ||
|
||
let simple_rules = rules.simple_rules(); | ||
assert_eq!(simple_rules.len(), 2); | ||
assert!(simple_rules.contains(&Sysno::clock_nanosleep)); | ||
assert!(simple_rules.contains(&Sysno::nanosleep)); | ||
} | ||
} |