diff options
Diffstat (limited to 'security/device_cgroup.c')
-rw-r--r-- | security/device_cgroup.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 842c254396db..b08d20c66c2e 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
@@ -164,8 +164,8 @@ static void dev_exception_clean(struct dev_cgroup *dev_cgroup) | |||
164 | struct dev_exception_item *ex, *tmp; | 164 | struct dev_exception_item *ex, *tmp; |
165 | 165 | ||
166 | list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { | 166 | list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { |
167 | list_del(&ex->list); | 167 | list_del_rcu(&ex->list); |
168 | kfree(ex); | 168 | kfree_rcu(ex, rcu); |
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
@@ -298,7 +298,7 @@ static int may_access(struct dev_cgroup *dev_cgroup, | |||
298 | struct dev_exception_item *ex; | 298 | struct dev_exception_item *ex; |
299 | bool match = false; | 299 | bool match = false; |
300 | 300 | ||
301 | list_for_each_entry(ex, &dev_cgroup->exceptions, list) { | 301 | list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) { |
302 | if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) | 302 | if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) |
303 | continue; | 303 | continue; |
304 | if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) | 304 | if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) |
@@ -352,6 +352,8 @@ static int parent_has_perm(struct dev_cgroup *childcg, | |||
352 | */ | 352 | */ |
353 | static inline int may_allow_all(struct dev_cgroup *parent) | 353 | static inline int may_allow_all(struct dev_cgroup *parent) |
354 | { | 354 | { |
355 | if (!parent) | ||
356 | return 1; | ||
355 | return parent->behavior == DEVCG_DEFAULT_ALLOW; | 357 | return parent->behavior == DEVCG_DEFAULT_ALLOW; |
356 | } | 358 | } |
357 | 359 | ||
@@ -376,11 +378,14 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
376 | int count, rc; | 378 | int count, rc; |
377 | struct dev_exception_item ex; | 379 | struct dev_exception_item ex; |
378 | struct cgroup *p = devcgroup->css.cgroup; | 380 | struct cgroup *p = devcgroup->css.cgroup; |
379 | struct dev_cgroup *parent = cgroup_to_devcgroup(p->parent); | 381 | struct dev_cgroup *parent = NULL; |
380 | 382 | ||
381 | if (!capable(CAP_SYS_ADMIN)) | 383 | if (!capable(CAP_SYS_ADMIN)) |
382 | return -EPERM; | 384 | return -EPERM; |
383 | 385 | ||
386 | if (p->parent) | ||
387 | parent = cgroup_to_devcgroup(p->parent); | ||
388 | |||
384 | memset(&ex, 0, sizeof(ex)); | 389 | memset(&ex, 0, sizeof(ex)); |
385 | b = buffer; | 390 | b = buffer; |
386 | 391 | ||
@@ -391,11 +396,14 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
391 | if (!may_allow_all(parent)) | 396 | if (!may_allow_all(parent)) |
392 | return -EPERM; | 397 | return -EPERM; |
393 | dev_exception_clean(devcgroup); | 398 | dev_exception_clean(devcgroup); |
399 | devcgroup->behavior = DEVCG_DEFAULT_ALLOW; | ||
400 | if (!parent) | ||
401 | break; | ||
402 | |||
394 | rc = dev_exceptions_copy(&devcgroup->exceptions, | 403 | rc = dev_exceptions_copy(&devcgroup->exceptions, |
395 | &parent->exceptions); | 404 | &parent->exceptions); |
396 | if (rc) | 405 | if (rc) |
397 | return rc; | 406 | return rc; |
398 | devcgroup->behavior = DEVCG_DEFAULT_ALLOW; | ||
399 | break; | 407 | break; |
400 | case DEVCG_DENY: | 408 | case DEVCG_DENY: |
401 | dev_exception_clean(devcgroup); | 409 | dev_exception_clean(devcgroup); |