1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Implementation of the AIDL interface `IVmPayloadService`.
16 
17 use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
18     BnVmPayloadService, IVmPayloadService, VM_PAYLOAD_SERVICE_SOCKET_NAME, AttestationResult::AttestationResult,
19     STATUS_FAILED_TO_PREPARE_CSR_AND_KEY
20 };
21 use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
22 use anyhow::{anyhow, Context, Result};
23 use avflog::LogResult;
24 use binder::{Interface, BinderFeatures, ExceptionCode, Strong, IntoBinderResult, Status};
25 use client_vm_csr::{generate_attestation_key_and_csr, ClientVmAttestationData};
26 use log::info;
27 use rpcbinder::RpcServer;
28 use crate::vm_secret::VmSecret;
29 use std::os::unix::io::OwnedFd;
30 
31 /// Implementation of `IVmPayloadService`.
32 struct VmPayloadService {
33     allow_restricted_apis: bool,
34     virtual_machine_service: Strong<dyn IVirtualMachineService>,
35     secret: VmSecret,
36 }
37 
38 impl IVmPayloadService for VmPayloadService {
notifyPayloadReady(&self) -> binder::Result<()>39     fn notifyPayloadReady(&self) -> binder::Result<()> {
40         self.virtual_machine_service.notifyPayloadReady()
41     }
42 
getVmInstanceSecret(&self, identifier: &[u8], size: i32) -> binder::Result<Vec<u8>>43     fn getVmInstanceSecret(&self, identifier: &[u8], size: i32) -> binder::Result<Vec<u8>> {
44         if !(0..=32).contains(&size) {
45             return Err(anyhow!("size {size} not in range (0..=32)"))
46                 .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
47         }
48         let mut instance_secret = vec![0; size.try_into().unwrap()];
49         self.secret
50             .derive_payload_sealing_key(identifier, &mut instance_secret)
51             .context("Failed to derive VM instance secret")
52             .with_log()
53             .or_service_specific_exception(-1)?;
54         Ok(instance_secret)
55     }
56 
getDiceAttestationChain(&self) -> binder::Result<Vec<u8>>57     fn getDiceAttestationChain(&self) -> binder::Result<Vec<u8>> {
58         self.check_restricted_apis_allowed()?;
59         if let Some(bcc) = self.secret.dice_artifacts().bcc() {
60             Ok(bcc.to_vec())
61         } else {
62             Err(anyhow!("bcc is none")).or_binder_exception(ExceptionCode::ILLEGAL_STATE)
63         }
64     }
65 
getDiceAttestationCdi(&self) -> binder::Result<Vec<u8>>66     fn getDiceAttestationCdi(&self) -> binder::Result<Vec<u8>> {
67         self.check_restricted_apis_allowed()?;
68         Ok(self.secret.dice_artifacts().cdi_attest().to_vec())
69     }
70 
requestAttestation( &self, challenge: &[u8], test_mode: bool, ) -> binder::Result<AttestationResult>71     fn requestAttestation(
72         &self,
73         challenge: &[u8],
74         test_mode: bool,
75     ) -> binder::Result<AttestationResult> {
76         let ClientVmAttestationData { private_key, csr } =
77             generate_attestation_key_and_csr(challenge, self.secret.dice_artifacts())
78                 .map_err(|e| {
79                     Status::new_service_specific_error_str(
80                         STATUS_FAILED_TO_PREPARE_CSR_AND_KEY,
81                         Some(format!("Failed to prepare the CSR and key pair: {e:?}")),
82                     )
83                 })
84                 .with_log()?;
85         let csr = csr
86             .into_cbor_vec()
87             .map_err(|e| {
88                 Status::new_service_specific_error_str(
89                     STATUS_FAILED_TO_PREPARE_CSR_AND_KEY,
90                     Some(format!("Failed to serialize CSR into CBOR: {e:?}")),
91                 )
92             })
93             .with_log()?;
94         let cert_chain = self.virtual_machine_service.requestAttestation(&csr, test_mode)?;
95         Ok(AttestationResult {
96             privateKey: private_key.as_slice().to_vec(),
97             certificateChain: cert_chain,
98         })
99     }
100 }
101 
102 impl Interface for VmPayloadService {}
103 
104 impl VmPayloadService {
105     /// Creates a new `VmPayloadService` instance from the `IVirtualMachineService` reference.
new( allow_restricted_apis: bool, vm_service: Strong<dyn IVirtualMachineService>, secret: VmSecret, ) -> VmPayloadService106     fn new(
107         allow_restricted_apis: bool,
108         vm_service: Strong<dyn IVirtualMachineService>,
109         secret: VmSecret,
110     ) -> VmPayloadService {
111         Self { allow_restricted_apis, virtual_machine_service: vm_service, secret }
112     }
113 
check_restricted_apis_allowed(&self) -> binder::Result<()>114     fn check_restricted_apis_allowed(&self) -> binder::Result<()> {
115         if self.allow_restricted_apis {
116             Ok(())
117         } else {
118             Err(anyhow!("Use of restricted APIs is not allowed"))
119                 .with_log()
120                 .or_binder_exception(ExceptionCode::SECURITY)
121         }
122     }
123 }
124 
125 /// Registers the `IVmPayloadService` service.
register_vm_payload_service( allow_restricted_apis: bool, vm_service: Strong<dyn IVirtualMachineService>, secret: VmSecret, vm_payload_service_fd: OwnedFd, ) -> Result<()>126 pub(crate) fn register_vm_payload_service(
127     allow_restricted_apis: bool,
128     vm_service: Strong<dyn IVirtualMachineService>,
129     secret: VmSecret,
130     vm_payload_service_fd: OwnedFd,
131 ) -> Result<()> {
132     let vm_payload_binder = BnVmPayloadService::new_binder(
133         VmPayloadService::new(allow_restricted_apis, vm_service, secret),
134         BinderFeatures::default(),
135     );
136 
137     let server = RpcServer::new_bound_socket(vm_payload_binder.as_binder(), vm_payload_service_fd)?;
138     info!("The RPC server '{}' is running.", VM_PAYLOAD_SERVICE_SOCKET_NAME);
139 
140     // Move server reference into a background thread and run it forever.
141     std::thread::spawn(move || {
142         server.join();
143     });
144     Ok(())
145 }
146