main.rs 27 KB

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