domain.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. /*
  2. * security/tomoyo/domain.c
  3. *
  4. * Implementation of the Domain-Based Mandatory Access Control.
  5. *
  6. * Copyright (C) 2005-2009 NTT DATA CORPORATION
  7. *
  8. * Version: 2.2.0 2009/04/01
  9. *
  10. */
  11. #include "common.h"
  12. #include "tomoyo.h"
  13. #include "realpath.h"
  14. #include <linux/binfmts.h>
  15. /* Variables definitions.*/
  16. /* The initial domain. */
  17. struct tomoyo_domain_info tomoyo_kernel_domain;
  18. /*
  19. * tomoyo_domain_list is used for holding list of domains.
  20. * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
  21. * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
  22. *
  23. * An entry is added by
  24. *
  25. * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
  26. * /sys/kernel/security/tomoyo/domain_policy
  27. *
  28. * and is deleted by
  29. *
  30. * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
  31. * /sys/kernel/security/tomoyo/domain_policy
  32. *
  33. * and all entries are retrieved by
  34. *
  35. * # cat /sys/kernel/security/tomoyo/domain_policy
  36. *
  37. * A domain is added by
  38. *
  39. * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
  40. *
  41. * and is deleted by
  42. *
  43. * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
  44. *
  45. * and all domains are retrieved by
  46. *
  47. * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
  48. *
  49. * Normally, a domainname is monotonically getting longer because a domainname
  50. * which the process will belong to if an execve() operation succeeds is
  51. * defined as a concatenation of "current domainname" + "pathname passed to
  52. * execve()".
  53. * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
  54. * exceptions.
  55. */
  56. LIST_HEAD(tomoyo_domain_list);
  57. /*
  58. * tomoyo_domain_initializer_entry is a structure which is used for holding
  59. * "initialize_domain" and "no_initialize_domain" entries.
  60. * It has following fields.
  61. *
  62. * (1) "list" which is linked to tomoyo_domain_initializer_list .
  63. * (2) "domainname" which is "a domainname" or "the last component of a
  64. * domainname". This field is NULL if "from" clause is not specified.
  65. * (3) "program" which is a program's pathname.
  66. * (4) "is_deleted" is a bool which is true if marked as deleted, false
  67. * otherwise.
  68. * (5) "is_not" is a bool which is true if "no_initialize_domain", false
  69. * otherwise.
  70. * (6) "is_last_name" is a bool which is true if "domainname" is "the last
  71. * component of a domainname", false otherwise.
  72. */
  73. struct tomoyo_domain_initializer_entry {
  74. struct list_head list;
  75. const struct tomoyo_path_info *domainname; /* This may be NULL */
  76. const struct tomoyo_path_info *program;
  77. bool is_deleted;
  78. bool is_not; /* True if this entry is "no_initialize_domain". */
  79. /* True if the domainname is tomoyo_get_last_name(). */
  80. bool is_last_name;
  81. };
  82. /*
  83. * tomoyo_domain_keeper_entry is a structure which is used for holding
  84. * "keep_domain" and "no_keep_domain" entries.
  85. * It has following fields.
  86. *
  87. * (1) "list" which is linked to tomoyo_domain_keeper_list .
  88. * (2) "domainname" which is "a domainname" or "the last component of a
  89. * domainname".
  90. * (3) "program" which is a program's pathname.
  91. * This field is NULL if "from" clause is not specified.
  92. * (4) "is_deleted" is a bool which is true if marked as deleted, false
  93. * otherwise.
  94. * (5) "is_not" is a bool which is true if "no_initialize_domain", false
  95. * otherwise.
  96. * (6) "is_last_name" is a bool which is true if "domainname" is "the last
  97. * component of a domainname", false otherwise.
  98. */
  99. struct tomoyo_domain_keeper_entry {
  100. struct list_head list;
  101. const struct tomoyo_path_info *domainname;
  102. const struct tomoyo_path_info *program; /* This may be NULL */
  103. bool is_deleted;
  104. bool is_not; /* True if this entry is "no_keep_domain". */
  105. /* True if the domainname is tomoyo_get_last_name(). */
  106. bool is_last_name;
  107. };
  108. /*
  109. * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
  110. * It has following fields.
  111. *
  112. * (1) "list" which is linked to tomoyo_alias_list .
  113. * (2) "original_name" which is a dereferenced pathname.
  114. * (3) "aliased_name" which is a symlink's pathname.
  115. * (4) "is_deleted" is a bool which is true if marked as deleted, false
  116. * otherwise.
  117. */
  118. struct tomoyo_alias_entry {
  119. struct list_head list;
  120. const struct tomoyo_path_info *original_name;
  121. const struct tomoyo_path_info *aliased_name;
  122. bool is_deleted;
  123. };
  124. /**
  125. * tomoyo_get_last_name - Get last component of a domainname.
  126. *
  127. * @domain: Pointer to "struct tomoyo_domain_info".
  128. *
  129. * Returns the last component of the domainname.
  130. */
  131. const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
  132. {
  133. const char *cp0 = domain->domainname->name;
  134. const char *cp1 = strrchr(cp0, ' ');
  135. if (cp1)
  136. return cp1 + 1;
  137. return cp0;
  138. }
  139. /*
  140. * tomoyo_domain_initializer_list is used for holding list of programs which
  141. * triggers reinitialization of domainname. Normally, a domainname is
  142. * monotonically getting longer. But sometimes, we restart daemon programs.
  143. * It would be convenient for us that "a daemon started upon system boot" and
  144. * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
  145. * provides a way to shorten domainnames.
  146. *
  147. * An entry is added by
  148. *
  149. * # echo 'initialize_domain /usr/sbin/httpd' > \
  150. * /sys/kernel/security/tomoyo/exception_policy
  151. *
  152. * and is deleted by
  153. *
  154. * # echo 'delete initialize_domain /usr/sbin/httpd' > \
  155. * /sys/kernel/security/tomoyo/exception_policy
  156. *
  157. * and all entries are retrieved by
  158. *
  159. * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
  160. *
  161. * In the example above, /usr/sbin/httpd will belong to
  162. * "<kernel> /usr/sbin/httpd" domain.
  163. *
  164. * You may specify a domainname using "from" keyword.
  165. * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
  166. * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
  167. * domain to belong to "<kernel> /usr/sbin/httpd" domain.
  168. *
  169. * You may add "no_" prefix to "initialize_domain".
  170. * "initialize_domain /usr/sbin/httpd" and
  171. * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
  172. * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
  173. * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
  174. */
  175. static LIST_HEAD(tomoyo_domain_initializer_list);
  176. /**
  177. * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
  178. *
  179. * @domainname: The name of domain. May be NULL.
  180. * @program: The name of program.
  181. * @is_not: True if it is "no_initialize_domain" entry.
  182. * @is_delete: True if it is a delete request.
  183. *
  184. * Returns 0 on success, negative value otherwise.
  185. *
  186. * Caller holds tomoyo_read_lock().
  187. */
  188. static int tomoyo_update_domain_initializer_entry(const char *domainname,
  189. const char *program,
  190. const bool is_not,
  191. const bool is_delete)
  192. {
  193. struct tomoyo_domain_initializer_entry *entry = NULL;
  194. struct tomoyo_domain_initializer_entry *ptr;
  195. const struct tomoyo_path_info *saved_program;
  196. const struct tomoyo_path_info *saved_domainname = NULL;
  197. int error = is_delete ? -ENOENT : -ENOMEM;
  198. bool is_last_name = false;
  199. if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
  200. return -EINVAL; /* No patterns allowed. */
  201. if (domainname) {
  202. if (!tomoyo_is_domain_def(domainname) &&
  203. tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
  204. is_last_name = true;
  205. else if (!tomoyo_is_correct_domain(domainname, __func__))
  206. return -EINVAL;
  207. saved_domainname = tomoyo_save_name(domainname);
  208. if (!saved_domainname)
  209. goto out;
  210. }
  211. saved_program = tomoyo_save_name(program);
  212. if (!saved_program)
  213. goto out;
  214. if (!is_delete)
  215. entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  216. mutex_lock(&tomoyo_policy_lock);
  217. list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
  218. if (ptr->is_not != is_not ||
  219. ptr->domainname != saved_domainname ||
  220. ptr->program != saved_program)
  221. continue;
  222. ptr->is_deleted = is_delete;
  223. error = 0;
  224. break;
  225. }
  226. if (!is_delete && error && tomoyo_memory_ok(entry)) {
  227. entry->domainname = saved_domainname;
  228. entry->program = saved_program;
  229. entry->is_not = is_not;
  230. entry->is_last_name = is_last_name;
  231. list_add_tail_rcu(&entry->list,
  232. &tomoyo_domain_initializer_list);
  233. entry = NULL;
  234. error = 0;
  235. }
  236. mutex_unlock(&tomoyo_policy_lock);
  237. out:
  238. kfree(entry);
  239. return error;
  240. }
  241. /**
  242. * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
  243. *
  244. * @head: Pointer to "struct tomoyo_io_buffer".
  245. *
  246. * Returns true on success, false otherwise.
  247. *
  248. * Caller holds tomoyo_read_lock().
  249. */
  250. bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
  251. {
  252. struct list_head *pos;
  253. bool done = true;
  254. list_for_each_cookie(pos, head->read_var2,
  255. &tomoyo_domain_initializer_list) {
  256. const char *no;
  257. const char *from = "";
  258. const char *domain = "";
  259. struct tomoyo_domain_initializer_entry *ptr;
  260. ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
  261. list);
  262. if (ptr->is_deleted)
  263. continue;
  264. no = ptr->is_not ? "no_" : "";
  265. if (ptr->domainname) {
  266. from = " from ";
  267. domain = ptr->domainname->name;
  268. }
  269. done = tomoyo_io_printf(head,
  270. "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
  271. "%s%s%s\n", no, ptr->program->name,
  272. from, domain);
  273. if (!done)
  274. break;
  275. }
  276. return done;
  277. }
  278. /**
  279. * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
  280. *
  281. * @data: String to parse.
  282. * @is_not: True if it is "no_initialize_domain" entry.
  283. * @is_delete: True if it is a delete request.
  284. *
  285. * Returns 0 on success, negative value otherwise.
  286. *
  287. * Caller holds tomoyo_read_lock().
  288. */
  289. int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
  290. const bool is_delete)
  291. {
  292. char *cp = strstr(data, " from ");
  293. if (cp) {
  294. *cp = '\0';
  295. return tomoyo_update_domain_initializer_entry(cp + 6, data,
  296. is_not,
  297. is_delete);
  298. }
  299. return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
  300. is_delete);
  301. }
  302. /**
  303. * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
  304. *
  305. * @domainname: The name of domain.
  306. * @program: The name of program.
  307. * @last_name: The last component of @domainname.
  308. *
  309. * Returns true if executing @program reinitializes domain transition,
  310. * false otherwise.
  311. *
  312. * Caller holds tomoyo_read_lock().
  313. */
  314. static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
  315. domainname,
  316. const struct tomoyo_path_info *program,
  317. const struct tomoyo_path_info *
  318. last_name)
  319. {
  320. struct tomoyo_domain_initializer_entry *ptr;
  321. bool flag = false;
  322. list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
  323. if (ptr->is_deleted)
  324. continue;
  325. if (ptr->domainname) {
  326. if (!ptr->is_last_name) {
  327. if (ptr->domainname != domainname)
  328. continue;
  329. } else {
  330. if (tomoyo_pathcmp(ptr->domainname, last_name))
  331. continue;
  332. }
  333. }
  334. if (tomoyo_pathcmp(ptr->program, program))
  335. continue;
  336. if (ptr->is_not) {
  337. flag = false;
  338. break;
  339. }
  340. flag = true;
  341. }
  342. return flag;
  343. }
  344. /*
  345. * tomoyo_domain_keeper_list is used for holding list of domainnames which
  346. * suppresses domain transition. Normally, a domainname is monotonically
  347. * getting longer. But sometimes, we want to suppress domain transition.
  348. * It would be convenient for us that programs executed from a login session
  349. * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
  350. * transition.
  351. *
  352. * An entry is added by
  353. *
  354. * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
  355. * /sys/kernel/security/tomoyo/exception_policy
  356. *
  357. * and is deleted by
  358. *
  359. * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
  360. * /sys/kernel/security/tomoyo/exception_policy
  361. *
  362. * and all entries are retrieved by
  363. *
  364. * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
  365. *
  366. * In the example above, any process which belongs to
  367. * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
  368. * unless explicitly specified by "initialize_domain" or "no_keep_domain".
  369. *
  370. * You may specify a program using "from" keyword.
  371. * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
  372. * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
  373. * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
  374. *
  375. * You may add "no_" prefix to "keep_domain".
  376. * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
  377. * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
  378. * cause "/usr/bin/passwd" to belong to
  379. * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
  380. * explicitly specified by "initialize_domain".
  381. */
  382. static LIST_HEAD(tomoyo_domain_keeper_list);
  383. /**
  384. * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
  385. *
  386. * @domainname: The name of domain.
  387. * @program: The name of program. May be NULL.
  388. * @is_not: True if it is "no_keep_domain" entry.
  389. * @is_delete: True if it is a delete request.
  390. *
  391. * Returns 0 on success, negative value otherwise.
  392. *
  393. * Caller holds tomoyo_read_lock().
  394. */
  395. static int tomoyo_update_domain_keeper_entry(const char *domainname,
  396. const char *program,
  397. const bool is_not,
  398. const bool is_delete)
  399. {
  400. struct tomoyo_domain_keeper_entry *entry = NULL;
  401. struct tomoyo_domain_keeper_entry *ptr;
  402. const struct tomoyo_path_info *saved_domainname;
  403. const struct tomoyo_path_info *saved_program = NULL;
  404. int error = is_delete ? -ENOENT : -ENOMEM;
  405. bool is_last_name = false;
  406. if (!tomoyo_is_domain_def(domainname) &&
  407. tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
  408. is_last_name = true;
  409. else if (!tomoyo_is_correct_domain(domainname, __func__))
  410. return -EINVAL;
  411. if (program) {
  412. if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
  413. return -EINVAL;
  414. saved_program = tomoyo_save_name(program);
  415. if (!saved_program)
  416. goto out;
  417. }
  418. saved_domainname = tomoyo_save_name(domainname);
  419. if (!saved_domainname)
  420. goto out;
  421. if (!is_delete)
  422. entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  423. mutex_lock(&tomoyo_policy_lock);
  424. list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
  425. if (ptr->is_not != is_not ||
  426. ptr->domainname != saved_domainname ||
  427. ptr->program != saved_program)
  428. continue;
  429. ptr->is_deleted = is_delete;
  430. error = 0;
  431. break;
  432. }
  433. if (!is_delete && error && tomoyo_memory_ok(entry)) {
  434. entry->domainname = saved_domainname;
  435. entry->program = saved_program;
  436. entry->is_not = is_not;
  437. entry->is_last_name = is_last_name;
  438. list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list);
  439. entry = NULL;
  440. error = 0;
  441. }
  442. mutex_unlock(&tomoyo_policy_lock);
  443. out:
  444. kfree(entry);
  445. return error;
  446. }
  447. /**
  448. * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
  449. *
  450. * @data: String to parse.
  451. * @is_not: True if it is "no_keep_domain" entry.
  452. * @is_delete: True if it is a delete request.
  453. *
  454. * Caller holds tomoyo_read_lock().
  455. */
  456. int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
  457. const bool is_delete)
  458. {
  459. char *cp = strstr(data, " from ");
  460. if (cp) {
  461. *cp = '\0';
  462. return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
  463. is_delete);
  464. }
  465. return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
  466. }
  467. /**
  468. * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
  469. *
  470. * @head: Pointer to "struct tomoyo_io_buffer".
  471. *
  472. * Returns true on success, false otherwise.
  473. *
  474. * Caller holds tomoyo_read_lock().
  475. */
  476. bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
  477. {
  478. struct list_head *pos;
  479. bool done = true;
  480. list_for_each_cookie(pos, head->read_var2,
  481. &tomoyo_domain_keeper_list) {
  482. struct tomoyo_domain_keeper_entry *ptr;
  483. const char *no;
  484. const char *from = "";
  485. const char *program = "";
  486. ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
  487. if (ptr->is_deleted)
  488. continue;
  489. no = ptr->is_not ? "no_" : "";
  490. if (ptr->program) {
  491. from = " from ";
  492. program = ptr->program->name;
  493. }
  494. done = tomoyo_io_printf(head,
  495. "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
  496. "%s%s%s\n", no, program, from,
  497. ptr->domainname->name);
  498. if (!done)
  499. break;
  500. }
  501. return done;
  502. }
  503. /**
  504. * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
  505. *
  506. * @domainname: The name of domain.
  507. * @program: The name of program.
  508. * @last_name: The last component of @domainname.
  509. *
  510. * Returns true if executing @program supresses domain transition,
  511. * false otherwise.
  512. *
  513. * Caller holds tomoyo_read_lock().
  514. */
  515. static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
  516. const struct tomoyo_path_info *program,
  517. const struct tomoyo_path_info *last_name)
  518. {
  519. struct tomoyo_domain_keeper_entry *ptr;
  520. bool flag = false;
  521. list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
  522. if (ptr->is_deleted)
  523. continue;
  524. if (!ptr->is_last_name) {
  525. if (ptr->domainname != domainname)
  526. continue;
  527. } else {
  528. if (tomoyo_pathcmp(ptr->domainname, last_name))
  529. continue;
  530. }
  531. if (ptr->program && tomoyo_pathcmp(ptr->program, program))
  532. continue;
  533. if (ptr->is_not) {
  534. flag = false;
  535. break;
  536. }
  537. flag = true;
  538. }
  539. return flag;
  540. }
  541. /*
  542. * tomoyo_alias_list is used for holding list of symlink's pathnames which are
  543. * allowed to be passed to an execve() request. Normally, the domainname which
  544. * the current process will belong to after execve() succeeds is calculated
  545. * using dereferenced pathnames. But some programs behave differently depending
  546. * on the name passed to argv[0]. For busybox, calculating domainname using
  547. * dereferenced pathnames will cause all programs in the busybox to belong to
  548. * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
  549. * pathname for checking execve()'s permission and calculating domainname which
  550. * the current process will belong to after execve() succeeds.
  551. *
  552. * An entry is added by
  553. *
  554. * # echo 'alias /bin/busybox /bin/cat' > \
  555. * /sys/kernel/security/tomoyo/exception_policy
  556. *
  557. * and is deleted by
  558. *
  559. * # echo 'delete alias /bin/busybox /bin/cat' > \
  560. * /sys/kernel/security/tomoyo/exception_policy
  561. *
  562. * and all entries are retrieved by
  563. *
  564. * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
  565. *
  566. * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
  567. * of /bin/cat is requested, permission is checked for /bin/cat rather than
  568. * /bin/busybox and domainname which the current process will belong to after
  569. * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
  570. */
  571. static LIST_HEAD(tomoyo_alias_list);
  572. /**
  573. * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
  574. *
  575. * @original_name: The original program's real name.
  576. * @aliased_name: The symbolic program's symbolic link's name.
  577. * @is_delete: True if it is a delete request.
  578. *
  579. * Returns 0 on success, negative value otherwise.
  580. *
  581. * Caller holds tomoyo_read_lock().
  582. */
  583. static int tomoyo_update_alias_entry(const char *original_name,
  584. const char *aliased_name,
  585. const bool is_delete)
  586. {
  587. struct tomoyo_alias_entry *entry = NULL;
  588. struct tomoyo_alias_entry *ptr;
  589. const struct tomoyo_path_info *saved_original_name;
  590. const struct tomoyo_path_info *saved_aliased_name;
  591. int error = is_delete ? -ENOENT : -ENOMEM;
  592. if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
  593. !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
  594. return -EINVAL; /* No patterns allowed. */
  595. saved_original_name = tomoyo_save_name(original_name);
  596. saved_aliased_name = tomoyo_save_name(aliased_name);
  597. if (!saved_original_name || !saved_aliased_name)
  598. goto out;
  599. if (!is_delete)
  600. entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  601. mutex_lock(&tomoyo_policy_lock);
  602. list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
  603. if (ptr->original_name != saved_original_name ||
  604. ptr->aliased_name != saved_aliased_name)
  605. continue;
  606. ptr->is_deleted = is_delete;
  607. error = 0;
  608. break;
  609. }
  610. if (!is_delete && error && tomoyo_memory_ok(entry)) {
  611. entry->original_name = saved_original_name;
  612. entry->aliased_name = saved_aliased_name;
  613. list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
  614. entry = NULL;
  615. error = 0;
  616. }
  617. mutex_unlock(&tomoyo_policy_lock);
  618. out:
  619. kfree(entry);
  620. return error;
  621. }
  622. /**
  623. * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
  624. *
  625. * @head: Pointer to "struct tomoyo_io_buffer".
  626. *
  627. * Returns true on success, false otherwise.
  628. *
  629. * Caller holds tomoyo_read_lock().
  630. */
  631. bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
  632. {
  633. struct list_head *pos;
  634. bool done = true;
  635. list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
  636. struct tomoyo_alias_entry *ptr;
  637. ptr = list_entry(pos, struct tomoyo_alias_entry, list);
  638. if (ptr->is_deleted)
  639. continue;
  640. done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
  641. ptr->original_name->name,
  642. ptr->aliased_name->name);
  643. if (!done)
  644. break;
  645. }
  646. return done;
  647. }
  648. /**
  649. * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
  650. *
  651. * @data: String to parse.
  652. * @is_delete: True if it is a delete request.
  653. *
  654. * Returns 0 on success, negative value otherwise.
  655. *
  656. * Caller holds tomoyo_read_lock().
  657. */
  658. int tomoyo_write_alias_policy(char *data, const bool is_delete)
  659. {
  660. char *cp = strchr(data, ' ');
  661. if (!cp)
  662. return -EINVAL;
  663. *cp++ = '\0';
  664. return tomoyo_update_alias_entry(data, cp, is_delete);
  665. }
  666. /**
  667. * tomoyo_find_or_assign_new_domain - Create a domain.
  668. *
  669. * @domainname: The name of domain.
  670. * @profile: Profile number to assign if the domain was newly created.
  671. *
  672. * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
  673. *
  674. * Caller holds tomoyo_read_lock().
  675. */
  676. struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
  677. domainname,
  678. const u8 profile)
  679. {
  680. struct tomoyo_domain_info *entry;
  681. struct tomoyo_domain_info *domain;
  682. const struct tomoyo_path_info *saved_domainname;
  683. bool found = false;
  684. if (!tomoyo_is_correct_domain(domainname, __func__))
  685. return NULL;
  686. saved_domainname = tomoyo_save_name(domainname);
  687. if (!saved_domainname)
  688. return NULL;
  689. entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  690. mutex_lock(&tomoyo_policy_lock);
  691. list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
  692. if (domain->is_deleted ||
  693. tomoyo_pathcmp(saved_domainname, domain->domainname))
  694. continue;
  695. found = true;
  696. break;
  697. }
  698. if (!found && tomoyo_memory_ok(entry)) {
  699. INIT_LIST_HEAD(&entry->acl_info_list);
  700. entry->domainname = saved_domainname;
  701. entry->profile = profile;
  702. list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
  703. domain = entry;
  704. entry = NULL;
  705. found = true;
  706. }
  707. mutex_unlock(&tomoyo_policy_lock);
  708. kfree(entry);
  709. return found ? domain : NULL;
  710. }
  711. /**
  712. * tomoyo_find_next_domain - Find a domain.
  713. *
  714. * @bprm: Pointer to "struct linux_binprm".
  715. *
  716. * Returns 0 on success, negative value otherwise.
  717. *
  718. * Caller holds tomoyo_read_lock().
  719. */
  720. int tomoyo_find_next_domain(struct linux_binprm *bprm)
  721. {
  722. /*
  723. * This function assumes that the size of buffer returned by
  724. * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
  725. */
  726. struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
  727. struct tomoyo_domain_info *old_domain = tomoyo_domain();
  728. struct tomoyo_domain_info *domain = NULL;
  729. const char *old_domain_name = old_domain->domainname->name;
  730. const char *original_name = bprm->filename;
  731. char *new_domain_name = NULL;
  732. char *real_program_name = NULL;
  733. char *symlink_program_name = NULL;
  734. const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
  735. const bool is_enforce = (mode == 3);
  736. int retval = -ENOMEM;
  737. struct tomoyo_path_info r; /* real name */
  738. struct tomoyo_path_info s; /* symlink name */
  739. struct tomoyo_path_info l; /* last name */
  740. static bool initialized;
  741. if (!tmp)
  742. goto out;
  743. if (!initialized) {
  744. /*
  745. * Built-in initializers. This is needed because policies are
  746. * not loaded until starting /sbin/init.
  747. */
  748. tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
  749. false, false);
  750. tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
  751. false, false);
  752. initialized = true;
  753. }
  754. /* Get tomoyo_realpath of program. */
  755. retval = -ENOENT;
  756. /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
  757. real_program_name = tomoyo_realpath(original_name);
  758. if (!real_program_name)
  759. goto out;
  760. /* Get tomoyo_realpath of symbolic link. */
  761. symlink_program_name = tomoyo_realpath_nofollow(original_name);
  762. if (!symlink_program_name)
  763. goto out;
  764. r.name = real_program_name;
  765. tomoyo_fill_path_info(&r);
  766. s.name = symlink_program_name;
  767. tomoyo_fill_path_info(&s);
  768. l.name = tomoyo_get_last_name(old_domain);
  769. tomoyo_fill_path_info(&l);
  770. /* Check 'alias' directive. */
  771. if (tomoyo_pathcmp(&r, &s)) {
  772. struct tomoyo_alias_entry *ptr;
  773. /* Is this program allowed to be called via symbolic links? */
  774. list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
  775. if (ptr->is_deleted ||
  776. tomoyo_pathcmp(&r, ptr->original_name) ||
  777. tomoyo_pathcmp(&s, ptr->aliased_name))
  778. continue;
  779. memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
  780. strncpy(real_program_name, ptr->aliased_name->name,
  781. TOMOYO_MAX_PATHNAME_LEN - 1);
  782. tomoyo_fill_path_info(&r);
  783. break;
  784. }
  785. }
  786. /* Check execute permission. */
  787. retval = tomoyo_check_exec_perm(old_domain, &r);
  788. if (retval < 0)
  789. goto out;
  790. new_domain_name = tmp->buffer;
  791. if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
  792. /* Transit to the child of tomoyo_kernel_domain domain. */
  793. snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
  794. TOMOYO_ROOT_NAME " " "%s", real_program_name);
  795. } else if (old_domain == &tomoyo_kernel_domain &&
  796. !tomoyo_policy_loaded) {
  797. /*
  798. * Needn't to transit from kernel domain before starting
  799. * /sbin/init. But transit from kernel domain if executing
  800. * initializers because they might start before /sbin/init.
  801. */
  802. domain = old_domain;
  803. } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
  804. /* Keep current domain. */
  805. domain = old_domain;
  806. } else {
  807. /* Normal domain transition. */
  808. snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
  809. "%s %s", old_domain_name, real_program_name);
  810. }
  811. if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
  812. goto done;
  813. domain = tomoyo_find_domain(new_domain_name);
  814. if (domain)
  815. goto done;
  816. if (is_enforce)
  817. goto done;
  818. domain = tomoyo_find_or_assign_new_domain(new_domain_name,
  819. old_domain->profile);
  820. done:
  821. if (domain)
  822. goto out;
  823. printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
  824. new_domain_name);
  825. if (is_enforce)
  826. retval = -EPERM;
  827. else
  828. old_domain->transition_failed = true;
  829. out:
  830. if (!domain)
  831. domain = old_domain;
  832. bprm->cred->security = domain;
  833. kfree(real_program_name);
  834. kfree(symlink_program_name);
  835. kfree(tmp);
  836. return retval;
  837. }