thread.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. #include <shim_internal.h>
  4. #include <shim_table.h>
  5. #include <shim_thread.h>
  6. #include <shim_handle.h>
  7. #include <shim_fs.h>
  8. #include <shim_utils.h>
  9. #include <pal.h>
  10. #include <pal_error.h>
  11. #include <asm/mman.h>
  12. #include <asm/unistd.h>
  13. #include <asm/prctl.h>
  14. #include <errno.h>
  15. static int parse_thread_name (const char * name,
  16. const char ** next, int * next_len,
  17. const char ** nextnext)
  18. {
  19. const char * p = name;
  20. int pid = 0;
  21. if (*p == '/')
  22. p++;
  23. if (!memcmp(p, "self", 4) && (!*(p + 4) || *(p + 4) == '/')) {
  24. p += 4;
  25. pid = get_cur_tid();
  26. } else {
  27. for ( ; *p && *p != '/' ; p++) {
  28. if (*p < '0' || *p > '9')
  29. return -ENOENT;
  30. pid = pid * 10 + *p - '0';
  31. }
  32. }
  33. if (next) {
  34. if (*(p++) == '/' && *p) {
  35. *next = p;
  36. if (next_len || nextnext)
  37. for ( ; *p && *p != '/' ; p++);
  38. if (next_len)
  39. *next_len = p - *next;
  40. if (nextnext)
  41. *nextnext = (*(p++) == '/' && *p) ? p : NULL;
  42. } else {
  43. *next = NULL;
  44. }
  45. }
  46. return pid;
  47. }
  48. static int find_thread_link (const char * name, struct shim_qstr * link,
  49. struct shim_dentry ** dentptr,
  50. struct shim_thread ** threadptr)
  51. {
  52. const char * next, * nextnext;
  53. int next_len;
  54. int pid = parse_thread_name(name, &next, &next_len, &nextnext);
  55. if (pid < 0)
  56. return pid;
  57. struct shim_thread * thread = lookup_thread(pid);
  58. struct shim_dentry * dent = NULL;
  59. int ret = 0;
  60. if (!thread)
  61. return -ENOENT;
  62. if (!thread->in_vm) {
  63. ret = -ENOENT;
  64. goto out;
  65. }
  66. lock(thread->lock);
  67. if (next_len == 4 && !memcmp(next, "root", next_len)) {
  68. dent = thread->root;
  69. get_dentry(dent);
  70. }
  71. if (next_len == 3 && !memcmp(next, "cwd", next_len)) {
  72. dent = thread->cwd;
  73. get_dentry(dent);
  74. }
  75. if (next_len == 3 && !memcmp(next, "exe", next_len)) {
  76. struct shim_handle * exec = thread->exec;
  77. if (!exec->dentry) {
  78. unlock(thread->lock);
  79. ret = -ENOENT;
  80. goto out;
  81. }
  82. dent = exec->dentry;
  83. get_dentry(dent);
  84. }
  85. unlock(thread->lock);
  86. if (nextnext) {
  87. struct shim_dentry * next_dent = NULL;
  88. ret = path_lookupat(dent, nextnext, 0, &next_dent);
  89. if (ret < 0)
  90. goto out;
  91. put_dentry(dent);
  92. dent = next_dent;
  93. }
  94. if (link) {
  95. int size;
  96. char * path = dentry_get_path(dent, true, &size);
  97. qstrsetstr(link, path, size);
  98. }
  99. if (dentptr) {
  100. get_dentry(dent);
  101. *dentptr = dent;
  102. }
  103. if (threadptr) {
  104. get_thread(thread);
  105. *threadptr = thread;
  106. }
  107. ret = 0;
  108. out:
  109. if (dent)
  110. put_dentry(dent);
  111. if (thread)
  112. put_thread(thread);
  113. return ret;
  114. }
  115. static int proc_thread_link_open (struct shim_handle * hdl,
  116. const char * name, int flags)
  117. {
  118. struct shim_dentry * dent;
  119. int ret = find_thread_link(name, NULL, &dent, NULL);
  120. if (ret < 0)
  121. return ret;
  122. if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->open) {
  123. ret = -EACCES;
  124. goto out;
  125. }
  126. ret = dent->fs->d_ops->open(hdl, dent, flags);
  127. out:
  128. put_dentry(dent);
  129. return 0;
  130. }
  131. static int proc_thread_link_mode (const char * name, mode_t * mode)
  132. {
  133. struct shim_dentry * dent;
  134. int ret = find_thread_link(name, NULL, &dent, NULL);
  135. if (ret < 0)
  136. return ret;
  137. if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->mode) {
  138. ret = -EACCES;
  139. goto out;
  140. }
  141. ret = dent->fs->d_ops->mode(dent, mode, true);
  142. out:
  143. put_dentry(dent);
  144. return ret;
  145. }
  146. static int proc_thread_link_stat (const char * name, struct stat * buf)
  147. {
  148. struct shim_dentry * dent;
  149. int ret = find_thread_link(name, NULL, &dent, NULL);
  150. if (ret < 0)
  151. return ret;
  152. if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->stat) {
  153. ret = -EACCES;
  154. goto out;
  155. }
  156. ret = dent->fs->d_ops->stat(dent, buf);
  157. out:
  158. put_dentry(dent);
  159. return ret;
  160. }
  161. static int proc_thread_link_follow_link (const char * name,
  162. struct shim_qstr * link)
  163. {
  164. return find_thread_link(name, link, NULL, NULL);
  165. }
  166. static const struct proc_fs_ops fs_thread_link = {
  167. .open = &proc_thread_link_open,
  168. .mode = &proc_thread_link_mode,
  169. .stat = &proc_thread_link_stat,
  170. .follow_link = &proc_thread_link_follow_link,
  171. };
  172. static int parse_thread_fd (const char * name, const char ** rest,
  173. struct shim_handle ** phdl)
  174. {
  175. const char * next, * nextnext;
  176. int next_len;
  177. int pid = parse_thread_name(name, &next, &next_len, &nextnext);
  178. if (!pid)
  179. return pid;
  180. if (!next || !nextnext || memcmp(next, "fd", next_len))
  181. return -EINVAL;
  182. const char * p = nextnext;
  183. int fd = 0;
  184. for ( ; *p && *p != '/' ; p++) {
  185. if (*p < '0' || *p > '9')
  186. return -ENOENT;
  187. fd = fd * 10 + *p - '0';
  188. if (fd >= MAX_FDS)
  189. return -ENOENT;
  190. }
  191. struct shim_thread * thread = lookup_thread(pid);
  192. if (!thread)
  193. return -ENOENT;
  194. struct shim_handle_map * handle_map = get_cur_handle_map(thread);
  195. lock(handle_map->lock);
  196. if (fd >= handle_map->fd_top ||
  197. handle_map->map[fd] == NULL ||
  198. handle_map->map[fd]->handle == NULL) {
  199. unlock(handle_map->lock);
  200. return -ENOENT;
  201. }
  202. if (phdl)
  203. *phdl = handle_map->map[fd]->handle;
  204. unlock(handle_map->lock);
  205. if (rest)
  206. *rest = *p ? p + 1 : NULL;
  207. return 0;
  208. }
  209. static int proc_match_thread_each_fd (const char * name)
  210. {
  211. return parse_thread_fd(name, NULL, NULL) == 0 ? 1 : 0;
  212. }
  213. static int proc_list_thread_each_fd (const char * name,
  214. struct shim_dirent ** buf, int count)
  215. {
  216. const char * next;
  217. int next_len;
  218. int pid = parse_thread_name(name, &next, &next_len, NULL);
  219. if (!pid)
  220. return pid;
  221. if (!next || memcmp(next, "fd", next_len))
  222. return -EINVAL;
  223. struct shim_thread * thread = lookup_thread(pid);
  224. if (!thread)
  225. return -ENOENT;
  226. struct shim_handle_map * handle_map = get_cur_handle_map(thread);
  227. int err = 0, bytes = 0;
  228. struct shim_dirent * dirent = *buf, ** last = NULL;
  229. lock(handle_map->lock);
  230. for (int i = 0 ; i < handle_map->fd_size ; i++, dirent = dirent->next)
  231. if (handle_map->map[i] &&
  232. handle_map->map[i]->handle) {
  233. int d = i, l = 0;
  234. for ( ; d ; d /= 10, l++);
  235. l = l ? : 1;
  236. bytes += sizeof(struct shim_dirent) + l + 1;
  237. if (bytes > count) {
  238. err = -ENOMEM;
  239. break;
  240. }
  241. dirent->next = (void *) (dirent + 1) + l + 1;
  242. dirent->ino = 1;
  243. dirent->type = LINUX_DT_LNK;
  244. dirent->name[0] = '0';
  245. dirent->name[l--] = 0;
  246. for (d = i ; d ; d /= 10)
  247. dirent->name[l--] = '0' + d % 10;
  248. last = &dirent->next;
  249. }
  250. unlock(handle_map->lock);
  251. put_thread(thread);
  252. if (last)
  253. *last = NULL;
  254. *buf = dirent;
  255. return err;
  256. }
  257. static const struct proc_nm_ops nm_thread_each_fd = {
  258. .match_name = &proc_match_thread_each_fd,
  259. .list_name = &proc_list_thread_each_fd,
  260. };
  261. static int find_thread_each_fd (const char * name, struct shim_qstr * link,
  262. struct shim_dentry ** dentptr)
  263. {
  264. const char * rest;
  265. struct shim_handle * handle;
  266. struct shim_dentry * dent = NULL;
  267. int ret;
  268. if ((ret = parse_thread_fd(name, &rest, &handle)) < 0)
  269. return ret;
  270. lock(handle->lock);
  271. if (handle->dentry) {
  272. dent = handle->dentry;
  273. get_dentry(dent);
  274. }
  275. unlock(handle->lock);
  276. if (!dent) {
  277. ret = -ENOENT;
  278. goto out;
  279. }
  280. if (rest) {
  281. struct shim_dentry * next_dent = NULL;
  282. ret = path_lookupat(dent, rest, 0, &next_dent);
  283. if (ret < 0)
  284. goto out;
  285. put_dentry(dent);
  286. dent = next_dent;
  287. }
  288. if (link) {
  289. int size;
  290. char * path = dentry_get_path(dent, true, &size);
  291. qstrsetstr(link, path, size);
  292. }
  293. if (dentptr) {
  294. get_dentry(dent);
  295. *dentptr = dent;
  296. }
  297. out:
  298. if (dent)
  299. put_dentry(dent);
  300. put_handle(handle);
  301. return ret;
  302. }
  303. static int proc_thread_each_fd_open (struct shim_handle * hdl,
  304. const char * name, int flags)
  305. {
  306. struct shim_dentry * dent;
  307. int ret = find_thread_each_fd(name, NULL, &dent);
  308. if (ret < 0)
  309. return ret;
  310. if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->open) {
  311. ret = -EACCES;
  312. goto out;
  313. }
  314. ret = dent->fs->d_ops->open(hdl, dent, flags);
  315. out:
  316. put_dentry(dent);
  317. return 0;
  318. }
  319. static int proc_thread_each_fd_mode (const char * name, mode_t * mode)
  320. {
  321. struct shim_dentry * dent;
  322. int ret = find_thread_each_fd(name, NULL, &dent);
  323. if (ret < 0)
  324. return ret;
  325. if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->mode) {
  326. ret = -EACCES;
  327. goto out;
  328. }
  329. ret = dent->fs->d_ops->mode(dent, mode, true);
  330. out:
  331. put_dentry(dent);
  332. return 0;
  333. }
  334. static int proc_thread_each_fd_stat (const char * name, struct stat * buf)
  335. {
  336. struct shim_dentry * dent;
  337. int ret = find_thread_each_fd(name, NULL, &dent);
  338. if (ret < 0)
  339. return ret;
  340. if (!dent->fs || !dent->fs->d_ops || !dent->fs->d_ops->stat) {
  341. ret = -EACCES;
  342. goto out;
  343. }
  344. ret = dent->fs->d_ops->stat(dent, buf);
  345. out:
  346. put_dentry(dent);
  347. return 0;
  348. }
  349. static int proc_thread_each_fd_follow_link (const char * name,
  350. struct shim_qstr * link)
  351. {
  352. return find_thread_each_fd(name, link, NULL);
  353. }
  354. static const struct proc_fs_ops fs_thread_each_fd = {
  355. .open = &proc_thread_each_fd_open,
  356. .mode = &proc_thread_each_fd_mode,
  357. .stat = &proc_thread_each_fd_stat,
  358. .follow_link = &proc_thread_each_fd_follow_link,
  359. };
  360. static const struct proc_dir dir_fd = { .size = 1, .ent = { {
  361. .nm_ops = &nm_thread_each_fd, .fs_ops = &fs_thread_each_fd,
  362. }, }, };
  363. static int proc_thread_dir_mode (const char * name, mode_t * mode)
  364. {
  365. const char * next;
  366. int next_len;
  367. int pid = parse_thread_name(name, &next, &next_len, NULL);
  368. if (pid < 0)
  369. return pid;
  370. *mode = 0500;
  371. return 0;
  372. }
  373. static int proc_thread_dir_stat (const char * name, struct stat * buf)
  374. {
  375. const char * next;
  376. int next_len;
  377. int pid = parse_thread_name(name, &next, &next_len, NULL);
  378. if (pid < 0)
  379. return pid;
  380. struct shim_thread * thread = lookup_thread(pid);
  381. if (!thread)
  382. return -ENOENT;
  383. memset(buf, 0, sizeof(struct stat));
  384. buf->st_dev = buf->st_ino = 1;
  385. buf->st_mode = 0500|S_IFDIR;
  386. lock(thread->lock);
  387. buf->st_uid = thread->uid;
  388. buf->st_gid = thread->gid;
  389. unlock(thread->lock);
  390. buf->st_size = 4096;
  391. return 0;
  392. }
  393. static const struct proc_fs_ops fs_thread_fd = {
  394. .mode = &proc_thread_dir_mode,
  395. .stat = &proc_thread_dir_stat,
  396. };
  397. static int proc_match_thread (const char * name)
  398. {
  399. int pid = parse_thread_name(name, NULL, NULL, NULL);
  400. if (pid < 0)
  401. return 0;
  402. struct shim_thread * thread = lookup_thread(pid);
  403. return thread ? 1 : 0;
  404. }
  405. static int proc_list_thread (const char * name, struct shim_dirent ** buf,
  406. int len)
  407. {
  408. struct walk_thread_arg {
  409. struct shim_dirent * buf, * buf_end;
  410. } args = {
  411. .buf = *buf, .buf_end = (void *) *buf + len,
  412. };
  413. int walk_cb (struct shim_thread * thread, void * arg, bool * unlocked) {
  414. struct walk_thread_arg * args = (struct walk_thread_arg *) arg;
  415. IDTYPE pid = thread->tid;
  416. int p = pid, l = 0;
  417. for ( ; p ; p /= 10, l++);
  418. if ((void *) (args->buf + 1) + l + 1 > (void *) args->buf_end)
  419. return -ENOBUFS;
  420. struct shim_dirent * buf = args->buf;
  421. buf->next = (void *) (buf + 1) + l + 1;
  422. buf->ino = 1;
  423. buf->type = LINUX_DT_DIR;
  424. buf->name[l--] = 0;
  425. for (p = pid ; p ; p /= 10)
  426. buf->name[l--] = p % 10 + '0';
  427. args->buf = buf->next;
  428. return 1;
  429. }
  430. int ret = walk_thread_list(&walk_cb, &args, false);
  431. if (ret < 0)
  432. return ret;
  433. *buf = args.buf;
  434. return 0;
  435. }
  436. const struct proc_nm_ops nm_thread = {
  437. .match_name = &proc_match_thread,
  438. .list_name = &proc_list_thread,
  439. };
  440. const struct proc_fs_ops fs_thread = {
  441. .mode = &proc_thread_dir_mode,
  442. .stat = &proc_thread_dir_stat,
  443. };
  444. const struct proc_dir dir_thread = { .size = 5, .ent = {
  445. { .name = "cwd", .fs_ops = &fs_thread_link, },
  446. { .name = "exe", .fs_ops = &fs_thread_link, },
  447. { .name = "root", .fs_ops = &fs_thread_link, },
  448. { .name = "fd", .dir = &dir_fd, .fs_ops = &fs_thread_fd, },
  449. }, };