device_cgroup.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. /*
  2. * device_cgroup.c - device cgroup subsystem
  3. *
  4. * Copyright 2007 IBM Corp
  5. */
  6. #include <linux/device_cgroup.h>
  7. #include <linux/cgroup.h>
  8. #include <linux/ctype.h>
  9. #include <linux/list.h>
  10. #include <linux/uaccess.h>
  11. #include <linux/seq_file.h>
  12. #include <linux/slab.h>
  13. #include <linux/rcupdate.h>
  14. #include <linux/mutex.h>
  15. #define ACC_MKNOD 1
  16. #define ACC_READ 2
  17. #define ACC_WRITE 4
  18. #define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE)
  19. #define DEV_BLOCK 1
  20. #define DEV_CHAR 2
  21. #define DEV_ALL 4 /* this represents all devices */
  22. static DEFINE_MUTEX(devcgroup_mutex);
  23. enum devcg_behavior {
  24. DEVCG_DEFAULT_NONE,
  25. DEVCG_DEFAULT_ALLOW,
  26. DEVCG_DEFAULT_DENY,
  27. };
  28. /*
  29. * exception list locking rules:
  30. * hold devcgroup_mutex for update/read.
  31. * hold rcu_read_lock() for read.
  32. */
  33. struct dev_exception_item {
  34. u32 major, minor;
  35. short type;
  36. short access;
  37. struct list_head list;
  38. struct rcu_head rcu;
  39. };
  40. struct dev_cgroup {
  41. struct cgroup_subsys_state css;
  42. struct list_head exceptions;
  43. enum devcg_behavior behavior;
  44. };
  45. static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
  46. {
  47. return s ? container_of(s, struct dev_cgroup, css) : NULL;
  48. }
  49. static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
  50. {
  51. return css_to_devcgroup(task_css(task, devices_subsys_id));
  52. }
  53. struct cgroup_subsys devices_subsys;
  54. static int devcgroup_can_attach(struct cgroup_subsys_state *new_css,
  55. struct cgroup_taskset *set)
  56. {
  57. struct task_struct *task = cgroup_taskset_first(set);
  58. if (current != task && !capable(CAP_SYS_ADMIN))
  59. return -EPERM;
  60. return 0;
  61. }
  62. /*
  63. * called under devcgroup_mutex
  64. */
  65. static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
  66. {
  67. struct dev_exception_item *ex, *tmp, *new;
  68. lockdep_assert_held(&devcgroup_mutex);
  69. list_for_each_entry(ex, orig, list) {
  70. new = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
  71. if (!new)
  72. goto free_and_exit;
  73. list_add_tail(&new->list, dest);
  74. }
  75. return 0;
  76. free_and_exit:
  77. list_for_each_entry_safe(ex, tmp, dest, list) {
  78. list_del(&ex->list);
  79. kfree(ex);
  80. }
  81. return -ENOMEM;
  82. }
  83. /*
  84. * called under devcgroup_mutex
  85. */
  86. static int dev_exception_add(struct dev_cgroup *dev_cgroup,
  87. struct dev_exception_item *ex)
  88. {
  89. struct dev_exception_item *excopy, *walk;
  90. lockdep_assert_held(&devcgroup_mutex);
  91. excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
  92. if (!excopy)
  93. return -ENOMEM;
  94. list_for_each_entry(walk, &dev_cgroup->exceptions, list) {
  95. if (walk->type != ex->type)
  96. continue;
  97. if (walk->major != ex->major)
  98. continue;
  99. if (walk->minor != ex->minor)
  100. continue;
  101. walk->access |= ex->access;
  102. kfree(excopy);
  103. excopy = NULL;
  104. }
  105. if (excopy != NULL)
  106. list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions);
  107. return 0;
  108. }
  109. /*
  110. * called under devcgroup_mutex
  111. */
  112. static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
  113. struct dev_exception_item *ex)
  114. {
  115. struct dev_exception_item *walk, *tmp;
  116. lockdep_assert_held(&devcgroup_mutex);
  117. list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) {
  118. if (walk->type != ex->type)
  119. continue;
  120. if (walk->major != ex->major)
  121. continue;
  122. if (walk->minor != ex->minor)
  123. continue;
  124. walk->access &= ~ex->access;
  125. if (!walk->access) {
  126. list_del_rcu(&walk->list);
  127. kfree_rcu(walk, rcu);
  128. }
  129. }
  130. }
  131. static void __dev_exception_clean(struct dev_cgroup *dev_cgroup)
  132. {
  133. struct dev_exception_item *ex, *tmp;
  134. list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
  135. list_del_rcu(&ex->list);
  136. kfree_rcu(ex, rcu);
  137. }
  138. }
  139. /**
  140. * dev_exception_clean - frees all entries of the exception list
  141. * @dev_cgroup: dev_cgroup with the exception list to be cleaned
  142. *
  143. * called under devcgroup_mutex
  144. */
  145. static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
  146. {
  147. lockdep_assert_held(&devcgroup_mutex);
  148. __dev_exception_clean(dev_cgroup);
  149. }
  150. static inline bool is_devcg_online(const struct dev_cgroup *devcg)
  151. {
  152. return (devcg->behavior != DEVCG_DEFAULT_NONE);
  153. }
  154. /**
  155. * devcgroup_online - initializes devcgroup's behavior and exceptions based on
  156. * parent's
  157. * @css: css getting online
  158. * returns 0 in case of success, error code otherwise
  159. */
  160. static int devcgroup_online(struct cgroup_subsys_state *css)
  161. {
  162. struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
  163. struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css_parent(css));
  164. int ret = 0;
  165. mutex_lock(&devcgroup_mutex);
  166. if (parent_dev_cgroup == NULL)
  167. dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
  168. else {
  169. ret = dev_exceptions_copy(&dev_cgroup->exceptions,
  170. &parent_dev_cgroup->exceptions);
  171. if (!ret)
  172. dev_cgroup->behavior = parent_dev_cgroup->behavior;
  173. }
  174. mutex_unlock(&devcgroup_mutex);
  175. return ret;
  176. }
  177. static void devcgroup_offline(struct cgroup_subsys_state *css)
  178. {
  179. struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
  180. mutex_lock(&devcgroup_mutex);
  181. dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
  182. mutex_unlock(&devcgroup_mutex);
  183. }
  184. /*
  185. * called from kernel/cgroup.c with cgroup_lock() held.
  186. */
  187. static struct cgroup_subsys_state *
  188. devcgroup_css_alloc(struct cgroup_subsys_state *parent_css)
  189. {
  190. struct dev_cgroup *dev_cgroup;
  191. dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
  192. if (!dev_cgroup)
  193. return ERR_PTR(-ENOMEM);
  194. INIT_LIST_HEAD(&dev_cgroup->exceptions);
  195. dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
  196. return &dev_cgroup->css;
  197. }
  198. static void devcgroup_css_free(struct cgroup_subsys_state *css)
  199. {
  200. struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
  201. __dev_exception_clean(dev_cgroup);
  202. kfree(dev_cgroup);
  203. }
  204. #define DEVCG_ALLOW 1
  205. #define DEVCG_DENY 2
  206. #define DEVCG_LIST 3
  207. #define MAJMINLEN 13
  208. #define ACCLEN 4
  209. static void set_access(char *acc, short access)
  210. {
  211. int idx = 0;
  212. memset(acc, 0, ACCLEN);
  213. if (access & ACC_READ)
  214. acc[idx++] = 'r';
  215. if (access & ACC_WRITE)
  216. acc[idx++] = 'w';
  217. if (access & ACC_MKNOD)
  218. acc[idx++] = 'm';
  219. }
  220. static char type_to_char(short type)
  221. {
  222. if (type == DEV_ALL)
  223. return 'a';
  224. if (type == DEV_CHAR)
  225. return 'c';
  226. if (type == DEV_BLOCK)
  227. return 'b';
  228. return 'X';
  229. }
  230. static void set_majmin(char *str, unsigned m)
  231. {
  232. if (m == ~0)
  233. strcpy(str, "*");
  234. else
  235. sprintf(str, "%u", m);
  236. }
  237. static int devcgroup_seq_read(struct cgroup_subsys_state *css,
  238. struct cftype *cft, struct seq_file *m)
  239. {
  240. struct dev_cgroup *devcgroup = css_to_devcgroup(css);
  241. struct dev_exception_item *ex;
  242. char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
  243. rcu_read_lock();
  244. /*
  245. * To preserve the compatibility:
  246. * - Only show the "all devices" when the default policy is to allow
  247. * - List the exceptions in case the default policy is to deny
  248. * This way, the file remains as a "whitelist of devices"
  249. */
  250. if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
  251. set_access(acc, ACC_MASK);
  252. set_majmin(maj, ~0);
  253. set_majmin(min, ~0);
  254. seq_printf(m, "%c %s:%s %s\n", type_to_char(DEV_ALL),
  255. maj, min, acc);
  256. } else {
  257. list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
  258. set_access(acc, ex->access);
  259. set_majmin(maj, ex->major);
  260. set_majmin(min, ex->minor);
  261. seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
  262. maj, min, acc);
  263. }
  264. }
  265. rcu_read_unlock();
  266. return 0;
  267. }
  268. /**
  269. * may_access - verifies if a new exception is part of what is allowed
  270. * by a dev cgroup based on the default policy +
  271. * exceptions. This is used to make sure a child cgroup
  272. * won't have more privileges than its parent or to
  273. * verify if a certain access is allowed.
  274. * @dev_cgroup: dev cgroup to be tested against
  275. * @refex: new exception
  276. * @behavior: behavior of the exception
  277. */
  278. static bool may_access(struct dev_cgroup *dev_cgroup,
  279. struct dev_exception_item *refex,
  280. enum devcg_behavior behavior)
  281. {
  282. struct dev_exception_item *ex;
  283. bool match = false;
  284. rcu_lockdep_assert(rcu_read_lock_held() ||
  285. lockdep_is_held(&devcgroup_mutex),
  286. "device_cgroup::may_access() called without proper synchronization");
  287. list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) {
  288. if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
  289. continue;
  290. if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR))
  291. continue;
  292. if (ex->major != ~0 && ex->major != refex->major)
  293. continue;
  294. if (ex->minor != ~0 && ex->minor != refex->minor)
  295. continue;
  296. if (refex->access & (~ex->access))
  297. continue;
  298. match = true;
  299. break;
  300. }
  301. if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
  302. if (behavior == DEVCG_DEFAULT_ALLOW) {
  303. /* the exception will deny access to certain devices */
  304. return true;
  305. } else {
  306. /* the exception will allow access to certain devices */
  307. if (match)
  308. /*
  309. * a new exception allowing access shouldn't
  310. * match an parent's exception
  311. */
  312. return false;
  313. return true;
  314. }
  315. } else {
  316. /* only behavior == DEVCG_DEFAULT_DENY allowed here */
  317. if (match)
  318. /* parent has an exception that matches the proposed */
  319. return true;
  320. else
  321. return false;
  322. }
  323. return false;
  324. }
  325. /*
  326. * parent_has_perm:
  327. * when adding a new allow rule to a device exception list, the rule
  328. * must be allowed in the parent device
  329. */
  330. static int parent_has_perm(struct dev_cgroup *childcg,
  331. struct dev_exception_item *ex)
  332. {
  333. struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css));
  334. if (!parent)
  335. return 1;
  336. return may_access(parent, ex, childcg->behavior);
  337. }
  338. /**
  339. * may_allow_all - checks if it's possible to change the behavior to
  340. * allow based on parent's rules.
  341. * @parent: device cgroup's parent
  342. * returns: != 0 in case it's allowed, 0 otherwise
  343. */
  344. static inline int may_allow_all(struct dev_cgroup *parent)
  345. {
  346. if (!parent)
  347. return 1;
  348. return parent->behavior == DEVCG_DEFAULT_ALLOW;
  349. }
  350. /**
  351. * revalidate_active_exceptions - walks through the active exception list and
  352. * revalidates the exceptions based on parent's
  353. * behavior and exceptions. The exceptions that
  354. * are no longer valid will be removed.
  355. * Called with devcgroup_mutex held.
  356. * @devcg: cgroup which exceptions will be checked
  357. *
  358. * This is one of the three key functions for hierarchy implementation.
  359. * This function is responsible for re-evaluating all the cgroup's active
  360. * exceptions due to a parent's exception change.
  361. * Refer to Documentation/cgroups/devices.txt for more details.
  362. */
  363. static void revalidate_active_exceptions(struct dev_cgroup *devcg)
  364. {
  365. struct dev_exception_item *ex;
  366. struct list_head *this, *tmp;
  367. list_for_each_safe(this, tmp, &devcg->exceptions) {
  368. ex = container_of(this, struct dev_exception_item, list);
  369. if (!parent_has_perm(devcg, ex))
  370. dev_exception_rm(devcg, ex);
  371. }
  372. }
  373. /**
  374. * propagate_exception - propagates a new exception to the children
  375. * @devcg_root: device cgroup that added a new exception
  376. * @ex: new exception to be propagated
  377. *
  378. * returns: 0 in case of success, != 0 in case of error
  379. */
  380. static int propagate_exception(struct dev_cgroup *devcg_root,
  381. struct dev_exception_item *ex)
  382. {
  383. struct cgroup_subsys_state *pos;
  384. int rc = 0;
  385. rcu_read_lock();
  386. css_for_each_descendant_pre(pos, &devcg_root->css) {
  387. struct dev_cgroup *devcg = css_to_devcgroup(pos);
  388. /*
  389. * Because devcgroup_mutex is held, no devcg will become
  390. * online or offline during the tree walk (see on/offline
  391. * methods), and online ones are safe to access outside RCU
  392. * read lock without bumping refcnt.
  393. */
  394. if (pos == &devcg_root->css || !is_devcg_online(devcg))
  395. continue;
  396. rcu_read_unlock();
  397. /*
  398. * in case both root's behavior and devcg is allow, a new
  399. * restriction means adding to the exception list
  400. */
  401. if (devcg_root->behavior == DEVCG_DEFAULT_ALLOW &&
  402. devcg->behavior == DEVCG_DEFAULT_ALLOW) {
  403. rc = dev_exception_add(devcg, ex);
  404. if (rc)
  405. break;
  406. } else {
  407. /*
  408. * in the other possible cases:
  409. * root's behavior: allow, devcg's: deny
  410. * root's behavior: deny, devcg's: deny
  411. * the exception will be removed
  412. */
  413. dev_exception_rm(devcg, ex);
  414. }
  415. revalidate_active_exceptions(devcg);
  416. rcu_read_lock();
  417. }
  418. rcu_read_unlock();
  419. return rc;
  420. }
  421. static inline bool has_children(struct dev_cgroup *devcgroup)
  422. {
  423. struct cgroup *cgrp = devcgroup->css.cgroup;
  424. return !list_empty(&cgrp->children);
  425. }
  426. /*
  427. * Modify the exception list using allow/deny rules.
  428. * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD
  429. * so we can give a container CAP_MKNOD to let it create devices but not
  430. * modify the exception list.
  431. * It seems likely we'll want to add a CAP_CONTAINER capability to allow
  432. * us to also grant CAP_SYS_ADMIN to containers without giving away the
  433. * device exception list controls, but for now we'll stick with CAP_SYS_ADMIN
  434. *
  435. * Taking rules away is always allowed (given CAP_SYS_ADMIN). Granting
  436. * new access is only allowed if you're in the top-level cgroup, or your
  437. * parent cgroup has the access you're asking for.
  438. */
  439. static int devcgroup_update_access(struct dev_cgroup *devcgroup,
  440. int filetype, const char *buffer)
  441. {
  442. const char *b;
  443. char temp[12]; /* 11 + 1 characters needed for a u32 */
  444. int count, rc = 0;
  445. struct dev_exception_item ex;
  446. struct dev_cgroup *parent = css_to_devcgroup(css_parent(&devcgroup->css));
  447. if (!capable(CAP_SYS_ADMIN))
  448. return -EPERM;
  449. memset(&ex, 0, sizeof(ex));
  450. b = buffer;
  451. switch (*b) {
  452. case 'a':
  453. switch (filetype) {
  454. case DEVCG_ALLOW:
  455. if (has_children(devcgroup))
  456. return -EINVAL;
  457. if (!may_allow_all(parent))
  458. return -EPERM;
  459. dev_exception_clean(devcgroup);
  460. devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
  461. if (!parent)
  462. break;
  463. rc = dev_exceptions_copy(&devcgroup->exceptions,
  464. &parent->exceptions);
  465. if (rc)
  466. return rc;
  467. break;
  468. case DEVCG_DENY:
  469. if (has_children(devcgroup))
  470. return -EINVAL;
  471. dev_exception_clean(devcgroup);
  472. devcgroup->behavior = DEVCG_DEFAULT_DENY;
  473. break;
  474. default:
  475. return -EINVAL;
  476. }
  477. return 0;
  478. case 'b':
  479. ex.type = DEV_BLOCK;
  480. break;
  481. case 'c':
  482. ex.type = DEV_CHAR;
  483. break;
  484. default:
  485. return -EINVAL;
  486. }
  487. b++;
  488. if (!isspace(*b))
  489. return -EINVAL;
  490. b++;
  491. if (*b == '*') {
  492. ex.major = ~0;
  493. b++;
  494. } else if (isdigit(*b)) {
  495. memset(temp, 0, sizeof(temp));
  496. for (count = 0; count < sizeof(temp) - 1; count++) {
  497. temp[count] = *b;
  498. b++;
  499. if (!isdigit(*b))
  500. break;
  501. }
  502. rc = kstrtou32(temp, 10, &ex.major);
  503. if (rc)
  504. return -EINVAL;
  505. } else {
  506. return -EINVAL;
  507. }
  508. if (*b != ':')
  509. return -EINVAL;
  510. b++;
  511. /* read minor */
  512. if (*b == '*') {
  513. ex.minor = ~0;
  514. b++;
  515. } else if (isdigit(*b)) {
  516. memset(temp, 0, sizeof(temp));
  517. for (count = 0; count < sizeof(temp) - 1; count++) {
  518. temp[count] = *b;
  519. b++;
  520. if (!isdigit(*b))
  521. break;
  522. }
  523. rc = kstrtou32(temp, 10, &ex.minor);
  524. if (rc)
  525. return -EINVAL;
  526. } else {
  527. return -EINVAL;
  528. }
  529. if (!isspace(*b))
  530. return -EINVAL;
  531. for (b++, count = 0; count < 3; count++, b++) {
  532. switch (*b) {
  533. case 'r':
  534. ex.access |= ACC_READ;
  535. break;
  536. case 'w':
  537. ex.access |= ACC_WRITE;
  538. break;
  539. case 'm':
  540. ex.access |= ACC_MKNOD;
  541. break;
  542. case '\n':
  543. case '\0':
  544. count = 3;
  545. break;
  546. default:
  547. return -EINVAL;
  548. }
  549. }
  550. switch (filetype) {
  551. case DEVCG_ALLOW:
  552. if (!parent_has_perm(devcgroup, &ex))
  553. return -EPERM;
  554. /*
  555. * If the default policy is to allow by default, try to remove
  556. * an matching exception instead. And be silent about it: we
  557. * don't want to break compatibility
  558. */
  559. if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
  560. dev_exception_rm(devcgroup, &ex);
  561. return 0;
  562. }
  563. rc = dev_exception_add(devcgroup, &ex);
  564. break;
  565. case DEVCG_DENY:
  566. /*
  567. * If the default policy is to deny by default, try to remove
  568. * an matching exception instead. And be silent about it: we
  569. * don't want to break compatibility
  570. */
  571. if (devcgroup->behavior == DEVCG_DEFAULT_DENY)
  572. dev_exception_rm(devcgroup, &ex);
  573. else
  574. rc = dev_exception_add(devcgroup, &ex);
  575. if (rc)
  576. break;
  577. /* we only propagate new restrictions */
  578. rc = propagate_exception(devcgroup, &ex);
  579. break;
  580. default:
  581. rc = -EINVAL;
  582. }
  583. return rc;
  584. }
  585. static int devcgroup_access_write(struct cgroup_subsys_state *css,
  586. struct cftype *cft, const char *buffer)
  587. {
  588. int retval;
  589. mutex_lock(&devcgroup_mutex);
  590. retval = devcgroup_update_access(css_to_devcgroup(css),
  591. cft->private, buffer);
  592. mutex_unlock(&devcgroup_mutex);
  593. return retval;
  594. }
  595. static struct cftype dev_cgroup_files[] = {
  596. {
  597. .name = "allow",
  598. .write_string = devcgroup_access_write,
  599. .private = DEVCG_ALLOW,
  600. },
  601. {
  602. .name = "deny",
  603. .write_string = devcgroup_access_write,
  604. .private = DEVCG_DENY,
  605. },
  606. {
  607. .name = "list",
  608. .read_seq_string = devcgroup_seq_read,
  609. .private = DEVCG_LIST,
  610. },
  611. { } /* terminate */
  612. };
  613. struct cgroup_subsys devices_subsys = {
  614. .name = "devices",
  615. .can_attach = devcgroup_can_attach,
  616. .css_alloc = devcgroup_css_alloc,
  617. .css_free = devcgroup_css_free,
  618. .css_online = devcgroup_online,
  619. .css_offline = devcgroup_offline,
  620. .subsys_id = devices_subsys_id,
  621. .base_cftypes = dev_cgroup_files,
  622. };
  623. /**
  624. * __devcgroup_check_permission - checks if an inode operation is permitted
  625. * @dev_cgroup: the dev cgroup to be tested against
  626. * @type: device type
  627. * @major: device major number
  628. * @minor: device minor number
  629. * @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD
  630. *
  631. * returns 0 on success, -EPERM case the operation is not permitted
  632. */
  633. static int __devcgroup_check_permission(short type, u32 major, u32 minor,
  634. short access)
  635. {
  636. struct dev_cgroup *dev_cgroup;
  637. struct dev_exception_item ex;
  638. int rc;
  639. memset(&ex, 0, sizeof(ex));
  640. ex.type = type;
  641. ex.major = major;
  642. ex.minor = minor;
  643. ex.access = access;
  644. rcu_read_lock();
  645. dev_cgroup = task_devcgroup(current);
  646. rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior);
  647. rcu_read_unlock();
  648. if (!rc)
  649. return -EPERM;
  650. return 0;
  651. }
  652. int __devcgroup_inode_permission(struct inode *inode, int mask)
  653. {
  654. short type, access = 0;
  655. if (S_ISBLK(inode->i_mode))
  656. type = DEV_BLOCK;
  657. if (S_ISCHR(inode->i_mode))
  658. type = DEV_CHAR;
  659. if (mask & MAY_WRITE)
  660. access |= ACC_WRITE;
  661. if (mask & MAY_READ)
  662. access |= ACC_READ;
  663. return __devcgroup_check_permission(type, imajor(inode), iminor(inode),
  664. access);
  665. }
  666. int devcgroup_inode_mknod(int mode, dev_t dev)
  667. {
  668. short type;
  669. if (!S_ISBLK(mode) && !S_ISCHR(mode))
  670. return 0;
  671. if (S_ISBLK(mode))
  672. type = DEV_BLOCK;
  673. else
  674. type = DEV_CHAR;
  675. return __devcgroup_check_permission(type, MAJOR(dev), MINOR(dev),
  676. ACC_MKNOD);
  677. }