1use selinux_policy_derive::{Parse, Serialize, Validate};
8
9use super::classes::ClassId;
10use super::context::Context;
11use super::error::{ParseError, SerializeError};
12use super::metadata::PolicyVersion;
13use super::parser::{Array, ByteArray, PolicyCursor, PolicyWriter};
14use super::traits::{Parse, Serialize};
15
16#[derive(Debug, Clone, Parse, Serialize, Validate)]
20pub struct FilesystemContext {
21 name: ByteArray,
22 fs_context: Context,
23 root_context: Context,
24}
25
26#[derive(Debug, Clone, Parse, Serialize, Validate)]
30pub struct NetworkInterfaceContext {
31 name: ByteArray,
32 if_context: Context,
33 msg_context: Context,
34}
35
36#[derive(Debug, Clone, Parse, Serialize, Validate)]
40pub struct PortContext {
41 protocol: u32,
42 low_port: u32,
43 high_port: u32,
44 context: Context,
45}
46
47#[derive(Debug, Clone, Parse, Serialize, Validate)]
51pub struct IPv4NodeContext {
52 address: u32,
53 mask: u32,
54 context: Context,
55}
56
57#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Parse, Serialize, Validate)]
59#[policy(wire_type = u32)]
60pub enum FsUseType {
61 Xattr = 1,
62 Trans = 2,
63 Task = 3,
64}
65
66#[derive(Debug, Clone, Parse, Serialize, Validate)]
71pub struct FsUse {
72 behavior: FsUseType,
73 name: ByteArray,
74 context: Context,
75}
76
77impl FsUse {
78 pub fn behavior(&self) -> FsUseType {
80 self.behavior
81 }
82
83 pub fn fs_type(&self) -> &[u8] {
85 &self.name
86 }
87
88 pub fn context(&self) -> &Context {
90 &self.context
91 }
92}
93
94#[derive(Debug, Clone, Parse, Serialize, Validate)]
98pub struct IPv6NodeContext {
99 address: [u32; 4],
100 mask: [u32; 4],
101 context: Context,
102}
103
104#[derive(Debug, Clone, Parse, Serialize, Validate)]
108pub struct InfiniBandPartitionKey {
109 low: u32,
110 high: u32,
111 context: Context,
112}
113
114#[derive(Debug, Clone, Parse, Serialize, Validate)]
118pub struct InfiniBandEndPort {
119 name: ByteArray,
120 port: u32,
121 context: Context,
122}
123
124#[derive(Debug, Clone, Validate)]
127pub struct ObjectContexts {
128 filesystems: Array<FilesystemContext>,
129 ports: Array<PortContext>,
130 network_interfaces: Array<NetworkInterfaceContext>,
131 ipv4_nodes: Array<IPv4NodeContext>,
132 fs_uses: Array<FsUse>,
133 ipv6_nodes: Array<IPv6NodeContext>,
134 infiniband_partition_keys: Array<InfiniBandPartitionKey>,
135 infiniband_end_ports: Array<InfiniBandEndPort>,
136}
137
138impl ObjectContexts {
139 pub fn filesystems(&self) -> &[FilesystemContext] {
141 &self.filesystems
142 }
143
144 pub fn ports(&self) -> &[PortContext] {
146 &self.ports
147 }
148
149 pub fn network_interfaces(&self) -> &[NetworkInterfaceContext] {
151 &self.network_interfaces
152 }
153
154 pub fn ipv4_nodes(&self) -> &[IPv4NodeContext] {
156 &self.ipv4_nodes
157 }
158
159 pub fn fs_uses(&self) -> &[FsUse] {
161 &self.fs_uses
162 }
163
164 pub fn ipv6_nodes(&self) -> &[IPv6NodeContext] {
166 &self.ipv6_nodes
167 }
168
169 pub fn infiniband_partition_keys(&self) -> &[InfiniBandPartitionKey] {
171 &self.infiniband_partition_keys
172 }
173
174 pub fn infiniband_end_ports(&self) -> &[InfiniBandEndPort] {
176 &self.infiniband_end_ports
177 }
178}
179
180impl Parse for ObjectContexts {
181 fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
182 let filesystems = Array::<FilesystemContext>::parse(cursor)?;
183 let ports = Array::<PortContext>::parse(cursor)?;
184 let network_interfaces = Array::<NetworkInterfaceContext>::parse(cursor)?;
185 let ipv4_nodes = Array::<IPv4NodeContext>::parse(cursor)?;
186 let fs_uses = Array::<FsUse>::parse(cursor)?;
187 let ipv6_nodes = Array::<IPv6NodeContext>::parse(cursor)?;
188 let (infiniband_partition_keys, infiniband_end_ports) =
189 if cursor.policy_version() >= PolicyVersion::MIN_INFINIBAND {
190 (
191 Array::<InfiniBandPartitionKey>::parse(cursor)?,
192 Array::<InfiniBandEndPort>::parse(cursor)?,
193 )
194 } else {
195 (Array::default(), Array::default())
196 };
197
198 Ok(Self {
199 filesystems,
200 ports,
201 network_interfaces,
202 ipv4_nodes,
203 fs_uses,
204 ipv6_nodes,
205 infiniband_partition_keys,
206 infiniband_end_ports,
207 })
208 }
209}
210
211impl Serialize for ObjectContexts {
212 fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
213 self.filesystems.serialize(writer)?;
214 self.ports.serialize(writer)?;
215 self.network_interfaces.serialize(writer)?;
216 self.ipv4_nodes.serialize(writer)?;
217 self.fs_uses.serialize(writer)?;
218 self.ipv6_nodes.serialize(writer)?;
219 if writer.version() >= PolicyVersion::MIN_INFINIBAND {
220 self.infiniband_partition_keys.serialize(writer)?;
221 self.infiniband_end_ports.serialize(writer)?;
222 }
223 Ok(())
224 }
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize, Validate)]
229pub struct GenfsConPath {
230 partial_path: ByteArray,
231 class: Option<ClassId>,
232 context: Context,
233}
234
235impl GenfsConPath {
236 pub fn partial_path(&self) -> &[u8] {
238 &self.partial_path
239 }
240
241 pub fn class(&self) -> Option<ClassId> {
243 self.class
244 }
245
246 pub fn context(&self) -> &Context {
248 &self.context
249 }
250}
251
252#[derive(Debug, Clone, PartialEq, Eq, Parse, Serialize, Validate)]
254pub struct GenfsCon {
255 fs_type: ByteArray,
256 paths: Array<GenfsConPath>,
257}
258
259impl GenfsCon {
260 pub fn fs_type(&self) -> &[u8] {
262 &self.fs_type
263 }
264
265 pub fn paths(&self) -> &[GenfsConPath] {
267 &self.paths
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274 use crate::new_policy::traits::PolicyId;
275 use crate::new_policy::{NewPolicy, UserId};
276
277 #[test]
278 fn test_object_contexts_minimal_policy() {
279 let policy_bytes =
280 include_bytes!("../../testdata/composite_policies/compiled/minimal_policy");
281 let policy = NewPolicy::parse(policy_bytes).expect("parse minimal_policy");
282 policy.validate().expect("validate minimal_policy");
283
284 let object_contexts = policy.object_contexts();
285 assert!(object_contexts.filesystems().is_empty());
286 assert!(object_contexts.ports().is_empty());
287 assert!(object_contexts.network_interfaces().is_empty());
288 assert!(object_contexts.ipv4_nodes().is_empty());
289 assert!(!object_contexts.fs_uses().is_empty());
290 assert!(object_contexts.ipv6_nodes().is_empty());
291 assert!(object_contexts.infiniband_partition_keys().is_empty());
292 assert!(object_contexts.infiniband_end_ports().is_empty());
293 }
294
295 #[test]
296 fn test_genfscon_parse_and_serialize() {
297 let data = [
298 5, 0, 0, 0, b's', b'y', b's', b'f', b's', 1, 0, 0, 0, 1, 0, 0, 0, b'/', 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
313 let mut cursor = PolicyCursor::new(&data);
314 let genfscon = GenfsCon::parse(&mut cursor).expect("parse GenfsCon");
315 assert_eq!(genfscon.fs_type(), b"sysfs");
316 assert_eq!(genfscon.paths().len(), 1);
317 let path = &genfscon.paths()[0];
318 assert_eq!(path.partial_path(), b"/");
319 assert_eq!(path.class(), None);
320 assert_eq!(path.context().user(), UserId::from_u32(1).unwrap());
321
322 let mut writer = Vec::new();
323 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
324 genfscon.serialize(&mut policy_writer).expect("serialize GenfsCon");
325 assert_eq!(writer.as_slice(), &data);
326 }
327}