PageRenderTime 1431ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/security/smack/smack_access.c

https://github.com/dingjiu/linux
C | 547 lines | 370 code | 32 blank | 145 comment | 68 complexity | 19110c10dc2510b8c4254f1bcdfc443b MD5 | raw file
  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. * @rule_list: the list of rules to search
  63. *
  64. * This function looks up the subject/object pair in the
  65. * access rule list and returns the access mode. If no
  66. * entry is found returns -ENOENT.
  67. *
  68. * NOTE:
  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_entry(char *subject_label, char *object_label,
  79. struct list_head *rule_list)
  80. {
  81. int may = -ENOENT;
  82. struct smack_rule *srp;
  83. list_for_each_entry_rcu(srp, rule_list, list) {
  84. if (srp->smk_subject == subject_label ||
  85. strcmp(srp->smk_subject, subject_label) == 0) {
  86. if (srp->smk_object == object_label ||
  87. strcmp(srp->smk_object, object_label) == 0) {
  88. may = srp->smk_access;
  89. break;
  90. }
  91. }
  92. }
  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. int 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. A negative response from smk_access_entry()
  170. * indicates there is no entry for this pair.
  171. */
  172. rcu_read_lock();
  173. may = smk_access_entry(subject_label, object_label, &smack_rule_list);
  174. rcu_read_unlock();
  175. if (may > 0 && (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. struct task_smack *tsp = current_security();
  199. char *sp = smk_of_task(tsp);
  200. int may;
  201. int rc;
  202. /*
  203. * Check the global rule list
  204. */
  205. rc = smk_access(sp, obj_label, mode, NULL);
  206. if (rc == 0) {
  207. /*
  208. * If there is an entry in the task's rule list
  209. * it can further restrict access.
  210. */
  211. may = smk_access_entry(sp, obj_label, &tsp->smk_rules);
  212. if (may < 0)
  213. goto out_audit;
  214. if ((mode & may) == mode)
  215. goto out_audit;
  216. rc = -EACCES;
  217. }
  218. /*
  219. * Return if a specific label has been designated as the
  220. * only one that gets privilege and current does not
  221. * have that label.
  222. */
  223. if (smack_onlycap != NULL && smack_onlycap != sp)
  224. goto out_audit;
  225. if (capable(CAP_MAC_OVERRIDE))
  226. rc = 0;
  227. out_audit:
  228. #ifdef CONFIG_AUDIT
  229. if (a)
  230. smack_log(sp, obj_label, mode, rc, a);
  231. #endif
  232. return rc;
  233. }
  234. #ifdef CONFIG_AUDIT
  235. /**
  236. * smack_str_from_perm : helper to transalate an int to a
  237. * readable string
  238. * @string : the string to fill
  239. * @access : the int
  240. *
  241. */
  242. static inline void smack_str_from_perm(char *string, int access)
  243. {
  244. int i = 0;
  245. if (access & MAY_READ)
  246. string[i++] = 'r';
  247. if (access & MAY_WRITE)
  248. string[i++] = 'w';
  249. if (access & MAY_EXEC)
  250. string[i++] = 'x';
  251. if (access & MAY_APPEND)
  252. string[i++] = 'a';
  253. string[i] = '\0';
  254. }
  255. /**
  256. * smack_log_callback - SMACK specific information
  257. * will be called by generic audit code
  258. * @ab : the audit_buffer
  259. * @a : audit_data
  260. *
  261. */
  262. static void smack_log_callback(struct audit_buffer *ab, void *a)
  263. {
  264. struct common_audit_data *ad = a;
  265. struct smack_audit_data *sad = &ad->smack_audit_data;
  266. audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
  267. ad->smack_audit_data.function,
  268. sad->result ? "denied" : "granted");
  269. audit_log_format(ab, " subject=");
  270. audit_log_untrustedstring(ab, sad->subject);
  271. audit_log_format(ab, " object=");
  272. audit_log_untrustedstring(ab, sad->object);
  273. audit_log_format(ab, " requested=%s", sad->request);
  274. }
  275. /**
  276. * smack_log - Audit the granting or denial of permissions.
  277. * @subject_label : smack label of the requester
  278. * @object_label : smack label of the object being accessed
  279. * @request: requested permissions
  280. * @result: result from smk_access
  281. * @a: auxiliary audit data
  282. *
  283. * Audit the granting or denial of permissions in accordance
  284. * with the policy.
  285. */
  286. void smack_log(char *subject_label, char *object_label, int request,
  287. int result, struct smk_audit_info *ad)
  288. {
  289. char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
  290. struct smack_audit_data *sad;
  291. struct common_audit_data *a = &ad->a;
  292. /* check if we have to log the current event */
  293. if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
  294. return;
  295. if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
  296. return;
  297. if (a->smack_audit_data.function == NULL)
  298. a->smack_audit_data.function = "unknown";
  299. /* end preparing the audit data */
  300. sad = &a->smack_audit_data;
  301. smack_str_from_perm(request_buffer, request);
  302. sad->subject = subject_label;
  303. sad->object = object_label;
  304. sad->request = request_buffer;
  305. sad->result = result;
  306. a->lsm_pre_audit = smack_log_callback;
  307. common_lsm_audit(a);
  308. }
  309. #else /* #ifdef CONFIG_AUDIT */
  310. void smack_log(char *subject_label, char *object_label, int request,
  311. int result, struct smk_audit_info *ad)
  312. {
  313. }
  314. #endif
  315. static DEFINE_MUTEX(smack_known_lock);
  316. /**
  317. * smk_import_entry - import a label, return the list entry
  318. * @string: a text string that might be a Smack label
  319. * @len: the maximum size, or zero if it is NULL terminated.
  320. *
  321. * Returns a pointer to the entry in the label list that
  322. * matches the passed string, adding it if necessary.
  323. */
  324. struct smack_known *smk_import_entry(const char *string, int len)
  325. {
  326. struct smack_known *skp;
  327. char smack[SMK_LABELLEN];
  328. int found;
  329. int i;
  330. if (len <= 0 || len > SMK_MAXLEN)
  331. len = SMK_MAXLEN;
  332. for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
  333. if (found)
  334. smack[i] = '\0';
  335. else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
  336. string[i] == '/' || string[i] == '"' ||
  337. string[i] == '\\' || string[i] == '\'') {
  338. smack[i] = '\0';
  339. found = 1;
  340. } else
  341. smack[i] = string[i];
  342. }
  343. if (smack[0] == '\0')
  344. return NULL;
  345. mutex_lock(&smack_known_lock);
  346. found = 0;
  347. list_for_each_entry_rcu(skp, &smack_known_list, list) {
  348. if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
  349. found = 1;
  350. break;
  351. }
  352. }
  353. if (found == 0) {
  354. skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
  355. if (skp != NULL) {
  356. strncpy(skp->smk_known, smack, SMK_MAXLEN);
  357. skp->smk_secid = smack_next_secid++;
  358. skp->smk_cipso = NULL;
  359. spin_lock_init(&skp->smk_cipsolock);
  360. /*
  361. * Make sure that the entry is actually
  362. * filled before putting it on the list.
  363. */
  364. list_add_rcu(&skp->list, &smack_known_list);
  365. }
  366. }
  367. mutex_unlock(&smack_known_lock);
  368. return skp;
  369. }
  370. /**
  371. * smk_import - import a smack label
  372. * @string: a text string that might be a Smack label
  373. * @len: the maximum size, or zero if it is NULL terminated.
  374. *
  375. * Returns a pointer to the label in the label list that
  376. * matches the passed string, adding it if necessary.
  377. */
  378. char *smk_import(const char *string, int len)
  379. {
  380. struct smack_known *skp;
  381. /* labels cannot begin with a '-' */
  382. if (string[0] == '-')
  383. return NULL;
  384. skp = smk_import_entry(string, len);
  385. if (skp == NULL)
  386. return NULL;
  387. return skp->smk_known;
  388. }
  389. /**
  390. * smack_from_secid - find the Smack label associated with a secid
  391. * @secid: an integer that might be associated with a Smack label
  392. *
  393. * Returns a pointer to the appropriate Smack label if there is one,
  394. * otherwise a pointer to the invalid Smack label.
  395. */
  396. char *smack_from_secid(const u32 secid)
  397. {
  398. struct smack_known *skp;
  399. rcu_read_lock();
  400. list_for_each_entry_rcu(skp, &smack_known_list, list) {
  401. if (skp->smk_secid == secid) {
  402. rcu_read_unlock();
  403. return skp->smk_known;
  404. }
  405. }
  406. /*
  407. * If we got this far someone asked for the translation
  408. * of a secid that is not on the list.
  409. */
  410. rcu_read_unlock();
  411. return smack_known_invalid.smk_known;
  412. }
  413. /**
  414. * smack_to_secid - find the secid associated with a Smack label
  415. * @smack: the Smack label
  416. *
  417. * Returns the appropriate secid if there is one,
  418. * otherwise 0
  419. */
  420. u32 smack_to_secid(const char *smack)
  421. {
  422. struct smack_known *skp;
  423. rcu_read_lock();
  424. list_for_each_entry_rcu(skp, &smack_known_list, list) {
  425. if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
  426. rcu_read_unlock();
  427. return skp->smk_secid;
  428. }
  429. }
  430. rcu_read_unlock();
  431. return 0;
  432. }
  433. /**
  434. * smack_from_cipso - find the Smack label associated with a CIPSO option
  435. * @level: Bell & LaPadula level from the network
  436. * @cp: Bell & LaPadula categories from the network
  437. * @result: where to put the Smack value
  438. *
  439. * This is a simple lookup in the label table.
  440. *
  441. * This is an odd duck as far as smack handling goes in that
  442. * it sends back a copy of the smack label rather than a pointer
  443. * to the master list. This is done because it is possible for
  444. * a foreign host to send a smack label that is new to this
  445. * machine and hence not on the list. That would not be an
  446. * issue except that adding an entry to the master list can't
  447. * be done at that point.
  448. */
  449. void smack_from_cipso(u32 level, char *cp, char *result)
  450. {
  451. struct smack_known *kp;
  452. char *final = NULL;
  453. rcu_read_lock();
  454. list_for_each_entry(kp, &smack_known_list, list) {
  455. if (kp->smk_cipso == NULL)
  456. continue;
  457. spin_lock_bh(&kp->smk_cipsolock);
  458. if (kp->smk_cipso->smk_level == level &&
  459. memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
  460. final = kp->smk_known;
  461. spin_unlock_bh(&kp->smk_cipsolock);
  462. }
  463. rcu_read_unlock();
  464. if (final == NULL)
  465. final = smack_known_huh.smk_known;
  466. strncpy(result, final, SMK_MAXLEN);
  467. return;
  468. }
  469. /**
  470. * smack_to_cipso - find the CIPSO option to go with a Smack label
  471. * @smack: a pointer to the smack label in question
  472. * @cp: where to put the result
  473. *
  474. * Returns zero if a value is available, non-zero otherwise.
  475. */
  476. int smack_to_cipso(const char *smack, struct smack_cipso *cp)
  477. {
  478. struct smack_known *kp;
  479. int found = 0;
  480. rcu_read_lock();
  481. list_for_each_entry_rcu(kp, &smack_known_list, list) {
  482. if (kp->smk_known == smack ||
  483. strcmp(kp->smk_known, smack) == 0) {
  484. found = 1;
  485. break;
  486. }
  487. }
  488. rcu_read_unlock();
  489. if (found == 0 || kp->smk_cipso == NULL)
  490. return -ENOENT;
  491. memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
  492. return 0;
  493. }