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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Capabilities for specifying capsule access to network resources
//!
//! A network capability specifies (1) with what IP addresses the holder of the
//! capability may communicate, (2) from which UDP ports the holder may send,
//! and (3) to which UDP ports the holder may send. In order to express various
//! ranges of IP addresses, one uses the AddrRange enum. One specifies ranges of
//! ports using the PortRange enum.
//!
//! Capsules must obtain static references to network capabilities from trusted
//! code (i.e. code that must use the unsafe keyword) since the constructor of
//! a network capability requires the NetworkCapabilityCreationCapability capability. Code that
//! checks these capabilities must possess the appropriate visibilty privileges.
//! UDP visibility privileges are given through the UdpVisibilityCapability capability and IP
//! visibility privileges are given through the IpVisibilityCapability capability.
//!
//! An example of the visibility capabilities can be found in udp_port_table.rs.
//! When attempting to bind to a port, we must first verify that the caller of
//! bind has a capability to send from that port. Therefore, we check the
//! network capability of the caller. In order to check the UDP-specific aspect
//! of the network capability, the port table must posses a UdpVisibilityCapability reference.
use crate::net::ipv6::ip_utils::IPAddr;
const MAX_ADDR_SET_SIZE: usize = 8;
const MAX_PORT_SET_SIZE: usize = 8;
use kernel::capabilities::NetworkCapabilityCreationCapability;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AddrRange {
Any, // Any address
NoAddrs,
AddrSet([IPAddr; MAX_ADDR_SET_SIZE]),
Addr(IPAddr),
Subnet(IPAddr, usize), // address, prefix length (max 128)
}
impl AddrRange {
pub fn is_addr_valid(&self, addr: IPAddr) -> bool {
match self {
AddrRange::Any => true,
AddrRange::NoAddrs => false,
AddrRange::AddrSet(allowed_addrs) => allowed_addrs.iter().any(|&a| a == addr),
AddrRange::Addr(allowed_addr) => addr == *allowed_addr, //TODO: refs?
AddrRange::Subnet(allowed_addr, prefix_len) => {
let full_bytes: usize = prefix_len / 8;
let remainder_bits: usize = prefix_len % 8;
// initial bytes -- TODO: edge case
if allowed_addr.0[0..full_bytes] != addr.0[0..full_bytes] {
false
} else if remainder_bits == 0 {
true //this case is necessary bc right shifting a u8 by 8 bits is UB
} else {
addr.0[full_bytes] >> (8 - remainder_bits)
== allowed_addr.0[full_bytes] >> (8 - remainder_bits)
}
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PortRange {
Any,
NoPorts,
PortSet([u16; MAX_PORT_SET_SIZE]),
Range(u16, u16),
Port(u16),
}
impl PortRange {
pub fn is_port_valid(&self, port: u16) -> bool {
match self {
PortRange::Any => true,
PortRange::NoPorts => false,
PortRange::PortSet(allowed_ports) => allowed_ports.iter().any(|&p| p == port), // TODO: check refs
PortRange::Range(low, high) => *low <= port && port <= *high,
PortRange::Port(allowed_port) => port == *allowed_port,
}
}
}
/// The UdpVisibilityCapability and IpVisibilityCapability has an empty private
/// field to make it so the only way to create these structs is via a call to
/// `new` which requires a NetworkCapabilityCreationCapability.
pub struct UdpVisibilityCapability {
_priv: (), // an empty private field
}
pub struct IpVisibilityCapability {
_priv: (), // an empty private field
}
impl UdpVisibilityCapability {
pub fn new(
_create_net_cap: &dyn NetworkCapabilityCreationCapability,
) -> UdpVisibilityCapability {
UdpVisibilityCapability { _priv: () }
}
}
impl IpVisibilityCapability {
pub fn new(
_create_net_cap: &dyn NetworkCapabilityCreationCapability,
) -> IpVisibilityCapability {
IpVisibilityCapability { _priv: () }
}
}
/// The NetworkCapability specifies access to network resourcess across the UDP
/// and IP layers. Access to layer-specific information is mediated by the
/// UdpVsibilityCapability and the IpVisibilityCapability.
pub struct NetworkCapability {
// can potentially add more
remote_addrs: AddrRange, // IP addresses with which the holder may communicate
remote_ports: PortRange, // ports to which the holder may send
local_ports: PortRange, // ports from which the holder may send
}
impl NetworkCapability {
pub fn new(
remote_addrs: AddrRange,
remote_ports: PortRange,
local_ports: PortRange,
_create_net_cap: &dyn NetworkCapabilityCreationCapability,
) -> NetworkCapability {
NetworkCapability {
remote_addrs,
remote_ports,
local_ports,
}
}
pub fn get_range(&self, _ip_cap: &'static IpVisibilityCapability) -> AddrRange {
self.remote_addrs
}
pub fn remote_addr_valid(
&self,
remote_addr: IPAddr,
_ip_cap: &'static IpVisibilityCapability,
) -> bool {
self.remote_addrs.is_addr_valid(remote_addr)
}
pub fn get_remote_ports(&self, _udp_cap: &'static UdpVisibilityCapability) -> PortRange {
self.remote_ports
}
pub fn get_local_ports(&self, _udp_cap: &'static UdpVisibilityCapability) -> PortRange {
self.local_ports
}
pub fn remote_port_valid(
&self,
remote_port: u16,
_udp_cap: &'static UdpVisibilityCapability,
) -> bool {
self.remote_ports.is_port_valid(remote_port)
}
pub fn local_port_valid(
&self,
local_port: u16,
_udp_cap: &'static UdpVisibilityCapability,
) -> bool {
self.local_ports.is_port_valid(local_port)
}
}