xref: /aosp_15_r20/external/crosvm/devices/src/virtio/fs/config.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
6*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
7*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
8*bb4ee6a4SAndroid Build Coastguard Worker use std::str::FromStr;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
12*bb4ee6a4SAndroid Build Coastguard Worker use libc;
13*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_imports)]
14*bb4ee6a4SAndroid Build Coastguard Worker use serde::de::Error;
15*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
16*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserializer;
17*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
18*bb4ee6a4SAndroid Build Coastguard Worker use serde_keyvalue::FromKeyValues;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker /// The caching policy that the file system should report to the FUSE client. By default the FUSE
21*bb4ee6a4SAndroid Build Coastguard Worker /// protocol uses close-to-open consistency. This means that any cached contents of the file are
22*bb4ee6a4SAndroid Build Coastguard Worker /// invalidated the next time that file is opened.
23*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, FromKeyValues)]
24*bb4ee6a4SAndroid Build Coastguard Worker #[serde(rename_all = "kebab-case")]
25*bb4ee6a4SAndroid Build Coastguard Worker pub enum CachePolicy {
26*bb4ee6a4SAndroid Build Coastguard Worker     /// The client should never cache file data and all I/O should be directly forwarded to the
27*bb4ee6a4SAndroid Build Coastguard Worker     /// server. This policy must be selected when file contents may change without the knowledge of
28*bb4ee6a4SAndroid Build Coastguard Worker     /// the FUSE client (i.e., the file system does not have exclusive access to the directory).
29*bb4ee6a4SAndroid Build Coastguard Worker     Never,
30*bb4ee6a4SAndroid Build Coastguard Worker 
31*bb4ee6a4SAndroid Build Coastguard Worker     /// The client is free to choose when and how to cache file data. This is the default policy
32*bb4ee6a4SAndroid Build Coastguard Worker     /// and uses close-to-open consistency as described in the enum documentation.
33*bb4ee6a4SAndroid Build Coastguard Worker     #[default]
34*bb4ee6a4SAndroid Build Coastguard Worker     Auto,
35*bb4ee6a4SAndroid Build Coastguard Worker 
36*bb4ee6a4SAndroid Build Coastguard Worker     /// The client should always cache file data. This means that the FUSE client will not
37*bb4ee6a4SAndroid Build Coastguard Worker     /// invalidate any cached data that was returned by the file system the last time the file was
38*bb4ee6a4SAndroid Build Coastguard Worker     /// opened. This policy should only be selected when the file system has exclusive access to
39*bb4ee6a4SAndroid Build Coastguard Worker     /// the directory.
40*bb4ee6a4SAndroid Build Coastguard Worker     Always,
41*bb4ee6a4SAndroid Build Coastguard Worker }
42*bb4ee6a4SAndroid Build Coastguard Worker 
config_default_timeout() -> Duration43*bb4ee6a4SAndroid Build Coastguard Worker const fn config_default_timeout() -> Duration {
44*bb4ee6a4SAndroid Build Coastguard Worker     Duration::from_secs(5)
45*bb4ee6a4SAndroid Build Coastguard Worker }
46*bb4ee6a4SAndroid Build Coastguard Worker 
config_default_negative_timeout() -> Duration47*bb4ee6a4SAndroid Build Coastguard Worker const fn config_default_negative_timeout() -> Duration {
48*bb4ee6a4SAndroid Build Coastguard Worker     Duration::ZERO
49*bb4ee6a4SAndroid Build Coastguard Worker }
50*bb4ee6a4SAndroid Build Coastguard Worker 
config_default_posix_acl() -> bool51*bb4ee6a4SAndroid Build Coastguard Worker const fn config_default_posix_acl() -> bool {
52*bb4ee6a4SAndroid Build Coastguard Worker     true
53*bb4ee6a4SAndroid Build Coastguard Worker }
54*bb4ee6a4SAndroid Build Coastguard Worker 
config_default_security_ctx() -> bool55*bb4ee6a4SAndroid Build Coastguard Worker const fn config_default_security_ctx() -> bool {
56*bb4ee6a4SAndroid Build Coastguard Worker     true
57*bb4ee6a4SAndroid Build Coastguard Worker }
58*bb4ee6a4SAndroid Build Coastguard Worker 
deserialize_timeout<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Duration, D::Error>59*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize_timeout<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Duration, D::Error> {
60*bb4ee6a4SAndroid Build Coastguard Worker     let secs = u64::deserialize(deserializer)?;
61*bb4ee6a4SAndroid Build Coastguard Worker 
62*bb4ee6a4SAndroid Build Coastguard Worker     Ok(Duration::from_secs(secs))
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker 
65*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
deserialize_privileged_quota_uids<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<Vec<libc::uid_t>, D::Error>66*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize_privileged_quota_uids<'de, D: Deserializer<'de>>(
67*bb4ee6a4SAndroid Build Coastguard Worker     deserializer: D,
68*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Vec<libc::uid_t>, D::Error> {
69*bb4ee6a4SAndroid Build Coastguard Worker     // space-separated list
70*bb4ee6a4SAndroid Build Coastguard Worker     let s: &str = serde::Deserialize::deserialize(deserializer)?;
71*bb4ee6a4SAndroid Build Coastguard Worker     s.split(" ")
72*bb4ee6a4SAndroid Build Coastguard Worker         .map(|s| {
73*bb4ee6a4SAndroid Build Coastguard Worker             s.parse::<libc::uid_t>().map_err(|e| {
74*bb4ee6a4SAndroid Build Coastguard Worker                 <D as Deserializer>::Error::custom(format!(
75*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to parse priviledged quota uid {s}: {e}"
76*bb4ee6a4SAndroid Build Coastguard Worker                 ))
77*bb4ee6a4SAndroid Build Coastguard Worker             })
78*bb4ee6a4SAndroid Build Coastguard Worker         })
79*bb4ee6a4SAndroid Build Coastguard Worker         .collect()
80*bb4ee6a4SAndroid Build Coastguard Worker }
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker /// Permission structure that is configured to map the UID-GID at runtime
83*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
84*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Eq, PartialEq, Serialize)]
85*bb4ee6a4SAndroid Build Coastguard Worker pub struct PermissionData {
86*bb4ee6a4SAndroid Build Coastguard Worker     /// UID to be set for all the files in the path inside guest.
87*bb4ee6a4SAndroid Build Coastguard Worker     pub guest_uid: libc::uid_t,
88*bb4ee6a4SAndroid Build Coastguard Worker 
89*bb4ee6a4SAndroid Build Coastguard Worker     /// GID to be set for all the files in the path inside guest.
90*bb4ee6a4SAndroid Build Coastguard Worker     pub guest_gid: libc::gid_t,
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker     /// UID to be set for all the files in the path in the host.
93*bb4ee6a4SAndroid Build Coastguard Worker     pub host_uid: libc::uid_t,
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker     /// GID to be set for all the files in the path in the host.
96*bb4ee6a4SAndroid Build Coastguard Worker     pub host_gid: libc::gid_t,
97*bb4ee6a4SAndroid Build Coastguard Worker 
98*bb4ee6a4SAndroid Build Coastguard Worker     /// umask to be set at runtime for the files in the path.
99*bb4ee6a4SAndroid Build Coastguard Worker     pub umask: libc::mode_t,
100*bb4ee6a4SAndroid Build Coastguard Worker 
101*bb4ee6a4SAndroid Build Coastguard Worker     /// This is the absolute path from the root of the shared directory.
102*bb4ee6a4SAndroid Build Coastguard Worker     pub perm_path: String,
103*bb4ee6a4SAndroid Build Coastguard Worker }
104*bb4ee6a4SAndroid Build Coastguard Worker 
105*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
process_ugid_map(result: Vec<Vec<String>>) -> Result<Vec<PermissionData>, io::Error>106*bb4ee6a4SAndroid Build Coastguard Worker fn process_ugid_map(result: Vec<Vec<String>>) -> Result<Vec<PermissionData>, io::Error> {
107*bb4ee6a4SAndroid Build Coastguard Worker     let mut permissions = Vec::new();
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker     for inner_vec in result {
110*bb4ee6a4SAndroid Build Coastguard Worker         let guest_uid = match libc::uid_t::from_str(&inner_vec[0]) {
111*bb4ee6a4SAndroid Build Coastguard Worker             Ok(uid) => uid,
112*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => {
113*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(io::Error::from_raw_os_error(libc::EINVAL));
114*bb4ee6a4SAndroid Build Coastguard Worker             }
115*bb4ee6a4SAndroid Build Coastguard Worker         };
116*bb4ee6a4SAndroid Build Coastguard Worker 
117*bb4ee6a4SAndroid Build Coastguard Worker         let guest_gid = match libc::gid_t::from_str(&inner_vec[1]) {
118*bb4ee6a4SAndroid Build Coastguard Worker             Ok(gid) => gid,
119*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => {
120*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(io::Error::from_raw_os_error(libc::EINVAL));
121*bb4ee6a4SAndroid Build Coastguard Worker             }
122*bb4ee6a4SAndroid Build Coastguard Worker         };
123*bb4ee6a4SAndroid Build Coastguard Worker 
124*bb4ee6a4SAndroid Build Coastguard Worker         let host_uid = match libc::uid_t::from_str(&inner_vec[2]) {
125*bb4ee6a4SAndroid Build Coastguard Worker             Ok(uid) => uid,
126*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => {
127*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(io::Error::from_raw_os_error(libc::EINVAL));
128*bb4ee6a4SAndroid Build Coastguard Worker             }
129*bb4ee6a4SAndroid Build Coastguard Worker         };
130*bb4ee6a4SAndroid Build Coastguard Worker 
131*bb4ee6a4SAndroid Build Coastguard Worker         let host_gid = match libc::gid_t::from_str(&inner_vec[3]) {
132*bb4ee6a4SAndroid Build Coastguard Worker             Ok(gid) => gid,
133*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => {
134*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(io::Error::from_raw_os_error(libc::EINVAL));
135*bb4ee6a4SAndroid Build Coastguard Worker             }
136*bb4ee6a4SAndroid Build Coastguard Worker         };
137*bb4ee6a4SAndroid Build Coastguard Worker 
138*bb4ee6a4SAndroid Build Coastguard Worker         let umask = match libc::mode_t::from_str(&inner_vec[4]) {
139*bb4ee6a4SAndroid Build Coastguard Worker             Ok(mode) => mode,
140*bb4ee6a4SAndroid Build Coastguard Worker             Err(_) => {
141*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(io::Error::from_raw_os_error(libc::EINVAL));
142*bb4ee6a4SAndroid Build Coastguard Worker             }
143*bb4ee6a4SAndroid Build Coastguard Worker         };
144*bb4ee6a4SAndroid Build Coastguard Worker 
145*bb4ee6a4SAndroid Build Coastguard Worker         let perm_path = inner_vec[5].clone();
146*bb4ee6a4SAndroid Build Coastguard Worker 
147*bb4ee6a4SAndroid Build Coastguard Worker         // Create PermissionData and push it to the vector
148*bb4ee6a4SAndroid Build Coastguard Worker         permissions.push(PermissionData {
149*bb4ee6a4SAndroid Build Coastguard Worker             guest_uid,
150*bb4ee6a4SAndroid Build Coastguard Worker             guest_gid,
151*bb4ee6a4SAndroid Build Coastguard Worker             host_uid,
152*bb4ee6a4SAndroid Build Coastguard Worker             host_gid,
153*bb4ee6a4SAndroid Build Coastguard Worker             umask,
154*bb4ee6a4SAndroid Build Coastguard Worker             perm_path,
155*bb4ee6a4SAndroid Build Coastguard Worker         });
156*bb4ee6a4SAndroid Build Coastguard Worker     }
157*bb4ee6a4SAndroid Build Coastguard Worker 
158*bb4ee6a4SAndroid Build Coastguard Worker     Ok(permissions)
159*bb4ee6a4SAndroid Build Coastguard Worker }
160*bb4ee6a4SAndroid Build Coastguard Worker 
161*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
deserialize_ugid_map<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<Vec<PermissionData>, D::Error>162*bb4ee6a4SAndroid Build Coastguard Worker fn deserialize_ugid_map<'de, D: Deserializer<'de>>(
163*bb4ee6a4SAndroid Build Coastguard Worker     deserializer: D,
164*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Vec<PermissionData>, D::Error> {
165*bb4ee6a4SAndroid Build Coastguard Worker     // space-separated list
166*bb4ee6a4SAndroid Build Coastguard Worker     let s: &str = serde::Deserialize::deserialize(deserializer)?;
167*bb4ee6a4SAndroid Build Coastguard Worker 
168*bb4ee6a4SAndroid Build Coastguard Worker     let result: Vec<Vec<String>> = s
169*bb4ee6a4SAndroid Build Coastguard Worker         .split(';')
170*bb4ee6a4SAndroid Build Coastguard Worker         .map(|group| group.trim().split(' ').map(String::from).collect())
171*bb4ee6a4SAndroid Build Coastguard Worker         .collect();
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker     // Length Validation for each inner vector
174*bb4ee6a4SAndroid Build Coastguard Worker     for inner_vec in &result {
175*bb4ee6a4SAndroid Build Coastguard Worker         if inner_vec.len() != 6 {
176*bb4ee6a4SAndroid Build Coastguard Worker             return Err(D::Error::custom(
177*bb4ee6a4SAndroid Build Coastguard Worker                 "Invalid ugid_map format. Each group must have 6 elements.",
178*bb4ee6a4SAndroid Build Coastguard Worker             ));
179*bb4ee6a4SAndroid Build Coastguard Worker         }
180*bb4ee6a4SAndroid Build Coastguard Worker     }
181*bb4ee6a4SAndroid Build Coastguard Worker 
182*bb4ee6a4SAndroid Build Coastguard Worker     let permissions = match process_ugid_map(result) {
183*bb4ee6a4SAndroid Build Coastguard Worker         Ok(p) => p,
184*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
185*bb4ee6a4SAndroid Build Coastguard Worker             return Err(D::Error::custom(format!(
186*bb4ee6a4SAndroid Build Coastguard Worker                 "Error processing uid_gid_map: {}",
187*bb4ee6a4SAndroid Build Coastguard Worker                 e
188*bb4ee6a4SAndroid Build Coastguard Worker             )));
189*bb4ee6a4SAndroid Build Coastguard Worker         }
190*bb4ee6a4SAndroid Build Coastguard Worker     };
191*bb4ee6a4SAndroid Build Coastguard Worker 
192*bb4ee6a4SAndroid Build Coastguard Worker     Ok(permissions)
193*bb4ee6a4SAndroid Build Coastguard Worker }
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker /// Options that configure the behavior of the file system.
196*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
197*bb4ee6a4SAndroid Build Coastguard Worker #[serde(deny_unknown_fields, rename_all = "snake_case")]
198*bb4ee6a4SAndroid Build Coastguard Worker pub struct Config {
199*bb4ee6a4SAndroid Build Coastguard Worker     /// How long the FUSE client should consider directory entries and file/directory attributes to
200*bb4ee6a4SAndroid Build Coastguard Worker     /// be valid.
201*bb4ee6a4SAndroid Build Coastguard Worker     /// This value corresponds to `entry_timeout` and `attr_timeout` in
202*bb4ee6a4SAndroid Build Coastguard Worker     /// [libfuse's `fuse_config`](https://libfuse.github.io/doxygen/structfuse__config.html), but
203*bb4ee6a4SAndroid Build Coastguard Worker     /// we use the same value for the two.
204*bb4ee6a4SAndroid Build Coastguard Worker     ///
205*bb4ee6a4SAndroid Build Coastguard Worker     /// If the contents of a directory or the attributes of a file or directory can only be
206*bb4ee6a4SAndroid Build Coastguard Worker     /// modified by the FUSE client (i.e., the file system has exclusive access), then this should
207*bb4ee6a4SAndroid Build Coastguard Worker     /// be a large value.
208*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is 5 seconds.
209*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(
210*bb4ee6a4SAndroid Build Coastguard Worker         default = "config_default_timeout",
211*bb4ee6a4SAndroid Build Coastguard Worker         deserialize_with = "deserialize_timeout"
212*bb4ee6a4SAndroid Build Coastguard Worker     )]
213*bb4ee6a4SAndroid Build Coastguard Worker     pub timeout: Duration,
214*bb4ee6a4SAndroid Build Coastguard Worker 
215*bb4ee6a4SAndroid Build Coastguard Worker     /// How long the FUSE client can cache negative lookup results.
216*bb4ee6a4SAndroid Build Coastguard Worker     /// If a file lookup fails, the client can assume the file doesn't exist until the timeout and
217*bb4ee6a4SAndroid Build Coastguard Worker     ///  won't send lookup.
218*bb4ee6a4SAndroid Build Coastguard Worker     /// The value 0 means that negative lookup shouldn't be cached.
219*bb4ee6a4SAndroid Build Coastguard Worker     ///
220*bb4ee6a4SAndroid Build Coastguard Worker     /// If the contents of a directory can only be modified by the FUSE client (i.e., the file
221*bb4ee6a4SAndroid Build Coastguard Worker     /// system has exclusive access), then this should be a large value.
222*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is 0 seconds (= no negative cache).
223*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(
224*bb4ee6a4SAndroid Build Coastguard Worker         default = "config_default_negative_timeout",
225*bb4ee6a4SAndroid Build Coastguard Worker         deserialize_with = "deserialize_timeout"
226*bb4ee6a4SAndroid Build Coastguard Worker     )]
227*bb4ee6a4SAndroid Build Coastguard Worker     pub negative_timeout: Duration,
228*bb4ee6a4SAndroid Build Coastguard Worker 
229*bb4ee6a4SAndroid Build Coastguard Worker     /// The caching policy the file system should use. See the documentation of `CachePolicy` for
230*bb4ee6a4SAndroid Build Coastguard Worker     /// more details.
231*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default, alias = "cache")]
232*bb4ee6a4SAndroid Build Coastguard Worker     pub cache_policy: CachePolicy,
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker     /// Whether the file system should enabled writeback caching. This can improve performance as
235*bb4ee6a4SAndroid Build Coastguard Worker     /// it allows the FUSE client to cache and coalesce multiple writes before sending them to
236*bb4ee6a4SAndroid Build Coastguard Worker     /// the file system. However, enabling this option can increase the risk of data corruption
237*bb4ee6a4SAndroid Build Coastguard Worker     /// if the file contents can change without the knowledge of the FUSE client (i.e., the
238*bb4ee6a4SAndroid Build Coastguard Worker     /// server does **NOT** have exclusive access). Additionally, the file system should have
239*bb4ee6a4SAndroid Build Coastguard Worker     /// read access to all files in the directory it is serving as the FUSE client may send
240*bb4ee6a4SAndroid Build Coastguard Worker     /// read requests even for files opened with `O_WRONLY`.
241*bb4ee6a4SAndroid Build Coastguard Worker     ///
242*bb4ee6a4SAndroid Build Coastguard Worker     /// Therefore callers should only enable this option when they can guarantee that: 1) the file
243*bb4ee6a4SAndroid Build Coastguard Worker     /// system has exclusive access to the directory and 2) the file system has read permissions
244*bb4ee6a4SAndroid Build Coastguard Worker     /// for all files in that directory.
245*bb4ee6a4SAndroid Build Coastguard Worker     ///
246*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is `false`.
247*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default)]
248*bb4ee6a4SAndroid Build Coastguard Worker     pub writeback: bool,
249*bb4ee6a4SAndroid Build Coastguard Worker 
250*bb4ee6a4SAndroid Build Coastguard Worker     /// Controls whether security.* xattrs (except for security.selinux) are re-written. When this
251*bb4ee6a4SAndroid Build Coastguard Worker     /// is set to true, the server will add a "user.virtiofs" prefix to xattrs in the security
252*bb4ee6a4SAndroid Build Coastguard Worker     /// namespace. Setting these xattrs requires CAP_SYS_ADMIN in the namespace where the file
253*bb4ee6a4SAndroid Build Coastguard Worker     /// system was mounted and since the server usually runs in an unprivileged user namespace,
254*bb4ee6a4SAndroid Build Coastguard Worker     /// it's unlikely to have that capability.
255*bb4ee6a4SAndroid Build Coastguard Worker     ///
256*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is `false`.
257*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default, alias = "rewrite-security-xattrs")]
258*bb4ee6a4SAndroid Build Coastguard Worker     pub rewrite_security_xattrs: bool,
259*bb4ee6a4SAndroid Build Coastguard Worker 
260*bb4ee6a4SAndroid Build Coastguard Worker     /// Use case-insensitive lookups for directory entries (ASCII only).
261*bb4ee6a4SAndroid Build Coastguard Worker     ///
262*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is `false`.
263*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default)]
264*bb4ee6a4SAndroid Build Coastguard Worker     pub ascii_casefold: bool,
265*bb4ee6a4SAndroid Build Coastguard Worker 
266*bb4ee6a4SAndroid Build Coastguard Worker     // UIDs which are privileged to perform quota-related operations. We cannot perform a
267*bb4ee6a4SAndroid Build Coastguard Worker     // CAP_FOWNER check so we consult this list when the VM tries to set the project quota and
268*bb4ee6a4SAndroid Build Coastguard Worker     // the process uid doesn't match the owner uid. In that case, all uids in this list are
269*bb4ee6a4SAndroid Build Coastguard Worker     // treated as if they have CAP_FOWNER.
270*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "arc_quota")]
271*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default, deserialize_with = "deserialize_privileged_quota_uids")]
272*bb4ee6a4SAndroid Build Coastguard Worker     pub privileged_quota_uids: Vec<libc::uid_t>,
273*bb4ee6a4SAndroid Build Coastguard Worker 
274*bb4ee6a4SAndroid Build Coastguard Worker     /// Use DAX for shared files.
275*bb4ee6a4SAndroid Build Coastguard Worker     ///
276*bb4ee6a4SAndroid Build Coastguard Worker     /// Enabling DAX can improve performance for frequently accessed files by mapping regions of
277*bb4ee6a4SAndroid Build Coastguard Worker     /// the file directly into the VM's memory region, allowing direct access with the cost of
278*bb4ee6a4SAndroid Build Coastguard Worker     /// slightly increased latency the first time the file is accessed. Additionally, since the
279*bb4ee6a4SAndroid Build Coastguard Worker     /// mapping is shared directly from the host kernel's file cache, enabling DAX can improve
280*bb4ee6a4SAndroid Build Coastguard Worker     /// performance even when the cache policy is `Never`.
281*bb4ee6a4SAndroid Build Coastguard Worker     ///
282*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is `false`.
283*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default, alias = "dax")]
284*bb4ee6a4SAndroid Build Coastguard Worker     pub use_dax: bool,
285*bb4ee6a4SAndroid Build Coastguard Worker 
286*bb4ee6a4SAndroid Build Coastguard Worker     /// Enable support for POSIX acls.
287*bb4ee6a4SAndroid Build Coastguard Worker     ///
288*bb4ee6a4SAndroid Build Coastguard Worker     /// Enable POSIX acl support for the shared directory. This requires that the underlying file
289*bb4ee6a4SAndroid Build Coastguard Worker     /// system also supports POSIX acls.
290*bb4ee6a4SAndroid Build Coastguard Worker     ///
291*bb4ee6a4SAndroid Build Coastguard Worker     /// The default value for this option is `true`.
292*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default = "config_default_posix_acl")]
293*bb4ee6a4SAndroid Build Coastguard Worker     pub posix_acl: bool,
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker     // Maximum number of dynamic permission paths.
296*bb4ee6a4SAndroid Build Coastguard Worker     //
297*bb4ee6a4SAndroid Build Coastguard Worker     // The dynamic permission paths are used to set specific paths certain uid/gid after virtiofs
298*bb4ee6a4SAndroid Build Coastguard Worker     // device is created. It is for arcvm special usage, normal device should not support
299*bb4ee6a4SAndroid Build Coastguard Worker     // this feature.
300*bb4ee6a4SAndroid Build Coastguard Worker     //
301*bb4ee6a4SAndroid Build Coastguard Worker     // The default value for this option is 0.
302*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default)]
303*bb4ee6a4SAndroid Build Coastguard Worker     pub max_dynamic_perm: usize,
304*bb4ee6a4SAndroid Build Coastguard Worker 
305*bb4ee6a4SAndroid Build Coastguard Worker     // Maximum number of dynamic xattr paths.
306*bb4ee6a4SAndroid Build Coastguard Worker     //
307*bb4ee6a4SAndroid Build Coastguard Worker     // The dynamic xattr paths are used to set specific paths certain xattr after virtiofs
308*bb4ee6a4SAndroid Build Coastguard Worker     // device is created. It is for arcvm special usage, normal device should not support
309*bb4ee6a4SAndroid Build Coastguard Worker     // this feature.
310*bb4ee6a4SAndroid Build Coastguard Worker     //
311*bb4ee6a4SAndroid Build Coastguard Worker     // The default value for this option is 0.
312*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default)]
313*bb4ee6a4SAndroid Build Coastguard Worker     pub max_dynamic_xattr: usize,
314*bb4ee6a4SAndroid Build Coastguard Worker 
315*bb4ee6a4SAndroid Build Coastguard Worker     // Controls whether fuse_security_context feature is enabled
316*bb4ee6a4SAndroid Build Coastguard Worker     //
317*bb4ee6a4SAndroid Build Coastguard Worker     // The FUSE_SECURITY_CONTEXT feature needs write data into /proc/thread-self/attr/fscreate.
318*bb4ee6a4SAndroid Build Coastguard Worker     // For the hosts that prohibit the write operation, the option should be set to false to
319*bb4ee6a4SAndroid Build Coastguard Worker     // disable the FUSE_SECURITY_CONTEXT feature. When FUSE_SECURITY_CONTEXT is disabled, the
320*bb4ee6a4SAndroid Build Coastguard Worker     // security context won't be passed with fuse request, which makes guest created files/dir
321*bb4ee6a4SAndroid Build Coastguard Worker     // having unlabeled security context or empty security context.
322*bb4ee6a4SAndroid Build Coastguard Worker     //
323*bb4ee6a4SAndroid Build Coastguard Worker     // The default value for this option is true
324*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default = "config_default_security_ctx")]
325*bb4ee6a4SAndroid Build Coastguard Worker     pub security_ctx: bool,
326*bb4ee6a4SAndroid Build Coastguard Worker 
327*bb4ee6a4SAndroid Build Coastguard Worker     // Specifies run-time UID/GID mapping that works without user namespaces.
328*bb4ee6a4SAndroid Build Coastguard Worker     //
329*bb4ee6a4SAndroid Build Coastguard Worker     // The virtio-fs usually does mapping of UIDs/GIDs between host and guest with user namespace.
330*bb4ee6a4SAndroid Build Coastguard Worker     // In Android, however, user namespace isn't available for non-root users.
331*bb4ee6a4SAndroid Build Coastguard Worker     // This allows mapping UIDs and GIDs without user namespace by intercepting FUSE
332*bb4ee6a4SAndroid Build Coastguard Worker     // requests and translating UID/GID in virito-fs's process at runtime.
333*bb4ee6a4SAndroid Build Coastguard Worker     //
334*bb4ee6a4SAndroid Build Coastguard Worker     // The format is "guest-uid, guest-gid, host-uid, host-gid, umask, path;{repeat}"
335*bb4ee6a4SAndroid Build Coastguard Worker     //
336*bb4ee6a4SAndroid Build Coastguard Worker     // guest-uid: UID to be set for all the files in the path inside guest.
337*bb4ee6a4SAndroid Build Coastguard Worker     // guest-gid: GID to be set for all the files in the path inside guest.
338*bb4ee6a4SAndroid Build Coastguard Worker     // host-uid: UID to be set for all the files in the path in the host.
339*bb4ee6a4SAndroid Build Coastguard Worker     // host-gid: GID to be set for all the files in the path in the host.
340*bb4ee6a4SAndroid Build Coastguard Worker     // umask: umask to be set at runtime for the files in the path.
341*bb4ee6a4SAndroid Build Coastguard Worker     // path: This is the absolute path from the root of the shared directory.
342*bb4ee6a4SAndroid Build Coastguard Worker     //
343*bb4ee6a4SAndroid Build Coastguard Worker     // This follows similar format to ARCVM IOCTL "FS_IOC_SETPERMISSION"
344*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "fs_runtime_ugid_map")]
345*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(default, deserialize_with = "deserialize_ugid_map")]
346*bb4ee6a4SAndroid Build Coastguard Worker     pub ugid_map: Vec<PermissionData>,
347*bb4ee6a4SAndroid Build Coastguard Worker }
348*bb4ee6a4SAndroid Build Coastguard Worker 
349*bb4ee6a4SAndroid Build Coastguard Worker impl Default for Config {
default() -> Self350*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
351*bb4ee6a4SAndroid Build Coastguard Worker         Config {
352*bb4ee6a4SAndroid Build Coastguard Worker             timeout: config_default_timeout(),
353*bb4ee6a4SAndroid Build Coastguard Worker             negative_timeout: config_default_negative_timeout(),
354*bb4ee6a4SAndroid Build Coastguard Worker             cache_policy: Default::default(),
355*bb4ee6a4SAndroid Build Coastguard Worker             writeback: false,
356*bb4ee6a4SAndroid Build Coastguard Worker             rewrite_security_xattrs: false,
357*bb4ee6a4SAndroid Build Coastguard Worker             ascii_casefold: false,
358*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "arc_quota")]
359*bb4ee6a4SAndroid Build Coastguard Worker             privileged_quota_uids: Default::default(),
360*bb4ee6a4SAndroid Build Coastguard Worker             use_dax: false,
361*bb4ee6a4SAndroid Build Coastguard Worker             posix_acl: config_default_posix_acl(),
362*bb4ee6a4SAndroid Build Coastguard Worker             max_dynamic_perm: 0,
363*bb4ee6a4SAndroid Build Coastguard Worker             max_dynamic_xattr: 0,
364*bb4ee6a4SAndroid Build Coastguard Worker             security_ctx: config_default_security_ctx(),
365*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "fs_runtime_ugid_map")]
366*bb4ee6a4SAndroid Build Coastguard Worker             ugid_map: Vec::new(),
367*bb4ee6a4SAndroid Build Coastguard Worker         }
368*bb4ee6a4SAndroid Build Coastguard Worker     }
369*bb4ee6a4SAndroid Build Coastguard Worker }
370*bb4ee6a4SAndroid Build Coastguard Worker 
371*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(test, feature = "fs_runtime_ugid_map"))]
372*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
373*bb4ee6a4SAndroid Build Coastguard Worker 
374*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
375*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_valid()376*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_valid() {
377*bb4ee6a4SAndroid Build Coastguard Worker         let input_string =
378*bb4ee6a4SAndroid Build Coastguard Worker             "\"1000 1000 1000 1000 0022 /path/to/dir;2000 2000 2000 2000 0022 /path/to/other/dir\"";
379*bb4ee6a4SAndroid Build Coastguard Worker 
380*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
381*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer).unwrap();
382*bb4ee6a4SAndroid Build Coastguard Worker 
383*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(result.len(), 2);
384*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
385*bb4ee6a4SAndroid Build Coastguard Worker             result,
386*bb4ee6a4SAndroid Build Coastguard Worker             vec![
387*bb4ee6a4SAndroid Build Coastguard Worker                 PermissionData {
388*bb4ee6a4SAndroid Build Coastguard Worker                     guest_uid: 1000,
389*bb4ee6a4SAndroid Build Coastguard Worker                     guest_gid: 1000,
390*bb4ee6a4SAndroid Build Coastguard Worker                     host_uid: 1000,
391*bb4ee6a4SAndroid Build Coastguard Worker                     host_gid: 1000,
392*bb4ee6a4SAndroid Build Coastguard Worker                     umask: 22,
393*bb4ee6a4SAndroid Build Coastguard Worker                     perm_path: "/path/to/dir".to_string(),
394*bb4ee6a4SAndroid Build Coastguard Worker                 },
395*bb4ee6a4SAndroid Build Coastguard Worker                 PermissionData {
396*bb4ee6a4SAndroid Build Coastguard Worker                     guest_uid: 2000,
397*bb4ee6a4SAndroid Build Coastguard Worker                     guest_gid: 2000,
398*bb4ee6a4SAndroid Build Coastguard Worker                     host_uid: 2000,
399*bb4ee6a4SAndroid Build Coastguard Worker                     host_gid: 2000,
400*bb4ee6a4SAndroid Build Coastguard Worker                     umask: 22,
401*bb4ee6a4SAndroid Build Coastguard Worker                     perm_path: "/path/to/other/dir".to_string(),
402*bb4ee6a4SAndroid Build Coastguard Worker                 },
403*bb4ee6a4SAndroid Build Coastguard Worker             ]
404*bb4ee6a4SAndroid Build Coastguard Worker         );
405*bb4ee6a4SAndroid Build Coastguard Worker     }
406*bb4ee6a4SAndroid Build Coastguard Worker 
407*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_process_ugid_map_valid()408*bb4ee6a4SAndroid Build Coastguard Worker     fn test_process_ugid_map_valid() {
409*bb4ee6a4SAndroid Build Coastguard Worker         let input_vec = vec![
410*bb4ee6a4SAndroid Build Coastguard Worker             vec![
411*bb4ee6a4SAndroid Build Coastguard Worker                 "1000".to_string(),
412*bb4ee6a4SAndroid Build Coastguard Worker                 "1000".to_string(),
413*bb4ee6a4SAndroid Build Coastguard Worker                 "1000".to_string(),
414*bb4ee6a4SAndroid Build Coastguard Worker                 "1000".to_string(),
415*bb4ee6a4SAndroid Build Coastguard Worker                 "0022".to_string(),
416*bb4ee6a4SAndroid Build Coastguard Worker                 "/path/to/dir".to_string(),
417*bb4ee6a4SAndroid Build Coastguard Worker             ],
418*bb4ee6a4SAndroid Build Coastguard Worker             vec![
419*bb4ee6a4SAndroid Build Coastguard Worker                 "2000".to_string(),
420*bb4ee6a4SAndroid Build Coastguard Worker                 "2000".to_string(),
421*bb4ee6a4SAndroid Build Coastguard Worker                 "2000".to_string(),
422*bb4ee6a4SAndroid Build Coastguard Worker                 "2000".to_string(),
423*bb4ee6a4SAndroid Build Coastguard Worker                 "0022".to_string(),
424*bb4ee6a4SAndroid Build Coastguard Worker                 "/path/to/other/dir".to_string(),
425*bb4ee6a4SAndroid Build Coastguard Worker             ],
426*bb4ee6a4SAndroid Build Coastguard Worker         ];
427*bb4ee6a4SAndroid Build Coastguard Worker 
428*bb4ee6a4SAndroid Build Coastguard Worker         let result = process_ugid_map(input_vec).unwrap();
429*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(result.len(), 2);
430*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
431*bb4ee6a4SAndroid Build Coastguard Worker             result,
432*bb4ee6a4SAndroid Build Coastguard Worker             vec![
433*bb4ee6a4SAndroid Build Coastguard Worker                 PermissionData {
434*bb4ee6a4SAndroid Build Coastguard Worker                     guest_uid: 1000,
435*bb4ee6a4SAndroid Build Coastguard Worker                     guest_gid: 1000,
436*bb4ee6a4SAndroid Build Coastguard Worker                     host_uid: 1000,
437*bb4ee6a4SAndroid Build Coastguard Worker                     host_gid: 1000,
438*bb4ee6a4SAndroid Build Coastguard Worker                     umask: 22,
439*bb4ee6a4SAndroid Build Coastguard Worker                     perm_path: "/path/to/dir".to_string(),
440*bb4ee6a4SAndroid Build Coastguard Worker                 },
441*bb4ee6a4SAndroid Build Coastguard Worker                 PermissionData {
442*bb4ee6a4SAndroid Build Coastguard Worker                     guest_uid: 2000,
443*bb4ee6a4SAndroid Build Coastguard Worker                     guest_gid: 2000,
444*bb4ee6a4SAndroid Build Coastguard Worker                     host_uid: 2000,
445*bb4ee6a4SAndroid Build Coastguard Worker                     host_gid: 2000,
446*bb4ee6a4SAndroid Build Coastguard Worker                     umask: 22,
447*bb4ee6a4SAndroid Build Coastguard Worker                     perm_path: "/path/to/other/dir".to_string(),
448*bb4ee6a4SAndroid Build Coastguard Worker                 },
449*bb4ee6a4SAndroid Build Coastguard Worker             ]
450*bb4ee6a4SAndroid Build Coastguard Worker         );
451*bb4ee6a4SAndroid Build Coastguard Worker     }
452*bb4ee6a4SAndroid Build Coastguard Worker 
453*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_invalid_format()454*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_invalid_format() {
455*bb4ee6a4SAndroid Build Coastguard Worker         let input_string = "\"1000 1000 1000 0022 /path/to/dir\""; // Missing one element
456*bb4ee6a4SAndroid Build Coastguard Worker 
457*bb4ee6a4SAndroid Build Coastguard Worker         // Create a Deserializer from the input string
458*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
459*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer);
460*bb4ee6a4SAndroid Build Coastguard Worker         assert!(result.is_err());
461*bb4ee6a4SAndroid Build Coastguard Worker     }
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_invalid_guest_uid()464*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_invalid_guest_uid() {
465*bb4ee6a4SAndroid Build Coastguard Worker         let input_string = "\"invalid 1000 1000 1000 0022 /path/to/dir\""; // Invalid guest-UID
466*bb4ee6a4SAndroid Build Coastguard Worker 
467*bb4ee6a4SAndroid Build Coastguard Worker         // Create a Deserializer from the input string
468*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
469*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer);
470*bb4ee6a4SAndroid Build Coastguard Worker         assert!(result.is_err());
471*bb4ee6a4SAndroid Build Coastguard Worker     }
472*bb4ee6a4SAndroid Build Coastguard Worker 
473*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_invalid_guest_gid()474*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_invalid_guest_gid() {
475*bb4ee6a4SAndroid Build Coastguard Worker         let input_string = "\"1000 invalid 1000 1000 0022 /path/to/dir\""; // Invalid guest-GID
476*bb4ee6a4SAndroid Build Coastguard Worker 
477*bb4ee6a4SAndroid Build Coastguard Worker         // Create a Deserializer from the input string
478*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
479*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer);
480*bb4ee6a4SAndroid Build Coastguard Worker         assert!(result.is_err());
481*bb4ee6a4SAndroid Build Coastguard Worker     }
482*bb4ee6a4SAndroid Build Coastguard Worker 
483*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_invalid_umask()484*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_invalid_umask() {
485*bb4ee6a4SAndroid Build Coastguard Worker         let input_string = "\"1000 1000 1000 1000 invalid /path/to/dir\""; // Invalid umask
486*bb4ee6a4SAndroid Build Coastguard Worker 
487*bb4ee6a4SAndroid Build Coastguard Worker         // Create a Deserializer from the input string
488*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
489*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer);
490*bb4ee6a4SAndroid Build Coastguard Worker         assert!(result.is_err());
491*bb4ee6a4SAndroid Build Coastguard Worker     }
492*bb4ee6a4SAndroid Build Coastguard Worker 
493*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_invalid_host_uid()494*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_invalid_host_uid() {
495*bb4ee6a4SAndroid Build Coastguard Worker         let input_string = "\"1000 1000 invalid 1000 0022 /path/to/dir\""; // Invalid host-UID
496*bb4ee6a4SAndroid Build Coastguard Worker 
497*bb4ee6a4SAndroid Build Coastguard Worker         // Create a Deserializer from the input string
498*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
499*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer);
500*bb4ee6a4SAndroid Build Coastguard Worker         assert!(result.is_err());
501*bb4ee6a4SAndroid Build Coastguard Worker     }
502*bb4ee6a4SAndroid Build Coastguard Worker 
503*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_deserialize_ugid_map_invalid_host_gid()504*bb4ee6a4SAndroid Build Coastguard Worker     fn test_deserialize_ugid_map_invalid_host_gid() {
505*bb4ee6a4SAndroid Build Coastguard Worker         let input_string = "\"1000 1000 1000 invalid 0022 /path/to/dir\""; // Invalid host-UID
506*bb4ee6a4SAndroid Build Coastguard Worker 
507*bb4ee6a4SAndroid Build Coastguard Worker         // Create a Deserializer from the input string
508*bb4ee6a4SAndroid Build Coastguard Worker         let mut deserializer = serde_json::Deserializer::from_str(input_string);
509*bb4ee6a4SAndroid Build Coastguard Worker         let result = deserialize_ugid_map(&mut deserializer);
510*bb4ee6a4SAndroid Build Coastguard Worker         assert!(result.is_err());
511*bb4ee6a4SAndroid Build Coastguard Worker     }
512*bb4ee6a4SAndroid Build Coastguard Worker }
513