fs.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * fs.c
  15. *
  16. * This file contains codes for implementation of 'chroot' filesystem.
  17. */
  18. #include <shim_internal.h>
  19. #include <shim_thread.h>
  20. #include <shim_handle.h>
  21. #include <shim_vma.h>
  22. #include <shim_fs.h>
  23. #include <shim_utils.h>
  24. #include <shim_profile.h>
  25. #include <pal.h>
  26. #include <pal_error.h>
  27. #include <errno.h>
  28. #include <linux/stat.h>
  29. #include <linux/fcntl.h>
  30. #include <asm/fcntl.h>
  31. #include <asm/mman.h>
  32. #include <asm/unistd.h>
  33. #include <asm/prctl.h>
  34. #define URI_MAX_SIZE STR_SIZE
  35. #define TTY_FILE_MODE 0666
  36. #define FILE_BUFMAP_SIZE (PAL_CB(pagesize) * 4)
  37. #define FILE_BUF_SIZE (PAL_CB(pagesize))
  38. struct mount_data {
  39. size_t data_size;
  40. enum shim_file_type base_type;
  41. unsigned long ino_base;
  42. size_t root_uri_len;
  43. char root_uri[];
  44. };
  45. #define HANDLE_MOUNT_DATA(h) ((struct mount_data*)(h)->fs->data)
  46. #define DENTRY_MOUNT_DATA(d) ((struct mount_data*)(d)->fs->data)
  47. static int chroot_mount (const char * uri, void ** mount_data)
  48. {
  49. enum shim_file_type type;
  50. if (strstartswith_static(uri, "file:")) {
  51. type = FILE_UNKNOWN;
  52. uri += 5;
  53. } else if (strstartswith_static(uri, "dev:")) {
  54. type = strstartswith_static(uri + static_strlen("dev:"), "tty") ? FILE_TTY : FILE_DEV;
  55. uri += 4;
  56. } else
  57. return -EINVAL;
  58. if (!(*uri))
  59. uri = ".";
  60. int uri_len = strlen(uri);
  61. int data_size = uri_len + 1 + sizeof(struct mount_data);
  62. struct mount_data * mdata = (struct mount_data *) malloc(data_size);
  63. mdata->data_size = data_size;
  64. mdata->base_type = type;
  65. mdata->ino_base = hash_path(uri, uri_len);
  66. mdata->root_uri_len = uri_len;
  67. memcpy(mdata->root_uri, uri, uri_len + 1);
  68. *mount_data = mdata;
  69. return 0;
  70. }
  71. static int chroot_unmount (void * mount_data)
  72. {
  73. free(mount_data);
  74. return 0;
  75. }
  76. static inline ssize_t concat_uri (char * buffer, size_t size, int type,
  77. const char * root, size_t root_len,
  78. const char * trim, size_t trim_len)
  79. {
  80. char * tmp = NULL;
  81. switch (type) {
  82. case FILE_UNKNOWN:
  83. case FILE_REGULAR:
  84. tmp = strcpy_static(buffer, "file:", size);
  85. break;
  86. case FILE_DIR:
  87. tmp = strcpy_static(buffer, "dir:", size);
  88. break;
  89. case FILE_DEV:
  90. case FILE_TTY:
  91. tmp = strcpy_static(buffer, "dev:", size);
  92. break;
  93. default:
  94. return -EINVAL;
  95. }
  96. if (!tmp || tmp + root_len + trim_len + 2 > buffer + size)
  97. return -ENAMETOOLONG;
  98. if (root_len) {
  99. memcpy(tmp, root, root_len + 1);
  100. tmp += root_len;
  101. }
  102. if (trim_len) {
  103. *(tmp++) = '/';
  104. memcpy(tmp, trim, trim_len + 1);
  105. tmp += trim_len;
  106. }
  107. return tmp - buffer;
  108. }
  109. /* simply just create data, sometimes it is individually called when the
  110. handle is not linked to a dentry */
  111. static struct shim_file_data * __create_data (void)
  112. {
  113. struct shim_file_data * data = calloc(1, sizeof(struct shim_file_data));
  114. if (!data)
  115. return NULL;
  116. create_lock(&data->lock);
  117. return data;
  118. }
  119. static void __destroy_data (struct shim_file_data * data)
  120. {
  121. qstrfree(&data->host_uri);
  122. destroy_lock(&data->lock);
  123. free(data);
  124. }
  125. static ssize_t make_uri (struct shim_dentry * dent)
  126. {
  127. struct mount_data * mdata = DENTRY_MOUNT_DATA(dent);
  128. assert(mdata);
  129. struct shim_file_data * data = FILE_DENTRY_DATA(dent);
  130. char uri[URI_MAX_SIZE];
  131. ssize_t len = concat_uri(uri, URI_MAX_SIZE, data->type,
  132. mdata->root_uri,
  133. mdata->root_uri_len,
  134. qstrgetstr(&dent->rel_path),
  135. dent->rel_path.len);
  136. if (len >= 0)
  137. qstrsetstr(&data->host_uri, uri, len);
  138. return len;
  139. }
  140. /* create a data in the dentry and compose it's uri. dent->lock needs to
  141. be held */
  142. static int create_data (struct shim_dentry * dent, const char * uri, size_t len)
  143. {
  144. if (dent->data)
  145. return 0;
  146. struct shim_file_data * data = __create_data();
  147. if (!data)
  148. return -ENOMEM;
  149. dent->data = data;
  150. struct mount_data * mdata = DENTRY_MOUNT_DATA(dent);
  151. assert(mdata);
  152. data->type = (dent->state & DENTRY_ISDIRECTORY) ?
  153. FILE_DIR : mdata->base_type;
  154. data->mode = NO_MODE;
  155. if (uri) {
  156. qstrsetstr(&data->host_uri, uri, len);
  157. } else {
  158. int ret = make_uri(dent);
  159. if (ret < 0)
  160. return ret;
  161. }
  162. atomic_set(&data->version, 0);
  163. return 0;
  164. }
  165. static int chroot_readdir (struct shim_dentry * dent,
  166. struct shim_dirent ** dirent);
  167. static int __query_attr (struct shim_dentry * dent,
  168. struct shim_file_data * data, PAL_HANDLE pal_handle)
  169. {
  170. PAL_STREAM_ATTR pal_attr;
  171. enum shim_file_type old_type = data->type;
  172. if (pal_handle ?
  173. !DkStreamAttributesQueryByHandle(pal_handle, &pal_attr) :
  174. !DkStreamAttributesQuery(qstrgetstr(&data->host_uri), &pal_attr))
  175. return -PAL_ERRNO;
  176. /* need to correct the data type */
  177. if (data->type == FILE_UNKNOWN)
  178. switch (pal_attr.handle_type) {
  179. case pal_type_file: data->type = FILE_REGULAR; if (dent) dent->type = S_IFREG; break;
  180. case pal_type_dir: data->type = FILE_DIR; if (dent) dent->type = S_IFDIR; break;
  181. case pal_type_dev: data->type = FILE_DEV; if (dent) dent->type = S_IFCHR; break;
  182. }
  183. data->mode = (pal_attr.readable ? S_IRUSR : 0) |
  184. (pal_attr.writable ? S_IWUSR : 0) |
  185. (pal_attr.runnable ? S_IXUSR : 0);
  186. atomic_set(&data->size, pal_attr.pending_size);
  187. if (data->type == FILE_DIR) {
  188. int ret;
  189. /* Move up the uri update; need to convert manifest-level file:
  190. * directives to 'dir:' uris */
  191. if (old_type != FILE_DIR) {
  192. dent->state |= DENTRY_ISDIRECTORY;
  193. if ((ret = make_uri(dent)) < 0) {
  194. unlock(&data->lock);
  195. return ret;
  196. }
  197. }
  198. /* DEP 3/18/17: If we have a directory, we need to find out how many
  199. * children it has by hand. */
  200. /* XXX: Keep coherent with rmdir/mkdir/creat, etc */
  201. struct shim_dirent *d, *dbuf = NULL;
  202. size_t nlink = 0;
  203. int rv = chroot_readdir(dent, &dbuf);
  204. if (rv != 0)
  205. return rv;
  206. if (dbuf) {
  207. for (d = dbuf; d; d = d->next)
  208. nlink++;
  209. free(dbuf);
  210. } else
  211. nlink = 2; // Educated guess...
  212. data->nlink = nlink;
  213. } else {
  214. /* DEP 3/18/17: Right now, we don't support hard links,
  215. * so just return 1;
  216. */
  217. data->nlink = 1;
  218. }
  219. data->queried = true;
  220. return 0;
  221. }
  222. /* do not need any lock */
  223. static void chroot_update_ino (struct shim_dentry * dent)
  224. {
  225. if (dent->state & DENTRY_INO_UPDATED)
  226. return;
  227. struct mount_data * mdata = DENTRY_MOUNT_DATA(dent);
  228. unsigned long ino = mdata->ino_base;
  229. if (!qstrempty(&dent->rel_path))
  230. ino = rehash_path(mdata->ino_base, qstrgetstr(&dent->rel_path),
  231. dent->rel_path.len);
  232. dent->ino = ino;
  233. dent->state |= DENTRY_INO_UPDATED;
  234. }
  235. static inline int try_create_data (struct shim_dentry * dent,
  236. const char * uri, size_t len,
  237. struct shim_file_data ** dataptr)
  238. {
  239. struct shim_file_data * data = FILE_DENTRY_DATA(dent);
  240. if (!data) {
  241. lock(&dent->lock);
  242. int ret = create_data(dent, uri, len);
  243. data = FILE_DENTRY_DATA(dent);
  244. unlock(&dent->lock);
  245. if (ret < 0) {
  246. return ret;
  247. }
  248. }
  249. *dataptr = data;
  250. return 0;
  251. }
  252. static int query_dentry (struct shim_dentry * dent, PAL_HANDLE pal_handle,
  253. mode_t * mode, struct stat * stat)
  254. {
  255. int ret = 0;
  256. struct shim_file_data * data;
  257. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  258. return ret;
  259. lock(&data->lock);
  260. if (!data->queried && (ret = __query_attr(dent, data, pal_handle)) < 0) {
  261. unlock(&data->lock);
  262. return ret;
  263. }
  264. if (mode)
  265. *mode = data->mode;
  266. if (stat) {
  267. struct mount_data * mdata = DENTRY_MOUNT_DATA(dent);
  268. chroot_update_ino(dent);
  269. memset(stat, 0, sizeof(struct stat));
  270. stat->st_mode = (mode_t) data->mode;
  271. stat->st_dev = (dev_t) mdata->ino_base;
  272. stat->st_ino = (ino_t) dent->ino;
  273. stat->st_size = (off_t) atomic_read(&data->size);
  274. stat->st_atime = (time_t) data->atime;
  275. stat->st_mtime = (time_t) data->mtime;
  276. stat->st_ctime = (time_t) data->ctime;
  277. stat->st_nlink = data->nlink;
  278. switch (data->type) {
  279. case FILE_REGULAR:
  280. stat->st_mode |= S_IFREG;
  281. break;
  282. case FILE_DIR:
  283. stat->st_mode |= S_IFDIR;
  284. break;
  285. case FILE_DEV:
  286. case FILE_TTY:
  287. stat->st_mode |= S_IFCHR;
  288. break;
  289. default: break;
  290. }
  291. }
  292. unlock(&data->lock);
  293. return 0;
  294. }
  295. static int chroot_mode (struct shim_dentry * dent, mode_t * mode)
  296. {
  297. return query_dentry(dent, NULL, mode, NULL);
  298. }
  299. static int chroot_stat (struct shim_dentry * dent, struct stat * statbuf)
  300. {
  301. return query_dentry(dent, NULL, NULL, statbuf);
  302. }
  303. static int chroot_lookup (struct shim_dentry * dent)
  304. {
  305. return query_dentry(dent, NULL, NULL, NULL);
  306. }
  307. static int __chroot_open (struct shim_dentry * dent,
  308. const char * uri, int flags, mode_t mode,
  309. struct shim_handle * hdl,
  310. struct shim_file_data * data)
  311. {
  312. int ret = 0;
  313. if (!uri) {
  314. uri = qstrgetstr(&data->host_uri);
  315. }
  316. int version = atomic_read(&data->version);
  317. int oldmode = flags & O_ACCMODE;
  318. int accmode = oldmode;
  319. int creat = flags & PAL_CREATE_MASK;
  320. int option = flags & PAL_OPTION_MASK;
  321. if ((data->type == FILE_REGULAR || data->type == FILE_UNKNOWN)
  322. && accmode == O_WRONLY)
  323. accmode = O_RDWR;
  324. PAL_HANDLE palhdl;
  325. if (hdl && hdl->pal_handle) {
  326. palhdl = hdl->pal_handle;
  327. } else {
  328. palhdl = DkStreamOpen(uri, accmode, mode, creat, option);
  329. if (!palhdl) {
  330. if (PAL_NATIVE_ERRNO == PAL_ERROR_DENIED &&
  331. accmode != oldmode)
  332. palhdl = DkStreamOpen(uri, oldmode, mode, creat, option);
  333. if (!palhdl)
  334. return -PAL_ERRNO;
  335. }
  336. }
  337. if (!data->queried) {
  338. lock(&data->lock);
  339. ret = __query_attr(dent, data, palhdl);
  340. unlock(&data->lock);
  341. }
  342. if (!hdl) {
  343. DkObjectClose(palhdl);
  344. return 0;
  345. }
  346. hdl->pal_handle = palhdl;
  347. hdl->info.file.type = data->type;
  348. hdl->info.file.version = version;
  349. hdl->info.file.size = atomic_read(&data->size);
  350. hdl->info.file.data = data;
  351. return ret;
  352. }
  353. static int chroot_open (struct shim_handle * hdl, struct shim_dentry * dent,
  354. int flags)
  355. {
  356. int ret = 0;
  357. struct shim_file_data * data;
  358. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  359. return ret;
  360. if (dent->mode == NO_MODE) {
  361. lock(&data->lock);
  362. ret = __query_attr(dent, data, NULL);
  363. dent->mode = data->mode;
  364. unlock(&data->lock);
  365. }
  366. if ((ret = __chroot_open(dent, NULL, flags, dent->mode, hdl, data)) < 0)
  367. return ret;
  368. struct shim_file_handle * file = &hdl->info.file;
  369. off_t size = atomic_read(&data->size);
  370. /* initialize hdl, does not need a lock because no one is sharing */
  371. hdl->type = TYPE_FILE;
  372. file->marker = (flags & O_APPEND) ? size : 0;
  373. file->size = size;
  374. file->buf_type = (data->type == FILE_REGULAR) ? FILEBUF_MAP : FILEBUF_NONE;
  375. hdl->flags = flags;
  376. hdl->acc_mode = ACC_MODE(flags & O_ACCMODE);
  377. qstrcopy(&hdl->uri, &data->host_uri);
  378. return 0;
  379. }
  380. static int chroot_creat (struct shim_handle * hdl, struct shim_dentry * dir,
  381. struct shim_dentry * dent, int flags, mode_t mode)
  382. {
  383. int ret = 0;
  384. struct shim_file_data * data;
  385. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  386. return ret;
  387. if ((ret = __chroot_open(dent, NULL, flags|O_CREAT|O_EXCL, mode, hdl,
  388. data)) < 0)
  389. return ret;
  390. if (!hdl)
  391. return 0;
  392. struct shim_file_handle * file = &hdl->info.file;
  393. off_t size = atomic_read(&data->size);
  394. /* initialize hdl, does not need a lock because no one is sharing */
  395. hdl->type = TYPE_FILE;
  396. file->marker = (flags & O_APPEND) ? size : 0;
  397. file->size = size;
  398. file->buf_type = (data->type == FILE_REGULAR) ? FILEBUF_MAP : FILEBUF_NONE;
  399. hdl->flags = flags;
  400. hdl->acc_mode = ACC_MODE(flags & O_ACCMODE);
  401. qstrcopy(&hdl->uri, &data->host_uri);
  402. /* Increment the parent's link count */
  403. struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
  404. if (parent_data) {
  405. lock(&parent_data->lock);
  406. if (parent_data->queried)
  407. parent_data->nlink++;
  408. unlock(&parent_data->lock);
  409. }
  410. return 0;
  411. }
  412. static int chroot_mkdir (struct shim_dentry * dir, struct shim_dentry * dent,
  413. mode_t mode)
  414. {
  415. int ret = 0;
  416. struct shim_file_data * data;
  417. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  418. return ret;
  419. if (data->type != FILE_DIR) {
  420. data->type = FILE_DIR;
  421. int ret = make_uri(dent);
  422. if (ret < 0)
  423. return ret;
  424. }
  425. ret = __chroot_open(dent, NULL, O_CREAT|O_EXCL, mode, NULL, data);
  426. /* Increment the parent's link count */
  427. struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
  428. if (parent_data) {
  429. lock(&parent_data->lock);
  430. if (parent_data->queried)
  431. parent_data->nlink++;
  432. unlock(&parent_data->lock);
  433. }
  434. return ret;
  435. }
  436. #define NEED_RECREATE(hdl) (!FILE_HANDLE_DATA(hdl))
  437. static int chroot_recreate (struct shim_handle * hdl)
  438. {
  439. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  440. int ret = 0;
  441. /* quickly bail out if the data is created */
  442. if (data)
  443. return 0;
  444. const char * uri = qstrgetstr(&hdl->uri);
  445. size_t len = hdl->uri.len;
  446. if (hdl->dentry) {
  447. if ((ret = try_create_data(hdl->dentry, uri, len, &data)) < 0)
  448. return ret;
  449. } else {
  450. data = __create_data();
  451. if (!data)
  452. return -ENOMEM;
  453. qstrsetstr(&data->host_uri, uri, len);
  454. }
  455. /*
  456. * when recreating a file handle after migration, the file should
  457. * not be created again.
  458. */
  459. return __chroot_open(hdl->dentry, uri, hdl->flags & ~(O_CREAT|O_EXCL),
  460. 0, hdl, data);
  461. }
  462. static inline bool check_version (struct shim_handle * hdl)
  463. {
  464. return atomic_read(&FILE_HANDLE_DATA(hdl)->version)
  465. == hdl->info.file.version;
  466. }
  467. static int chroot_hstat (struct shim_handle * hdl, struct stat * stat)
  468. {
  469. int ret;
  470. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0)
  471. return ret;
  472. if (!check_version(hdl) || !hdl->dentry) {
  473. struct shim_file_handle * file = &hdl->info.file;
  474. struct shim_dentry * dent = hdl->dentry;
  475. struct mount_data * mdata = dent ? DENTRY_MOUNT_DATA(dent) : NULL;
  476. if (dent)
  477. chroot_update_ino(dent);
  478. if (stat) {
  479. memset(stat, 0, sizeof(struct stat));
  480. stat->st_dev = mdata ? (dev_t) mdata->ino_base : 0;
  481. stat->st_ino = dent ? (ino_t) dent->ino : 0;
  482. stat->st_size = file->size;
  483. stat->st_mode |= (file->buf_type == FILEBUF_MAP) ? S_IFREG : S_IFCHR;
  484. }
  485. return 0;
  486. }
  487. return query_dentry(hdl->dentry, hdl->pal_handle, NULL, stat);
  488. }
  489. static int chroot_flush (struct shim_handle * hdl)
  490. {
  491. struct shim_file_handle * file = &hdl->info.file;
  492. if (file->buf_type == FILEBUF_MAP) {
  493. lock(&hdl->lock);
  494. void * mapbuf = file->mapbuf;
  495. size_t mapsize = file->mapsize;
  496. file->mapoffset = 0;
  497. file->mapbuf = NULL;
  498. unlock(&hdl->lock);
  499. if (mapbuf) {
  500. DkStreamUnmap(mapbuf, mapsize);
  501. if (bkeep_munmap(mapbuf, mapsize, VMA_INTERNAL) < 0)
  502. BUG();
  503. }
  504. }
  505. return 0;
  506. }
  507. static inline int __map_buffer (struct shim_handle * hdl, size_t size)
  508. {
  509. struct shim_file_handle * file = &hdl->info.file;
  510. if (file->mapbuf) {
  511. if (file->marker >= file->mapoffset &&
  512. file->marker + size <= file->mapoffset + file->mapsize)
  513. return 0;
  514. DkStreamUnmap(file->mapbuf, file->mapsize);
  515. if (bkeep_munmap(file->mapbuf, file->mapsize, VMA_INTERNAL) < 0)
  516. BUG();
  517. file->mapbuf = NULL;
  518. file->mapoffset = 0;
  519. }
  520. /* second, reallocate the buffer */
  521. size_t bufsize = file->mapsize ? : FILE_BUFMAP_SIZE;
  522. assert(IS_POWER_OF_2(bufsize));
  523. off_t mapoff = ALIGN_DOWN_POW2(file->marker, bufsize);
  524. size_t maplen = bufsize;
  525. int flags = MAP_FILE | MAP_PRIVATE | VMA_INTERNAL;
  526. int prot = PROT_READ;
  527. if (hdl->acc_mode & MAY_WRITE) {
  528. flags = MAP_FILE | MAP_SHARED | VMA_INTERNAL;
  529. prot |= PROT_WRITE;
  530. }
  531. while (mapoff + maplen < file->marker + size)
  532. maplen *= 2;
  533. /* Create the bookkeeping before allocating the memory. */
  534. void * mapbuf = bkeep_unmapped_any(maplen, prot, flags, mapoff, "filebuf");
  535. if (!mapbuf)
  536. return -ENOMEM;
  537. PAL_PTR mapped = DkStreamMap(hdl->pal_handle, mapbuf, PAL_PROT(prot, flags),
  538. mapoff, maplen);
  539. if (!mapped) {
  540. bkeep_munmap(mapbuf, maplen, flags);
  541. return -PAL_ERRNO;
  542. }
  543. assert((void*)mapped == mapbuf);
  544. file->mapbuf = mapbuf;
  545. file->mapoffset = mapoff;
  546. file->mapsize = maplen;
  547. return 0;
  548. }
  549. static ssize_t map_read (struct shim_handle * hdl, void * buf, size_t count)
  550. {
  551. struct shim_file_handle * file = &hdl->info.file;
  552. ssize_t ret = 0;
  553. lock(&hdl->lock);
  554. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  555. off_t size = atomic_read(&data->size);
  556. if (check_version(hdl) &&
  557. file->size < size)
  558. file->size = size;
  559. off_t marker = file->marker;
  560. if (marker >= file->size) {
  561. count = 0;
  562. goto out;
  563. }
  564. if ((ret = __map_buffer(hdl, count)) < 0) {
  565. unlock(&hdl->lock);
  566. return ret;
  567. }
  568. size_t bytes_left;
  569. if (!__builtin_sub_overflow(file->size, marker, &bytes_left) && bytes_left < count)
  570. count = bytes_left;
  571. if (count) {
  572. memcpy(buf, file->mapbuf + (marker - file->mapoffset), count);
  573. file->marker = marker + count;
  574. }
  575. out:
  576. unlock(&hdl->lock);
  577. return count;
  578. }
  579. static ssize_t map_write (struct shim_handle * hdl, const void * buf, size_t count)
  580. {
  581. struct shim_file_handle * file = &hdl->info.file;
  582. ssize_t ret = 0;
  583. lock(&hdl->lock);
  584. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  585. off_t marker = file->marker;
  586. off_t new_marker;
  587. if (__builtin_add_overflow(marker, count, &new_marker)) {
  588. // We can't handle this case reasonably.
  589. ret = -EFBIG;
  590. goto out;
  591. }
  592. if (new_marker > file->size) {
  593. file->size = new_marker;
  594. PAL_NUM pal_ret = DkStreamWrite(hdl->pal_handle, file->marker, count, (void *) buf, NULL);
  595. if (!pal_ret) {
  596. ret = -PAL_ERRNO;
  597. goto out;
  598. }
  599. if (pal_ret < count) {
  600. file->size -= count - pal_ret;
  601. }
  602. if (check_version(hdl)) {
  603. off_t size;
  604. do {
  605. if ((size = atomic_read(&data->size)) >= file->size) {
  606. file->size = size;
  607. break;
  608. }
  609. } while ((off_t) atomic_cmpxchg(&data->size, size, file->size) != size);
  610. }
  611. if (__builtin_add_overflow(marker, pal_ret, &file->marker)) {
  612. // Should never happen. Even if it would, we couldn't recover from this condition.
  613. BUG();
  614. }
  615. ret = (ssize_t) pal_ret;
  616. goto out;
  617. }
  618. if ((ret = __map_buffer(hdl, count)) < 0)
  619. goto out;
  620. if (count) {
  621. memcpy(file->mapbuf + (marker - file->mapoffset), buf, count);
  622. file->marker = new_marker;
  623. }
  624. ret = count;
  625. out:
  626. unlock(&hdl->lock);
  627. return ret;
  628. }
  629. static ssize_t chroot_read (struct shim_handle * hdl, void * buf, size_t count)
  630. {
  631. ssize_t ret = 0;
  632. if (count == 0)
  633. goto out;
  634. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0) {
  635. goto out;
  636. }
  637. if (!(hdl->acc_mode & MAY_READ)) {
  638. ret = -EBADF;
  639. goto out;
  640. }
  641. struct shim_file_handle * file = &hdl->info.file;
  642. off_t dummy_off_t;
  643. if (file->type != FILE_TTY && __builtin_add_overflow(file->marker, count, &dummy_off_t)) {
  644. ret = -EFBIG;
  645. goto out;
  646. }
  647. if (file->buf_type == FILEBUF_MAP) {
  648. ret = map_read(hdl, buf, count);
  649. if (ret != -EACCES)
  650. goto out;
  651. lock(&hdl->lock);
  652. file->buf_type = FILEBUF_NONE;
  653. } else {
  654. lock(&hdl->lock);
  655. }
  656. PAL_NUM pal_ret = DkStreamRead(hdl->pal_handle, file->marker, count, buf, NULL, 0);
  657. if (pal_ret > 0) {
  658. if (__builtin_add_overflow(pal_ret, 0, &ret))
  659. BUG();
  660. if (file->type != FILE_TTY && __builtin_add_overflow(file->marker, pal_ret, &file->marker))
  661. BUG();
  662. } else {
  663. ret = PAL_NATIVE_ERRNO == PAL_ERROR_ENDOFSTREAM ? 0 : -PAL_ERRNO;
  664. }
  665. unlock(&hdl->lock);
  666. out:
  667. return ret;
  668. }
  669. static ssize_t chroot_write (struct shim_handle * hdl, const void * buf, size_t count)
  670. {
  671. ssize_t ret;
  672. if (count == 0)
  673. return 0;
  674. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0) {
  675. goto out;
  676. }
  677. if (!(hdl->acc_mode & MAY_WRITE)) {
  678. ret = -EBADF;
  679. goto out;
  680. }
  681. struct shim_file_handle * file = &hdl->info.file;
  682. off_t dummy_off_t;
  683. if (file->type != FILE_TTY && __builtin_add_overflow(file->marker, count, &dummy_off_t)) {
  684. ret = -EFBIG;
  685. goto out;
  686. }
  687. if (hdl->info.file.buf_type == FILEBUF_MAP) {
  688. ret = map_write(hdl, buf, count);
  689. if (ret != -EACCES)
  690. goto out;
  691. lock(&hdl->lock);
  692. file->buf_type = FILEBUF_NONE;
  693. } else {
  694. lock(&hdl->lock);
  695. }
  696. PAL_NUM pal_ret = DkStreamWrite(hdl->pal_handle, file->marker, count, (void *) buf, NULL);
  697. if (pal_ret > 0) {
  698. if (__builtin_add_overflow(pal_ret, 0, &ret))
  699. BUG();
  700. if (file->type != FILE_TTY && __builtin_add_overflow(file->marker, pal_ret, &file->marker))
  701. BUG();
  702. } else {
  703. ret = PAL_NATIVE_ERRNO == PAL_ERROR_ENDOFSTREAM ? 0 : -PAL_ERRNO;
  704. }
  705. unlock(&hdl->lock);
  706. out:
  707. return ret;
  708. }
  709. static int chroot_mmap (struct shim_handle * hdl, void ** addr, size_t size,
  710. int prot, int flags, off_t offset)
  711. {
  712. int ret;
  713. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0)
  714. return ret;
  715. int pal_prot = PAL_PROT(prot, flags);
  716. #if MAP_FILE == 0
  717. if (flags & MAP_ANONYMOUS)
  718. #else
  719. if (!(flags & MAP_FILE))
  720. #endif
  721. return -EINVAL;
  722. void * alloc_addr =
  723. (void *) DkStreamMap(hdl->pal_handle, *addr, pal_prot, offset, size);
  724. if (!alloc_addr)
  725. return -PAL_ERRNO;
  726. *addr = alloc_addr;
  727. return 0;
  728. }
  729. static off_t chroot_seek (struct shim_handle * hdl, off_t offset, int wence)
  730. {
  731. off_t ret = -EINVAL;
  732. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0)
  733. return ret;
  734. struct shim_file_handle * file = &hdl->info.file;
  735. lock(&hdl->lock);
  736. off_t marker = file->marker;
  737. off_t size = file->size;
  738. if (check_version(hdl)) {
  739. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  740. if (data->type != FILE_REGULAR) {
  741. ret = -ESPIPE;
  742. goto out;
  743. }
  744. }
  745. switch (wence) {
  746. case SEEK_SET:
  747. if (offset < 0)
  748. goto out;
  749. marker = offset;
  750. break;
  751. case SEEK_CUR:
  752. marker += offset;
  753. break;
  754. case SEEK_END:
  755. marker = size + offset;
  756. break;
  757. }
  758. ret = file->marker = marker;
  759. out:
  760. unlock(&hdl->lock);
  761. return ret;
  762. }
  763. static int chroot_truncate (struct shim_handle * hdl, off_t len)
  764. {
  765. int ret = 0;
  766. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0)
  767. return ret;
  768. if (!(hdl->acc_mode & MAY_WRITE))
  769. return -EINVAL;
  770. struct shim_file_handle * file = &hdl->info.file;
  771. lock(&hdl->lock);
  772. file->size = len;
  773. if (check_version(hdl)) {
  774. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  775. atomic_set(&data->size, len);
  776. }
  777. PAL_NUM rv = DkStreamSetLength(hdl->pal_handle, len);
  778. if (rv) {
  779. // For an error, cast it back down to an int return code
  780. ret = -((int)rv);
  781. goto out;
  782. }
  783. // DEP 10/25/16: Truncate returns 0 on success, not the length
  784. ret = 0;
  785. if (file->marker > len)
  786. file->marker = len;
  787. out:
  788. unlock(&hdl->lock);
  789. return ret;
  790. }
  791. static int chroot_dput (struct shim_dentry * dent)
  792. {
  793. struct shim_file_data * data = FILE_DENTRY_DATA(dent);
  794. if (data) {
  795. __destroy_data(data);
  796. dent->data = NULL;
  797. }
  798. return 0;
  799. }
  800. static int chroot_readdir(struct shim_dentry* dent, struct shim_dirent** dirent) {
  801. struct shim_file_data* data = NULL;
  802. int ret = 0;
  803. PAL_HANDLE pal_hdl = NULL;
  804. size_t buf_size = MAX_PATH,
  805. dirent_buf_size = 0;
  806. char* buf = NULL;
  807. char* dirent_buf = NULL;
  808. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  809. return ret;
  810. chroot_update_ino(dent);
  811. const char* uri = qstrgetstr(&data->host_uri);
  812. assert(strstartswith_static(uri, "dir:"));
  813. pal_hdl = DkStreamOpen(uri, PAL_ACCESS_RDONLY, 0, 0, 0);
  814. if (!pal_hdl)
  815. return -PAL_ERRNO;
  816. buf = malloc(buf_size);
  817. if (!buf) {
  818. ret = -ENOMEM;
  819. goto out;
  820. }
  821. while (1) {
  822. /* DkStreamRead for directory will return as many entries as fits into the buffer. */
  823. size_t bytes = DkStreamRead(pal_hdl, 0, buf_size, buf, NULL, 0);
  824. if (!bytes) {
  825. if (PAL_NATIVE_ERRNO == PAL_ERROR_ENDOFSTREAM) {
  826. /* End of directory listing */
  827. ret = 0;
  828. break;
  829. }
  830. ret = -PAL_ERRNO;
  831. goto out;
  832. }
  833. /* Last entry must be null-terminated */
  834. assert(buf[bytes - 1] == '\0');
  835. size_t dirent_cur_off = dirent_buf_size;
  836. /* Calculate needed buffer size */
  837. size_t len = buf[0] != '\0' ? 1 : 0;
  838. for (size_t i = 1; i < bytes; i++) {
  839. if (buf[i] == '\0') {
  840. /* The PAL convention: if a name ends with '/', it is a directory.
  841. * struct shim_dirent has a field for a type, hence trailing slash
  842. * can be safely discarded. */
  843. if (buf[i - 1] == '/') {
  844. len--;
  845. }
  846. dirent_buf_size += SHIM_DIRENT_ALIGNED_SIZE(len + 1);
  847. len = 0;
  848. } else {
  849. len++;
  850. }
  851. }
  852. /* TODO: If realloc gets enabled delete following and uncomment rest */
  853. char* tmp = malloc(dirent_buf_size);
  854. if (!tmp) {
  855. ret = -ENOMEM;
  856. goto out;
  857. }
  858. memcpy(tmp, dirent_buf, dirent_cur_off);
  859. free(dirent_buf);
  860. dirent_buf = tmp;
  861. /*
  862. dirent_buf = realloc(dirent_buf, dirent_buf_size);
  863. if (!dirent_buf) {
  864. ret = -ENOMEM;
  865. goto out;
  866. }
  867. */
  868. size_t i = 0;
  869. while (i < bytes) {
  870. char* name = buf + i;
  871. size_t len = strnlen(name, bytes - i);
  872. i += len + 1;
  873. bool is_dir = false;
  874. /* Skipping trailing slash - explained above */
  875. if (name[len - 1] == '/') {
  876. is_dir = true;
  877. name[--len] = '\0';
  878. }
  879. struct shim_dirent* dptr = (struct shim_dirent*)(dirent_buf + dirent_cur_off);
  880. dptr->ino = rehash_name(dent->ino, name, len);
  881. dptr->type = is_dir ? LINUX_DT_DIR : LINUX_DT_REG;
  882. memcpy(dptr->name, name, len + 1);
  883. dirent_cur_off += SHIM_DIRENT_ALIGNED_SIZE(len + 1);
  884. }
  885. }
  886. *dirent = (struct shim_dirent*)dirent_buf;
  887. /*
  888. * Fix next field of struct shim_dirent to point to the next entry.
  889. * Since all entries are assumed to come from single allocation
  890. * (as free gets called just on the head of this list) this should have
  891. * been just entry size instead of a pointer (and probably needs to be
  892. * rewritten as such one day).
  893. */
  894. struct shim_dirent** last = NULL;
  895. for (size_t dirent_cur_off = 0; dirent_cur_off < dirent_buf_size; ) {
  896. struct shim_dirent* dptr = (struct shim_dirent*)(dirent_buf + dirent_cur_off);
  897. size_t len = SHIM_DIRENT_ALIGNED_SIZE(strlen(dptr->name) + 1);
  898. dptr->next = (struct shim_dirent*)(dirent_buf + dirent_cur_off + len);
  899. last = &dptr->next;
  900. dirent_cur_off += len;
  901. }
  902. if (last) {
  903. *last = NULL;
  904. }
  905. out:
  906. /* Need to free output buffer if error is returned */
  907. if (ret) {
  908. free(dirent_buf);
  909. }
  910. free(buf);
  911. DkObjectClose(pal_hdl);
  912. return ret;
  913. }
  914. static int chroot_checkout (struct shim_handle * hdl)
  915. {
  916. if (hdl->fs == &chroot_builtin_fs)
  917. hdl->fs = NULL;
  918. if (hdl->type == TYPE_FILE) {
  919. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  920. if (data)
  921. hdl->info.file.data = NULL;
  922. }
  923. if (hdl->pal_handle) {
  924. /*
  925. * if the file still exists in the host, no need to send
  926. * the handle over RPC; otherwise, send it.
  927. */
  928. PAL_STREAM_ATTR attr;
  929. if (DkStreamAttributesQuery(qstrgetstr(&hdl->uri), &attr))
  930. hdl->pal_handle = NULL;
  931. }
  932. hdl->info.file.mapsize = 0;
  933. hdl->info.file.mapoffset = 0;
  934. hdl->info.file.mapbuf = NULL;
  935. return 0;
  936. }
  937. static ssize_t chroot_checkpoint (void ** checkpoint, void * mount_data)
  938. {
  939. struct mount_data * mdata = mount_data;
  940. *checkpoint = mount_data;
  941. return mdata->root_uri_len + sizeof(struct mount_data) + 1;
  942. }
  943. static int chroot_migrate (void * checkpoint, void ** mount_data)
  944. {
  945. struct mount_data * mdata = checkpoint;
  946. size_t alloc_len = mdata->root_uri_len + sizeof(struct mount_data) + 1;
  947. void * new_data = malloc(alloc_len);
  948. if (!new_data)
  949. return -ENOMEM;
  950. memcpy(new_data, mdata, alloc_len);
  951. *mount_data = new_data;
  952. return 0;
  953. }
  954. static int chroot_unlink (struct shim_dentry * dir, struct shim_dentry * dent)
  955. {
  956. int ret;
  957. struct shim_file_data * data;
  958. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  959. return ret;
  960. PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&data->host_uri), 0, 0, 0, 0);
  961. if (!pal_hdl)
  962. return -PAL_ERRNO;
  963. DkStreamDelete(pal_hdl, 0);
  964. DkObjectClose(pal_hdl);
  965. dent->mode = NO_MODE;
  966. data->mode = 0;
  967. atomic_inc(&data->version);
  968. atomic_set(&data->size, 0);
  969. /* Drop the parent's link count */
  970. struct shim_file_data *parent_data = FILE_DENTRY_DATA(dir);
  971. if (parent_data) {
  972. lock(&parent_data->lock);
  973. if (parent_data->queried)
  974. parent_data->nlink--;
  975. unlock(&parent_data->lock);
  976. }
  977. return 0;
  978. }
  979. static off_t chroot_poll (struct shim_handle * hdl, int poll_type)
  980. {
  981. int ret;
  982. if (NEED_RECREATE(hdl) && (ret = chroot_recreate(hdl)) < 0)
  983. return ret;
  984. struct shim_file_data * data = FILE_HANDLE_DATA(hdl);
  985. off_t size = atomic_read(&data->size);
  986. if (poll_type == FS_POLL_SZ)
  987. return size;
  988. lock(&hdl->lock);
  989. struct shim_file_handle * file = &hdl->info.file;
  990. if (check_version(hdl) &&
  991. file->size < size)
  992. file->size = size;
  993. off_t marker = file->marker;
  994. if (file->buf_type == FILEBUF_MAP) {
  995. ret = poll_type & FS_POLL_WR;
  996. if ((poll_type & FS_POLL_RD) && file->size > marker)
  997. ret |= FS_POLL_RD;
  998. goto out;
  999. }
  1000. ret = -EAGAIN;
  1001. out:
  1002. unlock(&hdl->lock);
  1003. return ret;
  1004. }
  1005. static int chroot_rename(struct shim_dentry* old, struct shim_dentry* new) {
  1006. int ret;
  1007. struct shim_file_data* old_data;
  1008. if ((ret = try_create_data(old, NULL, 0, &old_data)) < 0) {
  1009. return ret;
  1010. }
  1011. struct shim_file_data* new_data;
  1012. if ((ret = try_create_data(new, NULL, 0, &new_data)) < 0) {
  1013. return ret;
  1014. }
  1015. PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&old_data->host_uri), 0, 0, 0, 0);
  1016. if (!pal_hdl) {
  1017. return -PAL_ERRNO;
  1018. }
  1019. if (!DkStreamChangeName(pal_hdl, qstrgetstr(&new_data->host_uri))) {
  1020. DkObjectClose(pal_hdl);
  1021. return -PAL_ERRNO;
  1022. }
  1023. new->mode = new_data->mode = old_data->mode;
  1024. old->mode = NO_MODE;
  1025. old_data->mode = 0;
  1026. new->type = old->type;
  1027. DkObjectClose(pal_hdl);
  1028. atomic_inc(&old_data->version);
  1029. atomic_set(&old_data->size, 0);
  1030. atomic_inc(&new_data->version);
  1031. return 0;
  1032. }
  1033. static int chroot_chmod (struct shim_dentry * dent, mode_t mode)
  1034. {
  1035. int ret;
  1036. struct shim_file_data * data;
  1037. if ((ret = try_create_data(dent, NULL, 0, &data)) < 0)
  1038. return ret;
  1039. PAL_HANDLE pal_hdl = DkStreamOpen(qstrgetstr(&data->host_uri), 0, 0, 0, 0);
  1040. if (!pal_hdl)
  1041. return -PAL_ERRNO;
  1042. PAL_STREAM_ATTR attr = { .share_flags = mode };
  1043. if (!DkStreamAttributesSetByHandle(pal_hdl, &attr)) {
  1044. DkObjectClose(pal_hdl);
  1045. return -PAL_ERRNO;
  1046. }
  1047. DkObjectClose(pal_hdl);
  1048. dent->mode = data->mode = mode;
  1049. return 0;
  1050. }
  1051. struct shim_fs_ops chroot_fs_ops = {
  1052. .mount = &chroot_mount,
  1053. .unmount = &chroot_unmount,
  1054. .flush = &chroot_flush,
  1055. .close = &chroot_flush,
  1056. .read = &chroot_read,
  1057. .write = &chroot_write,
  1058. .mmap = &chroot_mmap,
  1059. .seek = &chroot_seek,
  1060. .hstat = &chroot_hstat,
  1061. .truncate = &chroot_truncate,
  1062. .checkout = &chroot_checkout,
  1063. .checkpoint = &chroot_checkpoint,
  1064. .migrate = &chroot_migrate,
  1065. .poll = &chroot_poll,
  1066. };
  1067. struct shim_d_ops chroot_d_ops = {
  1068. .open = &chroot_open,
  1069. .mode = &chroot_mode,
  1070. .lookup = &chroot_lookup,
  1071. .creat = &chroot_creat,
  1072. .mkdir = &chroot_mkdir,
  1073. .stat = &chroot_stat,
  1074. .dput = &chroot_dput,
  1075. .readdir = &chroot_readdir,
  1076. .unlink = &chroot_unlink,
  1077. .rename = &chroot_rename,
  1078. .chmod = &chroot_chmod,
  1079. };
  1080. struct mount_data chroot_data = { .root_uri_len = 5,
  1081. .root_uri = "file:", };
  1082. struct shim_mount chroot_builtin_fs = { .type = "chroot",
  1083. .fs_ops = &chroot_fs_ops,
  1084. .d_ops = &chroot_d_ops,
  1085. .data = &chroot_data, };