1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::{
    extensible_bitmap::{MAP_NODE_BITS, MAX_BITMAP_ITEMS},
    metadata::{
        CONFIG_HANDLE_UNKNOWN_MASK, CONFIG_MLS_FLAG, POLICYDB_SIGNATURE,
        POLICYDB_STRING_MAX_LENGTH, POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN, SELINUX_MAGIC,
    },
    security_context::SecurityLevel,
    symbols::{ClassDefault, ClassDefaultRange},
    RoleId, SecurityContext, SecurityContextError, TypeId, UserId,
};

use selinux_common as sc;
use thiserror::Error;

/// Structured errors that may be encountered parsing a binary policy.
#[derive(Clone, Debug, Error, PartialEq)]
pub enum ParseError {
    #[error("expected MLS-enabled flag ({CONFIG_MLS_FLAG:#032b}), but found {found_config:#032b}")]
    ConfigMissingMlsFlag { found_config: u32 },
    #[error("expected handle-unknown config at most 1 bit set (mask {CONFIG_HANDLE_UNKNOWN_MASK:#032b}), but found {masked_bits:#032b}")]
    InvalidHandleUnknownConfigurationBits { masked_bits: u32 },
    #[error("expected end of policy, but found {num_bytes} additional bytes")]
    TrailingBytes { num_bytes: usize },
    #[error("expected data item of type {type_name} ({type_size} bytes), but found {num_bytes}")]
    MissingData { type_name: &'static str, type_size: usize, num_bytes: usize },
    #[error("expected {num_items} data item(s) of type {type_name} ({type_size} bytes), but found {num_bytes}")]
    MissingSliceData {
        type_name: &'static str,
        type_size: usize,
        num_items: usize,
        num_bytes: usize,
    },
    #[error("required parsing routine not implemented")]
    NotImplemented,
}

/// Structured errors that may be encountered validating a binary policy.
#[derive(Debug, Error, PartialEq)]
pub enum ValidateError {
    #[error("expected selinux magic value {SELINUX_MAGIC:#x}, but found {found_magic:#x}")]
    InvalidMagic { found_magic: u32 },
    #[error("expected signature length in range [0, {POLICYDB_STRING_MAX_LENGTH}], but found {found_length}")]
    InvalidSignatureLength { found_length: u32 },
    #[error("expected signature {POLICYDB_SIGNATURE:?}, but found {:?}", bstr::BStr::new(found_signature.as_slice()))]
    InvalidSignature { found_signature: Vec<u8> },
    #[error("expected policy version in range [{POLICYDB_VERSION_MIN}, {POLICYDB_VERSION_MAX}], but found {found_policy_version}")]
    InvalidPolicyVersion { found_policy_version: u32 },
    #[error("expected extensible bitmap item size to be exactly {MAP_NODE_BITS}, but found {found_size}")]
    InvalidExtensibleBitmapItemSize { found_size: u32 },
    #[error("expected extensible bitmap item high bit to be multiple of {found_size}, but found {found_high_bit}")]
    MisalignedExtensibleBitmapHighBit { found_size: u32, found_high_bit: u32 },
    #[error("expected extensible bitmap item high bit to be at most items_count + items_size = {found_count} + {found_size}, but found {found_high_bit}")]
    InvalidExtensibleBitmapHighBit { found_size: u32, found_high_bit: u32, found_count: u32 },
    #[error("expected extensible bitmap item count to be in range [0, {MAX_BITMAP_ITEMS}], but found {found_count}")]
    InvalidExtensibleBitmapCount { found_count: u32 },
    #[error("found extensible bitmap item count = 0, but high count != 0")]
    ExtensibleBitmapNonZeroHighBitAndZeroCount,
    #[error("expected extensible bitmap item start bit to be multiple of item size {found_size}, but found {found_start_bit}")]
    MisalignedExtensibleBitmapItemStartBit { found_start_bit: u32, found_size: u32 },
    #[error("expected extensible bitmap items to be in sorted order, but found item starting at {found_start_bit} after item that ends at {min_start}")]
    OutOfOrderExtensibleBitmapItems { found_start_bit: u32, min_start: u32 },
    #[error("expected extensible bitmap items to refer to bits in range [0, {found_high_bit}), but found item that ends at {found_items_end}")]
    ExtensibleBitmapItemOverflow { found_items_end: u32, found_high_bit: u32 },
    #[error(
        "expected class default binary value to be one of {}, {}, or {}, but found {value}",
        ClassDefault::DEFAULT_UNSPECIFIED,
        ClassDefault::DEFAULT_SOURCE,
        ClassDefault::DEFAULT_TARGET
    )]
    InvalidClassDefault { value: u32 },
    #[error(
        "expected class default binary value to be one of {:?}, but found {value}",
        [ClassDefaultRange::DEFAULT_UNSPECIFIED,
        ClassDefaultRange::DEFAULT_SOURCE_LOW,
        ClassDefaultRange::DEFAULT_SOURCE_HIGH,
        ClassDefaultRange::DEFAULT_SOURCE_LOW_HIGH,
        ClassDefaultRange::DEFAULT_TARGET_LOW,
        ClassDefaultRange::DEFAULT_TARGET_HIGH,
        ClassDefaultRange::DEFAULT_TARGET_LOW_HIGH,
        ClassDefaultRange::DEFAULT_UNKNOWN_USED_VALUE]
    )]
    InvalidClassDefaultRange { value: u32 },
    #[error("missing initial SID {initial_sid:?}")]
    MissingInitialSid { initial_sid: sc::InitialSid },
    #[error("non-optional Id field is zero")]
    NonOptionalIdIsZero,
    #[error("required validation routine not implemented")]
    NotImplemented,
}

/// Structured errors that may be encountered querying a binary policy.
#[derive(Debug, Error, PartialEq)]
pub enum QueryError {
    #[error("the class {class_name:?} does not exist")]
    UnknownClass { class_name: String },
    #[error("the permission {permission_name:?} does not exist for class {class_name:?}")]
    UnknownPermission { class_name: String, permission_name: String },
    #[error("the source type {source_type_name:?} does not exist")]
    UnknownSourceType { source_type_name: String },
    #[error("the target type {target_type_name:?} does not exist")]
    UnknownTargetType { target_type_name: String },
}

/// Structured errors that may be encountered computing new security contexts based on a binary
/// policy.
#[derive(Debug, Error, PartialEq)]
pub enum NewSecurityContextError {
    #[error(
        r#"role transition declared in policy, but not allowed by policy:
source security context: {source_security_context:#?}
target security context: {target_security_context:#?}
source role: {source_role:?}
new role: {new_role:?}"#
    )]
    RoleTransitionNotAllowed {
        source_security_context: SecurityContext,
        target_security_context: SecurityContext,
        source_role: String,
        new_role: String,
    },
    #[error(
        r#"failed to parse security context computed for new object:
source security context: {source_security_context:#?}
target security context: {target_security_context:#?}
computed user: {computed_user:?}
computed role: {computed_role:?}
computed user: {computed_type:?}
computed low level: {computed_low_level:?}
computed high level: {computed_high_level:?}
parsing error: {error:?}"#
    )]
    MalformedComputedSecurityContext {
        source_security_context: SecurityContext,
        target_security_context: SecurityContext,
        computed_user: UserId,
        computed_role: RoleId,
        computed_type: TypeId,
        computed_low_level: SecurityLevel,
        computed_high_level: Option<SecurityLevel>,
        error: SecurityContextError,
    },
}