1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
45//! Capabilities for specifying capsule access to network resources
6//!
7//! A network capability specifies (1) with what IP addresses the holder of the
8//! capability may communicate, (2) from which UDP ports the holder may send,
9//! and (3) to which UDP ports the holder may send. In order to express various
10//! ranges of IP addresses, one uses the AddrRange enum. One specifies ranges of
11//! ports using the PortRange enum.
12//!
13//! Capsules must obtain static references to network capabilities from trusted
14//! code (i.e. code that must use the unsafe keyword) since the constructor of
15//! a network capability requires the NetworkCapabilityCreationCapability capability. Code that
16//! checks these capabilities must possess the appropriate visibilty privileges.
17//! UDP visibility privileges are given through the UdpVisibilityCapability capability and IP
18//! visibility privileges are given through the IpVisibilityCapability capability.
19//!
20//! An example of the visibility capabilities can be found in udp_port_table.rs.
21//! When attempting to bind to a port, we must first verify that the caller of
22//! bind has a capability to send from that port. Therefore, we check the
23//! network capability of the caller. In order to check the UDP-specific aspect
24//! of the network capability, the port table must posses a UdpVisibilityCapability reference.
25use crate::net::ipv6::ip_utils::IPAddr;
2627const MAX_ADDR_SET_SIZE: usize = 8;
28const MAX_PORT_SET_SIZE: usize = 8;
2930use kernel::capabilities::NetworkCapabilityCreationCapability;
3132#[derive(Debug, Clone, Copy, PartialEq)]
33pub enum AddrRange {
34 Any, // Any address
35NoAddrs,
36 AddrSet([IPAddr; MAX_ADDR_SET_SIZE]),
37 Addr(IPAddr),
38 Subnet(IPAddr, usize), // address, prefix length (max 128)
39}
4041impl AddrRange {
42pub fn is_addr_valid(&self, addr: IPAddr) -> bool {
43match self {
44 AddrRange::Any => true,
45 AddrRange::NoAddrs => false,
46 AddrRange::AddrSet(allowed_addrs) => allowed_addrs.contains(&addr),
47 AddrRange::Addr(allowed_addr) => addr == *allowed_addr, //TODO: refs?
48AddrRange::Subnet(allowed_addr, prefix_len) => {
49let full_bytes: usize = prefix_len / 8;
50let remainder_bits: usize = prefix_len % 8;
51// initial bytes -- TODO: edge case
52if allowed_addr.0[0..full_bytes] != addr.0[0..full_bytes] {
53false
54} else if remainder_bits == 0 {
55true //this case is necessary bc right shifting a u8 by 8 bits is UB
56} else {
57 addr.0[full_bytes] >> (8 - remainder_bits)
58 == allowed_addr.0[full_bytes] >> (8 - remainder_bits)
59 }
60 }
61 }
62 }
63}
6465#[derive(Debug, Clone, Copy, PartialEq)]
66pub enum PortRange {
67 Any,
68 NoPorts,
69 PortSet([u16; MAX_PORT_SET_SIZE]),
70 Range(u16, u16),
71 Port(u16),
72}
7374impl PortRange {
75pub fn is_port_valid(&self, port: u16) -> bool {
76match self {
77 PortRange::Any => true,
78 PortRange::NoPorts => false,
79 PortRange::PortSet(allowed_ports) => allowed_ports.contains(&port), // TODO: check refs
80PortRange::Range(low, high) => *low <= port && port <= *high,
81 PortRange::Port(allowed_port) => port == *allowed_port,
82 }
83 }
84}
8586/// UDP visiblity capability.
87pub struct UdpVisibilityCapability {
88 _priv: (), // an empty private field
89}
9091/// IP visiblity capability.
92pub struct IpVisibilityCapability {
93 _priv: (), // an empty private field
94}
9596impl UdpVisibilityCapability {
97pub fn new(
98 _create_net_cap: &dyn NetworkCapabilityCreationCapability,
99 ) -> UdpVisibilityCapability {
100 UdpVisibilityCapability { _priv: () }
101 }
102}
103104impl IpVisibilityCapability {
105pub fn new(
106 _create_net_cap: &dyn NetworkCapabilityCreationCapability,
107 ) -> IpVisibilityCapability {
108 IpVisibilityCapability { _priv: () }
109 }
110}
111112/// Specifies access to network resourcess across the UDP and IP
113/// layers.
114///
115/// Access to layer-specific information is mediated by the
116/// UdpVsibilityCapability and the IpVisibilityCapability.
117pub struct NetworkCapability {
118// can potentially add more
119remote_addrs: AddrRange, // IP addresses with which the holder may communicate
120remote_ports: PortRange, // ports to which the holder may send
121local_ports: PortRange, // ports from which the holder may send
122}
123124impl NetworkCapability {
125pub fn new(
126 remote_addrs: AddrRange,
127 remote_ports: PortRange,
128 local_ports: PortRange,
129 _create_net_cap: &dyn NetworkCapabilityCreationCapability,
130 ) -> NetworkCapability {
131 NetworkCapability {
132 remote_addrs,
133 remote_ports,
134 local_ports,
135 }
136 }
137138pub fn get_range(&self, _ip_cap: &'static IpVisibilityCapability) -> AddrRange {
139self.remote_addrs
140 }
141142pub fn remote_addr_valid(
143&self,
144 remote_addr: IPAddr,
145 _ip_cap: &'static IpVisibilityCapability,
146 ) -> bool {
147self.remote_addrs.is_addr_valid(remote_addr)
148 }
149150pub fn get_remote_ports(&self, _udp_cap: &'static UdpVisibilityCapability) -> PortRange {
151self.remote_ports
152 }
153154pub fn get_local_ports(&self, _udp_cap: &'static UdpVisibilityCapability) -> PortRange {
155self.local_ports
156 }
157158pub fn remote_port_valid(
159&self,
160 remote_port: u16,
161 _udp_cap: &'static UdpVisibilityCapability,
162 ) -> bool {
163self.remote_ports.is_port_valid(remote_port)
164 }
165166pub fn local_port_valid(
167&self,
168 local_port: u16,
169 _udp_cap: &'static UdpVisibilityCapability,
170 ) -> bool {
171self.local_ports.is_port_valid(local_port)
172 }
173}