Features to support SE Linux policy file parsing
- Dominant language
- Rust
- Stars
- 2.6k
- Forks
- 179
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 29
Description
Fuchsia is [using zerocopy](https://fxrev.dev/952718) to parse SE Linux policy files. They have found it difficult to use zerocopy to achieve all of their goals. As far as I can tell, this stems from three requirements which zerocopy is not currently able to support:
- The SE Linux policy file format is a nested tree structure (see e.g. the [`ExtensibleBitmap`](https://fuchsia-review.googlesource.com/c/fuchsia/+/952718/8/src/starnix/lib/selinux_policy/src/extensible_bitmap.rs) type), and so converting from a `&[u8]` to a typed representation without copying or allocating would require producing a self-referential object.
- The SE Linux policy file format includes multiple variable-length objects stored within a single larger object, and so a typed representation would need to support this as well.
- Fuchsia wants to parse the format once and produce a parsed representation which can be stored for a long time. This requires transmuting from a type such as `Vec` into another owned representation.
At the time of writing, zerocopy is good at reasoning about the layouts of Rust types, and permits transmutation of reference-y types (`&T`, `Ref<_, T>`, etc) and of values (`T`). However:
- Since Rust supports neither self-referential types nor types with multiple unsized fields, there is no native Rust type that can be written whose layout corresponds to the layout of an SE Linux policy file.
- Zerocopy does not support transmutation of boxed values such as `Box`, `Vec`, etc.
In order to better support this use case, we would need to support the following:
- Self-referential objects
- Objects with multiple unsized fields
- Transmutation of container types: #114
It may also be worth considering a generalization of "objects with multiple unsized fields" to generally support *any* layout which does not correspond to a Rust type.
# Appendix
@angea has provided this description of SE Linux's policy file format.

## Overview
- The format is a pure sequence of structures:
- no jump, no pointer, no gap, no code.
- arrays are specified by count of element in advance.
- Most structure declaration are present in every file of this format,
even if empty. In this case, their 'count' will be just set to null,
but present.
## Basic types
All integers are Little-Endian, with no encoding.
### Integers
The default structure to store numbers is [uint32](#uint32).
Used in vast majority of fields, only a handful are 8 bit or 16 bit,
and one is 64 bit.
#### uint32
`0a 00 00 00` => 10
#### uint8
`0b` => 11
#### uint16
`0c 0d` => 513
#### uint64
`01 02 03 04 05 06 07 08` is read as the value
0x0807060504030201 (578437695752307201 in decimal)
### string
- ASCII string (typically lowercase alphanum, with some limited punctuation
(`/`, `_``)). No null terminator, no padding, no alignment, no codepage, no
encoding.
- with a fixed length as [uint32](#uint32) that is declared before in the
file, but not necessarily right before.
Ex:
`08 00 00 00 .S .E . .L .i .n .u .x` declares a length of 8
then a 8 byte string "SE Linux".
## File structure
1. Header, at offset 0
Name | Type | Notes
:-- | :-- | :--
magic | char\[4] | `F9 7C FF 8C`
*length* | [uint32](#uint32) | `8`
signature | char\[*length*] | 'SE Linux'
version | [uint32](#uint32) | in range [`30`:`33`]
configuration | [uint32](#uint32) | bitmask (*)
symbols count | [uint32](#uint32)
object context number | [uint32](#uint32)
policy capabilities | [extensible bitmap](#extensible-bitmap)
permissive bitmap | [extensible bitmap](#extensible-bitmap)
2. Symbols
1. Common symbols
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [common symbol](#common-symbol)\[*count*]
2. Classes
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [class](#class)\[*count*]
3. Roles
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [role](#role)\[*count*]
4. Types
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [type](#type)\[*count*]
5. Users
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [user](#user)\[*count*]
6. Conditional Booleans
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [conditional boolean](#conditional-boolean)\[*count*]
7. Sensitivities
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [sensitivity](#sensitivity)\[*count*]
8. Categories
Name | Type
:-- | :--
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [category](#category)\[*count*]
3. Access Vector table
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [access vector](#access-vector)\[*count*]
4. [Conditional list](#conditional-list)
5. [Role transition list](#role-transition-list)
6. [Role Allow list](#role-allow-list)
7. [Filename transition list](#filename-transition-list)
8. [Object contexts](#object-context)
1. Initial SID
2. File system
3. TCP & UDP port
4. Network interface
5. Node
6. FS use
7. IPv6 node
8. InfiniBand partition key (version 31 or later)
9. InfiniBand end port (version 31 or later)
9. Generic file systems contexts (GenFS)
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [GenFS context](#genfs-context)\[*count*]
10. Range
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [range translation](#range-translation)\[*count*]
11. Attribute map array
1. array: [extensible bitmap](#extensible-bitmap)\[Header
->Symbols[type=4].primary names count]
Notes:
- (*) `configuration`
- If bit `0` is set: MultiLevelSecurity is enabled.
- other bits are undocumented.
### Extensible bitmap
Name | Type | Notes
:-- | :--|:--
map size | [uint32](#uint32) | `0x40`
high bit | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [map item](#map-item)\[*count*]
#### Map item
Name | Type
:-- | :--
start bit | [uint32](#uint32)
map | [uint64](#uint64)
### Context
Name | Type
:-- | :--
user | [uint32](#uint32)
role | [uint32](#uint32)
type | [uint32](#uint32)
mls range | [mls range](#mls-range)
### MLS range
Name | Type | Presence
:-- | :--|:--
*count* | [uint32](#uint32)
sensitivity low | [uint32](#uint32)
sensitivity high | [uint32](#uint32) | if *count* > 1
low categories | [extensible bitmap](#extensible-bitmap) |
high categories | [extensible bitmap](#extensible-bitmap) | if *count* > 1
### GenFS context
Name | Type
:-- | :--
*length* | [uint32](#uint32)
type | char\[*length*]
*count* | [uint32](#uint32)
array | [FS context](#fs-context)\[*count*]
#### FS context
Name | Type
:-- | :--
*length* | [uint32](#uint32)
name | char\[*length*]
class | [uint32](#uint32)
context | [context](#context)
### Range translation
Name | Type
:-- | :--
source type | [uint32](#uint32)
target type | [uint32](#uint32)
target class | [uint32](#uint32)
mls range | [mls range](#mls-range)
### Object context
1. initial SID
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [initial sid](#initial-sid)\[*count*]
2. file system
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [file system](#file-system)\[*count*]
3. TCP & UDP port
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [port](#port)\[*count*]
4. network interface
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [network interface](#network-interface)\[*count*]
5. node
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [node](#node)\[*count*]
6. fs use
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [FS use](#fs-use)\[*count*]
7. IPv6 node
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [IPv6 node](#ipv6-node)\[*count*]
8. If *Header.version* >= `31`
8. InfiniBand partition key
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [InfiniBand PKEY](#infiniband-pkey)\[*count*]
9. InfiniBand end port
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [InfiniBand End Port](#infiniband-end-port)\[*count*]
*Object context count*:
- is set in the header
- should be `7` if version is `30`, `9` if `31` or higher.
#### Initial SID
Name | Type
:-- | :--
sid | [uint32](#uint32)
context | [context](#context)
#### File system
Name | Type
:-- | :--
*length* | [uint32](#uint32)
context name | char\[*length*]
context1 | [context](#context)
context2 | [context](#context)
#### Port
Name | Type
:-- | :--
protocol | [uint32](#uint32)
low port | [uint32](#uint32)
high port | [uint32](#uint32)
context | [context](#context)
#### Network interface
Name | Type
:-- | :--
*length* | [uint32](#uint32)
context name | char\[*length*]
context1 | [context](#context)
context2 | [context](#context)
#### Node
Name | Type
:-- | :--
node address | [uint32](#uint32)
node mask | [uint32](#uint32)
context | [context](#context)
#### FS use
Name | Type
:-- | :--
behavior | [uint32](#uint32)
*length* | [uint32](#uint32)
name | char\[*length*]
context | [context](#context)
#### IPv6 node
Name | Type
:-- | :--
node adresses | [uint32](#uint32)\[4]
node masks | [uint32](#uint32)\[4]
context | [context](#context)
#### InfiniBand PKEY
Name | Type
:-- | :--
low | [uint32](#uint32)
high | [uint32](#uint32)
context | [context](#context)
#### InfiniBand End Port
Name | Type
:-- | :--
*length* | [uint32](#uint32)
port | [uint32](#uint32)
name | char\[*length*]
context | [context](#context)
### Filename transition list
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [filename-transition](#filename-transition)\[*count*]
#### Filename transition
if *Header_version* < 33:
- then \[filename transition] = \[[filename transition old](#filename-transition-old)]
- else \[filename transition] = \[[filename transition new](#filename-transition-new)]
##### Filename transition old
Name | Type
:-- | :--
*length* | [uint32](#uint32)
filename | char\[*length*]
bit | [uint32](#uint32)
transition type | [uint32](#uint32)
transition class | [uint32](#uint32)
old type | [uint32](#uint32)
##### Filename transition new
Name | Type
:-- | :--
*length* | [uint32](#uint32)
filename | char\[*length*]
transition type | [uint32](#uint32)
transition class | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [ftnew item](#ftnew-item)\[*count*]
###### ftnew item
Name | Type
:-- | :--
s types | [extensible bitmap](#extensible-bitmap)
out type | [uint32](#uint32)
### Conditional list
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [conditional node](#conditional-node)\[*count*]
#### Conditional node
Name | Type
:-- | :--
state | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [node item](#node-item)\[*count*]
true list | [access vector list](#access-vector-list)
false list | [access vector list](#access-vector-list)
#### Node item
Name | Type
:-- | :--
type | [uint32](#uint32)
boolean | [uint32](#uint32)
### Access vector list
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [access vector](#access-vector)\[*count*]
#### Access vector
Name | Type
:-- | :--
source type | [uint16](#uint16)
target type | [uint16](#uint16)
class type | [uint16](#uint16)
*specified* | [uint16](#uint16)
if *specified* & 0x700:
Name | Type
:-- | :--
xperms specified | [uint8](#uint8)
xperms driver | [uint8](#uint8)
permissions | [uint32](#uint8)\[8]
else:
Name | Type
:-- | :--
data | [uint32](#uint32)
### Role transition list
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [role transition](#role-transition)\[*count*]
#### Role transition
Name | Type
:-- | :--
role | [uint32](#uint32)
type | [uint32](#uint32)
new role | [uint32](#uint32)
tclass | [uint32](#uint32)
#### Role set
Name | Type
:-- | :--
roles | [extensible bitmap](#extensible-bitmap)
flags | [uint32](#uint32)
### Role allow list
Name | Type
:-- | :--
*count* | [uint32](#uint32)
array | [role allow](#role-allow)\[*count*]
#### Role allow
Name | Type
:-- | :--
role | [uint32](#uint32)
new role | [uint32](#uint32)
### Symbols
#### Common symbol
Name | Type
:-- | :--
*length* | [uint32](#uint32)
value | [uint32](#uint32)
primary names count | [uint32](#uint32)
*count* | [uint32](#uint32)
key | char\[*length*]
permission table | [permission](#permission)\[*count*]
##### Permission
Name | Type
:-- | :--
*length* | [uint32](#uint32)
value | [uint32](#uint32)
key | char\[*length*]
#### Class
Name | Type
:-- | :--
*key length* | [uint32](#uint32)
*common key length* | [uint32](#uint32)
value | [uint32](#uint32)
primary names count | [uint32](#uint32)
*elements count* | [uint32](#uint32)
*constraint count* | [uint32](#uint32)
key | char\[*key length*]
common key | char\[*common key length*]
permission table | [permission](#permission)\[*elements count*]
constraint table | [constraint-list](#constraint-list)\[*constraint count*]
*validate transition count* | [uint32](#uint32)
validate transition rules | [constraint-list](#constraint-list)\[*validate transition count*]
default user | [uint32](#uint32)
default role | [uint32](#uint32)
default range | [uint32](#uint32)
default type | [uint32](#uint32)
##### Constraint list
Name | Type
:-- | :--
permissions | [uint32](#uint32)
*count* | [uint32](#uint32)
array | [constraint](#constraint)\[*count*]
##### Constraint
Name | Type | Presence
:-- | :--|:--
*type* | [uint32](#uint32) |
attribute | [uint32](#uint32) |
operand | [uint32](#uint32) |
names | [extensible bitmap](#extensible-bitmap) | if *type* == 5
names type set | [type set](#type-set) | if *type* == 5
##### Type set
Name | Type
:-- | :--
types | [extensible bitmap](#extensible-bitmap)
negative set | [extensible bitmap](#extensible-bitmap)
flags | [uint32](#uint32)
##### Role
Name | Type
:-- | :--
*length* | [uint32](#uint32)
value | [uint32](#uint32)
bounds | [uint32](#uint32)
key | char\[*length*]
role dominates | [extensible bitmap](#extensible-bitmap)
role types | [extensible bitmap](#extensible-bitmap)
#### Type
Name | Type
:-- | :--
*length* | [uint32](#uint32)
value | [uint32](#uint32)
properties | [uint32](#uint32)
bounds | [uint32](#uint32)
key | char\[*length*]
#### User
Name | Type
:-- | :--
*length* | [uint32](#uint32)
value | [uint32](#uint32)
bounds | [uint32](#uint32)
key | char\[*length*]
user roles | [extensible bitmap](#extensible-bitmap)
expanded range | [mls range](#mls-range)
default level | [mls level](#mls-level)
##### MLS level
Name | Type
:-- | :--
sensitivity | [uint32](#uint32)
categories | [extensible bitmap](#extensible-bitmap)
#### Conditional Boolean
Name | Type
:-- | :--
value | [uint32](#uint32)
state | [uint32](#uint32)
*length* | [uint32](#uint32)
key | char\[*length*]
#### Sensitivity
Name | Type
:-- | :--
*length* | [uint32](#uint32)
is alias | [uint32](#uint32)
key | char\[*length*]
level | [mls level](#mls-level)
#### Category
Name | Type
:-- | :--
*length* | [uint32](#uint32)
value | [uint32](#uint32)
is alias | [uint32](#uint32)
key | char\[*length*]
Contributor guide
Assessment
This issue has not been assessed yet.