smack_access.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /*
  2. * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, version 2.
  7. *
  8. * Author:
  9. * Casey Schaufler <casey@schaufler-ca.com>
  10. *
  11. */
  12. #include <linux/types.h>
  13. #include <linux/slab.h>
  14. #include <linux/fs.h>
  15. #include <linux/sched.h>
  16. #include "smack.h"
  17. struct smack_known smack_known_huh = {
  18. .smk_known = "?",
  19. .smk_secid = 2,
  20. .smk_cipso = NULL,
  21. };
  22. struct smack_known smack_known_hat = {
  23. .smk_known = "^",
  24. .smk_secid = 3,
  25. .smk_cipso = NULL,
  26. };
  27. struct smack_known smack_known_star = {
  28. .smk_known = "*",
  29. .smk_secid = 4,
  30. .smk_cipso = NULL,
  31. };
  32. struct smack_known smack_known_floor = {
  33. .smk_known = "_",
  34. .smk_secid = 5,
  35. .smk_cipso = NULL,
  36. };
  37. struct smack_known smack_known_invalid = {
  38. .smk_known = "",
  39. .smk_secid = 6,
  40. .smk_cipso = NULL,
  41. };
  42. struct smack_known smack_known_web = {
  43. .smk_known = "@",
  44. .smk_secid = 7,
  45. .smk_cipso = NULL,
  46. };
  47. LIST_HEAD(smack_known_list);
  48. /*
  49. * The initial value needs to be bigger than any of the
  50. * known values above.
  51. */
  52. static u32 smack_next_secid = 10;
  53. /*
  54. * what events do we log
  55. * can be overwritten at run-time by /smack/logging
  56. */
  57. int log_policy = SMACK_AUDIT_DENIED;
  58. /**
  59. * smk_access_entry - look up matching access rule
  60. * @subject_label: a pointer to the subject's Smack label
  61. * @object_label: a pointer to the object's Smack label
  62. *
  63. * This function looks up the subject/object pair in the
  64. * access rule list and returns pointer to the matching rule if found,
  65. * NULL otherwise.
  66. *
  67. * NOTE:
  68. * Even though Smack labels are usually shared on smack_list
  69. * labels that come in off the network can't be imported
  70. * and added to the list for locking reasons.
  71. *
  72. * Therefore, it is necessary to check the contents of the labels,
  73. * not just the pointer values. Of course, in most cases the labels
  74. * will be on the list, so checking the pointers may be a worthwhile
  75. * optimization.
  76. */
  77. int smk_access_entry(char *subject_label, char *object_label)
  78. {
  79. u32 may = MAY_NOT;
  80. struct smack_rule *srp;
  81. rcu_read_lock();
  82. list_for_each_entry_rcu(srp, &smack_rule_list, list) {
  83. if (srp->smk_subject == subject_label ||
  84. strcmp(srp->smk_subject, subject_label) == 0) {
  85. if (srp->smk_object == object_label ||
  86. strcmp(srp->smk_object, object_label) == 0) {
  87. may = srp->smk_access;
  88. break;
  89. }
  90. }
  91. }
  92. rcu_read_unlock();
  93. return may;
  94. }
  95. /**
  96. * smk_access - determine if a subject has a specific access to an object
  97. * @subject_label: a pointer to the subject's Smack label
  98. * @object_label: a pointer to the object's Smack label
  99. * @request: the access requested, in "MAY" format
  100. * @a : a pointer to the audit data
  101. *
  102. * This function looks up the subject/object pair in the
  103. * access rule list and returns 0 if the access is permitted,
  104. * non zero otherwise.
  105. *
  106. * Even though Smack labels are usually shared on smack_list
  107. * labels that come in off the network can't be imported
  108. * and added to the list for locking reasons.
  109. *
  110. * Therefore, it is necessary to check the contents of the labels,
  111. * not just the pointer values. Of course, in most cases the labels
  112. * will be on the list, so checking the pointers may be a worthwhile
  113. * optimization.
  114. */
  115. int smk_access(char *subject_label, char *object_label, int request,
  116. struct smk_audit_info *a)
  117. {
  118. u32 may = MAY_NOT;
  119. int rc = 0;
  120. /*
  121. * Hardcoded comparisons.
  122. *
  123. * A star subject can't access any object.
  124. */
  125. if (subject_label == smack_known_star.smk_known ||
  126. strcmp(subject_label, smack_known_star.smk_known) == 0) {
  127. rc = -EACCES;
  128. goto out_audit;
  129. }
  130. /*
  131. * An internet object can be accessed by any subject.
  132. * Tasks cannot be assigned the internet label.
  133. * An internet subject can access any object.
  134. */
  135. if (object_label == smack_known_web.smk_known ||
  136. subject_label == smack_known_web.smk_known ||
  137. strcmp(object_label, smack_known_web.smk_known) == 0 ||
  138. strcmp(subject_label, smack_known_web.smk_known) == 0)
  139. goto out_audit;
  140. /*
  141. * A star object can be accessed by any subject.
  142. */
  143. if (object_label == smack_known_star.smk_known ||
  144. strcmp(object_label, smack_known_star.smk_known) == 0)
  145. goto out_audit;
  146. /*
  147. * An object can be accessed in any way by a subject
  148. * with the same label.
  149. */
  150. if (subject_label == object_label ||
  151. strcmp(subject_label, object_label) == 0)
  152. goto out_audit;
  153. /*
  154. * A hat subject can read any object.
  155. * A floor object can be read by any subject.
  156. */
  157. if ((request & MAY_ANYREAD) == request) {
  158. if (object_label == smack_known_floor.smk_known ||
  159. strcmp(object_label, smack_known_floor.smk_known) == 0)
  160. goto out_audit;
  161. if (subject_label == smack_known_hat.smk_known ||
  162. strcmp(subject_label, smack_known_hat.smk_known) == 0)
  163. goto out_audit;
  164. }
  165. /*
  166. * Beyond here an explicit relationship is required.
  167. * If the requested access is contained in the available
  168. * access (e.g. read is included in readwrite) it's
  169. * good.
  170. */
  171. may = smk_access_entry(subject_label, object_label);
  172. /*
  173. * This is a bit map operation.
  174. */
  175. if ((request & may) == request)
  176. goto out_audit;
  177. rc = -EACCES;
  178. out_audit:
  179. #ifdef CONFIG_AUDIT
  180. if (a)
  181. smack_log(subject_label, object_label, request, rc, a);
  182. #endif
  183. return rc;
  184. }
  185. /**
  186. * smk_curacc - determine if current has a specific access to an object
  187. * @obj_label: a pointer to the object's Smack label
  188. * @mode: the access requested, in "MAY" format
  189. * @a : common audit data
  190. *
  191. * This function checks the current subject label/object label pair
  192. * in the access rule list and returns 0 if the access is permitted,
  193. * non zero otherwise. It allows that current may have the capability
  194. * to override the rules.
  195. */
  196. int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
  197. {
  198. int rc;
  199. char *sp = smk_of_current();
  200. rc = smk_access(sp, obj_label, mode, NULL);
  201. if (rc == 0)
  202. goto out_audit;
  203. /*
  204. * Return if a specific label has been designated as the
  205. * only one that gets privilege and current does not
  206. * have that label.
  207. */
  208. if (smack_onlycap != NULL && smack_onlycap != sp)
  209. goto out_audit;
  210. if (capable(CAP_MAC_OVERRIDE))
  211. return 0;
  212. out_audit:
  213. #ifdef CONFIG_AUDIT
  214. if (a)
  215. smack_log(sp, obj_label, mode, rc, a);
  216. #endif
  217. return rc;
  218. }
  219. #ifdef CONFIG_AUDIT
  220. /**
  221. * smack_str_from_perm : helper to transalate an int to a
  222. * readable string
  223. * @string : the string to fill
  224. * @access : the int
  225. *
  226. */
  227. static inline void smack_str_from_perm(char *string, int access)
  228. {
  229. int i = 0;
  230. if (access & MAY_READ)
  231. string[i++] = 'r';
  232. if (access & MAY_WRITE)
  233. string[i++] = 'w';
  234. if (access & MAY_EXEC)
  235. string[i++] = 'x';
  236. if (access & MAY_APPEND)
  237. string[i++] = 'a';
  238. string[i] = '\0';
  239. }
  240. /**
  241. * smack_log_callback - SMACK specific information
  242. * will be called by generic audit code
  243. * @ab : the audit_buffer
  244. * @a : audit_data
  245. *
  246. */
  247. static void smack_log_callback(struct audit_buffer *ab, void *a)
  248. {
  249. struct common_audit_data *ad = a;
  250. struct smack_audit_data *sad = &ad->smack_audit_data;
  251. audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
  252. ad->smack_audit_data.function,
  253. sad->result ? "denied" : "granted");
  254. audit_log_format(ab, " subject=");
  255. audit_log_untrustedstring(ab, sad->subject);
  256. audit_log_format(ab, " object=");
  257. audit_log_untrustedstring(ab, sad->object);
  258. audit_log_format(ab, " requested=%s", sad->request);
  259. }
  260. /**
  261. * smack_log - Audit the granting or denial of permissions.
  262. * @subject_label : smack label of the requester
  263. * @object_label : smack label of the object being accessed
  264. * @request: requested permissions
  265. * @result: result from smk_access
  266. * @a: auxiliary audit data
  267. *
  268. * Audit the granting or denial of permissions in accordance
  269. * with the policy.
  270. */
  271. void smack_log(char *subject_label, char *object_label, int request,
  272. int result, struct smk_audit_info *ad)
  273. {
  274. char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
  275. struct smack_audit_data *sad;
  276. struct common_audit_data *a = &ad->a;
  277. /* check if we have to log the current event */
  278. if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
  279. return;
  280. if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
  281. return;
  282. if (a->smack_audit_data.function == NULL)
  283. a->smack_audit_data.function = "unknown";
  284. /* end preparing the audit data */
  285. sad = &a->smack_audit_data;
  286. smack_str_from_perm(request_buffer, request);
  287. sad->subject = subject_label;
  288. sad->object = object_label;
  289. sad->request = request_buffer;
  290. sad->result = result;
  291. a->lsm_pre_audit = smack_log_callback;
  292. common_lsm_audit(a);
  293. }
  294. #else /* #ifdef CONFIG_AUDIT */
  295. void smack_log(char *subject_label, char *object_label, int request,
  296. int result, struct smk_audit_info *ad)
  297. {
  298. }
  299. #endif
  300. static DEFINE_MUTEX(smack_known_lock);
  301. /**
  302. * smk_import_entry - import a label, return the list entry
  303. * @string: a text string that might be a Smack label
  304. * @len: the maximum size, or zero if it is NULL terminated.
  305. *
  306. * Returns a pointer to the entry in the label list that
  307. * matches the passed string, adding it if necessary.
  308. */
  309. struct smack_known *smk_import_entry(const char *string, int len)
  310. {
  311. struct smack_known *skp;
  312. char smack[SMK_LABELLEN];
  313. int found;
  314. int i;
  315. if (len <= 0 || len > SMK_MAXLEN)
  316. len = SMK_MAXLEN;
  317. for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
  318. if (found)
  319. smack[i] = '\0';
  320. else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
  321. string[i] == '/' || string[i] == '"' ||
  322. string[i] == '\\' || string[i] == '\'') {
  323. smack[i] = '\0';
  324. found = 1;
  325. } else
  326. smack[i] = string[i];
  327. }
  328. if (smack[0] == '\0')
  329. return NULL;
  330. mutex_lock(&smack_known_lock);
  331. found = 0;
  332. list_for_each_entry_rcu(skp, &smack_known_list, list) {
  333. if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
  334. found = 1;
  335. break;
  336. }
  337. }
  338. if (found == 0) {
  339. skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
  340. if (skp != NULL) {
  341. strncpy(skp->smk_known, smack, SMK_MAXLEN);
  342. skp->smk_secid = smack_next_secid++;
  343. skp->smk_cipso = NULL;
  344. spin_lock_init(&skp->smk_cipsolock);
  345. /*
  346. * Make sure that the entry is actually
  347. * filled before putting it on the list.
  348. */
  349. list_add_rcu(&skp->list, &smack_known_list);
  350. }
  351. }
  352. mutex_unlock(&smack_known_lock);
  353. return skp;
  354. }
  355. /**
  356. * smk_import - import a smack label
  357. * @string: a text string that might be a Smack label
  358. * @len: the maximum size, or zero if it is NULL terminated.
  359. *
  360. * Returns a pointer to the label in the label list that
  361. * matches the passed string, adding it if necessary.
  362. */
  363. char *smk_import(const char *string, int len)
  364. {
  365. struct smack_known *skp;
  366. /* labels cannot begin with a '-' */
  367. if (string[0] == '-')
  368. return NULL;
  369. skp = smk_import_entry(string, len);
  370. if (skp == NULL)
  371. return NULL;
  372. return skp->smk_known;
  373. }
  374. /**
  375. * smack_from_secid - find the Smack label associated with a secid
  376. * @secid: an integer that might be associated with a Smack label
  377. *
  378. * Returns a pointer to the appropraite Smack label if there is one,
  379. * otherwise a pointer to the invalid Smack label.
  380. */
  381. char *smack_from_secid(const u32 secid)
  382. {
  383. struct smack_known *skp;
  384. rcu_read_lock();
  385. list_for_each_entry_rcu(skp, &smack_known_list, list) {
  386. if (skp->smk_secid == secid) {
  387. rcu_read_unlock();
  388. return skp->smk_known;
  389. }
  390. }
  391. /*
  392. * If we got this far someone asked for the translation
  393. * of a secid that is not on the list.
  394. */
  395. rcu_read_unlock();
  396. return smack_known_invalid.smk_known;
  397. }
  398. /**
  399. * smack_to_secid - find the secid associated with a Smack label
  400. * @smack: the Smack label
  401. *
  402. * Returns the appropriate secid if there is one,
  403. * otherwise 0
  404. */
  405. u32 smack_to_secid(const char *smack)
  406. {
  407. struct smack_known *skp;
  408. rcu_read_lock();
  409. list_for_each_entry_rcu(skp, &smack_known_list, list) {
  410. if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
  411. rcu_read_unlock();
  412. return skp->smk_secid;
  413. }
  414. }
  415. rcu_read_unlock();
  416. return 0;
  417. }
  418. /**
  419. * smack_from_cipso - find the Smack label associated with a CIPSO option
  420. * @level: Bell & LaPadula level from the network
  421. * @cp: Bell & LaPadula categories from the network
  422. * @result: where to put the Smack value
  423. *
  424. * This is a simple lookup in the label table.
  425. *
  426. * This is an odd duck as far as smack handling goes in that
  427. * it sends back a copy of the smack label rather than a pointer
  428. * to the master list. This is done because it is possible for
  429. * a foreign host to send a smack label that is new to this
  430. * machine and hence not on the list. That would not be an
  431. * issue except that adding an entry to the master list can't
  432. * be done at that point.
  433. */
  434. void smack_from_cipso(u32 level, char *cp, char *result)
  435. {
  436. struct smack_known *kp;
  437. char *final = NULL;
  438. rcu_read_lock();
  439. list_for_each_entry(kp, &smack_known_list, list) {
  440. if (kp->smk_cipso == NULL)
  441. continue;
  442. spin_lock_bh(&kp->smk_cipsolock);
  443. if (kp->smk_cipso->smk_level == level &&
  444. memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
  445. final = kp->smk_known;
  446. spin_unlock_bh(&kp->smk_cipsolock);
  447. }
  448. rcu_read_unlock();
  449. if (final == NULL)
  450. final = smack_known_huh.smk_known;
  451. strncpy(result, final, SMK_MAXLEN);
  452. return;
  453. }
  454. /**
  455. * smack_to_cipso - find the CIPSO option to go with a Smack label
  456. * @smack: a pointer to the smack label in question
  457. * @cp: where to put the result
  458. *
  459. * Returns zero if a value is available, non-zero otherwise.
  460. */
  461. int smack_to_cipso(const char *smack, struct smack_cipso *cp)
  462. {
  463. struct smack_known *kp;
  464. int found = 0;
  465. rcu_read_lock();
  466. list_for_each_entry_rcu(kp, &smack_known_list, list) {
  467. if (kp->smk_known == smack ||
  468. strcmp(kp->smk_known, smack) == 0) {
  469. found = 1;
  470. break;
  471. }
  472. }
  473. rcu_read_unlock();
  474. if (found == 0 || kp->smk_cipso == NULL)
  475. return -ENOENT;
  476. memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
  477. return 0;
  478. }