--- /dev/null
+From d2c2b11cfa134f4fbdcc34088824da26a084d8de Mon Sep 17 00:00:00 2001
+From: Aristeu Rozanski <aris@redhat.com>
+Date: Mon, 5 May 2014 11:18:59 -0400
+Subject: device_cgroup: check if exception removal is allowed
+
+From: Aristeu Rozanski <aris@redhat.com>
+
+commit d2c2b11cfa134f4fbdcc34088824da26a084d8de upstream.
+
+[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
+
+Cc: cgroups@vger.kernel.org
+Cc: Li Zefan <lizefan@huawei.com>
+Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
+Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/device_cgroup.c | 41 ++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 38 insertions(+), 3 deletions(-)
+
+--- a/security/device_cgroup.c
++++ b/security/device_cgroup.c
+@@ -466,6 +466,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
+@@ -700,17 +731,21 @@ static int devcgroup_update_access(struc
+
+ 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:
--- /dev/null
+From 79d719749d23234e9b725098aa49133f3ef7299d Mon Sep 17 00:00:00 2001
+From: Aristeu Rozanski <aris@redhat.com>
+Date: Mon, 21 Apr 2014 12:13:03 -0400
+Subject: device_cgroup: rework device access check and exception checking
+
+From: Aristeu Rozanski <aris@redhat.com>
+
+commit 79d719749d23234e9b725098aa49133f3ef7299d upstream.
+
+Whenever a device file is opened and checked against current device
+cgroup rules, it uses the same function (may_access()) as when a new
+exception rule is added by writing devices.{allow,deny}. And in both
+cases, the algorithm is the same, doesn't matter the behavior.
+
+First problem is having device access to be considered the same as rule
+checking. Consider the following structure:
+
+ A (default behavior: allow, exceptions disallow access)
+ \
+ B (default behavior: allow, exceptions disallow access)
+
+A new exception is added to B by writing devices.deny:
+
+ c 12:34 rw
+
+When checking if that exception is allowed in may_access():
+
+ if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
+ if (behavior == DEVCG_DEFAULT_ALLOW) {
+ /* the exception will deny access to certain devices */
+ return true;
+
+Which is ok, since B is not getting more privileges than A, it doesn't
+matter and the rule is accepted
+
+Now, consider it's a device file open check and the process belongs to
+cgroup B. The access will be generated as:
+
+ behavior: allow
+ exception: c 12:34 rw
+
+The very same chunk of code will allow it, even if there's an explicit
+exception telling to do otherwise.
+
+A simple test case:
+
+ # mkdir new_group
+ # cd new_group
+ # echo $$ >tasks
+ # echo "c 1:3 w" >devices.deny
+ # echo >/dev/null
+ # echo $?
+ 0
+
+This is a serious bug and was introduced on
+
+ c39a2a3018f8 devcg: prepare may_access() for hierarchy support
+
+To solve this problem, the device file open function was split from the
+new exception check.
+
+Second problem is how exceptions are processed by may_access(). The
+first part of the said function tries to match fully with an existing
+exception:
+
+ list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) {
+ if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
+ continue;
+ if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR))
+ continue;
+ if (ex->major != ~0 && ex->major != refex->major)
+ continue;
+ if (ex->minor != ~0 && ex->minor != refex->minor)
+ continue;
+ if (refex->access & (~ex->access))
+ continue;
+ match = true;
+ break;
+ }
+
+That means the new exception should be contained into an existing one to
+be considered a match:
+
+ New exception Existing match? notes
+ b 12:34 rwm b 12:34 rwm yes
+ b 12:34 r b *:34 rw yes
+ b 12:34 rw b 12:34 w no extra "r"
+ b *:34 rw b 12:34 rw no too broad "*"
+ b *:34 rw b *:34 rwm yes
+
+Which is fine in some cases. Consider:
+
+ A (default behavior: deny, exceptions allow access)
+ \
+ B (default behavior: deny, exceptions allow access)
+
+In this case the full match makes sense, the new exception cannot add
+more access than the parent allows
+
+But this doesn't always work, consider:
+
+ A (default behavior: allow, exceptions disallow access)
+ \
+ B (default behavior: deny, exceptions allow access)
+
+In this case, a new exception in B shouldn't match any of the exceptions
+in A, after all you can't allow something that was forbidden by A. But
+consider this scenario:
+
+ New exception Existing in A match? outcome
+ b 12:34 rw b 12:34 r no exception is accepted
+
+Because the new exception has "w" as extra, it doesn't match, so it'll
+be added to B's exception list.
+
+The same problem can happen during a file access check. Consider a
+cgroup with allow as default behavior:
+
+ Access Exception match?
+ b 12:34 rw b 12:34 r no
+
+In this case, the access didn't match any of the exceptions in the
+cgroup, which is required since exceptions will disallow access.
+
+To solve this problem, two new functions were created to match an
+exception either fully or partially. In the example above, a partial
+check will be performed and it'll produce a match since at least
+"b 12:34 r" from "b 12:34 rw" access matches.
+
+Cc: cgroups@vger.kernel.org
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Serge Hallyn <serge.hallyn@canonical.com>
+Cc: Li Zefan <lizefan@huawei.com>
+Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/device_cgroup.c | 162 +++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 122 insertions(+), 40 deletions(-)
+
+--- a/security/device_cgroup.c
++++ b/security/device_cgroup.c
+@@ -308,57 +308,139 @@ static int devcgroup_seq_show(struct seq
+ }
+
+ /**
+- * may_access - verifies if a new exception is part of what is allowed
+- * by a dev cgroup based on the default policy +
+- * exceptions. This is used to make sure a child cgroup
+- * won't have more privileges than its parent or to
+- * verify if a certain access is allowed.
+- * @dev_cgroup: dev cgroup to be tested against
+- * @refex: new exception
+- * @behavior: behavior of the exception
++ * match_exception - iterates the exception list trying to match a rule
++ * based on type, major, minor and access type. It is
++ * considered a match if an exception is found that
++ * will contain the entire range of provided parameters.
++ * @exceptions: list of exceptions
++ * @type: device type (DEV_BLOCK or DEV_CHAR)
++ * @major: device file major number, ~0 to match all
++ * @minor: device file minor number, ~0 to match all
++ * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD)
++ *
++ * returns: true in case it matches an exception completely
+ */
+-static bool may_access(struct dev_cgroup *dev_cgroup,
+- struct dev_exception_item *refex,
+- enum devcg_behavior behavior)
++static bool match_exception(struct list_head *exceptions, short type,
++ u32 major, u32 minor, short access)
+ {
+ struct dev_exception_item *ex;
+- bool match = false;
+
+- rcu_lockdep_assert(rcu_read_lock_held() ||
+- lockdep_is_held(&devcgroup_mutex),
+- "device_cgroup::may_access() called without proper synchronization");
++ list_for_each_entry_rcu(ex, exceptions, list) {
++ if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
++ continue;
++ if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR))
++ continue;
++ if (ex->major != ~0 && ex->major != major)
++ continue;
++ if (ex->minor != ~0 && ex->minor != minor)
++ continue;
++ /* provided access cannot have more than the exception rule */
++ if (access & (~ex->access))
++ continue;
++ return true;
++ }
++ return false;
++}
++
++/**
++ * match_exception_partial - iterates the exception list trying to match a rule
++ * based on type, major, minor and access type. It is
++ * considered a match if an exception's range is
++ * found to contain *any* of the devices specified by
++ * provided parameters. This is used to make sure no
++ * extra access is being granted that is forbidden by
++ * any of the exception list.
++ * @exceptions: list of exceptions
++ * @type: device type (DEV_BLOCK or DEV_CHAR)
++ * @major: device file major number, ~0 to match all
++ * @minor: device file minor number, ~0 to match all
++ * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD)
++ *
++ * returns: true in case the provided range mat matches an exception completely
++ */
++static bool match_exception_partial(struct list_head *exceptions, short type,
++ u32 major, u32 minor, short access)
++{
++ struct dev_exception_item *ex;
+
+- list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) {
+- if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
++ list_for_each_entry_rcu(ex, exceptions, list) {
++ if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
+ continue;
+- if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR))
++ if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR))
+ continue;
+- if (ex->major != ~0 && ex->major != refex->major)
++ /*
++ * We must be sure that both the exception and the provided
++ * range aren't masking all devices
++ */
++ if (ex->major != ~0 && major != ~0 && ex->major != major)
+ continue;
+- if (ex->minor != ~0 && ex->minor != refex->minor)
++ if (ex->minor != ~0 && minor != ~0 && ex->minor != minor)
+ continue;
+- if (refex->access & (~ex->access))
++ /*
++ * In order to make sure the provided range isn't matching
++ * an exception, all its access bits shouldn't match the
++ * exception's access bits
++ */
++ if (!(access & ex->access))
+ continue;
+- match = true;
+- break;
++ return true;
+ }
++ return false;
++}
++
++/**
++ * verify_new_ex - verifies if a new exception is part of what is allowed
++ * by a dev cgroup based on the default policy +
++ * exceptions. This is used to make sure a child cgroup
++ * won't have more privileges than its parent
++ * @dev_cgroup: dev cgroup to be tested against
++ * @refex: new exception
++ * @behavior: behavior of the exception's dev_cgroup
++ */
++static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
++ struct dev_exception_item *refex,
++ enum devcg_behavior behavior)
++{
++ bool match = false;
++
++ rcu_lockdep_assert(rcu_read_lock_held() ||
++ lockdep_is_held(&devcgroup_mutex),
++ "device_cgroup:verify_new_ex called without proper synchronization");
+
+ if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
+ if (behavior == DEVCG_DEFAULT_ALLOW) {
+- /* the exception will deny access to certain devices */
++ /*
++ * new exception in the child doesn't matter, only
++ * adding extra restrictions
++ */
+ return true;
+ } else {
+- /* the exception will allow access to certain devices */
++ /*
++ * new exception in the child will add more devices
++ * that can be acessed, so it can't match any of
++ * parent's exceptions, even slightly
++ */
++ match = match_exception_partial(&dev_cgroup->exceptions,
++ refex->type,
++ refex->major,
++ refex->minor,
++ refex->access);
++
+ if (match)
+- /*
+- * a new exception allowing access shouldn't
+- * match an parent's exception
+- */
+ return false;
+ return true;
+ }
+ } else {
+- /* only behavior == DEVCG_DEFAULT_DENY allowed here */
++ /*
++ * Only behavior == DEVCG_DEFAULT_DENY allowed here, therefore
++ * the new exception will add access to more devices and must
++ * be contained completely in an parent's exception to be
++ * allowed
++ */
++ match = match_exception(&dev_cgroup->exceptions, refex->type,
++ refex->major, refex->minor,
++ refex->access);
++
+ if (match)
+ /* parent has an exception that matches the proposed */
+ return true;
+@@ -380,7 +462,7 @@ static int parent_has_perm(struct dev_cg
+
+ if (!parent)
+ return 1;
+- return may_access(parent, ex, childcg->behavior);
++ return verify_new_ex(parent, ex, childcg->behavior);
+ }
+
+ /**
+@@ -708,18 +790,18 @@ static int __devcgroup_check_permission(
+ short access)
+ {
+ struct dev_cgroup *dev_cgroup;
+- struct dev_exception_item ex;
+- int rc;
+-
+- memset(&ex, 0, sizeof(ex));
+- ex.type = type;
+- ex.major = major;
+- ex.minor = minor;
+- ex.access = access;
++ bool rc;
+
+ rcu_read_lock();
+ dev_cgroup = task_devcgroup(current);
+- rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior);
++ if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW)
++ /* Can't match any of the exceptions, even partially */
++ rc = !match_exception_partial(&dev_cgroup->exceptions,
++ type, major, minor, access);
++ else
++ /* Need to match completely one exception to be allowed */
++ rc = match_exception(&dev_cgroup->exceptions, type, major,
++ minor, access);
+ rcu_read_unlock();
+
+ if (!rc)
--- /dev/null
+From 1b31e9b76ef8c62291e698dfdb973499986a7f68 Mon Sep 17 00:00:00 2001
+From: "Chew, Kean ho" <kean.ho.chew@intel.com>
+Date: Sat, 1 Mar 2014 00:03:56 +0800
+Subject: i2c: i801: enable Intel BayTrail SMBUS
+
+From: "Chew, Kean ho" <kean.ho.chew@intel.com>
+
+commit 1b31e9b76ef8c62291e698dfdb973499986a7f68 upstream.
+
+Add Device ID of Intel BayTrail SMBus Controller.
+
+Signed-off-by: Chew, Kean ho <kean.ho.chew@intel.com>
+Signed-off-by: Chew, Chiau Ee <chiau.ee.chew@intel.com>
+Reviewed-by: Jean Delvare <jdelvare@suse.de>
+Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
+Cc: "Chang, Rebecca Swee Fun" <rebecca.swee.fun.chang@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ Documentation/i2c/busses/i2c-i801 | 1 +
+ drivers/i2c/busses/Kconfig | 1 +
+ drivers/i2c/busses/i2c-i801.c | 3 +++
+ 3 files changed, 5 insertions(+)
+
+--- a/Documentation/i2c/busses/i2c-i801
++++ b/Documentation/i2c/busses/i2c-i801
+@@ -26,6 +26,7 @@ Supported adapters:
+ * Intel Wellsburg (PCH)
+ * Intel Coleto Creek (PCH)
+ * Intel Wildcat Point-LP (PCH)
++ * Intel BayTrail (SOC)
+ Datasheets: Publicly available at the Intel website
+
+ On Intel Patsburg and later chipsets, both the normal host SMBus controller
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -110,6 +110,7 @@ config I2C_I801
+ Wellsburg (PCH)
+ Coleto Creek (PCH)
+ Wildcat Point-LP (PCH)
++ BayTrail (SOC)
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-i801.
+--- a/drivers/i2c/busses/i2c-i801.c
++++ b/drivers/i2c/busses/i2c-i801.c
+@@ -60,6 +60,7 @@
+ Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
+ Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
+ Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
++ BayTrail (SOC) 0x0f12 32 hard yes yes yes
+
+ Features supported by this driver:
+ Software PEC no
+@@ -161,6 +162,7 @@
+ STATUS_ERROR_FLAGS)
+
+ /* Older devices have their ID defined in <linux/pci_ids.h> */
++#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
+ #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
+ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
+ /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+@@ -822,6 +824,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids)
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
+ { 0, }
+ };
+