pub struct XousNames { /* private fields */ }Expand description
§Xous API: names
xous-names resolves plaintext server names to 128-bit randomly
assigned server IDs. It is also the front-line gatekeeper for
restricting access to services by preventing connections or
discoverability (or more accurately, discoverability is inherently
hard because it requires brute-forcing the server ID in a 128-bit
space of randomly assigned numbers).
See the Xous Book for more details. The Xous Book should be considered normative; the specification below is historical.
§Specification
Server IDs (SIDs) are used by processes to send messages to servers. It is thus an attack surface. Furthermore, if a process can forge an SID before a server can claim it, it can “become” the server. Thus, it’s helpful to keep the SID a secret.
In Xous, an SID is a 128-bit number that, with two exceptions, is only
known to the server itself, and an oracle known as xous-name-server.
SIDs are never revealed to a process. Processes establish connections
to servers using a descriptive, human-readable string name. Since the
SIDs are random numbers, there is no way to turn the descriptive
string into the SID except by resolving it with xous-name-server.
On boot, a trusted set of processes are started which form the
operating system. These must all claim names in the name space before
any further processes are started, to prevent later processes from
claiming their names. Servers can also optionally limit the total
number of connections allowed, which effectively makes them unreachable
by less trusted code that is run after the core trusted set of processes
have started up. The trusted_init_done() libary call on the name
server will return true if all the servers that have a connection
limit have fully populated all of their connections.
The exception to random SIDs are the xous-name-server,
xous-log-server (note the trailing space), and ticktimer-server.
These are three well known names that have a defined,
fixed SID so that all processes can talk to them; xous-name-server is
necessarily well-known as it is the mechanism to resolve further
names, xous-log-server is necessary for debugging, so that bugs upstream
of name resolution can be logged. xous-name-server was picked because
name-server already has a meaning in the context of DNS. ticktimer-server
is necessary for implementing deterministic timing delays in
xous-name-server upon failure, and also for other processes to
wait a fixed period of time on initialization while the initial set
of name registrations occur.
A new process that intends to receive messages uses the register_name convenience
function in the xous-names/src/lib.rs file, with the following procedure.
-
It calls
register_namewith a preferred ASCII name string, limited to 64 characters. It also specifies how many connections the server will allow.Noneon the specifier means no limit. -
xous-name-serverreturns the borrowed memory to the server, where the buffer has been replaced with a response field. In the case that the registration is affirmed, the SID field inRegistrationcontains the assigned SID of calling process. In the case that the name is determined to be invalid (perhaps because it is already reserved or registered), it will return an error code. -
If the registration is denied, the server can attempt to re-register its SID with a different ASCII name string by repeating steps 2-3.
A process that would like to send a server a message must first request the
name server to broker a connection to the target process. It does this by
typically calling the request_conneciton_blocking convenience function
with the registered name of the server.
-
request_connection_blockingis called with the maximum 64-character ASCII name string. -
The convencience function creates a
Lookupmessage which is lent to the name server. -
xous-name-servercan respond with one of three results: A. affirm the connection by returning a connection ID B. a flat denial of the connection; or C. a slot containing a request to authenticate.
Here are the cases worked out:
A. affirming the connection: xous-name-server would use
MessageSender.pid() to extract the sender’s PID, and call
ConnectForProcess(PID,SID) on behalf of the sender. The sender can
then use the CID as the first argument to send_message(). This is
the common case, and many servers follow this path, such as those
asking for access to the ticktimer or other public services.
B. flat denial: xous-name-server simply returns a message saying the
request was denied. This is also the case when the request is malformed or incorrect.
No information shall be leaked about the
nature of the denial. Denials are also delayed to the nearest 0.1 second interval since boot
to eliminate side channels and to rate limit fuzzing requests. Some
services (such as the key server) are restricted to only a set of
trusted process loaded at boot, and therefore it should not be
discoverable.
C. request to authenticate: xous-name-server responds with success set
to false, but authenticate_request to true. The pubkey_id field
is populated with the ID of an acceptable Ed25519 public key for authentication, and
a 256-bit challenge nonce is provided in the challenge field. Authentication
consists of the requesting server proving that it has knowledge of a shared
secret, namely, an Ed25519 private key.
Upon generating the request to authenticate, xous-name-server computes
the correct response to the challenge and stores it in a table with
a timestamp.
The sending process must then sign the challenge and return an
Authenticate message, constructed similarly to the Lookup
message but with the response_to_challenge field filled out. It must
do this before AUTHENTICATE_TIMEOUT milliseconds have passed.
The server, upon receipt of an Authenticate message, merely checks
if the response_to_challenge matches any response stored in its
table, and if it does, it accepts the process as authenticated. It is
cryptographically unlikely for there to be a collision in the table;
however, this implementation is weak to an attacker potentially
stealing the response and using it. That being said, if an attacker
already has that level of control in the calling process, there
are bigger problems.
The AUTHENTICATE_TIMEOUT field is used to give xous-name-server
a chance to depopulate the response table over time, so that it
does not “leak” memory.
§Current Implementation
The current implementation is a hash map that matches randomly generated names with a list of names each server selects for itself. Currently, any request to lookup and connect to a server will succeed up to the limit of connections (if any) specified by a server, but the hooks are there to enforce permissions and deny connections, and/or request authentication for connection.
Server names are crate-local, and are bound through library functions called during the creation of server access objects. In other words, there is no global name space for servers.
Implementations§
Source§impl XousNames
impl XousNames
pub fn new() -> Result<Self, Error>
Sourcepub fn unregister_server(&self, sid: SID) -> Result<(), Error>
pub fn unregister_server(&self, sid: SID) -> Result<(), Error>
Searches the name table and removes a given SID from the table. It’s considered “secure” because you’d have to guess a random 128-bit SID to destroy someone else’s SID.
Sourcepub fn register_name(
&self,
name: &str,
max_conns: Option<u32>,
) -> Result<SID, Error>
pub fn register_name( &self, name: &str, max_conns: Option<u32>, ) -> Result<SID, Error>
Register a server with a plaintext name. When specified, xous-names will
limit the number of connections brokered to the value in max_conns. This
effectively blocks further services from connecting to the server in a
Trust-On-First-Use (TOFU) model.
Sourcepub fn request_connection_with_token(
&self,
name: &str,
) -> Result<(CID, Option<[u32; 4]>), Error>
pub fn request_connection_with_token( &self, name: &str, ) -> Result<(CID, Option<[u32; 4]>), Error>
Request a connection to the server with name. If the connection is allowed,
a 128-bit token is provided (in the form of a [u32; 4]) which can be used
later on to disconnect from the server, effectively decrementing the total
number of counts in against the max_count limit.
Sourcepub fn disconnect_with_token(
&self,
name: &str,
token: [u32; 4],
) -> Result<(), Error>
pub fn disconnect_with_token( &self, name: &str, token: [u32; 4], ) -> Result<(), Error>
Disconnects from server with name. Must provide the same token returned on
connection, or else the call will be disregarded.
Sourcepub fn request_connection(&self, name: &str) -> Result<CID, Error>
pub fn request_connection(&self, name: &str) -> Result<CID, Error>
Requests a permanent connection to server with name. Xous names brokers the
entire connection, so the return value is the process-local CID (connection ID);
the 128-bit server ID is never revealed.
This call will fail if the server has not yet started up, which is a common
problem during the boot process as the server start order is not guaranteed. Refer to
request_connection_blocking() for a call that will automatically retry.
Sourcepub fn request_connection_blocking(&self, name: &str) -> Result<CID, Error>
pub fn request_connection_blocking(&self, name: &str) -> Result<CID, Error>
Requests a permanent connection to server with name. Xous names brokers the
entire connection, so the return value is the process-local CID (connection ID);
the 128-bit server ID is never revealed.
This call uses the API already in place in libstd, hence the different style of
argument passing, and tons of unsafe code.
Sourcepub fn trusted_init_done(&self) -> Result<bool, Error>
pub fn trusted_init_done(&self) -> Result<bool, Error>
Returns true if every server that specified a max_conn count has filled
every slot available. Once all the limited slots are filled, the system has
finished TOFU initialization and can begin regular operations.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for XousNames
impl RefUnwindSafe for XousNames
impl Send for XousNames
impl Sync for XousNames
impl Unpin for XousNames
impl UnwindSafe for XousNames
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.