| 1145 | /// UIDs/GIDs (passed directly to `chown` without a passwd lookup). |
| 1146 | #[cfg(unix)] |
| 1147 | pub fn prepare_filesystem(policy: &SandboxPolicy) -> Result<()> { |
| 1148 | use nix::unistd::chown; |
| 1149 | use nix::unistd::{Gid, Uid}; |
| 1150 | |
| 1151 | let user_name = match policy.process.run_as_user.as_deref() { |
| 1152 | Some(name) if !name.is_empty() => Some(name), |
| 1153 | _ => None, |
| 1154 | }; |
| 1155 | let group_name = match policy.process.run_as_group.as_deref() { |
| 1156 | Some(name) if !name.is_empty() => Some(name), |
| 1157 | _ => None, |
| 1158 | }; |
| 1159 | |
| 1160 | // If no user/group configured, nothing to do |
| 1161 | if user_name.is_none() && group_name.is_none() { |
| 1162 | return Ok(()); |
| 1163 | } |
| 1164 | |
| 1165 | // Resolve UID: numeric values are passed directly; names resolve via passwd. |
| 1166 | let uid = match user_name { |
| 1167 | Some(name) if name.parse::<u32>().is_ok() => { |
| 1168 | Some(Uid::from_raw(name.parse().into_diagnostic()?)) |
| 1169 | } |
| 1170 | Some(name) => User::from_name(name).into_diagnostic()?.map(|u| u.uid), |
| 1171 | _ => None, |
| 1172 | }; |
| 1173 | |
| 1174 | // Resolve GID: numeric values are passed directly; names resolve via group. |
| 1175 | let gid = match group_name { |
| 1176 | Some(name) if name.parse::<u32>().is_ok() => { |
| 1177 | Some(Gid::from_raw(name.parse().into_diagnostic()?)) |
| 1178 | } |
| 1179 | Some(name) => Group::from_name(name).into_diagnostic()?.map(|g| g.gid), |
| 1180 | _ => None, |
| 1181 | }; |
| 1182 | |
| 1183 | // Create missing read_write paths and only chown the ones we created. |
| 1184 | for path in &policy.filesystem.read_write { |
| 1185 | if prepare_read_write_path(path)? { |
| 1186 | debug!( |
| 1187 | path = %path.display(), |
| 1188 | ?uid, |
| 1189 | ?gid, |
| 1190 | "Setting ownership on newly created read_write path" |
| 1191 | ); |
| 1192 | chown(path, uid, gid).into_diagnostic()?; |
| 1193 | } |
| 1194 | } |
| 1195 | |
| 1196 | // When a driver injects a custom UID/GID via environment variables, the |
| 1197 | // /sandbox home directory may already exist with image-default ownership |
| 1198 | // (e.g. UID 1000) that differs from the driver-assigned identity. |
| 1199 | // Recursively chown /sandbox so the sandbox process can use its home |
| 1200 | // directory. |
| 1201 | if std::env::var(openshell_core::sandbox_env::SANDBOX_UID).is_ok() { |
| 1202 | let sandbox_home = Path::new("/sandbox"); |
| 1203 | if sandbox_home.exists() { |
| 1204 | info!(?uid, ?gid, "Chowning /sandbox for driver-injected UID/GID"); |