Merge changes from topic "custom_smcs_allowlist" into main

* changes:
  Implement permission check for VMs that request tee_services
  vm cli: add --tee_services flag
  virtmngr: get secontext of the caller app
  Add teeServices field to AppConfig & RawConfig
  Propagate RELEASE_AVF_ENABLE_VM_TO_TEE_SERVICES_ALLOWLIST to avf_build_flags_rust
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 4fb8be4..4538248 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -21,7 +21,7 @@
 use crate::debug_config::DebugConfig;
 use crate::dt_overlay::{create_device_tree_overlay, VM_DT_OVERLAY_MAX_SIZE, VM_DT_OVERLAY_PATH};
 use crate::payload::{add_microdroid_payload_images, add_microdroid_system_images, add_microdroid_vendor_image};
-use crate::selinux::{getfilecon, SeContext};
+use crate::selinux::{check_tee_service_permission, getfilecon, getprevcon, SeContext};
 use android_os_permissions_aidl::aidl::android::os::IPermissionController;
 use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::{
     Certificate::Certificate,
@@ -502,6 +502,9 @@
             check_config_allowed_for_early_vms(config)?;
         }
 
+        let caller_secontext = getprevcon().or_service_specific_exception(-1)?;
+        info!("callers secontext: {}", caller_secontext);
+
         // Allocating VM context checks the MANAGE_VIRTUAL_MACHINE permission.
         let (vm_context, cid, temporary_directory) = if cfg!(early) {
             self.create_early_vm_context(config)?
@@ -564,6 +567,10 @@
         let config = config.as_ref();
         *is_protected = config.protectedVm;
 
+        check_tee_service_permission(&caller_secontext, &config.teeServices)
+            .with_log()
+            .or_binder_exception(ExceptionCode::SECURITY)?;
+
         // Check if partition images are labeled incorrectly. This is to prevent random images
         // which are not protected by the Android Verified Boot (e.g. bits downloaded by apps) from
         // being loaded in a pVM. This applies to everything but the instance image in the raw
@@ -1158,6 +1165,8 @@
         for param in custom_config.extraKernelCmdlineParams.iter() {
             append_kernel_param(param, &mut vm_config);
         }
+
+        vm_config.teeServices.clone_from(&custom_config.teeServices);
     }
 
     // Unfortunately specifying page_shift = 14 in bootconfig doesn't enable 16k pages emulation,
@@ -1775,6 +1784,26 @@
     Ok(())
 }
 
+fn check_no_tee_services(config: &VirtualMachineConfig) -> binder::Result<()> {
+    match config {
+        VirtualMachineConfig::RawConfig(config) => {
+            if !config.teeServices.is_empty() {
+                return Err(anyhow!("tee_services_allowlist feature is disabled"))
+                    .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+            }
+        }
+        VirtualMachineConfig::AppConfig(config) => {
+            if let Some(custom_config) = &config.customConfig {
+                if !custom_config.teeServices.is_empty() {
+                    return Err(anyhow!("tee_services_allowlist feature is disabled"))
+                        .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+                }
+            }
+        }
+    };
+    Ok(())
+}
+
 fn check_protected_vm_is_supported() -> binder::Result<()> {
     let is_pvm_supported =
         hypervisor_props::is_protected_vm_supported().or_service_specific_exception(-1)?;
@@ -1799,6 +1828,9 @@
     if !cfg!(debuggable_vms_improvements) {
         check_no_extra_kernel_cmdline_params(config)?;
     }
+    if !cfg!(tee_services_allowlist) {
+        check_no_tee_services(config)?;
+    }
     Ok(())
 }
 
diff --git a/android/virtmgr/src/selinux.rs b/android/virtmgr/src/selinux.rs
index ba62b7f..a8c895f 100644
--- a/android/virtmgr/src/selinux.rs
+++ b/android/virtmgr/src/selinux.rs
@@ -15,13 +15,30 @@
 //! Wrapper to libselinux
 
 use anyhow::{anyhow, bail, Context, Result};
-use std::ffi::{CStr, CString};
+use std::ffi::{c_int, CStr, CString};
 use std::fmt;
 use std::io;
 use std::ops::Deref;
 use std::os::fd::AsRawFd;
 use std::os::raw::c_char;
 use std::ptr;
+use std::sync;
+
+static SELINUX_LOG_INIT: sync::Once = sync::Once::new();
+
+fn redirect_selinux_logs_to_logcat() {
+    let cb =
+        selinux_bindgen::selinux_callback { func_log: Some(selinux_bindgen::selinux_log_callback) };
+    // SAFETY: `selinux_set_callback` assigns the static lifetime function pointer
+    // `selinux_log_callback` to a static lifetime variable.
+    unsafe {
+        selinux_bindgen::selinux_set_callback(selinux_bindgen::SELINUX_CB_LOG as c_int, cb);
+    }
+}
+
+fn init_logger_once() {
+    SELINUX_LOG_INIT.call_once(redirect_selinux_logs_to_logcat)
+}
 
 // Partially copied from system/security/keystore2/selinux/src/lib.rs
 /// SeContext represents an SELinux context string. It can take ownership of a raw
@@ -101,6 +118,56 @@
     }
 }
 
+/// Takes ownership of context handle returned by `selinux_android_tee_service_context_handle`
+/// and closes it via `selabel_close` when dropped.
+struct TeeServiceSelinuxBackend {
+    handle: *mut selinux_bindgen::selabel_handle,
+}
+
+impl TeeServiceSelinuxBackend {
+    const BACKEND_ID: i32 = selinux_bindgen::SELABEL_CTX_ANDROID_SERVICE as i32;
+
+    /// Creates a new instance representing selinux context handle returned from
+    /// `selinux_android_tee_service_context_handle`.
+    fn new() -> Result<Self> {
+        // SAFETY: selinux_android_tee_service_context_handle is always safe to call. The returned
+        // handle is valid until `selabel_close` is called on it (see the safety comment on the drop
+        // trait).
+        let handle = unsafe { selinux_bindgen::selinux_android_tee_service_context_handle() };
+        if handle.is_null() {
+            Err(anyhow!("selinux_android_tee_service_context_handle returned a NULL context"))
+        } else {
+            Ok(TeeServiceSelinuxBackend { handle })
+        }
+    }
+
+    fn lookup(&self, tee_service: &str) -> Result<SeContext> {
+        let mut con: *mut c_char = ptr::null_mut();
+        let c_key = CString::new(tee_service).context("failed to convert to CString")?;
+        // SAFETY: the returned pointer `con` is valid until `freecon` is called on it.
+        match unsafe {
+            selinux_bindgen::selabel_lookup(self.handle, &mut con, c_key.as_ptr(), Self::BACKEND_ID)
+        } {
+            0 => {
+                if !con.is_null() {
+                    Ok(SeContext::Raw(con))
+                } else {
+                    Err(anyhow!("selabel_lookup returned a NULL context"))
+                }
+            }
+            _ => Err(anyhow!(io::Error::last_os_error())).context("selabel_lookup failed"),
+        }
+    }
+}
+
+impl Drop for TeeServiceSelinuxBackend {
+    fn drop(&mut self) {
+        // SAFETY: the TeeServiceSelinuxBackend is created only with a pointer is set by
+        // libselinux and has to be freed with `selabel_close`.
+        unsafe { selinux_bindgen::selabel_close(self.handle) };
+    }
+}
+
 pub fn getfilecon<F: AsRawFd>(file: &F) -> Result<SeContext> {
     let fd = file.as_raw_fd();
     let mut con: *mut c_char = ptr::null_mut();
@@ -117,3 +184,90 @@
         _ => Err(anyhow!(io::Error::last_os_error())).context("fgetfilecon failed"),
     }
 }
+
+pub fn getprevcon() -> Result<SeContext> {
+    let mut con: *mut c_char = ptr::null_mut();
+    // SAFETY: the returned pointer `con` is wrapped in SeContext::Raw which is freed with
+    // `freecon` when it is dropped.
+    match unsafe { selinux_bindgen::getprevcon(&mut con) } {
+        0.. => {
+            if !con.is_null() {
+                Ok(SeContext::Raw(con))
+            } else {
+                Err(anyhow!("getprevcon returned a NULL context"))
+            }
+        }
+        _ => Err(anyhow!(io::Error::last_os_error())).context("getprevcon failed"),
+    }
+}
+
+// Wrapper around selinux_check_access
+fn check_access(source: &CStr, target: &CStr, tclass: &str, perm: &str) -> Result<()> {
+    let c_tclass = CString::new(tclass).context("failed to convert tclass to CString")?;
+    let c_perm = CString::new(perm).context("failed to convert perm to CString")?;
+
+    // SAFETY: lifecycle of pointers passed to the selinux_check_access outlive the duration of the
+    // call.
+    match unsafe {
+        selinux_bindgen::selinux_check_access(
+            source.as_ptr(),
+            target.as_ptr(),
+            c_tclass.as_ptr(),
+            c_perm.as_ptr(),
+            ptr::null_mut(),
+        )
+    } {
+        0 => Ok(()),
+        _ => Err(anyhow!(io::Error::last_os_error())).with_context(|| {
+            format!(
+                "check_access: Failed with sctx: {:?} tctx: {:?} tclass: {:?} perm {:?}",
+                source, target, tclass, perm
+            )
+        }),
+    }
+}
+
+pub fn check_tee_service_permission(caller_ctx: &SeContext, tee_services: &[String]) -> Result<()> {
+    init_logger_once();
+
+    let backend = TeeServiceSelinuxBackend::new()?;
+
+    for tee_service in tee_services {
+        let tee_service_ctx = backend.lookup(tee_service)?;
+        check_access(caller_ctx, &tee_service_ctx, "tee_service", "use")
+            .with_context(|| format!("permission denied for {:?}", tee_service))?;
+    }
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_check_tee_service_permission_has_permission() -> Result<()> {
+        if cfg!(not(tee_services_allowlist)) {
+            // Skip test on release configurations without tee_services_allowlist feature enabled.
+            return Ok(());
+        }
+
+        let caller_ctx = SeContext::new("u:r:shell:s0")?;
+        let tee_services = [String::from("test_pkvm_tee_service")];
+        check_tee_service_permission(&caller_ctx, &tee_services)
+    }
+
+    #[test]
+    fn test_check_tee_service_permission_invalid_tee_service() -> Result<()> {
+        if cfg!(not(tee_services_allowlist)) {
+            // Skip test on release configurations without tee_services_allowlist feature enabled.
+            return Ok(());
+        }
+
+        let caller_ctx = SeContext::new("u:r:shell:s0")?;
+        let tee_services = [String::from("test_tee_service_does_not_exist")];
+        let ret = check_tee_service_permission(&caller_ctx, &tee_services);
+        assert!(ret.is_err());
+        Ok(())
+    }
+}
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index 9123742..114a851 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -130,6 +130,9 @@
 
         /** Additional parameters to pass to the VM's kernel cmdline. */
         String[] extraKernelCmdlineParams;
+
+        /** List of tee services this VM wants to access */
+        String[] teeServices;
     }
 
     /** Configuration parameters guarded by android.permission.USE_CUSTOM_VIRTUAL_MACHINE */
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index 9f2a23e..5728a68 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -110,4 +110,7 @@
 
     /** Enable or disable USB passthrough support */
     @nullable UsbConfig usbConfig;
+
+    /** List of tee services this VM wants to access */
+    String[] teeServices;
 }
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index 110e0ca..7bfd957 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -72,6 +72,11 @@
     /// Boost uclamp to stablise results for benchmarks.
     #[arg(short, long)]
     boost_uclamp: bool,
+
+    /// Secure services this VM wants to access.
+    #[cfg(tee_services_allowlist)]
+    #[arg(long)]
+    tee_services: Vec<String>,
 }
 
 impl CommonConfig {
@@ -84,6 +89,16 @@
             }
         }
     }
+
+    fn tee_services(&self) -> &[String] {
+        cfg_if::cfg_if! {
+            if #[cfg(tee_services_allowlist)] {
+                &self.tee_services
+            } else {
+                &[]
+            }
+        }
+    }
 }
 
 #[derive(Args, Default)]
diff --git a/android/vm/src/run.rs b/android/vm/src/run.rs
index b07a472..2157ea8 100644
--- a/android/vm/src/run.rs
+++ b/android/vm/src/run.rs
@@ -156,6 +156,7 @@
             })
             .collect::<Result<_, _>>()?,
         networkSupported: config.common.network_supported(),
+        teeServices: config.common.tee_services().to_vec(),
         ..Default::default()
     };
 
@@ -263,8 +264,8 @@
     if let Some(mem) = config.common.mem {
         vm_config.memoryMib = mem as i32;
     }
-    if let Some(name) = config.common.name {
-        vm_config.name = name;
+    if let Some(ref name) = config.common.name {
+        vm_config.name = name.to_string();
     } else {
         vm_config.name = String::from("VmRun");
     }
@@ -274,6 +275,7 @@
     vm_config.cpuTopology = config.common.cpu_topology;
     vm_config.hugePages = config.common.hugepages;
     vm_config.boostUclamp = config.common.boost_uclamp;
+    vm_config.teeServices = config.common.tee_services().to_vec();
     run(
         get_service()?.as_ref(),
         &VirtualMachineConfig::RawConfig(vm_config),
diff --git a/build/Android.bp b/build/Android.bp
index 4c4fbba..2b97927 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -41,6 +41,9 @@
     }) + select(release_flag("RELEASE_AVF_ENABLE_VENDOR_MODULES"), {
         true: ["vendor_modules"],
         default: [],
+    }) + select(release_flag("RELEASE_AVF_ENABLE_VM_TO_TEE_SERVICES_ALLOWLIST"), {
+        true: ["tee_services_allowlist"],
+        default: [],
     }) + select(release_flag("RELEASE_AVF_ENABLE_VIRT_CPUFREQ"), {
         true: ["virt_cpufreq"],
         default: [],
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 3d1964d..8230166 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -744,6 +744,7 @@
                                     return usbConfig;
                                 })
                         .orElse(null);
+        config.teeServices = EMPTY_STRING_ARRAY;
         return config;
     }
 
@@ -798,6 +799,7 @@
                     new VirtualMachineAppConfig.CustomConfig();
             customConfig.devices = EMPTY_STRING_ARRAY;
             customConfig.extraKernelCmdlineParams = EMPTY_STRING_ARRAY;
+            customConfig.teeServices = EMPTY_STRING_ARRAY;
             try {
                 customConfig.vendorImage =
                         ParcelFileDescriptor.open(mVendorDiskImage, MODE_READ_ONLY);