device_cgroup: check if exception removal is allowed
Subsystems (2)
PATCH 1/1 device_cgroup: check if exception removal is allowed
In a scenario when the child cgroup is trying to remove an exception which will effectively add more access rights, verify if the parent's rules allow it.
--- security/device_cgroup.c | 36 +++++++++++++++++++++++++++++++++--- 1 files changed, 33 insertions(+), 3 deletions(-)
security/device_cgroup.c +33 -3
@@ -463,6 +463,32 @@ static int parent_has_perm(struct dev_cgroup *childcg,return verify_new_ex (parent, ex, childcg->behavior); } +/* +* parent_allows_removal - check if the parent cgroup allows an exception to +* be removed +* @childcg: child cgroup from where the exception will be removed +* @ex: exception being removed +*/ +static bool parent_allows_removal (struct dev_cgroup *childcg, +struct dev_exception_item *ex) +{ +struct dev_cgroup *parent =css_to_devcgroup (css_parent (&childcg->css)); + +if (!parent) +return true; + +if (childcg->behavior ==DEVCG_DEFAULT_DENY ) +/* It's always allowed to remove access to devices */ +return true; + +/* +* Make sure you're not removing part or a whole exception existing in +* the parent cgroup +*/ +return !match_exception_partial (&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); +} +/** * may_allow_all - checks if it's possible to change the behavior to * allow based on parent's rules.
@@ -698,17 +724,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,switch (filetype) {case DEVCG_ALLOW : -if (!parent_has_perm (devcgroup, &ex)) -return -EPERM ;/* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { +/* Check if the parent allows removing it first */ +if (!parent_allows_removal (devcgroup, &ex)) +return -EPERM ;dev_exception_rm (devcgroup, &ex); -return 0 ; +break ; } + +if (!parent_has_perm (devcgroup, &ex)) +return -EPERM ; rc =dev_exception_add (devcgroup, &ex);break ;case DEVCG_DENY :
Signature · 1 line
1.7.1
Quoted 9 lines · Aristeu Rozanski
In a scenario when the child cgroup is trying to remove an exception which will effectively add more access rights, verify if the parent's rules allow it.
Cc Tejun Heo <[email protected]>Cc Serge Hallyn <[email protected]>Cc Li Zefan <[email protected]>Signed-off-by Aristeu Rozanski <[email protected]>
Thanks, this looks good. (Though I'm going based on the comment of match_exception_partial() in the comment cleanup patch, as the tree I'm looking at doesn't yet have that fn; still, looks good)
Quoted 69 lines
--- security/device_cgroup.c | 36 +++++++++++++++++++++++++++++++++--- 1 files changed, 33 insertions(+), 3 deletions(-)security/device_cgroup.c +33
-3@@ -463,6 +463,32 @@ static int parent_has_perm(struct dev_cgroup *childcg,return verify_new_ex (parent, ex, childcg->behavior); } +/* +* parent_allows_removal - check if the parent cgroup allows an exception to +* be removed +* @childcg: child cgroup from where the exception will be removed +* @ex: exception being removed +*/ +static bool parent_allows_removal (struct dev_cgroup *childcg, +struct dev_exception_item *ex) +{ +struct dev_cgroup *parent =css_to_devcgroup (css_parent (&childcg->css)); + +if (!parent) +return true; + +if (childcg->behavior ==DEVCG_DEFAULT_DENY ) +/* It's always allowed to remove access to devices */ +return true; + +/* +* Make sure you're not removing part or a whole exception existing in +* the parent cgroup +*/ +return !match_exception_partial (&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); +} +/** * may_allow_all - checks if it's possible to change the behavior to * allow based on parent's rules. @@ -698,17 +724,21 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,switch (filetype) {case DEVCG_ALLOW : -if (!parent_has_perm (devcgroup, &ex)) -return -EPERM ;/* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { +/* Check if the parent allows removing it first */ +if (!parent_allows_removal (devcgroup, &ex)) +return -EPERM ;dev_exception_rm (devcgroup, &ex); -return 0 ; +break ; } + +if (!parent_has_perm (devcgroup, &ex)) +return -EPERM ; rc =dev_exception_add (devcgroup, &ex);break ;case DEVCG_DENY :Signature · 1 line
1.7.1
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 3 lines · Aristeu Rozanski
In a scenario when the child cgroup is trying to remove an exception which will effectively add more access rights, verify if the parent's rules allow it.
Can you please elaborate a bit more on how the bug was introduced and what its implications are? People can't really decipher what the patch means from the above text.
Quoted 1 line
+/*
/**
Quoted 2 lines
+ *
parent_allows_removal- check if the parent cgroup allows an exception to
+ * be removed
Why is devcg using a different comment form from everything else?
/**
* FUNC_NAME - one line description
* @params: description
*
* Long description
*/
security/device_cgroup.c static int parent_has_perm(struct dev_cgroup *childcg, · line 481
Quoted 13 lines
+ * @childcg: child cgroup from where the exception will be removed
+ * @ex: exception being removed
+ */security/device_cgroup.c +10
-0+static bool parent_allows_removal (struct dev_cgroup *childcg, +struct dev_exception_item *ex) +{ +struct dev_cgroup *parent =css_to_devcgroup (css_parent (&childcg->css)); + +if (!parent) +return true; + +if (childcg->behavior ==DEVCG_DEFAULT_DENY ) +/* It's always allowed to remove access to devices */
If you don't wanna add {}, move the comment above if.
security/device_cgroup.c static int parent_has_perm(struct dev_cgroup *childcg, · line 490
Quoted 9 lines
security/device_cgroup.c +9
-0+return true; + +/* +* Make sure you're not removing part or a whole exception existing in +* the parent cgroup +*/ +return !match_exception_partial (&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); +}
Thanks.
Signature · 1 line
tejun
A message that is not in the archive (sent off-list or not yet received): 20140502152930.GF10204-Gd/HAXX7CRxy/[email protected]
PATCH v2 1/1 device_cgroup: check if exception removal is allowed
When the device cgroup hierarchy was introduced in
bd2953ebbb53 - devcg: propagate local changes down the hierarchy
a specific case was overlooked. Consider the hierarchy bellow:
A default policy: ALLOW, exceptions will deny access
\
B default policy: ALLOW, exceptions will deny access
There's no need to verify when an new exception is added to B because in this case exceptions will deny access to further devices, which is always fine. Hierarchy in device cgroup only makes sure B won't have more access than A.
But when an exception is removed (by writing devices.allow), it isn't checked if the user is in fact removing an inherited exception from A, thus giving more access to B.
Example:
# echo 'a' >A/devices.allow # echo 'c 1:3 rw' >A/devices.deny # echo $$ >A/B/tasks # echo >/dev/null -bash: /dev/null: Operation not permitted # echo 'c 1:3 w' >A/B/devices.allow # echo >/dev/null #
This shouldn't be allowed and this patch fixes it by making sure to never allow exceptions in this case to be removed if the exception is partially or fully present on the parent.
v2: improved log message and formatting fixes
--- security/device_cgroup.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
security/device_cgroup.c +38 -3
@@ -463,6 +463,37 @@ static int parent_has_perm(struct dev_cgreturn verify_new_ex (parent, ex, childcg->behavior); } +/* +* parent_allows_removal - verify if it's ok to remove an exception +* @childcg: child cgroup from where the exception will be removed +* @ex: exception being removed +* +* When removing an exception in cgroups with default ALLOW policy, it must +* be checked if removing it will give the child cgroup more access than the +* parent. +* +* Return: true if it's ok to remove exception, false otherwise +*/ +static bool parent_allows_removal (struct dev_cgroup *childcg, +struct dev_exception_item *ex) +{ +struct dev_cgroup *parent =css_to_devcgroup (css_parent (&childcg->css)); + +if (!parent) +return true; + +/* It's always allowed to remove access to devices */ +if (childcg->behavior ==DEVCG_DEFAULT_DENY ) +return true; + +/* +* Make sure you're not removing part or a whole exception existing in +* the parent cgroup +*/ +return !match_exception_partial (&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); +} +/** * may_allow_all - checks if it's possible to change the behavior to * allow based on parent's rules.
@@ -698,17 +729,21 @@ case '\0':switch (filetype) {case DEVCG_ALLOW : -if (!parent_has_perm (devcgroup, &ex)) -return -EPERM ;/* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { +/* Check if the parent allows removing it first */ +if (!parent_allows_removal (devcgroup, &ex)) +return -EPERM ;dev_exception_rm (devcgroup, &ex); -return 0 ; +break ; } + +if (!parent_has_perm (devcgroup, &ex)) +return -EPERM ; rc =dev_exception_add (devcgroup, &ex);break ;case DEVCG_DENY :
Tejun Heo
maintainerQuoted 1 line · Aristeu Rozanski
+/*
/**
Quoted 2 lines
+ *
parent_allows_removal- verify if it's ok to remove an exception
+ * @childcg: child cgroup from where the exception will be removed
I'll wait for v3.
Thanks.
Signature · 1 line
tejun
PATCH v3 1/1 device_cgroup: check if exception removal is allowed
[PATCH v3 1/2] device_cgroup: check if exception removal is allowed
When the device cgroup hierarchy was introduced in
bd2953ebbb53 - devcg: propagate local changes down the hierarchy
a specific case was overlooked. Consider the hierarchy bellow:
A default policy: ALLOW, exceptions will deny access
\
B default policy: ALLOW, exceptions will deny access
There's no need to verify when an new exception is added to B because in this case exceptions will deny access to further devices, which is always fine. Hierarchy in device cgroup only makes sure B won't have more access than A.
But when an exception is removed (by writing devices.allow), it isn't checked if the user is in fact removing an inherited exception from A, thus giving more access to B.
Example:
# echo 'a' >A/devices.allow # echo 'c 1:3 rw' >A/devices.deny # echo $$ >A/B/tasks # echo >/dev/null -bash: /dev/null: Operation not permitted # echo 'c 1:3 w' >A/B/devices.allow # echo >/dev/null #
This shouldn't be allowed and this patch fixes it by making sure to never allow exceptions in this case to be removed if the exception is partially or fully present on the parent.
v3: missing '*' in function description
v2: improved log message and formatting fixes
--- security/device_cgroup.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
security/device_cgroup.c +38 -3
@@ -464,6 +464,37 @@ static int parent_has_perm(struct dev_cg }/** +* parent_allows_removal - verify if it's ok to remove an exception +* @childcg: child cgroup from where the exception will be removed +* @ex: exception being removed +* +* When removing an exception in cgroups with default ALLOW policy, it must +* be checked if removing it will give the child cgroup more access than the +* parent. +* +* Return: true if it's ok to remove exception, false otherwise +*/ +static bool parent_allows_removal (struct dev_cgroup *childcg, +struct dev_exception_item *ex) +{ +struct dev_cgroup *parent =css_to_devcgroup (css_parent (&childcg->css)); + +if (!parent) +return true; + +/* It's always allowed to remove access to devices */ +if (childcg->behavior ==DEVCG_DEFAULT_DENY ) +return true; + +/* +* Make sure you're not removing part or a whole exception existing in +* the parent cgroup +*/ +return !match_exception_partial (&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); +} + +/** * may_allow_all - checks if it's possible to change the behavior to * allow based on parent's rules. * @parent: device cgroup's parent
@@ -698,17 +729,21 @@ case '\0':switch (filetype) {case DEVCG_ALLOW : -if (!parent_has_perm (devcgroup, &ex)) -return -EPERM ;/* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { +/* Check if the parent allows removing it first */ +if (!parent_allows_removal (devcgroup, &ex)) +return -EPERM ;dev_exception_rm (devcgroup, &ex); -return 0 ; +break ; } + +if (!parent_has_perm (devcgroup, &ex)) +return -EPERM ; rc =dev_exception_add (devcgroup, &ex);break ;case DEVCG_DENY :
A message that is not in the archive (sent off-list or not yet received): [email protected]
Tejun Heo
AppliedQuoted 38 lines · Aristeu Rozanski
[PATCH v3 1/2]
device_cgroup: check if exception removal is allowedWhen the device cgroup hierarchy was introduced in
bd2953ebbb53- devcg: propagate local changes down the hierarchya specific case was overlooked. Consider the hierarchy bellow:
A default policy: ALLOW, exceptions will deny access
\
B default policy: ALLOW, exceptions will deny accessThere's no need to verify when an new exception is added to B because in this case exceptions will deny access to further devices, which is always fine. Hierarchy in device cgroup only makes sure B won't have more access than A.
But when an exception is removed (by writing devices.allow), it isn't checked if the user is in fact removing an inherited exception from A, thus giving more access to B.
Example:
# echo 'a' >A/devices.allow # echo 'c 1:3 rw' >A/devices.deny # echo $$ >A/B/tasks # echo >/dev/null -bash: /dev/null: Operation not permitted # echo 'c 1:3 w' >A/B/devices.allow # echo >/dev/null #This shouldn't be allowed and this patch fixes it by making sure to never allow exceptions in this case to be removed if the exception is partially or fully present on the parent.
v3: missing '*' in function description
v2: improved log message and formatting fixes
Quoted 6 lines
Cc Tejun Heo <[email protected]>Cc Serge Hallyn <[email protected]>Cc Li Zefan <[email protected]>Signed-off-by Aristeu Rozanski <[email protected]>
Applied to cgroup/for-3.15-fixes.
Thanks.
Signature · 1 line
tejun
Quoted 35 lines · Aristeu Rozanski
[PATCH v3 1/2]
device_cgroup: check if exception removal is allowedWhen the device cgroup hierarchy was introduced in
bd2953ebbb53- devcg: propagate local changes down the hierarchya specific case was overlooked. Consider the hierarchy bellow:
A default policy: ALLOW, exceptions will deny access
\
B default policy: ALLOW, exceptions will deny accessThere's no need to verify when an new exception is added to B because in this case exceptions will deny access to further devices, which is always fine. Hierarchy in device cgroup only makes sure B won't have more access than A.
But when an exception is removed (by writing devices.allow), it isn't checked if the user is in fact removing an inherited exception from A, thus giving more access to B.
Example:
# echo 'a' >A/devices.allow # echo 'c 1:3 rw' >A/devices.deny # echo $$ >A/B/tasks # echo >/dev/null -bash: /dev/null: Operation not permitted # echo 'c 1:3 w' >A/B/devices.allow # echo >/dev/null #This shouldn't be allowed and this patch fixes it by making sure to never allow exceptions in this case to be removed if the exception is partially or fully present on the parent.
Quoted 6 lines
v3: missing '*' in function description
v2: improved log message and formatting fixes
(stared at this for quite some time, looks good, thanks :)
Quoted 72 lines
Cc Li Zefan <[email protected]>Signed-off-by Aristeu Rozanski <[email protected]>--- security/device_cgroup.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)security/device_cgroup.c +38
-3@@ -464,6 +464,37 @@ static int parent_has_perm(struct dev_cg }/** +* parent_allows_removal - verify if it's ok to remove an exception +* @childcg: child cgroup from where the exception will be removed +* @ex: exception being removed +* +* When removing an exception in cgroups with default ALLOW policy, it must +* be checked if removing it will give the child cgroup more access than the +* parent. +* +* Return: true if it's ok to remove exception, false otherwise +*/ +static bool parent_allows_removal (struct dev_cgroup *childcg, +struct dev_exception_item *ex) +{ +struct dev_cgroup *parent =css_to_devcgroup (css_parent (&childcg->css)); + +if (!parent) +return true; + +/* It's always allowed to remove access to devices */ +if (childcg->behavior ==DEVCG_DEFAULT_DENY ) +return true; + +/* +* Make sure you're not removing part or a whole exception existing in +* the parent cgroup +*/ +return !match_exception_partial (&parent->exceptions, ex->type, + ex->major, ex->minor, ex->access); +} + +/** * may_allow_all - checks if it's possible to change the behavior to * allow based on parent's rules. * @parent: device cgroup's parent @@ -698,17 +729,21 @@ case '\0':switch (filetype) {case DEVCG_ALLOW : -if (!parent_has_perm (devcgroup, &ex)) -return -EPERM ;/* * If the default policy is to allow by default, try to remove * an matching exception instead. And be silent about it: we * don't want to break compatibility */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { +/* Check if the parent allows removing it first */ +if (!parent_allows_removal (devcgroup, &ex)) +return -EPERM ;dev_exception_rm (devcgroup, &ex); -return 0 ; +break ; } + +if (!parent_has_perm (devcgroup, &ex)) +return -EPERM ; rc =dev_exception_add (devcgroup, &ex);break ;case DEVCG_DENY :