Skip to content

Commit 6fda99e

Browse files
committed
whippet: fix default values and wildcard usage
Use the correct default value for the `max_fds` fields of send and receive records. Replace wildcard values for send and receive rules with an empty string as this is what the broker uses for fallback rules. Signed-off-by: Arnaldo Garcia Rincon <agarrcia@amazon.com>
1 parent 232834d commit 6fda99e

File tree

5 files changed

+165
-18
lines changed

5 files changed

+165
-18
lines changed

sources/Cargo.lock

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

sources/whippet/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ zvariant = { workspace = true }
2424

2525
[build-dependencies]
2626
generate-readme.workspace = true
27+
28+
[dev-dependencies]
29+
test-case.workspace = true

sources/whippet/src/dbus_policy.rs

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use serde::Serialize;
2626
use snafu::ResultExt;
2727
use zvariant::{Type, Value as ZVariantValue};
2828

29+
const DEFAULT_MAX_FDS: u64 = u64::MAX;
30+
2931
/// Top-level policy structure that matches launcher's Dbus format. It is crucial that
3032
/// the order of the fields remains like it is, otherwise the broker rejects the policy.
3133
///
@@ -72,7 +74,7 @@ pub struct OwnRecord {
7274
/// https://github.com/bus1/dbus-broker/blob/b0db0890d1254477cf832e5f9f0a798360c80fd9/src/launch/policy.c#L877
7375
macro_rules! impl_record {
7476
($record_type:ident, $rule_variant:path, [$(($struct_field:ident, $rule_field:ident)),*]) => {
75-
#[derive(Debug, Type, Serialize, Clone, ZVariantValue, Default)]
77+
#[derive(Debug, Type, Serialize, Clone, ZVariantValue)]
7678
pub struct $record_type {
7779
pub verdict: bool,
7880
pub priority: u64,
@@ -86,6 +88,23 @@ macro_rules! impl_record {
8688
pub max_fds: u64,
8789
}
8890

91+
impl Default for $record_type {
92+
fn default() -> Self {
93+
Self {
94+
verdict: Default::default(),
95+
priority: Default::default(),
96+
name: Default::default(),
97+
path: Default::default(),
98+
interface: Default::default(),
99+
member: Default::default(),
100+
record_type: Default::default(),
101+
broadcast: Default::default(),
102+
min_fds: Default::default(),
103+
max_fds: crate::dbus_policy::DEFAULT_MAX_FDS,
104+
}
105+
}
106+
}
107+
89108
impl TryFrom<&Rule> for $record_type {
90109
type Error = crate::error::Error;
91110

@@ -99,6 +118,10 @@ macro_rules! impl_record {
99118
} => Ok(Self {
100119
verdict: *allow,
101120
priority: *priority,
121+
name: rule.name()?,
122+
interface: rule.interface()?,
123+
member: rule.member()?,
124+
path: rule.path()?,
102125
$($struct_field: $rule_field.clone(),)*
103126
..Self::default()
104127
}),
@@ -113,23 +136,17 @@ macro_rules! impl_record {
113136
};
114137
}
115138

116-
impl_record!(SendRecord, Rule::Send, [
117-
(broadcast, send_broadcast),
118-
(name, send_destination),
119-
(interface, send_interface),
120-
(member, send_member),
121-
(path, send_path),
122-
(record_type, send_type)
123-
]);
124-
125-
impl_record!(ReceiveRecord, Rule::Receive, [
126-
(broadcast, receive_broadcast),
127-
(interface, receive_interface),
128-
(member, receive_member),
129-
(path, receive_path),
130-
(name, receive_sender),
131-
(record_type, receive_type)
132-
]);
139+
impl_record!(
140+
SendRecord,
141+
Rule::Send,
142+
[(broadcast, send_broadcast), (record_type, send_type)]
143+
);
144+
145+
impl_record!(
146+
ReceiveRecord,
147+
Rule::Receive,
148+
[(broadcast, receive_broadcast), (record_type, receive_type)]
149+
);
133150

134151
impl DbusPolicy {
135152
/// Builds a new DbusPolicy object using "system" as the only supported bus_type
@@ -428,4 +445,42 @@ mod tests {
428445
let dbus_policy: DbusPolicy = policy.try_into().unwrap();
429446
assert_eq!(dbus_policy.uid_entries[1].1.send_rules.len(), 2);
430447
}
448+
449+
#[test]
450+
fn test_wildcards_replaced_with_empty_string() {
451+
let config_str = r#"
452+
[default]
453+
rules = [
454+
{ allow = true, send_interface = "*", send_destination = "*", send_path = "*", send_member = "*" },
455+
]
456+
"#;
457+
let mut policy: Policy = toml::from_str(config_str).unwrap();
458+
policy.set_rule_priorities(&mut 0u64);
459+
policy.prepare().unwrap();
460+
461+
let dbus_policy: DbusPolicy = policy.try_into().unwrap();
462+
assert_eq!(dbus_policy.uid_entries[0].1.send_rules[0].interface, "");
463+
assert_eq!(dbus_policy.uid_entries[0].1.send_rules[0].name, "");
464+
assert_eq!(dbus_policy.uid_entries[0].1.send_rules[0].member, "");
465+
assert_eq!(dbus_policy.uid_entries[0].1.send_rules[0].path, "");
466+
}
467+
468+
#[test]
469+
fn test_max_fds_are_always_the_default() {
470+
let config_str = r#"
471+
[default]
472+
rules = [
473+
{ allow = true, send_interface = "*", send_destination = "*", send_path = "*", send_member = "*" },
474+
]
475+
"#;
476+
let mut policy: Policy = toml::from_str(config_str).unwrap();
477+
policy.set_rule_priorities(&mut 0u64);
478+
policy.prepare().unwrap();
479+
480+
let dbus_policy: DbusPolicy = policy.try_into().unwrap();
481+
assert_eq!(
482+
dbus_policy.uid_entries[0].1.send_rules[0].max_fds,
483+
DEFAULT_MAX_FDS
484+
);
485+
}
431486
}

sources/whippet/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,7 @@ pub enum Error {
133133
uid: String,
134134
source: std::num::ParseIntError,
135135
},
136+
137+
#[snafu(display("Can't get property '{property}' from rule '{rule_type}'"))]
138+
InvalidPropertyForRule { property: String, rule_type: String },
136139
}

sources/whippet/src/policy.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,31 @@ fn find_priority_threshold(rules: &[Rule]) -> u64 {
465465
.unwrap_or_default()
466466
}
467467

468+
/// Macro to generate rule methods that extract fields and replace wildcards with empty strings
469+
/// See: https://github.com/bus1/dbus-broker/blob/e3324b3736fd40d95e7943fca6e485013d15d643/src/launch/policy.c#L97
470+
macro_rules! impl_wildcard_getter {
471+
($method_name:ident, ($($rule_type:ident => $field:ident),*)) => {
472+
pub(crate) fn $method_name(&self) -> Result<String> {
473+
match self {
474+
$(
475+
Self::$rule_type { $field, .. } => {
476+
if $field == "*" {
477+
Ok("".to_string())
478+
} else {
479+
Ok($field.to_owned())
480+
}
481+
}
482+
)*
483+
_ => error::InvalidPropertyForRuleSnafu {
484+
property: stringify!($method_name).to_string(),
485+
rule_type: format!("{self:?}"),
486+
}
487+
.fail(),
488+
}
489+
}
490+
};
491+
}
492+
468493
impl Rule {
469494
/// Sets the priority of the rule
470495
fn set_priority(&mut self, new_priority: u64) {
@@ -489,6 +514,11 @@ impl Rule {
489514
fn is_connect(&self) -> bool {
490515
matches!(self, Self::ConnectUser { .. })
491516
}
517+
518+
impl_wildcard_getter!(interface, (Send => send_interface, Receive => receive_interface));
519+
impl_wildcard_getter!(name, (Send => send_destination, Receive => receive_sender));
520+
impl_wildcard_getter!(member, (Send => send_member, Receive => receive_member));
521+
impl_wildcard_getter!(path, (Send => send_path, Receive => receive_path));
492522
}
493523

494524
impl Context {
@@ -551,6 +581,7 @@ impl UsernameResolver for PasswdUsernameResolver {
551581
#[cfg(test)]
552582
mod tests {
553583
use super::*;
584+
use test_case::test_case;
554585

555586
const ALICE_USER: u32 = 1;
556587
const BOB_USER: u32 = 2;
@@ -920,4 +951,58 @@ mod tests {
920951
clean_connect_rules(4, &mut rules);
921952
assert!(rules.is_empty());
922953
}
954+
955+
#[test_case(Rule::Send {
956+
allow: false,
957+
priority: u64::default(),
958+
send_broadcast: u32::default(),
959+
send_destination: "*".to_string(),
960+
send_interface: "*".to_string(),
961+
send_member: "*".to_string(),
962+
send_path: "*".to_string(),
963+
send_type: MessageType::default(),
964+
}; "with a send rule wildcards are replaced with empty strings")]
965+
#[test_case(Rule::Receive {
966+
allow: false,
967+
priority: u64::default(),
968+
receive_broadcast: u32::default(),
969+
receive_interface: "*".to_string(),
970+
receive_member: "*".to_string(),
971+
receive_path: "*".to_string(),
972+
receive_sender: "*".to_string(),
973+
receive_type: MessageType::default(),
974+
}; "with a receive rule wildcards are replaced with empty strings")]
975+
fn rules_with_wildcards(rule: Rule) {
976+
assert_eq!(rule.name().unwrap(), "");
977+
assert_eq!(rule.interface().unwrap(), "");
978+
assert_eq!(rule.member().unwrap(), "");
979+
assert_eq!(rule.path().unwrap(), "");
980+
}
981+
982+
#[test_case(Rule::Send {
983+
allow: false,
984+
priority: u64::default(),
985+
send_broadcast: u32::default(),
986+
send_destination: "name".to_string(),
987+
send_interface: "interface".to_string(),
988+
send_member: "member".to_string(),
989+
send_path: "path".to_string(),
990+
send_type: MessageType::default(),
991+
}; "with a send rule the original value is returned")]
992+
#[test_case(Rule::Receive {
993+
allow: false,
994+
priority: u64::default(),
995+
receive_broadcast: u32::default(),
996+
receive_interface: "interface".to_string(),
997+
receive_member: "member".to_string(),
998+
receive_path: "path".to_string(),
999+
receive_sender: "name".to_string(),
1000+
receive_type: MessageType::default(),
1001+
}; "with a receive rule the original value is returned")]
1002+
fn rules_without_wildcards(rule: Rule) {
1003+
assert_eq!(rule.name().unwrap(), "name");
1004+
assert_eq!(rule.interface().unwrap(), "interface");
1005+
assert_eq!(rule.member().unwrap(), "member");
1006+
assert_eq!(rule.path().unwrap(), "path");
1007+
}
9231008
}

0 commit comments

Comments
 (0)