smack_access.c 13 KB

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