1use super::constraints::evaluate_constraint;
6use super::error::{ParseError, ValidateError};
7use super::parser::PolicyData;
8use super::security_context::SecurityContext;
9use super::{
10 AccessDecision, AccessVector, ClassId, SELINUX_AVD_FLAGS_PERMISSIVE, TypeId,
11 XpermsAccessDecision, XpermsKind,
12};
13use crate::PolicyCap;
14use crate::new_policy::rules::{
15 ExtendedPermissions, HasRuleKey, RuleKind, XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES,
16 XPERMS_TYPE_IOCTL_PREFIXES, XPERMS_TYPE_NLMSG, XpermsBitmap,
17};
18use crate::new_policy::traits::HasPolicyId;
19use crate::new_policy::{Class, GenfsConPath, NewPolicy};
20use std::ops::Deref;
21use std::sync::Arc;
22
23use anyhow::Context as _;
24use std::iter::Iterator;
25
26const MAXIMUM_POLICY_SIZE: usize = 1 << 24;
28
29#[derive(Debug)]
31pub struct ParsedPolicy {
32 new_policy: Arc<NewPolicy>,
34}
35
36impl Deref for ParsedPolicy {
37 type Target = NewPolicy;
38 fn deref(&self) -> &Self::Target {
39 &self.new_policy
40 }
41}
42
43impl ParsedPolicy {
44 pub fn has_policycap(&self, policy_cap: PolicyCap) -> bool {
46 self.new_policy.policy_capabilities().contains(policy_cap)
47 }
48
49 pub(super) fn compute_access_decision(
61 &self,
62 source_context: &SecurityContext,
63 target_context: &SecurityContext,
64 target_class: &Class,
65 ) -> AccessDecision {
66 let mut access_decision = self.compute_explicitly_allowed(
67 source_context.type_(),
68 target_context.type_(),
69 target_class,
70 );
71 access_decision.allow -=
72 self.compute_denied_by_constraints(source_context, target_context, target_class);
73 access_decision
74 }
75
76 pub(super) fn compute_explicitly_allowed(
81 &self,
82 source_type: TypeId,
83 target_type: TypeId,
84 target_class: &Class,
85 ) -> AccessDecision {
86 let target_class_id = target_class.id();
87
88 let mut computed_access_vector = AccessVector::NONE;
89 let mut computed_audit_allow = AccessVector::NONE;
90 let mut computed_audit_deny = AccessVector::ALL;
91
92 let source_attribute_set = &self.type_attribute_maps()[source_type];
93 let target_attribute_set = &self.type_attribute_maps()[target_type];
94
95 for source_id in source_attribute_set.iter() {
96 for target_id in target_attribute_set.iter() {
97 for rule in self.new_policy.access_vector_rules().find_av_rules(
98 source_id,
99 target_id,
100 target_class_id,
101 ) {
102 match rule.kind() {
103 RuleKind::Allow => computed_access_vector |= rule.access_vector(),
104 RuleKind::AuditAllow => computed_audit_allow |= rule.access_vector(),
105 RuleKind::DontAudit => computed_audit_deny &= rule.access_vector(),
106 _ => {}
107 }
108 }
109 }
110 }
111
112 if let Some(parent) = self.types().get_by_id(source_type).unwrap().bounded_by() {
116 let access = if source_type == target_type {
119 self.compute_explicitly_allowed(parent, parent, target_class)
120 } else {
121 self.compute_explicitly_allowed(parent, target_type, target_class)
122 };
123 computed_access_vector &= access.allow;
124 }
125
126 let mut flags = 0;
127 if self.permissive_map().contains(source_type) {
128 flags |= SELINUX_AVD_FLAGS_PERMISSIVE;
129 }
130 AccessDecision {
131 allow: computed_access_vector,
132 auditallow: computed_audit_allow,
133 auditdeny: computed_audit_deny,
134 flags,
135 todo_bug: None,
136 }
137 }
138
139 fn compute_denied_by_constraints(
141 &self,
142 source_context: &SecurityContext,
143 target_context: &SecurityContext,
144 target_class: &Class,
145 ) -> AccessVector {
146 let mut denied = AccessVector::NONE;
147 for constraint in target_class.constraints() {
148 if !evaluate_constraint(constraint.constraint_expr(), source_context, target_context) {
149 denied |= constraint.access_vector();
150 }
151 }
152 denied
153 }
154
155 pub(super) fn compute_xperms_access_decision(
158 &self,
159 xperms_kind: XpermsKind,
160 source_context: &SecurityContext,
161 target_context: &SecurityContext,
162 target_class: &Class,
163 xperms_prefix: u8,
164 ) -> XpermsAccessDecision {
165 let target_class_id = target_class.id();
166
167 let mut explicit_allow: Option<XpermsBitmap> = None;
168 let mut auditallow = XpermsBitmap::NONE;
169 let mut auditdeny = XpermsBitmap::ALL;
170
171 let xperms_types = match xperms_kind {
172 XpermsKind::Ioctl => {
173 [XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES, XPERMS_TYPE_IOCTL_PREFIXES].as_slice()
174 }
175 XpermsKind::Nlmsg => [XPERMS_TYPE_NLMSG].as_slice(),
176 };
177 let bitmap_if_prefix_matches =
178 |xperms_prefix: u8, xperms: &ExtendedPermissions| match xperms_kind {
179 XpermsKind::Ioctl => match xperms.xperms_type() {
180 XPERMS_TYPE_IOCTL_PREFIX_AND_POSTFIXES => (xperms.xperms_optional_prefix()
181 == xperms_prefix)
182 .then_some(*xperms.xperms_bitmap()),
183 XPERMS_TYPE_IOCTL_PREFIXES => {
184 xperms.xperms_bitmap().contains(xperms_prefix).then_some(XpermsBitmap::ALL)
185 }
186 _ => None,
187 },
188 XpermsKind::Nlmsg => match xperms.xperms_type() {
189 XPERMS_TYPE_NLMSG => (xperms.xperms_optional_prefix() == xperms_prefix)
190 .then_some(*xperms.xperms_bitmap()),
191 _ => None,
192 },
193 };
194
195 let source_attribute_set = &self.type_attribute_maps()[source_context.type_()];
196 let target_attribute_set = &self.type_attribute_maps()[target_context.type_()];
197
198 for source_id in source_attribute_set.iter() {
199 for target_id in target_attribute_set.iter() {
200 for rule in self.new_policy.access_vector_rules().find_xperm_rules(
201 source_id,
202 target_id,
203 target_class_id,
204 ) {
205 let xperms = rule.extended_permissions();
206 if rule.kind() == RuleKind::AllowXperm
207 && xperms_types.contains(&xperms.xperms_type())
208 {
209 explicit_allow.get_or_insert(XpermsBitmap::NONE);
210 }
211
212 if let Some(xperms_bitmap) = bitmap_if_prefix_matches(xperms_prefix, xperms) {
213 match rule.kind() {
214 RuleKind::AllowXperm => {
215 (*explicit_allow.get_or_insert(XpermsBitmap::NONE)) |=
216 xperms_bitmap;
217 }
218 RuleKind::AuditAllowXperm => auditallow |= xperms_bitmap,
219 RuleKind::DontAuditXperm => auditdeny -= xperms_bitmap,
220 _ => {}
221 }
222 }
223 }
224 }
225 }
226 let allow = explicit_allow.unwrap_or(XpermsBitmap::ALL);
227 XpermsAccessDecision { allow, auditallow, auditdeny }
228 }
229
230 pub(super) fn genfscon_find_all<'a>(
231 &'a self,
232 fs_type: &'a [u8],
233 ) -> impl Iterator<Item = &'a GenfsConPath> {
234 self.generic_fs_contexts()
235 .iter()
236 .filter(move |entry| entry.fs_type() == fs_type)
237 .flat_map(|entry| entry.paths().iter())
238 }
239
240 pub(super) fn compute_filename_transition(
241 &self,
242 source_type: TypeId,
243 target_type: TypeId,
244 class: ClassId,
245 name: &[u8],
246 ) -> Option<TypeId> {
247 self.new_policy.filename_transitions().compute_filename_transition(
248 source_type,
249 target_type,
250 class,
251 name,
252 )
253 }
254
255 pub(super) fn initial_context(&self, mut id: crate::InitialSid) -> &crate::new_policy::Context {
256 let need_init_sid = self.has_policycap(PolicyCap::UserspaceInitialContext);
257 if id == crate::InitialSid::Init && !need_init_sid {
258 id = crate::InitialSid::Kernel;
259 }
260 self.new_policy
261 .initial_sids()
262 .get_by_id(id as u32)
263 .expect("initial SID must be present in validated policy")
264 }
265}
266
267impl ParsedPolicy {
268 pub(super) fn parse(data: PolicyData) -> Result<Self, anyhow::Error> {
271 let policy_size = data.len();
272 if MAXIMUM_POLICY_SIZE <= policy_size {
273 return Err(anyhow::Error::from(ParseError::UnsupportedlyLarge {
274 observed: policy_size,
275 limit: MAXIMUM_POLICY_SIZE,
276 }));
277 }
278 let new_policy =
279 NewPolicy::parse(&data).map_err(|e| anyhow::anyhow!("new parser failed: {:?}", e))?;
280 new_policy.validate().context("validating new policy structure")?;
281
282 Ok(ParsedPolicy { new_policy: Arc::new(new_policy) })
283 }
284}
285
286impl ParsedPolicy {
287 pub fn validate(&self) -> Result<(), anyhow::Error> {
288 let need_init_sid = self.has_policycap(PolicyCap::UserspaceInitialContext);
290 for initial_sid in crate::InitialSid::all_variants() {
291 if *initial_sid == crate::InitialSid::Init && !need_init_sid {
292 continue;
293 }
294 self.new_policy
295 .initial_sids()
296 .get_by_id(*initial_sid as u32)
297 .ok_or(ValidateError::MissingInitialSid { initial_sid: *initial_sid })?;
298 }
299
300 Ok(())
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310 use crate::new_policy::TypeSet;
311 use crate::new_policy::traits::PolicyId;
312 use crate::policy::Parse;
313 use crate::policy::parser::PolicyCursor;
314 use std::sync::Arc;
315
316 #[test]
317 fn test_id_set_parse_compatibility() {
318 let bytes = [
319 64, 0, 0, 0, 128, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, ];
329 let data: PolicyData = Arc::from(bytes);
330 let cursor = PolicyCursor::new(&data);
331 let (id_set, tail) = TypeSet::parse(cursor).unwrap();
332 assert_eq!(tail.offset(), bytes.len() as u32);
333 assert!(id_set.contains(TypeId::from_u32(1).unwrap()));
334 assert!(!id_set.contains(TypeId::from_u32(2).unwrap()));
335 assert!(id_set.contains(TypeId::from_u32(3).unwrap()));
336 assert!(id_set.contains(TypeId::from_u32(66).unwrap()));
337 }
338}