blob: 2b5b73129f71d35068a2ad58eac32917cde9938c [file] [log] [blame]
// Copyright 2021 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 {
crate::{error::RightsRoutingError, walk_state::WalkStateUnit},
fidl_fuchsia_io as fio,
lazy_static::lazy_static,
std::convert::From,
};
lazy_static! {
// TODO: const initialization of bitflag types with bitwise-or is not supported in FIDL. Change
// when supported.
/// All rights corresponding to r*.
pub static ref READ_RIGHTS: fio::Operations =
fio::Operations::CONNECT
| fio::Operations::ENUMERATE
| fio::Operations::TRAVERSE
| fio::Operations::READ_BYTES
| fio::Operations::GET_ATTRIBUTES;
/// All rights corresponding to w*.
pub static ref WRITE_RIGHTS: fio::Operations =
fio::Operations::CONNECT
| fio::Operations::ENUMERATE
| fio::Operations::TRAVERSE
| fio::Operations::WRITE_BYTES
| fio::Operations::MODIFY_DIRECTORY
| fio::Operations::UPDATE_ATTRIBUTES;
/// All rights corresponding to x*.
pub static ref EXECUTE_RIGHTS: fio::Operations =
fio::Operations::CONNECT
| fio::Operations::ENUMERATE
| fio::Operations::TRAVERSE
| fio::Operations::EXECUTE;
/// All rights corresponding to rw*.
pub static ref READ_WRITE_RIGHTS: fio::Operations =
fio::Operations::CONNECT
| fio::Operations::ENUMERATE
| fio::Operations::TRAVERSE
| fio::Operations::READ_BYTES
| fio::Operations::WRITE_BYTES
| fio::Operations::MODIFY_DIRECTORY
| fio::Operations::GET_ATTRIBUTES
| fio::Operations::UPDATE_ATTRIBUTES;
/// All the fio rights required to represent fio::OpenFlags::RIGHT_READABLE.
static ref LEGACY_READABLE_RIGHTS: fio::Operations =
fio::Operations::READ_BYTES
| fio::Operations::GET_ATTRIBUTES
| fio::Operations::TRAVERSE
| fio::Operations::ENUMERATE;
/// All the fio rights required to represent fio::OpenFlags::RIGHT_WRITABLE.
static ref LEGACY_WRITABLE_RIGHTS: fio::Operations =
fio::Operations::WRITE_BYTES
| fio::Operations::UPDATE_ATTRIBUTES
| fio::Operations::MODIFY_DIRECTORY;
/// All the fio rights required to represent fio::OpenFlags::RIGHT_EXECUTABLE.
static ref LEGACY_EXECUTABLE_RIGHTS: fio::Operations = fio::Operations::EXECUTE;
}
/// Opaque rights type to define new traits like PartialOrd on.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Rights(fio::Operations);
impl Rights {
/// Converts new fuchsia.io directory rights to legacy fuchsia.io compatible rights. This will
/// be remove once new rights are supported by component manager.
pub fn into_legacy(&self) -> fio::OpenFlags {
let mut flags = fio::OpenFlags::empty();
let Self(rights) = self;
// The `intersects` below is intentional. The translation from io2 to io rights is lossy
// in the sense that a single io2 right may require an io right with coarser permissions.
if rights.intersects(*LEGACY_READABLE_RIGHTS) {
flags |= fio::OpenFlags::RIGHT_READABLE;
}
if rights.intersects(*LEGACY_WRITABLE_RIGHTS) {
flags |= fio::OpenFlags::RIGHT_WRITABLE;
}
if rights.contains(fio::Operations::EXECUTE) {
flags |= fio::OpenFlags::RIGHT_EXECUTABLE;
}
// Since there is no direct translation for connect in CV1 we must explicitly define it
// here as both flags.
//
// TODO(fxbug.dev/60673): Is this correct? ReadBytes | Connect seems like it should translate to
// READABLE | WRITABLE, not empty rights.
if flags.is_empty() && rights.contains(fio::Operations::CONNECT) {
flags |= fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE;
}
flags
}
}
/// Allows creating rights from fio::Operations.
impl From<fio::Operations> for Rights {
fn from(operations: fio::Operations) -> Self {
Rights(operations)
}
}
impl WalkStateUnit for Rights {
type Error = RightsRoutingError;
/// Ensures the next walk state of rights satisfies a monotonic increasing sequence. Used to
/// verify the expectation that no right requested from a use, offer, or expose is missing as
/// capability routing walks from the capability's consumer to its provider.
fn validate_next(&self, next_rights: &Rights) -> Result<(), Self::Error> {
if next_rights.0.contains(self.0) {
Ok(())
} else {
Err(RightsRoutingError::Invalid)
}
}
fn finalize_error() -> Self::Error {
RightsRoutingError::MissingRightsSource
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn validate_next() {
assert_matches!(
Rights::from(fio::Operations::empty())
.validate_next(&Rights::from(*LEGACY_READABLE_RIGHTS)),
Ok(())
);
assert_matches!(
Rights::from(fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES)
.validate_next(&Rights::from(*LEGACY_READABLE_RIGHTS)),
Ok(())
);
assert_matches!(
Rights::from(Rights::from(*LEGACY_READABLE_RIGHTS)).validate_next(&Rights::from(
fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES
)),
Err(RightsRoutingError::Invalid)
);
assert_matches!(
Rights::from(fio::Operations::WRITE_BYTES).validate_next(&Rights::from(
fio::Operations::READ_BYTES | fio::Operations::GET_ATTRIBUTES
)),
Err(RightsRoutingError::Invalid)
);
}
#[test]
fn into_legacy() {
assert_eq!(
Rights::from(*LEGACY_READABLE_RIGHTS).into_legacy(),
fio::OpenFlags::RIGHT_READABLE
);
assert_eq!(
Rights::from(*LEGACY_WRITABLE_RIGHTS).into_legacy(),
fio::OpenFlags::RIGHT_WRITABLE
);
assert_eq!(
Rights::from(*LEGACY_EXECUTABLE_RIGHTS).into_legacy(),
fio::OpenFlags::RIGHT_EXECUTABLE
);
assert_eq!(
Rights::from(*LEGACY_READABLE_RIGHTS | *LEGACY_WRITABLE_RIGHTS).into_legacy(),
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE
);
assert_eq!(
Rights::from(
*LEGACY_READABLE_RIGHTS | *LEGACY_WRITABLE_RIGHTS | *LEGACY_EXECUTABLE_RIGHTS
)
.into_legacy(),
fio::OpenFlags::RIGHT_READABLE
| fio::OpenFlags::RIGHT_WRITABLE
| fio::OpenFlags::RIGHT_EXECUTABLE
);
assert_eq!(
Rights::from(fio::Operations::READ_BYTES).into_legacy(),
fio::OpenFlags::RIGHT_READABLE
);
assert_eq!(
Rights::from(fio::Operations::GET_ATTRIBUTES).into_legacy(),
fio::OpenFlags::RIGHT_READABLE
);
assert_eq!(
Rights::from(fio::Operations::TRAVERSE).into_legacy(),
fio::OpenFlags::RIGHT_READABLE
);
assert_eq!(
Rights::from(fio::Operations::ENUMERATE).into_legacy(),
fio::OpenFlags::RIGHT_READABLE
);
assert_eq!(
Rights::from(fio::Operations::WRITE_BYTES).into_legacy(),
fio::OpenFlags::RIGHT_WRITABLE
);
assert_eq!(
Rights::from(fio::Operations::UPDATE_ATTRIBUTES).into_legacy(),
fio::OpenFlags::RIGHT_WRITABLE
);
assert_eq!(
Rights::from(fio::Operations::MODIFY_DIRECTORY).into_legacy(),
fio::OpenFlags::RIGHT_WRITABLE
);
}
}