securityfs.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * SafeSetID Linux Security Module
  4. *
  5. * Author: Micah Morton <mortonm@chromium.org>
  6. *
  7. * Copyright (C) 2018 The Chromium OS Authors.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2, as
  11. * published by the Free Software Foundation.
  12. *
  13. */
  14. #define pr_fmt(fmt) "SafeSetID: " fmt
  15. #include <linux/security.h>
  16. #include <linux/cred.h>
  17. #include "lsm.h"
  18. static DEFINE_MUTEX(uid_policy_update_lock);
  19. static DEFINE_MUTEX(gid_policy_update_lock);
  20. /*
  21. * In the case the input buffer contains one or more invalid IDs, the kid_t
  22. * variables pointed to by @parent and @child will get updated but this
  23. * function will return an error.
  24. * Contents of @buf may be modified.
  25. */
  26. static int parse_policy_line(struct file *file, char *buf,
  27. struct setid_rule *rule)
  28. {
  29. char *child_str;
  30. int ret;
  31. u32 parsed_parent, parsed_child;
  32. /* Format of |buf| string should be <UID>:<UID> or <GID>:<GID> */
  33. child_str = strchr(buf, ':');
  34. if (child_str == NULL)
  35. return -EINVAL;
  36. *child_str = '\0';
  37. child_str++;
  38. ret = kstrtou32(buf, 0, &parsed_parent);
  39. if (ret)
  40. return ret;
  41. ret = kstrtou32(child_str, 0, &parsed_child);
  42. if (ret)
  43. return ret;
  44. if (rule->type == UID){
  45. rule->src_id.uid = make_kuid(file->f_cred->user_ns, parsed_parent);
  46. rule->dst_id.uid = make_kuid(file->f_cred->user_ns, parsed_child);
  47. if (!uid_valid(rule->src_id.uid) || !uid_valid(rule->dst_id.uid))
  48. return -EINVAL;
  49. } else if (rule->type == GID){
  50. rule->src_id.gid = make_kgid(file->f_cred->user_ns, parsed_parent);
  51. rule->dst_id.gid = make_kgid(file->f_cred->user_ns, parsed_child);
  52. if (!gid_valid(rule->src_id.gid) || !gid_valid(rule->dst_id.gid))
  53. return -EINVAL;
  54. } else {
  55. /* Error, rule->type is an invalid type */
  56. return -EINVAL;
  57. }
  58. return 0;
  59. }
  60. static void __release_ruleset(struct rcu_head *rcu)
  61. {
  62. struct setid_ruleset *pol =
  63. container_of(rcu, struct setid_ruleset, rcu);
  64. int bucket;
  65. struct setid_rule *rule;
  66. struct hlist_node *tmp;
  67. hash_for_each_safe(pol->rules, bucket, tmp, rule, next)
  68. kfree(rule);
  69. kfree(pol->policy_str);
  70. kfree(pol);
  71. }
  72. static void release_ruleset(struct setid_ruleset *pol){
  73. call_rcu(&pol->rcu, __release_ruleset);
  74. }
  75. static void insert_rule(struct setid_ruleset *pol, struct setid_rule *rule)
  76. {
  77. if (pol->type == UID)
  78. hash_add(pol->rules, &rule->next, __kuid_val(rule->src_id.uid));
  79. else if (pol->type == GID)
  80. hash_add(pol->rules, &rule->next, __kgid_val(rule->src_id.gid));
  81. else /* Error, pol->type is neither UID or GID */
  82. return;
  83. }
  84. static int verify_ruleset(struct setid_ruleset *pol)
  85. {
  86. int bucket;
  87. struct setid_rule *rule, *nrule;
  88. int res = 0;
  89. hash_for_each(pol->rules, bucket, rule, next) {
  90. if (_setid_policy_lookup(pol, rule->dst_id, INVALID_ID) == SIDPOL_DEFAULT) {
  91. if (pol->type == UID) {
  92. pr_warn("insecure policy detected: uid %d is constrained but transitively unconstrained through uid %d\n",
  93. __kuid_val(rule->src_id.uid),
  94. __kuid_val(rule->dst_id.uid));
  95. } else if (pol->type == GID) {
  96. pr_warn("insecure policy detected: gid %d is constrained but transitively unconstrained through gid %d\n",
  97. __kgid_val(rule->src_id.gid),
  98. __kgid_val(rule->dst_id.gid));
  99. } else { /* pol->type is an invalid type */
  100. res = -EINVAL;
  101. return res;
  102. }
  103. res = -EINVAL;
  104. /* fix it up */
  105. nrule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL);
  106. if (!nrule)
  107. return -ENOMEM;
  108. if (pol->type == UID){
  109. nrule->src_id.uid = rule->dst_id.uid;
  110. nrule->dst_id.uid = rule->dst_id.uid;
  111. nrule->type = UID;
  112. } else { /* pol->type must be GID if we've made it to here */
  113. nrule->src_id.gid = rule->dst_id.gid;
  114. nrule->dst_id.gid = rule->dst_id.gid;
  115. nrule->type = GID;
  116. }
  117. insert_rule(pol, nrule);
  118. }
  119. }
  120. return res;
  121. }
  122. static ssize_t handle_policy_update(struct file *file,
  123. const char __user *ubuf, size_t len, enum setid_type policy_type)
  124. {
  125. struct setid_ruleset *pol;
  126. char *buf, *p, *end;
  127. int err;
  128. if (len >= KMALLOC_MAX_SIZE)
  129. return -EINVAL;
  130. pol = kmalloc(sizeof(struct setid_ruleset), GFP_KERNEL);
  131. if (!pol)
  132. return -ENOMEM;
  133. pol->policy_str = NULL;
  134. pol->type = policy_type;
  135. hash_init(pol->rules);
  136. p = buf = memdup_user_nul(ubuf, len);
  137. if (IS_ERR(buf)) {
  138. err = PTR_ERR(buf);
  139. goto out_free_pol;
  140. }
  141. pol->policy_str = kstrdup(buf, GFP_KERNEL);
  142. if (pol->policy_str == NULL) {
  143. err = -ENOMEM;
  144. goto out_free_buf;
  145. }
  146. /* policy lines, including the last one, end with \n */
  147. while (*p != '\0') {
  148. struct setid_rule *rule;
  149. end = strchr(p, '\n');
  150. if (end == NULL) {
  151. err = -EINVAL;
  152. goto out_free_buf;
  153. }
  154. *end = '\0';
  155. rule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL);
  156. if (!rule) {
  157. err = -ENOMEM;
  158. goto out_free_buf;
  159. }
  160. rule->type = policy_type;
  161. err = parse_policy_line(file, p, rule);
  162. if (err)
  163. goto out_free_rule;
  164. if (_setid_policy_lookup(pol, rule->src_id, rule->dst_id) == SIDPOL_ALLOWED) {
  165. pr_warn("bad policy: duplicate entry\n");
  166. err = -EEXIST;
  167. goto out_free_rule;
  168. }
  169. insert_rule(pol, rule);
  170. p = end + 1;
  171. continue;
  172. out_free_rule:
  173. kfree(rule);
  174. goto out_free_buf;
  175. }
  176. err = verify_ruleset(pol);
  177. /* bogus policy falls through after fixing it up */
  178. if (err && err != -EINVAL)
  179. goto out_free_buf;
  180. /*
  181. * Everything looks good, apply the policy and release the old one.
  182. * What we really want here is an xchg() wrapper for RCU, but since that
  183. * doesn't currently exist, just use a spinlock for now.
  184. */
  185. if (policy_type == UID) {
  186. mutex_lock(&uid_policy_update_lock);
  187. pol = rcu_replace_pointer(safesetid_setuid_rules, pol,
  188. lockdep_is_held(&uid_policy_update_lock));
  189. mutex_unlock(&uid_policy_update_lock);
  190. } else if (policy_type == GID) {
  191. mutex_lock(&gid_policy_update_lock);
  192. pol = rcu_replace_pointer(safesetid_setgid_rules, pol,
  193. lockdep_is_held(&gid_policy_update_lock));
  194. mutex_unlock(&gid_policy_update_lock);
  195. } else {
  196. /* Error, policy type is neither UID or GID */
  197. pr_warn("error: bad policy type");
  198. }
  199. err = len;
  200. out_free_buf:
  201. kfree(buf);
  202. out_free_pol:
  203. if (pol)
  204. release_ruleset(pol);
  205. return err;
  206. }
  207. static ssize_t safesetid_uid_file_write(struct file *file,
  208. const char __user *buf,
  209. size_t len,
  210. loff_t *ppos)
  211. {
  212. if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN))
  213. return -EPERM;
  214. if (*ppos != 0)
  215. return -EINVAL;
  216. return handle_policy_update(file, buf, len, UID);
  217. }
  218. static ssize_t safesetid_gid_file_write(struct file *file,
  219. const char __user *buf,
  220. size_t len,
  221. loff_t *ppos)
  222. {
  223. if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN))
  224. return -EPERM;
  225. if (*ppos != 0)
  226. return -EINVAL;
  227. return handle_policy_update(file, buf, len, GID);
  228. }
  229. static ssize_t safesetid_file_read(struct file *file, char __user *buf,
  230. size_t len, loff_t *ppos, struct mutex *policy_update_lock, struct __rcu setid_ruleset* ruleset)
  231. {
  232. ssize_t res = 0;
  233. struct setid_ruleset *pol;
  234. const char *kbuf;
  235. mutex_lock(policy_update_lock);
  236. pol = rcu_dereference_protected(ruleset, lockdep_is_held(policy_update_lock));
  237. if (pol) {
  238. kbuf = pol->policy_str;
  239. res = simple_read_from_buffer(buf, len, ppos,
  240. kbuf, strlen(kbuf));
  241. }
  242. mutex_unlock(policy_update_lock);
  243. return res;
  244. }
  245. static ssize_t safesetid_uid_file_read(struct file *file, char __user *buf,
  246. size_t len, loff_t *ppos)
  247. {
  248. return safesetid_file_read(file, buf, len, ppos,
  249. &uid_policy_update_lock, safesetid_setuid_rules);
  250. }
  251. static ssize_t safesetid_gid_file_read(struct file *file, char __user *buf,
  252. size_t len, loff_t *ppos)
  253. {
  254. return safesetid_file_read(file, buf, len, ppos,
  255. &gid_policy_update_lock, safesetid_setgid_rules);
  256. }
  257. static const struct file_operations safesetid_uid_file_fops = {
  258. .read = safesetid_uid_file_read,
  259. .write = safesetid_uid_file_write,
  260. };
  261. static const struct file_operations safesetid_gid_file_fops = {
  262. .read = safesetid_gid_file_read,
  263. .write = safesetid_gid_file_write,
  264. };
  265. static int __init safesetid_init_securityfs(void)
  266. {
  267. int ret;
  268. struct dentry *policy_dir;
  269. struct dentry *uid_policy_file;
  270. struct dentry *gid_policy_file;
  271. if (!safesetid_initialized)
  272. return 0;
  273. policy_dir = securityfs_create_dir("safesetid", NULL);
  274. if (IS_ERR(policy_dir)) {
  275. ret = PTR_ERR(policy_dir);
  276. goto error;
  277. }
  278. uid_policy_file = securityfs_create_file("uid_allowlist_policy", 0600,
  279. policy_dir, NULL, &safesetid_uid_file_fops);
  280. if (IS_ERR(uid_policy_file)) {
  281. ret = PTR_ERR(uid_policy_file);
  282. goto error;
  283. }
  284. gid_policy_file = securityfs_create_file("gid_allowlist_policy", 0600,
  285. policy_dir, NULL, &safesetid_gid_file_fops);
  286. if (IS_ERR(gid_policy_file)) {
  287. ret = PTR_ERR(gid_policy_file);
  288. goto error;
  289. }
  290. return 0;
  291. error:
  292. securityfs_remove(policy_dir);
  293. return ret;
  294. }
  295. fs_initcall(safesetid_init_securityfs);