main.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. // SPDX-License-Identifier: AGPL-3.0-or-later
  2. mod config;
  3. use btfproto::{
  4. local_fs::{LocalFs, ModeAuthorizer},
  5. server::{new_fs_server, FsProvider},
  6. };
  7. use btlib::{
  8. config_helpers::from_envvar,
  9. crypto::{tpm::TpmCredStore, CredStore, Creds},
  10. };
  11. use btmsg::Receiver;
  12. use config::{Config, ConfigRef, Envvars};
  13. use std::{
  14. net::{IpAddr, Ipv6Addr},
  15. path::PathBuf,
  16. str::FromStr,
  17. sync::Arc,
  18. };
  19. const ENVVARS: Envvars<'static> = Envvars {
  20. ip_addr: "BTFSD_IPADDR",
  21. tabrmd: "BTFSD_TABRMD",
  22. tpm_state_path: "BTFSD_TPMSTATE",
  23. block_dir: "BTFSD_BLOCKDIR",
  24. };
  25. const DEFAULT_CONFIG: ConfigRef<'static> = ConfigRef {
  26. ip_addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
  27. tabrmd: "bus_type=session",
  28. tpm_state_path: "./tpm_state",
  29. block_dir: "./bt",
  30. };
  31. async fn provider<C: 'static + Send + Sync + Creds>(
  32. block_dir: PathBuf,
  33. creds: C,
  34. ) -> impl FsProvider {
  35. if block_dir.exists() {
  36. LocalFs::new_existing(block_dir, creds, ModeAuthorizer).unwrap()
  37. } else {
  38. std::fs::create_dir_all(&block_dir).unwrap();
  39. LocalFs::new_empty(block_dir, 0, creds, ModeAuthorizer)
  40. .await
  41. .unwrap()
  42. }
  43. }
  44. async fn receiver(config: Config) -> impl Receiver {
  45. let cred_store = TpmCredStore::from_tabrmd(&config.tabrmd, config.tpm_state_path).unwrap();
  46. let node_creds = cred_store.node_creds().unwrap();
  47. let provider = Arc::new(provider(config.block_dir, node_creds.clone()).await);
  48. new_fs_server(config.ip_addr, Arc::new(node_creds), provider).unwrap()
  49. }
  50. #[tokio::main]
  51. async fn main() {
  52. let ip_addr = from_envvar(ENVVARS.ip_addr)
  53. .unwrap()
  54. .map(|txt| IpAddr::from_str(&txt).unwrap());
  55. let tabrmd = from_envvar(ENVVARS.tabrmd).unwrap();
  56. let tpm_state_path = from_envvar(ENVVARS.tpm_state_path)
  57. .unwrap()
  58. .map(PathBuf::from);
  59. let block_dir = from_envvar(ENVVARS.block_dir).unwrap().map(PathBuf::from);
  60. let config = Config::builder()
  61. .with_ip_addr(ip_addr)
  62. .with_tabrmd(tabrmd)
  63. .with_tpm_state_path(tpm_state_path)
  64. .with_block_dir(block_dir)
  65. .build();
  66. let receiver = receiver(config).await;
  67. receiver.complete().unwrap().await.unwrap();
  68. }
  69. #[cfg(test)]
  70. mod tests {
  71. use super::*;
  72. use btfproto::{client::FsClient, msg::*};
  73. use btlib::{
  74. crypto::{ConcreteCreds, CredsPriv, CredsPub},
  75. log::BuilderExt,
  76. AuthzAttrs, BlockMetaSecrets, Epoch, IssuedProcRec, Principaled, ProcRec,
  77. };
  78. use btlib_tests::TpmCredStoreHarness;
  79. use btmsg::{BlockAddr, Transmitter};
  80. use btserde::from_slice;
  81. use std::{future::ready, net::Ipv4Addr, time::Duration};
  82. use swtpm_harness::SwtpmHarness;
  83. use tempdir::TempDir;
  84. const LOG_LEVEL: &str = "warn";
  85. #[ctor::ctor]
  86. fn ctor() {
  87. std::env::set_var("RUST_LOG", LOG_LEVEL);
  88. env_logger::Builder::from_default_env().btformat().init();
  89. }
  90. struct TestCase<R, T> {
  91. client: FsClient<T>,
  92. rx: R,
  93. harness: TpmCredStoreHarness,
  94. _dir: TempDir,
  95. }
  96. const ROOT_PASSWD: &str = "existential_threat";
  97. const LOCALHOST: IpAddr = IpAddr::V6(Ipv6Addr::LOCALHOST);
  98. const BT_DIR: &str = "bt";
  99. async fn test_case(
  100. dir: TempDir,
  101. harness: TpmCredStoreHarness,
  102. ip_addr: IpAddr,
  103. ) -> TestCase<impl Receiver, impl Transmitter> {
  104. let config = Config {
  105. ip_addr,
  106. tabrmd: harness.swtpm().tabrmd_config().to_owned(),
  107. tpm_state_path: harness.swtpm().state_path().to_owned(),
  108. block_dir: dir.path().join(BT_DIR),
  109. };
  110. let rx = receiver(config).await;
  111. let tx = rx.transmitter(rx.addr().clone()).await.unwrap();
  112. let client = FsClient::new(tx);
  113. TestCase {
  114. _dir: dir,
  115. harness,
  116. rx,
  117. client,
  118. }
  119. }
  120. async fn new_case() -> TestCase<impl Receiver, impl Transmitter> {
  121. let dir = TempDir::new("btfsd").unwrap();
  122. let harness = TpmCredStoreHarness::new(ROOT_PASSWD.to_owned()).unwrap();
  123. test_case(dir, harness, LOCALHOST).await
  124. }
  125. async fn existing_case<R: Receiver, T: Transmitter>(
  126. case: TestCase<R, T>,
  127. ) -> TestCase<impl Receiver, impl Transmitter> {
  128. case.rx.stop().await.unwrap();
  129. case.rx.complete().unwrap().await.unwrap();
  130. let TestCase {
  131. _dir,
  132. harness: _harness,
  133. ..
  134. } = case;
  135. test_case(_dir, _harness, IpAddr::V4(Ipv4Addr::LOCALHOST)).await
  136. }
  137. #[allow(dead_code)]
  138. async fn manual_test() {
  139. let case = new_case().await;
  140. case.rx.complete().unwrap().await.unwrap();
  141. }
  142. #[tokio::test]
  143. async fn create_write_read() {
  144. const FILENAME: &str = "file.txt";
  145. const EXPECTED: &[u8] = b"potato";
  146. let case = new_case().await;
  147. let client = case.client;
  148. let CreateReply { inode, handle, .. } = client
  149. .create(
  150. SpecInodes::RootDir.into(),
  151. FILENAME,
  152. FlagValue::ReadWrite.into(),
  153. 0o644,
  154. 0,
  155. )
  156. .await
  157. .unwrap();
  158. let WriteReply { written, .. } = client.write(inode, handle, 0, EXPECTED).await.unwrap();
  159. assert_eq!(EXPECTED.len() as u64, written);
  160. let actual = client
  161. .read(inode, handle, 0, EXPECTED.len() as u64, |reply| {
  162. let mut buf = Vec::with_capacity(EXPECTED.len());
  163. buf.extend_from_slice(reply.data);
  164. ready(buf)
  165. })
  166. .await
  167. .unwrap();
  168. assert_eq!(EXPECTED, &actual);
  169. }
  170. #[tokio::test]
  171. async fn read_from_different_instance() {
  172. const FILENAME: &str = "file.txt";
  173. const EXPECTED: &[u8] = b"potato";
  174. let case = new_case().await;
  175. let client = &case.client;
  176. let CreateReply { inode, handle, .. } = client
  177. .create(
  178. SpecInodes::RootDir.into(),
  179. FILENAME,
  180. FlagValue::ReadWrite.into(),
  181. 0o644,
  182. 0,
  183. )
  184. .await
  185. .unwrap();
  186. let WriteReply { written, .. } = client.write(inode, handle, 0, EXPECTED).await.unwrap();
  187. assert_eq!(EXPECTED.len() as u64, written);
  188. client.flush(inode, handle).await.unwrap();
  189. let case = existing_case(case).await;
  190. let client = &case.client;
  191. let LookupReply { inode, .. } = client
  192. .lookup(SpecInodes::RootDir.into(), FILENAME)
  193. .await
  194. .unwrap();
  195. let OpenReply { handle, .. } = client
  196. .open(inode, FlagValue::ReadOnly.into())
  197. .await
  198. .unwrap();
  199. let actual = client
  200. .read(inode, handle, 0, EXPECTED.len() as u64, |reply| {
  201. let mut buf = Vec::with_capacity(EXPECTED.len());
  202. buf.extend_from_slice(reply.data);
  203. ready(buf)
  204. })
  205. .await
  206. .unwrap();
  207. assert_eq!(EXPECTED, &actual);
  208. }
  209. #[tokio::test]
  210. async fn create_lookup() {
  211. const FILENAME: &str = "file.txt";
  212. let case = new_case().await;
  213. let client = case.client;
  214. let CreateReply {
  215. inode: expected, ..
  216. } = client
  217. .create(
  218. SpecInodes::RootDir.into(),
  219. FILENAME,
  220. FlagValue::ReadOnly.into(),
  221. 0o644,
  222. 0,
  223. )
  224. .await
  225. .unwrap();
  226. let LookupReply { inode: actual, .. } = client
  227. .lookup(SpecInodes::RootDir.into(), FILENAME)
  228. .await
  229. .unwrap();
  230. assert_eq!(expected, actual);
  231. }
  232. #[tokio::test]
  233. async fn open_existing() {
  234. const FILENAME: &str = "file.txt";
  235. let case = new_case().await;
  236. let client = case.client;
  237. let CreateReply { inode, .. } = client
  238. .create(
  239. SpecInodes::RootDir.into(),
  240. FILENAME,
  241. FlagValue::ReadOnly.into(),
  242. 0o644,
  243. 0,
  244. )
  245. .await
  246. .unwrap();
  247. let result = client.open(inode, FlagValue::ReadWrite.into()).await;
  248. assert!(result.is_ok());
  249. }
  250. #[tokio::test]
  251. async fn write_flush_close_read() {
  252. const FILENAME: &str = "lyrics.txt";
  253. const EXPECTED: &[u8] = b"Fate, or something better";
  254. let case = new_case().await;
  255. let client = &case.client;
  256. let CreateReply { inode, handle, .. } = client
  257. .create(
  258. SpecInodes::RootDir.into(),
  259. FILENAME,
  260. FlagValue::ReadWrite.into(),
  261. 0o644,
  262. 0,
  263. )
  264. .await
  265. .unwrap();
  266. let WriteReply { written, .. } = client.write(inode, handle, 0, EXPECTED).await.unwrap();
  267. assert_eq!(EXPECTED.len() as u64, written);
  268. client.flush(inode, handle).await.unwrap();
  269. client.close(inode, handle).await.unwrap();
  270. let OpenReply { handle, .. } = client
  271. .open(inode, FlagValue::ReadOnly.into())
  272. .await
  273. .unwrap();
  274. let actual = client
  275. .read(inode, handle, 0, EXPECTED.len() as u64, |reply| {
  276. ready(reply.data.to_owned())
  277. })
  278. .await
  279. .unwrap();
  280. assert_eq!(EXPECTED, &actual);
  281. }
  282. #[tokio::test]
  283. async fn link() {
  284. const FIRSTNAME: &str = "Jean-Luc";
  285. const LASTNAME: &str = "Picard";
  286. let case = new_case().await;
  287. let client = &case.client;
  288. let CreateReply { inode, .. } = client
  289. .create(
  290. SpecInodes::RootDir.into(),
  291. FIRSTNAME,
  292. Flags::default(),
  293. 0o644,
  294. 0,
  295. )
  296. .await
  297. .unwrap();
  298. client
  299. .link(inode, SpecInodes::RootDir.into(), LASTNAME)
  300. .await
  301. .unwrap();
  302. let OpenReply {
  303. handle: root_handle,
  304. ..
  305. } = client
  306. .open(
  307. SpecInodes::RootDir.into(),
  308. FlagValue::ReadOnly | FlagValue::Directory,
  309. )
  310. .await
  311. .unwrap();
  312. let ReadDirReply { entries, .. } = client
  313. .read_dir(SpecInodes::RootDir.into(), root_handle, 0, 0)
  314. .await
  315. .unwrap();
  316. let filenames: Vec<_> = entries.iter().map(|e| e.0.as_str()).collect();
  317. assert!(filenames.contains(&FIRSTNAME));
  318. assert!(filenames.contains(&LASTNAME));
  319. }
  320. #[tokio::test]
  321. async fn unlink() {
  322. const FIRSTNAME: &str = "Jean-Luc";
  323. const LASTNAME: &str = "Picard";
  324. let case = new_case().await;
  325. let client = &case.client;
  326. let CreateReply { inode, .. } = client
  327. .create(
  328. SpecInodes::RootDir.into(),
  329. FIRSTNAME,
  330. Flags::default(),
  331. 0o644,
  332. 0,
  333. )
  334. .await
  335. .unwrap();
  336. client
  337. .link(inode, SpecInodes::RootDir.into(), LASTNAME)
  338. .await
  339. .unwrap();
  340. client
  341. .unlink(SpecInodes::RootDir.into(), FIRSTNAME)
  342. .await
  343. .unwrap();
  344. let OpenReply {
  345. handle: root_handle,
  346. ..
  347. } = client
  348. .open(
  349. SpecInodes::RootDir.into(),
  350. FlagValue::ReadOnly | FlagValue::Directory,
  351. )
  352. .await
  353. .unwrap();
  354. let ReadDirReply { entries, .. } = client
  355. .read_dir(SpecInodes::RootDir.into(), root_handle, 0, 0)
  356. .await
  357. .unwrap();
  358. let filenames: Vec<_> = entries.iter().map(|e| e.0.as_str()).collect();
  359. assert!(filenames.contains(&LASTNAME));
  360. assert!(!filenames.contains(&FIRSTNAME));
  361. }
  362. #[tokio::test]
  363. async fn delete() {
  364. const FILENAME: &str = "MANIFESTO.tex";
  365. let case = new_case().await;
  366. let client = &case.client;
  367. client
  368. .create(
  369. SpecInodes::RootDir.into(),
  370. FILENAME,
  371. Flags::default(),
  372. 0o644,
  373. 0,
  374. )
  375. .await
  376. .unwrap();
  377. client
  378. .unlink(SpecInodes::RootDir.into(), FILENAME)
  379. .await
  380. .unwrap();
  381. let OpenReply {
  382. handle: root_handle,
  383. ..
  384. } = client
  385. .open(
  386. SpecInodes::RootDir.into(),
  387. FlagValue::ReadOnly | FlagValue::Directory,
  388. )
  389. .await
  390. .unwrap();
  391. let ReadDirReply { entries, .. } = client
  392. .read_dir(SpecInodes::RootDir.into(), root_handle, 0, 0)
  393. .await
  394. .unwrap();
  395. let filenames: Vec<_> = entries.iter().map(|e| e.0.as_str()).collect();
  396. assert!(!filenames.contains(&FILENAME));
  397. }
  398. #[tokio::test]
  399. async fn read_meta() {
  400. const FILENAME: &str = "kibosh.txt";
  401. const EXPECTED: u32 = 0o600;
  402. let case = new_case().await;
  403. let client = &case.client;
  404. let before_create = Epoch::now();
  405. let CreateReply { inode, handle, .. } = client
  406. .create(
  407. SpecInodes::RootDir.into(),
  408. FILENAME,
  409. FlagValue::ReadWrite.into(),
  410. EXPECTED,
  411. 0,
  412. )
  413. .await
  414. .unwrap();
  415. let before_read = Epoch::now();
  416. let ReadMetaReply { attrs, .. } = client.read_meta(inode, Some(handle)).await.unwrap();
  417. let actual = attrs.mode;
  418. assert_eq!(FileType::Reg | EXPECTED, actual);
  419. assert!(before_create <= attrs.ctime && attrs.ctime <= before_read);
  420. assert!(before_create <= attrs.mtime && attrs.mtime <= before_read);
  421. assert!(before_create <= attrs.atime && attrs.atime <= before_read);
  422. assert_eq!(attrs.block_id.inode, inode);
  423. assert_eq!(attrs.size, 0);
  424. assert!(attrs.tags.is_empty());
  425. }
  426. #[tokio::test]
  427. async fn write_meta() {
  428. fn assert_eq(expected: &Attrs, actual: &BlockMetaSecrets) {
  429. assert_eq!(expected.mode, actual.mode);
  430. assert_eq!(expected.uid, actual.uid);
  431. assert_eq!(expected.gid, actual.gid);
  432. assert_eq!(expected.atime, actual.atime);
  433. assert_eq!(expected.mtime, actual.mtime);
  434. assert_eq!(expected.ctime, actual.ctime);
  435. assert_eq!(expected.tags.len(), actual.tags.len());
  436. for (key, expected_value) in expected.tags.iter() {
  437. let actual_value = actual.tags.get(key).unwrap();
  438. assert_eq!(expected_value, actual_value);
  439. }
  440. }
  441. const FILENAME: &str = "word_salad.docx";
  442. let expected = Attrs {
  443. mode: 0o600,
  444. uid: 9290,
  445. gid: 2190,
  446. atime: 23193.into(),
  447. mtime: 53432.into(),
  448. ctime: 87239.into(),
  449. tags: Vec::new(),
  450. };
  451. let case = new_case().await;
  452. let client = &case.client;
  453. let CreateReply { inode, handle, .. } = client
  454. .create(
  455. SpecInodes::RootDir.into(),
  456. FILENAME,
  457. FlagValue::ReadWrite.into(),
  458. expected.mode | 0o011,
  459. 0,
  460. )
  461. .await
  462. .unwrap();
  463. let WriteMetaReply { attrs, .. } = client
  464. .write_meta(inode, Some(handle), expected.clone(), AttrsSet::ALL)
  465. .await
  466. .unwrap();
  467. assert_eq(&expected, &attrs);
  468. let ReadMetaReply { attrs, .. } = client.read_meta(inode, Some(handle)).await.unwrap();
  469. assert_eq(&expected, &attrs);
  470. }
  471. #[tokio::test]
  472. async fn allocate_when_empty() {
  473. const FILENAME: &str = "output.dat";
  474. const EXPECTED: &[u8] = &[0u8; 8];
  475. let case = new_case().await;
  476. let client = &case.client;
  477. let CreateReply { inode, handle, .. } = client
  478. .create(
  479. SpecInodes::RootDir.into(),
  480. FILENAME,
  481. FlagValue::ReadWrite.into(),
  482. 0o644,
  483. 0,
  484. )
  485. .await
  486. .unwrap();
  487. client
  488. .allocate(inode, handle, EXPECTED.len() as u64)
  489. .await
  490. .unwrap();
  491. let actual = client
  492. .read(inode, handle, 0, EXPECTED.len() as u64, |reply| {
  493. ready(Vec::from(reply.data))
  494. })
  495. .await
  496. .unwrap();
  497. assert_eq!(EXPECTED, actual);
  498. }
  499. #[tokio::test]
  500. async fn allocate_with_data_present() {
  501. const FILENAME: &str = "output.dat";
  502. const EXPECTED: &[u8] = &[1, 1, 1, 1, 0, 0, 0, 0];
  503. let case = new_case().await;
  504. let client = &case.client;
  505. let CreateReply { inode, handle, .. } = client
  506. .create(
  507. SpecInodes::RootDir.into(),
  508. FILENAME,
  509. FlagValue::ReadWrite.into(),
  510. 0o644,
  511. 0,
  512. )
  513. .await
  514. .unwrap();
  515. client.write(inode, handle, 0, &[1, 1, 1, 1]).await.unwrap();
  516. client
  517. .allocate(inode, handle, EXPECTED.len() as u64)
  518. .await
  519. .unwrap();
  520. let actual = client
  521. .read(inode, handle, 0, EXPECTED.len() as u64, |reply| {
  522. ready(Vec::from(reply.data))
  523. })
  524. .await
  525. .unwrap();
  526. assert_eq!(EXPECTED, actual);
  527. }
  528. #[tokio::test]
  529. async fn forget() {
  530. const FILENAME: &str = "seed.dat";
  531. let case = new_case().await;
  532. let client = &case.client;
  533. let CreateReply { inode, handle, .. } = client
  534. .create(
  535. SpecInodes::RootDir.into(),
  536. FILENAME,
  537. FlagValue::ReadWrite.into(),
  538. 0o644,
  539. 0,
  540. )
  541. .await
  542. .unwrap();
  543. client.close(inode, handle).await.unwrap();
  544. let result = client.forget(inode, 1).await;
  545. assert!(result.is_ok());
  546. }
  547. #[tokio::test]
  548. async fn add_readcap() {
  549. const FILENAME: &str = "net";
  550. let case = new_case().await;
  551. let client = &case.client;
  552. let creds = ConcreteCreds::generate().unwrap();
  553. let CreateReply { inode, handle, .. } = client
  554. .create(
  555. SpecInodes::RootDir.into(),
  556. FILENAME,
  557. FlagValue::ReadWrite | FlagValue::Directory,
  558. 0o755,
  559. 0,
  560. )
  561. .await
  562. .unwrap();
  563. client
  564. .add_readcap(inode, handle, creds.principal(), creds.concrete_pub().enc)
  565. .await
  566. .unwrap();
  567. }
  568. #[tokio::test]
  569. async fn grant_access_to_root() {
  570. let case = new_case().await;
  571. let client = &case.client;
  572. let mut creds = ConcreteCreds::generate().unwrap();
  573. let root_creds = case.harness.root_creds().unwrap();
  574. let writecap = root_creds
  575. .issue_writecap(
  576. creds.principal(),
  577. vec![],
  578. Epoch::now() + Duration::from_secs(3600),
  579. )
  580. .unwrap();
  581. creds.set_writecap(writecap);
  582. let expected = IssuedProcRec {
  583. addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
  584. pub_creds: creds.concrete_pub(),
  585. writecap: creds.writecap().unwrap().to_owned(),
  586. authz_attrs: AuthzAttrs {
  587. uid: 9001,
  588. gid: 9001,
  589. supp_gids: vec![12, 41, 19],
  590. },
  591. };
  592. client
  593. .grant_access(SpecInodes::RootDir.into(), expected.clone())
  594. .await
  595. .unwrap();
  596. let LookupReply { inode, entry, .. } = client
  597. .lookup(SpecInodes::RootDir.into(), &creds.principal().to_string())
  598. .await
  599. .unwrap();
  600. let OpenReply { handle, .. } = client
  601. .open(inode, FlagValue::ReadOnly.into())
  602. .await
  603. .unwrap();
  604. let record = client
  605. .read(inode, handle, 0, entry.attr.size, |reply| {
  606. ready(from_slice::<ProcRec>(reply.data))
  607. })
  608. .await
  609. .unwrap()
  610. .unwrap();
  611. let actual = record.validate().unwrap();
  612. assert_eq!(expected, actual);
  613. }
  614. #[tokio::test]
  615. async fn grant_access_to_non_root_dir() {
  616. const DIRNAME: &str = "var";
  617. let case = new_case().await;
  618. let client = &case.client;
  619. let mut creds = ConcreteCreds::generate().unwrap();
  620. let root_creds = case.harness.root_creds().unwrap();
  621. let writecap = root_creds
  622. .issue_writecap(
  623. creds.principal(),
  624. vec![DIRNAME.to_owned()],
  625. Epoch::now() + Duration::from_secs(3600),
  626. )
  627. .unwrap();
  628. creds.set_writecap(writecap);
  629. let expected = IssuedProcRec {
  630. addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
  631. pub_creds: creds.concrete_pub(),
  632. writecap: creds.writecap().unwrap().to_owned(),
  633. authz_attrs: AuthzAttrs {
  634. uid: 9001,
  635. gid: 9001,
  636. supp_gids: vec![12, 41, 19],
  637. },
  638. };
  639. let CreateReply { inode, handle, .. } = client
  640. .create(
  641. SpecInodes::RootDir.into(),
  642. DIRNAME,
  643. FlagValue::Directory | FlagValue::ReadWrite,
  644. 0o755,
  645. 0,
  646. )
  647. .await
  648. .unwrap();
  649. client.close(inode, handle).await.unwrap();
  650. client.grant_access(inode, expected.clone()).await.unwrap();
  651. let LookupReply {
  652. inode: record_inode,
  653. entry,
  654. ..
  655. } = client
  656. .lookup(inode, &creds.principal().to_string())
  657. .await
  658. .unwrap();
  659. let OpenReply {
  660. handle: record_handle,
  661. ..
  662. } = client
  663. .open(record_inode, FlagValue::ReadOnly.into())
  664. .await
  665. .unwrap();
  666. let record = client
  667. .read(record_inode, record_handle, 0, entry.attr.size, |reply| {
  668. ready(from_slice::<ProcRec>(reply.data))
  669. })
  670. .await
  671. .unwrap()
  672. .unwrap();
  673. let actual = record.validate().unwrap();
  674. assert_eq!(expected, actual);
  675. }
  676. #[tokio::test]
  677. async fn grant_access_non_root_user() {
  678. const ROOT_FILE: &str = "root.txt";
  679. const USER_FILE: &str = "user.txt";
  680. let user_tpm = SwtpmHarness::new().unwrap();
  681. let case = new_case().await;
  682. let client = &case.client;
  683. let root_creds = case.harness.root_creds().unwrap();
  684. let user_creds = {
  685. let cred_store = TpmCredStore::from_context(
  686. user_tpm.context().unwrap(),
  687. user_tpm.state_path().to_owned(),
  688. )
  689. .unwrap();
  690. let mut creds = cred_store.node_creds().unwrap();
  691. let writecap = root_creds
  692. .issue_writecap(
  693. creds.principal(),
  694. vec![],
  695. Epoch::now() + Duration::from_secs(3600),
  696. )
  697. .unwrap();
  698. cred_store
  699. .assign_node_writecap(&mut creds, writecap)
  700. .unwrap();
  701. creds
  702. };
  703. let expected = IssuedProcRec {
  704. addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
  705. pub_creds: user_creds.concrete_pub(),
  706. writecap: user_creds.writecap().unwrap().to_owned(),
  707. authz_attrs: AuthzAttrs {
  708. uid: 9001,
  709. gid: 9001,
  710. supp_gids: vec![12, 41, 19],
  711. },
  712. };
  713. let root_inode = SpecInodes::RootDir.into();
  714. client
  715. .grant_access(root_inode, expected.clone())
  716. .await
  717. .unwrap();
  718. // Note that non-root users do not have permission to write to ROOT_FILE, but
  719. // UID 9001 has permission to write to USER_FILE.
  720. client
  721. .create(root_inode, ROOT_FILE, FlagValue::ReadWrite.into(), 0o644, 0)
  722. .await
  723. .unwrap();
  724. let CreateReply { inode, handle, .. } = client
  725. .create(root_inode, USER_FILE, FlagValue::ReadWrite.into(), 0o644, 0)
  726. .await
  727. .unwrap();
  728. let mut attrs = Attrs::default();
  729. attrs.uid = expected.authz_attrs.uid;
  730. attrs.gid = expected.authz_attrs.gid;
  731. client
  732. .write_meta(inode, Some(handle), attrs, AttrsSet::UID | AttrsSet::GID)
  733. .await
  734. .unwrap();
  735. let node_creds = case.harness.cred_store().node_creds().unwrap();
  736. let bind_path = node_creds.writecap().unwrap().bind_path();
  737. let block_addr = Arc::new(BlockAddr::new(LOCALHOST, Arc::new(bind_path)));
  738. let tx = btmsg::transmitter(block_addr, Arc::new(user_creds))
  739. .await
  740. .unwrap();
  741. let client = FsClient::new(tx);
  742. let root_dir = SpecInodes::RootDir.value();
  743. let LookupReply { inode, .. } = client.lookup(root_dir, USER_FILE).await.unwrap();
  744. let result = client.open(inode, FlagValue::ReadWrite.into()).await;
  745. assert!(result.is_ok());
  746. let LookupReply { inode, .. } = client.lookup(root_dir, ROOT_FILE).await.unwrap();
  747. let result = client.open(inode, FlagValue::ReadWrite.into()).await;
  748. let err = result.err().unwrap().to_string();
  749. assert_eq!("write access denied", err);
  750. }
  751. }