Skip to main content

selinux/new_policy/
users.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use selinux_policy_derive::{HasName, HasPolicyId, Parse, Serialize, Validate};
6
7use super::context::{MlsLevel, MlsRange};
8use super::error::{ParseError, SerializeError, ValidateError};
9use super::parser::{PolicyCursor, PolicyWriter};
10use super::traits::{Parse, PolicyId, Serialize, Validate};
11use super::{NewPolicy, RoleSet, UserId};
12
13/// Parsed SELinux user definition.
14#[derive(Debug, Validate, HasName, HasPolicyId)]
15pub struct User {
16    id: UserId,
17    name: Box<[u8]>,
18    bounds: Option<UserId>,
19    roles: RoleSet,
20    range: MlsRange,
21    default_level: MlsLevel,
22}
23
24impl User {
25    pub fn bounds(&self) -> Option<UserId> {
26        self.bounds
27    }
28
29    pub fn roles(&self) -> &RoleSet {
30        &self.roles
31    }
32
33    pub fn mls_range(&self) -> &MlsRange {
34        &self.range
35    }
36
37    #[cfg(test)]
38    pub fn default_level(&self) -> &MlsLevel {
39        &self.default_level
40    }
41}
42
43#[derive(Parse, Serialize)]
44struct BinaryUserMetadata {
45    key_length: u32,
46    id: UserId,
47    bounds: Option<UserId>,
48}
49
50impl Parse for User {
51    fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
52        let metadata = BinaryUserMetadata::parse(cursor)?;
53        let name = Box::from(cursor.read_bytes(metadata.key_length as usize)?);
54        let roles = RoleSet::parse(cursor)?;
55        let range = MlsRange::parse(cursor)?;
56        let default_level = MlsLevel::parse(cursor)?;
57
58        Ok(Self { id: metadata.id, name, bounds: metadata.bounds, roles, range, default_level })
59    }
60}
61
62impl Serialize for User {
63    fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
64        let metadata = BinaryUserMetadata {
65            key_length: self.name.len() as u32,
66            id: self.id,
67            bounds: self.bounds,
68        };
69        metadata.serialize(writer)?;
70        writer.write_bytes(&self.name);
71        self.roles.serialize(writer)?;
72        self.range.serialize(writer)?;
73        self.default_level.serialize(writer)?;
74        Ok(())
75    }
76}
77
78impl Validate for UserId {
79    fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
80        policy
81            .users()
82            .get_by_id(*self)
83            .map(|_| ())
84            .ok_or_else(|| ValidateError::UnknownId { kind: "user", id: self.as_u32() })
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91    use crate::new_policy::metadata::PolicyVersion;
92    use crate::new_policy::traits::{HasName, HasPolicyId};
93
94    #[test]
95    fn test_user_parse_and_serialize() {
96        let data = [
97            // BinaryUserMetadata
98            4, 0, 0, 0, // key_length = 4
99            1, 0, 0, 0, // id = 1
100            0, 0, 0, 0, // bounds = 0 (None)
101            // name: "test"
102            b't', b'e', b's', b't', // roles (empty RoleSet)
103            64, 0, 0, 0, // map_item_size_bits = 64
104            0, 0, 0, 0, // high_bit = 0
105            0, 0, 0, 0, // count = 0
106            // range (MlsRange with low level only)
107            1, 0, 0, 0, // count = 1
108            1, 0, 0, 0, // sensitivity_low = 1
109            // low_categories (empty CategorySet)
110            64, 0, 0, 0, // map_item_size_bits = 64
111            0, 0, 0, 0, // high_bit = 0
112            0, 0, 0, 0, // count = 0
113            // default_level (MlsLevel)
114            1, 0, 0, 0, // sensitivity = 1
115            // categories (empty CategorySet)
116            64, 0, 0, 0, // map_item_size_bits = 64
117            0, 0, 0, 0, // high_bit = 0
118            0, 0, 0, 0, // count = 0
119        ];
120        let mut cursor = PolicyCursor::new(&data);
121        let user = User::parse(&mut cursor).unwrap();
122        assert_eq!(user.id(), UserId::from_u32(1).unwrap());
123        assert_eq!(user.name(), b"test");
124        assert!(user.bounds().is_none());
125        assert!(user.roles().is_empty());
126        assert_eq!(user.mls_range().low().sensitivity().as_u32(), 1);
127        assert_eq!(user.default_level().sensitivity().as_u32(), 1);
128
129        let mut writer = Vec::new();
130        let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
131        user.serialize(&mut policy_writer).unwrap();
132        assert_eq!(writer, data);
133    }
134}