Keystore 2.0: Refactor permissions. 2/5
Move implement_permission macro to libkeystore2_selinux.
Test: keystore2_test
Bug: 203555519
Change-Id: I85d2411872aecaaa12876f848e9205431a8b0fa4
diff --git a/keystore2/selinux/src/lib.rs b/keystore2/selinux/src/lib.rs
index 902e9a4..aeb0e15 100644
--- a/keystore2/selinux/src/lib.rs
+++ b/keystore2/selinux/src/lib.rs
@@ -333,6 +333,241 @@
}
}
+/// This macro implements an enum with values mapped to SELinux permission names.
+/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
+/// * From<i32> and Into<i32> are implemented. Where the implementation of From maps
+/// any variant not specified to the default.
+/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
+/// representation.
+/// * `MyPermission::to_selinux(&self)` returns the SELinux string representation of the
+/// corresponding permission.
+/// * An implicit default values `MyPermission::None` is created with a numeric representation
+/// of `0` and a string representation of `"none"`.
+/// * Specifying a value is optional. If the value is omitted it is set to the value of the
+/// previous variant left shifted by 1.
+///
+/// ## Example
+/// ```
+/// implement_permission!(
+/// /// MyPermission documentation.
+/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+/// pub enum MyPermission {
+/// #[selinux(name = foo)]
+/// Foo = 1,
+/// #[selinux(name = bar)]
+/// Bar = 2,
+/// #[selinux(name = snafu)]
+/// Snafu, // Implicit value: MyPermission::Bar << 1 = 4
+/// }
+/// );
+/// ```
+#[macro_export]
+macro_rules! implement_permission {
+ (
+ $(#[$enum_meta:meta])*
+ $enum_vis:vis enum $enum_name:ident {
+ $(
+ $(#[$($emeta:tt)+])*
+ $vname:ident$( = $vval:tt)?
+ ),* $(,)?
+ }
+ ) => {
+ implement_permission!{
+ @extract_attr
+ $(#[$enum_meta])*
+ $enum_vis enum $enum_name {
+ 1
+ []
+ [$(
+ [] [$(#[$($emeta)+])*]
+ $vname$( = $vval)?,
+ )*]
+ }
+ }
+ };
+
+ (
+ @extract_attr
+ $(#[$enum_meta:meta])*
+ $enum_vis:vis enum $enum_name:ident {
+ $next_val:tt
+ [$($out:tt)*]
+ [
+ [$(#[$mout:meta])*]
+ [
+ #[selinux(name = $selinux_name:ident)]
+ $(#[$($mtail:tt)+])*
+ ]
+ $vname:ident = $vval:tt,
+ $($tail:tt)*
+ ]
+ }
+ ) => {
+ implement_permission!{
+ @extract_attr
+ $(#[$enum_meta])*
+ $enum_vis enum $enum_name {
+ ($vval << 1)
+ [
+ $($out)*
+ $(#[$mout])*
+ $(#[$($mtail)+])*
+ $selinux_name $vname = $vval,
+ ]
+ [$($tail)*]
+ }
+ }
+ };
+
+ (
+ @extract_attr
+ $(#[$enum_meta:meta])*
+ $enum_vis:vis enum $enum_name:ident {
+ $next_val:tt
+ [$($out:tt)*]
+ [
+ [$(#[$mout:meta])*]
+ [
+ #[selinux(name = $selinux_name:ident)]
+ $(#[$($mtail:tt)+])*
+ ]
+ $vname:ident,
+ $($tail:tt)*
+ ]
+ }
+ ) => {
+ implement_permission!{
+ @extract_attr
+ $(#[$enum_meta])*
+ $enum_vis enum $enum_name {
+ ($next_val << 1)
+ [
+ $($out)*
+ $(#[$mout])*
+ $(#[$($mtail)+])*
+ $selinux_name $vname = $next_val,
+ ]
+ [$($tail)*]
+ }
+ }
+ };
+
+
+ (
+ @extract_attr
+ $(#[$enum_meta:meta])*
+ $enum_vis:vis enum $enum_name:ident {
+ $next_val:tt
+ [$($out:tt)*]
+ [
+ [$(#[$mout:meta])*]
+ [
+ #[$front:meta]
+ $(#[$($mtail:tt)+])*
+ ]
+ $vname:ident$( = $vval:tt)?,
+ $($tail:tt)*
+ ]
+ }
+ ) => {
+ implement_permission!{
+ @extract_attr
+ $(#[$enum_meta])*
+ $enum_vis enum $enum_name {
+ $next_val
+ [$($out)*]
+ [
+ [
+ $(#[$mout])*
+ #[$front]
+ ]
+ [$(#[$($mtail)+])*]
+ $vname$( = $vval)?,
+ $($tail)*
+ ]
+ }
+ }
+ };
+
+ (
+ @extract_attr
+ $(#[$enum_meta:meta])*
+ $enum_vis:vis enum $enum_name:ident {
+ $next_val:tt
+ [$($out:tt)*]
+ []
+ }
+ ) => {
+ implement_permission!{
+ @spill
+ $(#[$enum_meta])*
+ $enum_vis enum $enum_name {
+ $($out)*
+ }
+ }
+ };
+
+ (
+ @spill
+ $(#[$enum_meta:meta])*
+ $enum_vis:vis enum $enum_name:ident {
+ $(
+ $(#[$emeta:meta])*
+ $selinux_name:ident $vname:ident = $vval:tt,
+ )*
+ }
+ ) => {
+ $(#[$enum_meta])*
+ $enum_vis enum $enum_name {
+ /// The default variant of an enum.
+ None = 0,
+ $(
+ $(#[$emeta])*
+ $vname = $vval,
+ )*
+ }
+
+ impl From<i32> for $enum_name {
+ #[allow(non_upper_case_globals)]
+ fn from (p: i32) -> Self {
+ // Creating constants forces the compiler to evaluate the value expressions
+ // so that they can be used in the match statement below.
+ $(const $vname: i32 = $vval;)*
+ match p {
+ 0 => Self::None,
+ $($vname => Self::$vname,)*
+ _ => Self::None,
+ }
+ }
+ }
+
+ impl From<$enum_name> for i32 {
+ fn from(p: $enum_name) -> i32 {
+ p as i32
+ }
+ }
+
+ impl $enum_name {
+
+ /// Returns a string representation of the permission as required by
+ /// `selinux::check_access`.
+ pub fn to_selinux(self) -> &'static str {
+ match self {
+ Self::None => &"none",
+ $(Self::$vname => stringify!($selinux_name),)*
+ }
+ }
+
+ /// Creates an instance representing a permission with the same name.
+ pub const fn none() -> Self { Self::None }
+ $(
+ /// Creates an instance representing a permission with the same name.
+ pub const fn $selinux_name() -> Self { Self::$vname }
+ )*
+ }
+ };
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 97b241f..fad5636 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -18,23 +18,18 @@
//! It also provides KeystorePerm and KeyPerm as convenience wrappers for the SELinux permission
//! defined by keystore2 and keystore2_key respectively.
+use crate::error::Error as KsError;
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
};
-
+use anyhow::Context as AnyhowContext;
+use keystore2_selinux as selinux;
+use lazy_static::lazy_static;
+use selinux::{implement_permission, Backend};
use std::cmp::PartialEq;
use std::convert::From;
use std::ffi::CStr;
-use crate::error::Error as KsError;
-use keystore2_selinux as selinux;
-
-use anyhow::Context as AnyhowContext;
-
-use selinux::Backend;
-
-use lazy_static::lazy_static;
-
// Replace getcon with a mock in the test situation
#[cfg(not(test))]
use selinux::getcon;
@@ -206,240 +201,6 @@
}
);
-/// This macro implements an enum with values mapped to SELinux permission names.
-/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
-/// * From<i32> and Into<i32> are implemented. Where the implementation of From maps
-/// any variant not specified to the default.
-/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
-/// representation.
-/// * `MyPermission::to_selinux(&self)` returns the SELinux string representation of the
-/// corresponding permission.
-/// * An implicit default values `MyPermission::None` is created with a numeric representation
-/// of `0` and a string representation of `"none"`.
-/// * Specifying a value is optional. If the value is omitted it is set to the value of the
-/// previous variant left shifted by 1.
-///
-/// ## Example
-/// ```
-/// implement_permission!(
-/// /// MyPermission documentation.
-/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
-/// pub enum MyPermission {
-/// #[selinux(name = foo)]
-/// Foo = 1,
-/// #[selinux(name = bar)]
-/// Bar = 2,
-/// #[selinux(name = snafu)]
-/// Snafu, // Implicit value: MyPermission::Bar << 1 = 4
-/// }
-/// );
-/// ```
-macro_rules! implement_permission {
- (
- $(#[$enum_meta:meta])*
- $enum_vis:vis enum $enum_name:ident {
- $(
- $(#[$($emeta:tt)+])*
- $vname:ident$( = $vval:tt)?
- ),* $(,)?
- }
- ) => {
- implement_permission!{
- @extract_attr
- $(#[$enum_meta])*
- $enum_vis enum $enum_name {
- 1
- []
- [$(
- [] [$(#[$($emeta)+])*]
- $vname$( = $vval)?,
- )*]
- }
- }
- };
-
- (
- @extract_attr
- $(#[$enum_meta:meta])*
- $enum_vis:vis enum $enum_name:ident {
- $next_val:tt
- [$($out:tt)*]
- [
- [$(#[$mout:meta])*]
- [
- #[selinux(name = $selinux_name:ident)]
- $(#[$($mtail:tt)+])*
- ]
- $vname:ident = $vval:tt,
- $($tail:tt)*
- ]
- }
- ) => {
- implement_permission!{
- @extract_attr
- $(#[$enum_meta])*
- $enum_vis enum $enum_name {
- ($vval << 1)
- [
- $($out)*
- $(#[$mout])*
- $(#[$($mtail)+])*
- $selinux_name $vname = $vval,
- ]
- [$($tail)*]
- }
- }
- };
-
- (
- @extract_attr
- $(#[$enum_meta:meta])*
- $enum_vis:vis enum $enum_name:ident {
- $next_val:tt
- [$($out:tt)*]
- [
- [$(#[$mout:meta])*]
- [
- #[selinux(name = $selinux_name:ident)]
- $(#[$($mtail:tt)+])*
- ]
- $vname:ident,
- $($tail:tt)*
- ]
- }
- ) => {
- implement_permission!{
- @extract_attr
- $(#[$enum_meta])*
- $enum_vis enum $enum_name {
- ($next_val << 1)
- [
- $($out)*
- $(#[$mout])*
- $(#[$($mtail)+])*
- $selinux_name $vname = $next_val,
- ]
- [$($tail)*]
- }
- }
- };
-
-
- (
- @extract_attr
- $(#[$enum_meta:meta])*
- $enum_vis:vis enum $enum_name:ident {
- $next_val:tt
- [$($out:tt)*]
- [
- [$(#[$mout:meta])*]
- [
- #[$front:meta]
- $(#[$($mtail:tt)+])*
- ]
- $vname:ident$( = $vval:tt)?,
- $($tail:tt)*
- ]
- }
- ) => {
- implement_permission!{
- @extract_attr
- $(#[$enum_meta])*
- $enum_vis enum $enum_name {
- $next_val
- [$($out)*]
- [
- [
- $(#[$mout])*
- #[$front]
- ]
- [$(#[$($mtail)+])*]
- $vname$( = $vval)?,
- $($tail)*
- ]
- }
- }
- };
-
- (
- @extract_attr
- $(#[$enum_meta:meta])*
- $enum_vis:vis enum $enum_name:ident {
- $next_val:tt
- [$($out:tt)*]
- []
- }
- ) => {
- implement_permission!{
- @spill
- $(#[$enum_meta])*
- $enum_vis enum $enum_name {
- $($out)*
- }
- }
- };
-
- (
- @spill
- $(#[$enum_meta:meta])*
- $enum_vis:vis enum $enum_name:ident {
- $(
- $(#[$emeta:meta])*
- $selinux_name:ident $vname:ident = $vval:tt,
- )*
- }
- ) => {
- $(#[$enum_meta])*
- $enum_vis enum $enum_name {
- /// The default variant of an enum.
- None = 0,
- $(
- $(#[$emeta])*
- $vname = $vval,
- )*
- }
-
- impl From<i32> for $enum_name {
- #[allow(non_upper_case_globals)]
- fn from (p: i32) -> Self {
- // Creating constants forces the compiler to evaluate the value expressions
- // so that they can be used in the match statement below.
- $(const $vname: i32 = $vval;)*
- match p {
- 0 => Self::None,
- $($vname => Self::$vname,)*
- _ => Self::None,
- }
- }
- }
-
- impl From<$enum_name> for i32 {
- fn from(p: $enum_name) -> i32 {
- p as i32
- }
- }
-
- impl $enum_name {
-
- /// Returns a string representation of the permission as required by
- /// `selinux::check_access`.
- pub fn to_selinux(self) -> &'static str {
- match self {
- Self::None => &"none",
- $(Self::$vname => stringify!($selinux_name),)*
- }
- }
-
- /// Creates an instance representing a permission with the same name.
- pub const fn none() -> Self { Self::None }
- $(
- /// Creates an instance representing a permission with the same name.
- pub const fn $selinux_name() -> Self { Self::$vname }
- )*
- }
- };
-}
-
implement_permission!(
/// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
/// Using the implement_permission macro we get the same features as `KeyPerm`.