summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2020-04-23 23:18:49 +0100
committerBen Hutchings <ben@decadent.org.uk>2020-04-23 23:33:58 +0100
commitd58cdcc6e1b8a6cdbf39f5274d1c336052d4e823 (patch)
tree32d7588abc60636a4d4ca850e60939457542c370
parentc53be8ef0c3d3bcf3c92c0e932eb0a7332b07b99 (diff)
downloadlinux-stable-queue-d58cdcc6e1b8a6cdbf39f5274d1c336052d4e823.tar.gz
Add more security fixes and related changes
-rw-r--r--queue-3.16/chardev-add-helper-function-to-register-char-devs-with-a-struct.patch208
-rw-r--r--queue-3.16/drivers-media-media-devnode-clear-private_data-before.patch32
-rw-r--r--queue-3.16/media-device-dynamically-allocate-struct-media_devnode.patch241
-rw-r--r--queue-3.16/media-devnode-add-missing-mutex-lock-in-error-handler.patch30
-rw-r--r--queue-3.16/media-devnode-fix-namespace-mess.patch344
-rw-r--r--queue-3.16/media-devnode-just-return-0-instead-of-using-a-var.patch34
-rw-r--r--queue-3.16/media-fix-media-devnode-ioctl-syscall-and-unregister-race.patch168
-rw-r--r--queue-3.16/media-fix-media_open-to-clear-filp-private_data-in-error.patch28
-rw-r--r--queue-3.16/media-fix-use-after-free-in-cdev_put-when-app-exits-after.patch207
-rw-r--r--queue-3.16/ptp-create-pins-together-with-the-rest-of-attributes.patch158
-rw-r--r--queue-3.16/ptp-do-not-explicitly-set-drvdata-in-ptp_clock_register.patch28
-rw-r--r--queue-3.16/ptp-fix-pass-zero-to-err_ptr-in-ptp_clock_register.patch45
-rw-r--r--queue-3.16/ptp-fix-the-race-between-the-release-of-ptp_clock-and-cdev.patch314
-rw-r--r--queue-3.16/ptp-free-ptp-device-pin-descriptors-properly.patch48
-rw-r--r--queue-3.16/ptp-use-is_visible-method-to-hide-unused-attributes.patch206
-rw-r--r--queue-3.16/series16
-rw-r--r--queue-3.16/slcan-don-t-transmit-uninitialized-stack-data-in-padding.patch48
17 files changed, 2155 insertions, 0 deletions
diff --git a/queue-3.16/chardev-add-helper-function-to-register-char-devs-with-a-struct.patch b/queue-3.16/chardev-add-helper-function-to-register-char-devs-with-a-struct.patch
new file mode 100644
index 00000000..0b9bb357
--- /dev/null
+++ b/queue-3.16/chardev-add-helper-function-to-register-char-devs-with-a-struct.patch
@@ -0,0 +1,208 @@
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Fri, 17 Mar 2017 12:48:08 -0600
+Subject: chardev: add helper function to register char devs with a struct
+ device
+
+commit 233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0 upstream.
+
+Credit for this patch goes is shared with Dan Williams [1]. I've
+taken things one step further to make the helper function more
+useful and clean up calling code.
+
+There's a common pattern in the kernel whereby a struct cdev is placed
+in a structure along side a struct device which manages the life-cycle
+of both. In the naive approach, the reference counting is broken and
+the struct device can free everything before the chardev code
+is entirely released.
+
+Many developers have solved this problem by linking the internal kobjs
+in this fashion:
+
+cdev.kobj.parent = &parent_dev.kobj;
+
+The cdev code explicitly gets and puts a reference to it's kobj parent.
+So this seems like it was intended to be used this way. Dmitrty Torokhov
+first put this in place in 2012 with this commit:
+
+2f0157f char_dev: pin parent kobject
+
+and the first instance of the fix was then done in the input subsystem
+in the following commit:
+
+4a215aa Input: fix use-after-free introduced with dynamic minor changes
+
+Subsequently over the years, however, this issue seems to have tripped
+up multiple developers independently. For example, see these commits:
+
+0d5b7da iio: Prevent race between IIO chardev opening and IIO device
+(by Lars-Peter Clausen in 2013)
+
+ba0ef85 tpm: Fix initialization of the cdev
+(by Jason Gunthorpe in 2015)
+
+5b28dde [media] media: fix use-after-free in cdev_put() when app exits
+after driver unbind
+(by Shauh Khan in 2016)
+
+This technique is similarly done in at least 15 places within the kernel
+and probably should have been done so in another, at least, 5 places.
+The kobj line also looks very suspect in that one would not expect
+drivers to have to mess with kobject internals in this way.
+Even highly experienced kernel developers can be surprised by this
+code, as seen in [2].
+
+To help alleviate this situation, and hopefully prevent future
+wasted effort on this problem, this patch introduces a helper function
+to register a char device along with its parent struct device.
+This creates a more regular API for tying a char device to its parent
+without the developer having to set members in the underlying kobject.
+
+This patch introduce cdev_device_add and cdev_device_del which
+replaces a common pattern including setting the kobj parent, calling
+cdev_add and then calling device_add. It also introduces cdev_set_parent
+for the few cases that set the kobject parent without using device_add.
+
+[1] https://lkml.org/lkml/2017/2/13/700
+[2] https://lkml.org/lkml/2017/2/10/370
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
+Reviewed-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ fs/char_dev.c | 86 ++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/cdev.h | 5 +++
+ 2 files changed, 91 insertions(+)
+
+--- a/fs/char_dev.c
++++ b/fs/char_dev.c
+@@ -488,6 +488,85 @@ int cdev_add(struct cdev *p, dev_t dev,
+ return 0;
+ }
+
++/**
++ * cdev_set_parent() - set the parent kobject for a char device
++ * @p: the cdev structure
++ * @kobj: the kobject to take a reference to
++ *
++ * cdev_set_parent() sets a parent kobject which will be referenced
++ * appropriately so the parent is not freed before the cdev. This
++ * should be called before cdev_add.
++ */
++void cdev_set_parent(struct cdev *p, struct kobject *kobj)
++{
++ WARN_ON(!kobj->state_initialized);
++ p->kobj.parent = kobj;
++}
++
++/**
++ * cdev_device_add() - add a char device and it's corresponding
++ * struct device, linkink
++ * @dev: the device structure
++ * @cdev: the cdev structure
++ *
++ * cdev_device_add() adds the char device represented by @cdev to the system,
++ * just as cdev_add does. It then adds @dev to the system using device_add
++ * The dev_t for the char device will be taken from the struct device which
++ * needs to be initialized first. This helper function correctly takes a
++ * reference to the parent device so the parent will not get released until
++ * all references to the cdev are released.
++ *
++ * This helper uses dev->devt for the device number. If it is not set
++ * it will not add the cdev and it will be equivalent to device_add.
++ *
++ * This function should be used whenever the struct cdev and the
++ * struct device are members of the same structure whose lifetime is
++ * managed by the struct device.
++ *
++ * NOTE: Callers must assume that userspace was able to open the cdev and
++ * can call cdev fops callbacks at any time, even if this function fails.
++ */
++int cdev_device_add(struct cdev *cdev, struct device *dev)
++{
++ int rc = 0;
++
++ if (dev->devt) {
++ cdev_set_parent(cdev, &dev->kobj);
++
++ rc = cdev_add(cdev, dev->devt, 1);
++ if (rc)
++ return rc;
++ }
++
++ rc = device_add(dev);
++ if (rc)
++ cdev_del(cdev);
++
++ return rc;
++}
++
++/**
++ * cdev_device_del() - inverse of cdev_device_add
++ * @dev: the device structure
++ * @cdev: the cdev structure
++ *
++ * cdev_device_del() is a helper function to call cdev_del and device_del.
++ * It should be used whenever cdev_device_add is used.
++ *
++ * If dev->devt is not set it will not remove the cdev and will be equivalent
++ * to device_del.
++ *
++ * NOTE: This guarantees that associated sysfs callbacks are not running
++ * or runnable, however any cdevs already open will remain and their fops
++ * will still be callable even after this function returns.
++ */
++void cdev_device_del(struct cdev *cdev, struct device *dev)
++{
++ device_del(dev);
++ if (dev->devt)
++ cdev_del(cdev);
++}
++
+ static void cdev_unmap(dev_t dev, unsigned count)
+ {
+ kobj_unmap(cdev_map, dev, count);
+@@ -499,6 +578,10 @@ static void cdev_unmap(dev_t dev, unsign
+ *
+ * cdev_del() removes @p from the system, possibly freeing the structure
+ * itself.
++ *
++ * NOTE: This guarantees that cdev device will no longer be able to be
++ * opened, however any cdevs already open will remain and their fops will
++ * still be callable even after cdev_del returns.
+ */
+ void cdev_del(struct cdev *p)
+ {
+@@ -589,6 +672,9 @@ EXPORT_SYMBOL(cdev_init);
+ EXPORT_SYMBOL(cdev_alloc);
+ EXPORT_SYMBOL(cdev_del);
+ EXPORT_SYMBOL(cdev_add);
++EXPORT_SYMBOL(cdev_set_parent);
++EXPORT_SYMBOL(cdev_device_add);
++EXPORT_SYMBOL(cdev_device_del);
+ EXPORT_SYMBOL(__register_chrdev);
+ EXPORT_SYMBOL(__unregister_chrdev);
+ EXPORT_SYMBOL(directly_mappable_cdev_bdi);
+--- a/include/linux/cdev.h
++++ b/include/linux/cdev.h
+@@ -4,6 +4,7 @@
+ #include <linux/kobject.h>
+ #include <linux/kdev_t.h>
+ #include <linux/list.h>
++#include <linux/device.h>
+
+ struct file_operations;
+ struct inode;
+@@ -26,6 +27,10 @@ void cdev_put(struct cdev *p);
+
+ int cdev_add(struct cdev *, dev_t, unsigned);
+
++void cdev_set_parent(struct cdev *p, struct kobject *kobj);
++int cdev_device_add(struct cdev *cdev, struct device *dev);
++void cdev_device_del(struct cdev *cdev, struct device *dev);
++
+ void cdev_del(struct cdev *);
+
+ void cd_forget(struct inode *);
diff --git a/queue-3.16/drivers-media-media-devnode-clear-private_data-before.patch b/queue-3.16/drivers-media-media-devnode-clear-private_data-before.patch
new file mode 100644
index 00000000..cdb7af40
--- /dev/null
+++ b/queue-3.16/drivers-media-media-devnode-clear-private_data-before.patch
@@ -0,0 +1,32 @@
+From: Max Kellermann <max@duempel.org>
+Date: Mon, 21 Mar 2016 10:30:28 -0300
+Subject: [media] drivers/media/media-devnode: clear private_data before
+ put_device()
+
+commit bf244f665d76d20312c80524689b32a752888838 upstream.
+
+Callbacks invoked from put_device() may free the struct media_devnode
+pointer, so any cleanup needs to be done before put_device().
+
+Signed-off-by: Max Kellermann <max@duempel.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/media/media-devnode.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -197,10 +197,11 @@ static int media_release(struct inode *i
+ if (mdev->fops->release)
+ mdev->fops->release(filp);
+
++ filp->private_data = NULL;
++
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+ put_device(&mdev->dev);
+- filp->private_data = NULL;
+ return 0;
+ }
+
diff --git a/queue-3.16/media-device-dynamically-allocate-struct-media_devnode.patch b/queue-3.16/media-device-dynamically-allocate-struct-media_devnode.patch
new file mode 100644
index 00000000..7e4d58e9
--- /dev/null
+++ b/queue-3.16/media-device-dynamically-allocate-struct-media_devnode.patch
@@ -0,0 +1,241 @@
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Date: Wed, 27 Apr 2016 19:28:26 -0300
+Subject: [media] media-device: dynamically allocate struct media_devnode
+
+commit a087ce704b802becbb4b0f2a20f2cb3f6911802e upstream.
+
+struct media_devnode is currently embedded at struct media_device.
+
+While this works fine during normal usage, it leads to a race
+condition during devnode unregister. the problem is that drivers
+assume that, after calling media_device_unregister(), the struct
+that contains media_device can be freed. This is not true, as it
+can't be freed until userspace closes all opened /dev/media devnodes.
+
+In other words, if the media devnode is still open, and media_device
+gets freed, any call to an ioctl will make the core to try to access
+struct media_device, with will cause an use-after-free and even GPF.
+
+Fix this by dynamically allocating the struct media_devnode and only
+freeing it when it is safe.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 3.16:
+ - Drop change in au0828
+ - Include <linux/slab.h> in media-device.c
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -24,6 +24,7 @@
+ #include <linux/export.h>
+ #include <linux/ioctl.h>
+ #include <linux/media.h>
++#include <linux/slab.h>
+ #include <linux/types.h>
+
+ #include <media/media-device.h>
+@@ -236,7 +237,7 @@ static long media_device_ioctl(struct fi
+ unsigned long arg)
+ {
+ struct media_devnode *devnode = media_devnode_data(filp);
+- struct media_device *dev = to_media_device(devnode);
++ struct media_device *dev = devnode->media_dev;
+ long ret;
+
+ switch (cmd) {
+@@ -305,7 +306,7 @@ static long media_device_compat_ioctl(st
+ unsigned long arg)
+ {
+ struct media_devnode *devnode = media_devnode_data(filp);
+- struct media_device *dev = to_media_device(devnode);
++ struct media_device *dev = devnode->media_dev;
+ long ret;
+
+ switch (cmd) {
+@@ -346,7 +347,8 @@ static const struct media_file_operation
+ static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
+ {
+- struct media_device *mdev = to_media_device(to_media_devnode(cd));
++ struct media_devnode *devnode = to_media_devnode(cd);
++ struct media_device *mdev = devnode->media_dev;
+
+ return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
+ }
+@@ -374,6 +376,7 @@ static void media_device_release(struct
+ int __must_check __media_device_register(struct media_device *mdev,
+ struct module *owner)
+ {
++ struct media_devnode *devnode;
+ int ret;
+
+ if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
+@@ -384,17 +387,27 @@ int __must_check __media_device_register
+ spin_lock_init(&mdev->lock);
+ mutex_init(&mdev->graph_mutex);
+
++ devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
++ if (!devnode)
++ return -ENOMEM;
++
+ /* Register the device node. */
+- mdev->devnode.fops = &media_device_fops;
+- mdev->devnode.parent = mdev->dev;
+- mdev->devnode.release = media_device_release;
+- ret = media_devnode_register(&mdev->devnode, owner);
+- if (ret < 0)
++ mdev->devnode = devnode;
++ devnode->fops = &media_device_fops;
++ devnode->parent = mdev->dev;
++ devnode->release = media_device_release;
++ ret = media_devnode_register(mdev, devnode, owner);
++ if (ret < 0) {
++ mdev->devnode = NULL;
++ kfree(devnode);
+ return ret;
++ }
+
+- ret = device_create_file(&mdev->devnode.dev, &dev_attr_model);
++ ret = device_create_file(&devnode->dev, &dev_attr_model);
+ if (ret < 0) {
+- media_devnode_unregister(&mdev->devnode);
++ mdev->devnode = NULL;
++ media_devnode_unregister(devnode);
++ kfree(devnode);
+ return ret;
+ }
+
+@@ -415,8 +428,11 @@ void media_device_unregister(struct medi
+ list_for_each_entry_safe(entity, next, &mdev->entities, list)
+ media_device_unregister_entity(entity);
+
+- device_remove_file(&mdev->devnode.dev, &dev_attr_model);
+- media_devnode_unregister(&mdev->devnode);
++ /* Check if mdev devnode was registered */
++ if (media_devnode_is_registered(mdev->devnode)) {
++ device_remove_file(&mdev->devnode->dev, &dev_attr_model);
++ media_devnode_unregister(mdev->devnode);
++ }
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -44,6 +44,7 @@
+ #include <linux/uaccess.h>
+
+ #include <media/media-devnode.h>
++#include <media/media-device.h>
+
+ #define MEDIA_NUM_DEVICES 256
+ #define MEDIA_NAME "media"
+@@ -74,6 +75,8 @@ static void media_devnode_release(struct
+ /* Release media_devnode and perform other cleanups as needed. */
+ if (devnode->release)
+ devnode->release(devnode);
++
++ kfree(devnode);
+ }
+
+ static struct bus_type media_bus_type = {
+@@ -221,6 +224,7 @@ static const struct file_operations medi
+
+ /**
+ * media_devnode_register - register a media device node
++ * @media_dev: struct media_device we want to register a device node
+ * @devnode: media device node structure we want to register
+ *
+ * The registration code assigns minor numbers and registers the new device node
+@@ -233,7 +237,8 @@ static const struct file_operations medi
+ * the media_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
+-int __must_check media_devnode_register(struct media_devnode *devnode,
++int __must_check media_devnode_register(struct media_device *mdev,
++ struct media_devnode *devnode,
+ struct module *owner)
+ {
+ int minor;
+@@ -252,6 +257,7 @@ int __must_check media_devnode_register(
+ mutex_unlock(&media_devnode_lock);
+
+ devnode->minor = minor;
++ devnode->media_dev = mdev;
+
+ /* Part 2: Initialize and register the character device */
+ cdev_init(&devnode->cdev, &media_devnode_fops);
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -60,7 +60,7 @@ struct device;
+ struct media_device {
+ /* dev->driver_data points to this struct. */
+ struct device *dev;
+- struct media_devnode devnode;
++ struct media_devnode *devnode;
+
+ char model[32];
+ char serial[40];
+@@ -84,9 +84,6 @@ struct media_device {
+ #define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0
+ #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
+
+-/* media_devnode to media_device */
+-#define to_media_device(node) container_of(node, struct media_device, devnode)
+-
+ int __must_check __media_device_register(struct media_device *mdev,
+ struct module *owner);
+ #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE)
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -1640,7 +1640,7 @@ static void uvc_delete(struct uvc_device
+ if (dev->vdev.dev)
+ v4l2_device_unregister(&dev->vdev);
+ #ifdef CONFIG_MEDIA_CONTROLLER
+- if (media_devnode_is_registered(&dev->mdev.devnode))
++ if (media_devnode_is_registered(dev->mdev.devnode))
+ media_device_unregister(&dev->mdev);
+ #endif
+
+--- a/include/media/media-devnode.h
++++ b/include/media/media-devnode.h
+@@ -33,6 +33,8 @@
+ #include <linux/device.h>
+ #include <linux/cdev.h>
+
++struct media_device;
++
+ /*
+ * Flag to mark the media_devnode struct as registered. Drivers must not touch
+ * this flag directly, it will be set and cleared by media_devnode_register and
+@@ -63,6 +65,8 @@ struct media_file_operations {
+ * before registering the node.
+ */
+ struct media_devnode {
++ struct media_device *media_dev;
++
+ /* device ops */
+ const struct media_file_operations *fops;
+
+@@ -82,7 +86,8 @@ struct media_devnode {
+ /* dev to media_devnode */
+ #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+
+-int __must_check media_devnode_register(struct media_devnode *devnode,
++int __must_check media_devnode_register(struct media_device *mdev,
++ struct media_devnode *devnode,
+ struct module *owner);
+ void media_devnode_unregister(struct media_devnode *devnode);
+
+@@ -93,6 +98,9 @@ static inline struct media_devnode *medi
+
+ static inline int media_devnode_is_registered(struct media_devnode *devnode)
+ {
++ if (!devnode)
++ return false;
++
+ return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+ }
+
diff --git a/queue-3.16/media-devnode-add-missing-mutex-lock-in-error-handler.patch b/queue-3.16/media-devnode-add-missing-mutex-lock-in-error-handler.patch
new file mode 100644
index 00000000..d035fe7c
--- /dev/null
+++ b/queue-3.16/media-devnode-add-missing-mutex-lock-in-error-handler.patch
@@ -0,0 +1,30 @@
+From: Max Kellermann <max@duempel.org>
+Date: Mon, 21 Mar 2016 04:33:12 -0700
+Subject: [media] media-devnode: add missing mutex lock in error handler
+
+commit 88336e174645948da269e1812f138f727cd2896b upstream.
+
+We should protect the device unregister patch too, at the error
+condition.
+
+Signed-off-by: Max Kellermann <max@duempel.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/media/media-devnode.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -282,8 +282,11 @@ int __must_check media_devnode_register(
+ return 0;
+
+ error:
++ mutex_lock(&media_devnode_lock);
+ cdev_del(&mdev->cdev);
+ clear_bit(mdev->minor, media_devnode_nums);
++ mutex_unlock(&media_devnode_lock);
++
+ return ret;
+ }
+
diff --git a/queue-3.16/media-devnode-fix-namespace-mess.patch b/queue-3.16/media-devnode-fix-namespace-mess.patch
new file mode 100644
index 00000000..d8db22b2
--- /dev/null
+++ b/queue-3.16/media-devnode-fix-namespace-mess.patch
@@ -0,0 +1,344 @@
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Date: Wed, 23 Mar 2016 11:22:57 -0300
+Subject: [media] media-devnode: fix namespace mess
+
+commit 163f1e93e995048b894c5fc86a6034d16beed740 upstream.
+
+Along all media controller code, "mdev" is used to represent
+a pointer to struct media_device, and "devnode" for a pointer
+to struct media_devnode.
+
+However, inside media-devnode.[ch], "mdev" is used to represent
+a pointer to struct media_devnode.
+
+This is very confusing and may lead to development errors.
+
+So, let's change all occurrences at media-devnode.[ch] to
+also use "devnode" for such pointers.
+
+This patch doesn't make any functional changes.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 3.16: adjust filename, context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/media/media-devnode.c | 110 +++++++++++++++++-----------------
+ include/media/media-devnode.h | 16 ++---
+ 2 files changed, 63 insertions(+), 63 deletions(-)
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -59,21 +59,21 @@ static DECLARE_BITMAP(media_devnode_nums
+ /* Called when the last user of the media device exits. */
+ static void media_devnode_release(struct device *cd)
+ {
+- struct media_devnode *mdev = to_media_devnode(cd);
++ struct media_devnode *devnode = to_media_devnode(cd);
+
+ mutex_lock(&media_devnode_lock);
+
+ /* Delete the cdev on this minor as well */
+- cdev_del(&mdev->cdev);
++ cdev_del(&devnode->cdev);
+
+ /* Mark device node number as free */
+- clear_bit(mdev->minor, media_devnode_nums);
++ clear_bit(devnode->minor, media_devnode_nums);
+
+ mutex_unlock(&media_devnode_lock);
+
+ /* Release media_devnode and perform other cleanups as needed. */
+- if (mdev->release)
+- mdev->release(mdev);
++ if (devnode->release)
++ devnode->release(devnode);
+ }
+
+ static struct bus_type media_bus_type = {
+@@ -83,37 +83,37 @@ static struct bus_type media_bus_type =
+ static ssize_t media_read(struct file *filp, char __user *buf,
+ size_t sz, loff_t *off)
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+- if (!mdev->fops->read)
++ if (!devnode->fops->read)
+ return -EINVAL;
+- if (!media_devnode_is_registered(mdev))
++ if (!media_devnode_is_registered(devnode))
+ return -EIO;
+- return mdev->fops->read(filp, buf, sz, off);
++ return devnode->fops->read(filp, buf, sz, off);
+ }
+
+ static ssize_t media_write(struct file *filp, const char __user *buf,
+ size_t sz, loff_t *off)
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+- if (!mdev->fops->write)
++ if (!devnode->fops->write)
+ return -EINVAL;
+- if (!media_devnode_is_registered(mdev))
++ if (!media_devnode_is_registered(devnode))
+ return -EIO;
+- return mdev->fops->write(filp, buf, sz, off);
++ return devnode->fops->write(filp, buf, sz, off);
+ }
+
+ static unsigned int media_poll(struct file *filp,
+ struct poll_table_struct *poll)
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+- if (!media_devnode_is_registered(mdev))
++ if (!media_devnode_is_registered(devnode))
+ return POLLERR | POLLHUP;
+- if (!mdev->fops->poll)
++ if (!devnode->fops->poll)
+ return DEFAULT_POLLMASK;
+- return mdev->fops->poll(filp, poll);
++ return devnode->fops->poll(filp, poll);
+ }
+
+ static long
+@@ -121,12 +121,12 @@ __media_ioctl(struct file *filp, unsigne
+ long (*ioctl_func)(struct file *filp, unsigned int cmd,
+ unsigned long arg))
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+ if (!ioctl_func)
+ return -ENOTTY;
+
+- if (!media_devnode_is_registered(mdev))
++ if (!media_devnode_is_registered(devnode))
+ return -EIO;
+
+ return ioctl_func(filp, cmd, arg);
+@@ -134,9 +134,9 @@ __media_ioctl(struct file *filp, unsigne
+
+ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+- return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl);
++ return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
+ }
+
+ #ifdef CONFIG_COMPAT
+@@ -144,9 +144,9 @@ static long media_ioctl(struct file *fil
+ static long media_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+- return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl);
++ return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
+ }
+
+ #endif /* CONFIG_COMPAT */
+@@ -154,7 +154,7 @@ static long media_compat_ioctl(struct fi
+ /* Override for the open function */
+ static int media_open(struct inode *inode, struct file *filp)
+ {
+- struct media_devnode *mdev;
++ struct media_devnode *devnode;
+ int ret;
+
+ /* Check if the media device is available. This needs to be done with
+@@ -164,23 +164,23 @@ static int media_open(struct inode *inod
+ * a crash.
+ */
+ mutex_lock(&media_devnode_lock);
+- mdev = container_of(inode->i_cdev, struct media_devnode, cdev);
++ devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
+ /* return ENXIO if the media device has been removed
+ already or if it is not registered anymore. */
+- if (!media_devnode_is_registered(mdev)) {
++ if (!media_devnode_is_registered(devnode)) {
+ mutex_unlock(&media_devnode_lock);
+ return -ENXIO;
+ }
+ /* and increase the device refcount */
+- get_device(&mdev->dev);
++ get_device(&devnode->dev);
+ mutex_unlock(&media_devnode_lock);
+
+- filp->private_data = mdev;
++ filp->private_data = devnode;
+
+- if (mdev->fops->open) {
+- ret = mdev->fops->open(filp);
++ if (devnode->fops->open) {
++ ret = devnode->fops->open(filp);
+ if (ret) {
+- put_device(&mdev->dev);
++ put_device(&devnode->dev);
+ filp->private_data = NULL;
+ return ret;
+ }
+@@ -192,16 +192,16 @@ static int media_open(struct inode *inod
+ /* Override for the release function */
+ static int media_release(struct inode *inode, struct file *filp)
+ {
+- struct media_devnode *mdev = media_devnode_data(filp);
++ struct media_devnode *devnode = media_devnode_data(filp);
+
+- if (mdev->fops->release)
+- mdev->fops->release(filp);
++ if (devnode->fops->release)
++ devnode->fops->release(filp);
+
+ filp->private_data = NULL;
+
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+- put_device(&mdev->dev);
++ put_device(&devnode->dev);
+ return 0;
+ }
+
+@@ -221,7 +221,7 @@ static const struct file_operations medi
+
+ /**
+ * media_devnode_register - register a media device node
+- * @mdev: media device node structure we want to register
++ * @devnode: media device node structure we want to register
+ *
+ * The registration code assigns minor numbers and registers the new device node
+ * with the kernel. An error is returned if no free minor number can be found,
+@@ -233,7 +233,7 @@ static const struct file_operations medi
+ * the media_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
+-int __must_check media_devnode_register(struct media_devnode *mdev,
++int __must_check media_devnode_register(struct media_devnode *devnode,
+ struct module *owner)
+ {
+ int minor;
+@@ -251,40 +251,40 @@ int __must_check media_devnode_register(
+ set_bit(minor, media_devnode_nums);
+ mutex_unlock(&media_devnode_lock);
+
+- mdev->minor = minor;
++ devnode->minor = minor;
+
+ /* Part 2: Initialize and register the character device */
+- cdev_init(&mdev->cdev, &media_devnode_fops);
+- mdev->cdev.owner = owner;
++ cdev_init(&devnode->cdev, &media_devnode_fops);
++ devnode->cdev.owner = owner;
+
+- ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
++ ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1);
+ if (ret < 0) {
+ pr_err("%s: cdev_add failed\n", __func__);
+ goto error;
+ }
+
+ /* Part 3: Register the media device */
+- mdev->dev.bus = &media_bus_type;
+- mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor);
+- mdev->dev.release = media_devnode_release;
+- if (mdev->parent)
+- mdev->dev.parent = mdev->parent;
+- dev_set_name(&mdev->dev, "media%d", mdev->minor);
+- ret = device_register(&mdev->dev);
++ devnode->dev.bus = &media_bus_type;
++ devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
++ devnode->dev.release = media_devnode_release;
++ if (devnode->parent)
++ devnode->dev.parent = devnode->parent;
++ dev_set_name(&devnode->dev, "media%d", devnode->minor);
++ ret = device_register(&devnode->dev);
+ if (ret < 0) {
+ pr_err("%s: device_register failed\n", __func__);
+ goto error;
+ }
+
+ /* Part 4: Activate this minor. The char device can now be used. */
+- set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++ set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+
+ return 0;
+
+ error:
+ mutex_lock(&media_devnode_lock);
+- cdev_del(&mdev->cdev);
+- clear_bit(mdev->minor, media_devnode_nums);
++ cdev_del(&devnode->cdev);
++ clear_bit(devnode->minor, media_devnode_nums);
+ mutex_unlock(&media_devnode_lock);
+
+ return ret;
+@@ -292,7 +292,7 @@ error:
+
+ /**
+ * media_devnode_unregister - unregister a media device node
+- * @mdev: the device node to unregister
++ * @devnode: the device node to unregister
+ *
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+@@ -300,16 +300,16 @@ error:
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
+-void media_devnode_unregister(struct media_devnode *mdev)
++void media_devnode_unregister(struct media_devnode *devnode)
+ {
+- /* Check if mdev was ever registered at all */
+- if (!media_devnode_is_registered(mdev))
++ /* Check if devnode was ever registered at all */
++ if (!media_devnode_is_registered(devnode))
+ return;
+
+ mutex_lock(&media_devnode_lock);
+- clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++ clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+ mutex_unlock(&media_devnode_lock);
+- device_unregister(&mdev->dev);
++ device_unregister(&devnode->dev);
+ }
+
+ /*
+--- a/include/media/media-devnode.h
++++ b/include/media/media-devnode.h
+@@ -76,24 +76,24 @@ struct media_devnode {
+ unsigned long flags; /* Use bitops to access flags */
+
+ /* callbacks */
+- void (*release)(struct media_devnode *mdev);
++ void (*release)(struct media_devnode *devnode);
+ };
+
+ /* dev to media_devnode */
+ #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+
+-int __must_check media_devnode_register(struct media_devnode *mdev,
++int __must_check media_devnode_register(struct media_devnode *devnode,
+ struct module *owner);
+-void media_devnode_unregister(struct media_devnode *mdev);
++void media_devnode_unregister(struct media_devnode *devnode);
+
+ static inline struct media_devnode *media_devnode_data(struct file *filp)
+ {
+ return filp->private_data;
+ }
+
+-static inline int media_devnode_is_registered(struct media_devnode *mdev)
++static inline int media_devnode_is_registered(struct media_devnode *devnode)
+ {
+- return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
++ return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+ }
+
+ #endif /* _MEDIA_DEVNODE_H */
diff --git a/queue-3.16/media-devnode-just-return-0-instead-of-using-a-var.patch b/queue-3.16/media-devnode-just-return-0-instead-of-using-a-var.patch
new file mode 100644
index 00000000..9285850f
--- /dev/null
+++ b/queue-3.16/media-devnode-just-return-0-instead-of-using-a-var.patch
@@ -0,0 +1,34 @@
+From: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Date: Wed, 3 Sep 2014 15:18:27 -0300
+Subject: [media] media-devnode: just return 0 instead of using a var
+
+commit 8b37c6455fc8f43e0e95db2847284e618db6a4f8 upstream.
+
+Instead of allocating a var to store 0 and just return it,
+change the code to return 0 directly.
+
+Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/media/media-devnode.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -192,7 +192,6 @@ static int media_open(struct inode *inod
+ static int media_release(struct inode *inode, struct file *filp)
+ {
+ struct media_devnode *mdev = media_devnode_data(filp);
+- int ret = 0;
+
+ if (mdev->fops->release)
+ mdev->fops->release(filp);
+@@ -201,7 +200,7 @@ static int media_release(struct inode *i
+ return value is ignored. */
+ put_device(&mdev->dev);
+ filp->private_data = NULL;
+- return ret;
++ return 0;
+ }
+
+ static const struct file_operations media_devnode_fops = {
diff --git a/queue-3.16/media-fix-media-devnode-ioctl-syscall-and-unregister-race.patch b/queue-3.16/media-fix-media-devnode-ioctl-syscall-and-unregister-race.patch
new file mode 100644
index 00000000..197943a9
--- /dev/null
+++ b/queue-3.16/media-fix-media-devnode-ioctl-syscall-and-unregister-race.patch
@@ -0,0 +1,168 @@
+From: Shuah Khan <shuahkh@osg.samsung.com>
+Date: Fri, 10 Jun 2016 14:37:23 -0300
+Subject: [media] media: fix media devnode ioctl/syscall and unregister race
+
+commit 6f0dd24a084a17f9984dd49dffbf7055bf123993 upstream.
+
+Media devnode open/ioctl could be in progress when media device unregister
+is initiated. System calls and ioctls check media device registered status
+at the beginning, however, there is a window where unregister could be in
+progress without changing the media devnode status to unregistered.
+
+process 1 process 2
+fd = open(/dev/media0)
+media_devnode_is_registered()
+ (returns true here)
+
+ media_device_unregister()
+ (unregister is in progress
+ and devnode isn't
+ unregistered yet)
+ ...
+ioctl(fd, ...)
+__media_ioctl()
+media_devnode_is_registered()
+ (returns true here)
+ ...
+ media_devnode_unregister()
+ ...
+ (driver releases the media device
+ memory)
+
+media_device_ioctl()
+ (By this point
+ devnode->media_dev does not
+ point to allocated memory.
+ use-after free in in mutex_lock_nested)
+
+BUG: KASAN: use-after-free in mutex_lock_nested+0x79c/0x800 at addr
+ffff8801ebe914f0
+
+Fix it by clearing register bit when unregister starts to avoid the race.
+
+process 1 process 2
+fd = open(/dev/media0)
+media_devnode_is_registered()
+ (could return true here)
+
+ media_device_unregister()
+ (clear the register bit,
+ then start unregister.)
+ ...
+ioctl(fd, ...)
+__media_ioctl()
+media_devnode_is_registered()
+ (return false here, ioctl
+ returns I/O error, and
+ will not access media
+ device memory)
+ ...
+ media_devnode_unregister()
+ ...
+ (driver releases the media device
+ memory)
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Suggested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Reported-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Tested-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 3.16: adjut filename, context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -407,6 +407,7 @@ int __must_check __media_device_register
+ if (ret < 0) {
+ /* devnode free is handled in media_devnode_*() */
+ mdev->devnode = NULL;
++ media_devnode_unregister_prepare(devnode);
+ media_devnode_unregister(devnode);
+ return ret;
+ }
+@@ -425,16 +426,16 @@ void media_device_unregister(struct medi
+ struct media_entity *entity;
+ struct media_entity *next;
+
++ /* Clear the devnode register bit to avoid races with media dev open */
++ media_devnode_unregister_prepare(mdev->devnode);
++
+ list_for_each_entry_safe(entity, next, &mdev->entities, list)
+ media_device_unregister_entity(entity);
+
+- /* Check if mdev devnode was registered */
+- if (media_devnode_is_registered(mdev->devnode)) {
+- device_remove_file(&mdev->devnode->dev, &dev_attr_model);
+- media_devnode_unregister(mdev->devnode);
+- /* devnode free is handled in media_devnode_*() */
+- mdev->devnode = NULL;
+- }
++ device_remove_file(&mdev->devnode->dev, &dev_attr_model);
++ media_devnode_unregister(mdev->devnode);
++ /* devnode free is handled in media_devnode_*() */
++ mdev->devnode = NULL;
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -302,6 +302,17 @@ cdev_add_error:
+ return ret;
+ }
+
++void media_devnode_unregister_prepare(struct media_devnode *devnode)
++{
++ /* Check if devnode was ever registered at all */
++ if (!media_devnode_is_registered(devnode))
++ return;
++
++ mutex_lock(&media_devnode_lock);
++ clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
++ mutex_unlock(&media_devnode_lock);
++}
++
+ /**
+ * media_devnode_unregister - unregister a media device node
+ * @devnode: the device node to unregister
+@@ -309,17 +320,11 @@ cdev_add_error:
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+ *
+- * This function can safely be called if the device node has never been
+- * registered or has already been unregistered.
++ * Should be called after media_devnode_unregister_prepare()
+ */
+ void media_devnode_unregister(struct media_devnode *devnode)
+ {
+- /* Check if devnode was ever registered at all */
+- if (!media_devnode_is_registered(devnode))
+- return;
+-
+ mutex_lock(&media_devnode_lock);
+- clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+ /* Delete the cdev on this minor as well */
+ cdev_del(&devnode->cdev);
+ mutex_unlock(&media_devnode_lock);
+--- a/include/media/media-devnode.h
++++ b/include/media/media-devnode.h
+@@ -89,6 +89,20 @@ struct media_devnode {
+ int __must_check media_devnode_register(struct media_device *mdev,
+ struct media_devnode *devnode,
+ struct module *owner);
++
++/**
++ * media_devnode_unregister_prepare - clear the media device node register bit
++ * @devnode: the device node to prepare for unregister
++ *
++ * This clears the passed device register bit. Future open calls will be met
++ * with errors. Should be called before media_devnode_unregister() to avoid
++ * races with unregister and device file open calls.
++ *
++ * This function can safely be called if the device node has never been
++ * registered or has already been unregistered.
++ */
++void media_devnode_unregister_prepare(struct media_devnode *devnode);
++
+ void media_devnode_unregister(struct media_devnode *devnode);
+
+ static inline struct media_devnode *media_devnode_data(struct file *filp)
diff --git a/queue-3.16/media-fix-media_open-to-clear-filp-private_data-in-error.patch b/queue-3.16/media-fix-media_open-to-clear-filp-private_data-in-error.patch
new file mode 100644
index 00000000..4be93d5c
--- /dev/null
+++ b/queue-3.16/media-fix-media_open-to-clear-filp-private_data-in-error.patch
@@ -0,0 +1,28 @@
+From: Shuah Khan <shuahkh@osg.samsung.com>
+Date: Wed, 27 Jan 2016 21:49:33 -0200
+Subject: [media] media: Fix media_open() to clear filp->private_data in error
+ leg
+
+commit d40ec6fdb0b03b7be4c7923a3da0e46bf943740a upstream.
+
+Fix media_open() to clear filp->private_data when file open
+fails.
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/media/media-devnode.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -181,6 +181,7 @@ static int media_open(struct inode *inod
+ ret = mdev->fops->open(filp);
+ if (ret) {
+ put_device(&mdev->dev);
++ filp->private_data = NULL;
+ return ret;
+ }
+ }
diff --git a/queue-3.16/media-fix-use-after-free-in-cdev_put-when-app-exits-after.patch b/queue-3.16/media-fix-use-after-free-in-cdev_put-when-app-exits-after.patch
new file mode 100644
index 00000000..32a81312
--- /dev/null
+++ b/queue-3.16/media-fix-use-after-free-in-cdev_put-when-app-exits-after.patch
@@ -0,0 +1,207 @@
+From: Shuah Khan <shuahkh@osg.samsung.com>
+Date: Wed, 4 May 2016 16:48:28 -0300
+Subject: [media] media: fix use-after-free in cdev_put() when app exits after
+ driver unbind
+
+commit 5b28dde51d0ccc54cee70756e1800d70bed7114a upstream.
+
+When driver unbinds while media_ioctl is in progress, cdev_put() fails with
+when app exits after driver unbinds.
+
+Add devnode struct device kobj as the cdev parent kobject. cdev_add() gets
+a reference to it and releases it in cdev_del() ensuring that the devnode
+is not deallocated as long as the application has the device file open.
+
+media_devnode_register() initializes the struct device kobj before calling
+cdev_add(). media_devnode_unregister() does cdev_del() and then deletes the
+device. devnode is released when the last reference to the struct device is
+gone.
+
+This problem is found on uvcvideo, em28xx, and au0828 drivers and fix has
+been tested on all three.
+
+kernel: [ 193.599736] BUG: KASAN: use-after-free in cdev_put+0x4e/0x50
+kernel: [ 193.599745] Read of size 8 by task media_device_te/1851
+kernel: [ 193.599792] INFO: Allocated in __media_device_register+0x54
+kernel: [ 193.599951] INFO: Freed in media_devnode_release+0xa4/0xc0
+
+kernel: [ 193.601083] Call Trace:
+kernel: [ 193.601093] [<ffffffff81aecac3>] dump_stack+0x67/0x94
+kernel: [ 193.601102] [<ffffffff815359b2>] print_trailer+0x112/0x1a0
+kernel: [ 193.601111] [<ffffffff8153b5e4>] object_err+0x34/0x40
+kernel: [ 193.601119] [<ffffffff8153d9d4>] kasan_report_error+0x224/0x530
+kernel: [ 193.601128] [<ffffffff814a2c3d>] ? kzfree+0x2d/0x40
+kernel: [ 193.601137] [<ffffffff81539d72>] ? kfree+0x1d2/0x1f0
+kernel: [ 193.601154] [<ffffffff8157ca7e>] ? cdev_put+0x4e/0x50
+kernel: [ 193.601162] [<ffffffff8157ca7e>] cdev_put+0x4e/0x50
+kernel: [ 193.601170] [<ffffffff815767eb>] __fput+0x52b/0x6c0
+kernel: [ 193.601179] [<ffffffff8117743a>] ? switch_task_namespaces+0x2a
+kernel: [ 193.601188] [<ffffffff815769ee>] ____fput+0xe/0x10
+kernel: [ 193.601196] [<ffffffff81170023>] task_work_run+0x133/0x1f0
+kernel: [ 193.601204] [<ffffffff8117746e>] ? switch_task_namespaces+0x5e
+kernel: [ 193.601213] [<ffffffff8111b50c>] do_exit+0x72c/0x2c20
+kernel: [ 193.601224] [<ffffffff8111ade0>] ? release_task+0x1250/0x1250
+-
+-
+-
+kernel: [ 193.601360] [<ffffffff81003587>] ? exit_to_usermode_loop+0xe7
+kernel: [ 193.601368] [<ffffffff810035c0>] exit_to_usermode_loop+0x120
+kernel: [ 193.601376] [<ffffffff810061da>] syscall_return_slowpath+0x16a
+kernel: [ 193.601386] [<ffffffff82848b33>] entry_SYSCALL_64_fastpath+0xa6
+
+Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
+Tested-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+[bwh: Backported to 3.16: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/media/media-device.c | 6 +++--
+ drivers/media/media-devnode.c | 48 +++++++++++++++++++++--------------
+ 2 files changed, 33 insertions(+), 21 deletions(-)
+
+--- a/drivers/media/media-device.c
++++ b/drivers/media/media-device.c
+@@ -398,16 +398,16 @@ int __must_check __media_device_register
+ devnode->release = media_device_release;
+ ret = media_devnode_register(mdev, devnode, owner);
+ if (ret < 0) {
++ /* devnode free is handled in media_devnode_*() */
+ mdev->devnode = NULL;
+- kfree(devnode);
+ return ret;
+ }
+
+ ret = device_create_file(&devnode->dev, &dev_attr_model);
+ if (ret < 0) {
++ /* devnode free is handled in media_devnode_*() */
+ mdev->devnode = NULL;
+ media_devnode_unregister(devnode);
+- kfree(devnode);
+ return ret;
+ }
+
+@@ -432,6 +432,8 @@ void media_device_unregister(struct medi
+ if (media_devnode_is_registered(mdev->devnode)) {
+ device_remove_file(&mdev->devnode->dev, &dev_attr_model);
+ media_devnode_unregister(mdev->devnode);
++ /* devnode free is handled in media_devnode_*() */
++ mdev->devnode = NULL;
+ }
+ }
+ EXPORT_SYMBOL_GPL(media_device_unregister);
+--- a/drivers/media/media-devnode.c
++++ b/drivers/media/media-devnode.c
+@@ -63,13 +63,8 @@ static void media_devnode_release(struct
+ struct media_devnode *devnode = to_media_devnode(cd);
+
+ mutex_lock(&media_devnode_lock);
+-
+- /* Delete the cdev on this minor as well */
+- cdev_del(&devnode->cdev);
+-
+ /* Mark device node number as free */
+ clear_bit(devnode->minor, media_devnode_nums);
+-
+ mutex_unlock(&media_devnode_lock);
+
+ /* Release media_devnode and perform other cleanups as needed. */
+@@ -77,6 +72,7 @@ static void media_devnode_release(struct
+ devnode->release(devnode);
+
+ kfree(devnode);
++ pr_debug("%s: Media Devnode Deallocated\n", __func__);
+ }
+
+ static struct bus_type media_bus_type = {
+@@ -205,6 +201,8 @@ static int media_release(struct inode *i
+ /* decrease the refcount unconditionally since the release()
+ return value is ignored. */
+ put_device(&devnode->dev);
++
++ pr_debug("%s: Media Release\n", __func__);
+ return 0;
+ }
+
+@@ -250,6 +248,7 @@ int __must_check media_devnode_register(
+ if (minor == MEDIA_NUM_DEVICES) {
+ mutex_unlock(&media_devnode_lock);
+ pr_err("could not get a free minor\n");
++ kfree(devnode);
+ return -ENFILE;
+ }
+
+@@ -259,27 +258,31 @@ int __must_check media_devnode_register(
+ devnode->minor = minor;
+ devnode->media_dev = mdev;
+
++ /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
++ devnode->dev.bus = &media_bus_type;
++ devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
++ devnode->dev.release = media_devnode_release;
++ if (devnode->parent)
++ devnode->dev.parent = devnode->parent;
++ dev_set_name(&devnode->dev, "media%d", devnode->minor);
++ device_initialize(&devnode->dev);
++
+ /* Part 2: Initialize and register the character device */
+ cdev_init(&devnode->cdev, &media_devnode_fops);
+ devnode->cdev.owner = owner;
++ devnode->cdev.kobj.parent = &devnode->dev.kobj;
+
+ ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1);
+ if (ret < 0) {
+ pr_err("%s: cdev_add failed\n", __func__);
+- goto error;
++ goto cdev_add_error;
+ }
+
+- /* Part 3: Register the media device */
+- devnode->dev.bus = &media_bus_type;
+- devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
+- devnode->dev.release = media_devnode_release;
+- if (devnode->parent)
+- devnode->dev.parent = devnode->parent;
+- dev_set_name(&devnode->dev, "media%d", devnode->minor);
+- ret = device_register(&devnode->dev);
++ /* Part 3: Add the media device */
++ ret = device_add(&devnode->dev);
+ if (ret < 0) {
+- pr_err("%s: device_register failed\n", __func__);
+- goto error;
++ pr_err("%s: device_add failed\n", __func__);
++ goto device_add_error;
+ }
+
+ /* Part 4: Activate this minor. The char device can now be used. */
+@@ -287,12 +290,15 @@ int __must_check media_devnode_register(
+
+ return 0;
+
+-error:
+- mutex_lock(&media_devnode_lock);
++device_add_error:
+ cdev_del(&devnode->cdev);
++cdev_add_error:
++ mutex_lock(&media_devnode_lock);
+ clear_bit(devnode->minor, media_devnode_nums);
++ devnode->media_dev = NULL;
+ mutex_unlock(&media_devnode_lock);
+
++ put_device(&devnode->dev);
+ return ret;
+ }
+
+@@ -314,8 +320,12 @@ void media_devnode_unregister(struct med
+
+ mutex_lock(&media_devnode_lock);
+ clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
++ /* Delete the cdev on this minor as well */
++ cdev_del(&devnode->cdev);
+ mutex_unlock(&media_devnode_lock);
+- device_unregister(&devnode->dev);
++ device_del(&devnode->dev);
++ devnode->media_dev = NULL;
++ put_device(&devnode->dev);
+ }
+
+ /*
diff --git a/queue-3.16/ptp-create-pins-together-with-the-rest-of-attributes.patch b/queue-3.16/ptp-create-pins-together-with-the-rest-of-attributes.patch
new file mode 100644
index 00000000..225ca16f
--- /dev/null
+++ b/queue-3.16/ptp-create-pins-together-with-the-rest-of-attributes.patch
@@ -0,0 +1,158 @@
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Tue, 14 Feb 2017 10:23:34 -0800
+Subject: ptp: create "pins" together with the rest of attributes
+
+commit 85a66e55019583da1e0f18706b7a8281c9f6de5b upstream.
+
+Let's switch to using device_create_with_groups(), which will allow us to
+create "pins" attribute group together with the rest of ptp device
+attributes, and before userspace gets notified about ptp device creation.
+
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[bwh: Backported to 3.16: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/ptp/ptp_clock.c | 20 +++++++++++---------
+ drivers/ptp/ptp_private.h | 7 ++++---
+ drivers/ptp/ptp_sysfs.c | 39 +++++++++------------------------------
+ 3 files changed, 24 insertions(+), 42 deletions(-)
+
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -210,16 +210,17 @@ struct ptp_clock *ptp_clock_register(str
+ mutex_init(&ptp->pincfg_mux);
+ init_waitqueue_head(&ptp->tsev_wq);
+
++ err = ptp_populate_pin_groups(ptp);
++ if (err)
++ goto no_pin_groups;
++
+ /* Create a new device in our class. */
+- ptp->dev = device_create(ptp_class, parent, ptp->devid, ptp,
+- "ptp%d", ptp->index);
++ ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid,
++ ptp, ptp->pin_attr_groups,
++ "ptp%d", ptp->index);
+ if (IS_ERR(ptp->dev))
+ goto no_device;
+
+- err = ptp_populate_sysfs(ptp);
+- if (err)
+- goto no_sysfs;
+-
+ /* Register a new PPS source. */
+ if (info->pps) {
+ struct pps_source_info pps;
+@@ -247,10 +248,10 @@ no_clock:
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+ no_pps:
+- ptp_cleanup_sysfs(ptp);
+-no_sysfs:
+ device_destroy(ptp_class, ptp->devid);
+ no_device:
++ ptp_cleanup_pin_groups(ptp);
++no_pin_groups:
+ mutex_destroy(&ptp->tsevq_mux);
+ mutex_destroy(&ptp->pincfg_mux);
+ no_slot:
+@@ -268,8 +269,9 @@ int ptp_clock_unregister(struct ptp_cloc
+ /* Release the clock's resources. */
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+- ptp_cleanup_sysfs(ptp);
++
+ device_destroy(ptp_class, ptp->devid);
++ ptp_cleanup_pin_groups(ptp);
+
+ posix_clock_unregister(&ptp->clock);
+ return 0;
+--- a/drivers/ptp/ptp_private.h
++++ b/drivers/ptp/ptp_private.h
+@@ -54,6 +54,8 @@ struct ptp_clock {
+ struct device_attribute *pin_dev_attr;
+ struct attribute **pin_attr;
+ struct attribute_group pin_attr_group;
++ /* 1st entry is a pointer to the real group, 2nd is NULL terminator */
++ const struct attribute_group *pin_attr_groups[2];
+ };
+
+ /*
+@@ -94,8 +96,7 @@ uint ptp_poll(struct posix_clock *pc,
+
+ extern const struct attribute_group *ptp_groups[];
+
+-int ptp_cleanup_sysfs(struct ptp_clock *ptp);
+-
+-int ptp_populate_sysfs(struct ptp_clock *ptp);
++int ptp_populate_pin_groups(struct ptp_clock *ptp);
++void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
+
+ #endif
+--- a/drivers/ptp/ptp_sysfs.c
++++ b/drivers/ptp/ptp_sysfs.c
+@@ -268,25 +268,14 @@ static ssize_t ptp_pin_store(struct devi
+ return count;
+ }
+
+-int ptp_cleanup_sysfs(struct ptp_clock *ptp)
++int ptp_populate_pin_groups(struct ptp_clock *ptp)
+ {
+- struct device *dev = ptp->dev;
+- struct ptp_clock_info *info = ptp->info;
+-
+- if (info->n_pins) {
+- sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group);
+- kfree(ptp->pin_attr);
+- kfree(ptp->pin_dev_attr);
+- }
+- return 0;
+-}
+-
+-static int ptp_populate_pins(struct ptp_clock *ptp)
+-{
+- struct device *dev = ptp->dev;
+ struct ptp_clock_info *info = ptp->info;
+ int err = -ENOMEM, i, n_pins = info->n_pins;
+
++ if (!n_pins)
++ return 0;
++
+ ptp->pin_dev_attr = kzalloc(n_pins * sizeof(*ptp->pin_dev_attr),
+ GFP_KERNEL);
+ if (!ptp->pin_dev_attr)
+@@ -310,28 +299,18 @@ static int ptp_populate_pins(struct ptp_
+ ptp->pin_attr_group.name = "pins";
+ ptp->pin_attr_group.attrs = ptp->pin_attr;
+
+- err = sysfs_create_group(&dev->kobj, &ptp->pin_attr_group);
+- if (err)
+- goto no_group;
++ ptp->pin_attr_groups[0] = &ptp->pin_attr_group;
++
+ return 0;
+
+-no_group:
+- kfree(ptp->pin_attr);
+ no_pin_attr:
+ kfree(ptp->pin_dev_attr);
+ no_dev_attr:
+ return err;
+ }
+
+-int ptp_populate_sysfs(struct ptp_clock *ptp)
++void ptp_cleanup_pin_groups(struct ptp_clock *ptp)
+ {
+- struct ptp_clock_info *info = ptp->info;
+- int err;
+-
+- if (info->n_pins) {
+- err = ptp_populate_pins(ptp);
+- if (err)
+- return err;
+- }
+- return 0;
++ kfree(ptp->pin_attr);
++ kfree(ptp->pin_dev_attr);
+ }
diff --git a/queue-3.16/ptp-do-not-explicitly-set-drvdata-in-ptp_clock_register.patch b/queue-3.16/ptp-do-not-explicitly-set-drvdata-in-ptp_clock_register.patch
new file mode 100644
index 00000000..9df60aaa
--- /dev/null
+++ b/queue-3.16/ptp-do-not-explicitly-set-drvdata-in-ptp_clock_register.patch
@@ -0,0 +1,28 @@
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Tue, 14 Feb 2017 10:23:31 -0800
+Subject: ptp: do not explicitly set drvdata in ptp_clock_register()
+
+commit 882f312dc0751c973db26478f07f082c584d16aa upstream.
+
+We do not need explicitly call dev_set_drvdata(), as it is done for us by
+device_create().
+
+Acked-by: Richard Cochran <richardcochran@gmail.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/ptp/ptp_clock.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -216,8 +216,6 @@ struct ptp_clock *ptp_clock_register(str
+ if (IS_ERR(ptp->dev))
+ goto no_device;
+
+- dev_set_drvdata(ptp->dev, ptp);
+-
+ err = ptp_populate_sysfs(ptp);
+ if (err)
+ goto no_sysfs;
diff --git a/queue-3.16/ptp-fix-pass-zero-to-err_ptr-in-ptp_clock_register.patch b/queue-3.16/ptp-fix-pass-zero-to-err_ptr-in-ptp_clock_register.patch
new file mode 100644
index 00000000..69fd5d85
--- /dev/null
+++ b/queue-3.16/ptp-fix-pass-zero-to-err_ptr-in-ptp_clock_register.patch
@@ -0,0 +1,45 @@
+From: YueHaibing <yuehaibing@huawei.com>
+Date: Fri, 23 Nov 2018 09:54:55 +0800
+Subject: ptp: Fix pass zero to ERR_PTR() in ptp_clock_register
+
+commit aea0a897af9e44c258e8ab9296fad417f1bc063a upstream.
+
+Fix smatch warning:
+
+drivers/ptp/ptp_clock.c:298 ptp_clock_register() warn:
+ passing zero to 'ERR_PTR'
+
+'err' should be set while device_create_with_groups and
+pps_register_source fails
+
+Fixes: 85a66e550195 ("ptp: create "pins" together with the rest of attributes")
+Signed-off-by: YueHaibing <yuehaibing@huawei.com>
+Acked-by: Richard Cochran <richardcochran@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/ptp/ptp_clock.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -218,8 +218,10 @@ struct ptp_clock *ptp_clock_register(str
+ ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid,
+ ptp, ptp->pin_attr_groups,
+ "ptp%d", ptp->index);
+- if (IS_ERR(ptp->dev))
++ if (IS_ERR(ptp->dev)) {
++ err = PTR_ERR(ptp->dev);
+ goto no_device;
++ }
+
+ /* Register a new PPS source. */
+ if (info->pps) {
+@@ -230,6 +232,7 @@ struct ptp_clock *ptp_clock_register(str
+ pps.owner = info->owner;
+ ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS);
+ if (!ptp->pps_source) {
++ err = -EINVAL;
+ pr_err("failed to register pps source\n");
+ goto no_pps;
+ }
diff --git a/queue-3.16/ptp-fix-the-race-between-the-release-of-ptp_clock-and-cdev.patch b/queue-3.16/ptp-fix-the-race-between-the-release-of-ptp_clock-and-cdev.patch
new file mode 100644
index 00000000..8090a6f5
--- /dev/null
+++ b/queue-3.16/ptp-fix-the-race-between-the-release-of-ptp_clock-and-cdev.patch
@@ -0,0 +1,314 @@
+From: Vladis Dronov <vdronov@redhat.com>
+Date: Fri, 27 Dec 2019 03:26:27 +0100
+Subject: ptp: fix the race between the release of ptp_clock and cdev
+
+commit a33121e5487b424339636b25c35d3a180eaa5f5e upstream.
+
+In a case when a ptp chardev (like /dev/ptp0) is open but an underlying
+device is removed, closing this file leads to a race. This reproduces
+easily in a kvm virtual machine:
+
+ts# cat openptp0.c
+int main() { ... fp = fopen("/dev/ptp0", "r"); ... sleep(10); }
+ts# uname -r
+5.5.0-rc3-46cf053e
+ts# cat /proc/cmdline
+... slub_debug=FZP
+ts# modprobe ptp_kvm
+ts# ./openptp0 &
+[1] 670
+opened /dev/ptp0, sleeping 10s...
+ts# rmmod ptp_kvm
+ts# ls /dev/ptp*
+ls: cannot access '/dev/ptp*': No such file or directory
+ts# ...woken up
+[ 48.010809] general protection fault: 0000 [#1] SMP
+[ 48.012502] CPU: 6 PID: 658 Comm: openptp0 Not tainted 5.5.0-rc3-46cf053e #25
+[ 48.014624] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), ...
+[ 48.016270] RIP: 0010:module_put.part.0+0x7/0x80
+[ 48.017939] RSP: 0018:ffffb3850073be00 EFLAGS: 00010202
+[ 48.018339] RAX: 000000006b6b6b6b RBX: 6b6b6b6b6b6b6b6b RCX: ffff89a476c00ad0
+[ 48.018936] RDX: fffff65a08d3ea08 RSI: 0000000000000247 RDI: 6b6b6b6b6b6b6b6b
+[ 48.019470] ... ^^^ a slub poison
+[ 48.023854] Call Trace:
+[ 48.024050] __fput+0x21f/0x240
+[ 48.024288] task_work_run+0x79/0x90
+[ 48.024555] do_exit+0x2af/0xab0
+[ 48.024799] ? vfs_write+0x16a/0x190
+[ 48.025082] do_group_exit+0x35/0x90
+[ 48.025387] __x64_sys_exit_group+0xf/0x10
+[ 48.025737] do_syscall_64+0x3d/0x130
+[ 48.026056] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 48.026479] RIP: 0033:0x7f53b12082f6
+[ 48.026792] ...
+[ 48.030945] Modules linked in: ptp i6300esb watchdog [last unloaded: ptp_kvm]
+[ 48.045001] Fixing recursive fault but reboot is needed!
+
+This happens in:
+
+static void __fput(struct file *file)
+{ ...
+ if (file->f_op->release)
+ file->f_op->release(inode, file); <<< cdev is kfree'd here
+ if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL &&
+ !(mode & FMODE_PATH))) {
+ cdev_put(inode->i_cdev); <<< cdev fields are accessed here
+
+Namely:
+
+__fput()
+ posix_clock_release()
+ kref_put(&clk->kref, delete_clock) <<< the last reference
+ delete_clock()
+ delete_ptp_clock()
+ kfree(ptp) <<< cdev is embedded in ptp
+ cdev_put
+ module_put(p->owner) <<< *p is kfree'd, bang!
+
+Here cdev is embedded in posix_clock which is embedded in ptp_clock.
+The race happens because ptp_clock's lifetime is controlled by two
+refcounts: kref and cdev.kobj in posix_clock. This is wrong.
+
+Make ptp_clock's sysfs device a parent of cdev with cdev_device_add()
+created especially for such cases. This way the parent device with its
+ptp_clock is not released until all references to the cdev are released.
+This adds a requirement that an initialized but not exposed struct
+device should be provided to posix_clock_register() by a caller instead
+of a simple dev_t.
+
+This approach was adopted from the commit 72139dfa2464 ("watchdog: Fix
+the race between the release of watchdog_core_data and cdev"). See
+details of the implementation in the commit 233ed09d7fda ("chardev: add
+helper function to register char devs with a struct device").
+
+Link: https://lore.kernel.org/linux-fsdevel/20191125125342.6189-1-vdronov@redhat.com/T/#u
+Analyzed-by: Stephen Johnston <sjohnsto@redhat.com>
+Analyzed-by: Vern Lovejoy <vlovejoy@redhat.com>
+Signed-off-by: Vladis Dronov <vdronov@redhat.com>
+Acked-by: Richard Cochran <richardcochran@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/ptp/ptp_clock.c | 31 ++++++++++++++-----------------
+ drivers/ptp/ptp_private.h | 2 +-
+ include/linux/posix-clock.h | 19 +++++++++++--------
+ kernel/time/posix-clock.c | 31 +++++++++++++------------------
+ 4 files changed, 39 insertions(+), 44 deletions(-)
+
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -167,9 +167,9 @@ static struct posix_clock_operations ptp
+ .read = ptp_read,
+ };
+
+-static void delete_ptp_clock(struct posix_clock *pc)
++static void ptp_clock_release(struct device *dev)
+ {
+- struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
++ struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
+
+ mutex_destroy(&ptp->tsevq_mux);
+ mutex_destroy(&ptp->pincfg_mux);
+@@ -201,7 +201,6 @@ struct ptp_clock *ptp_clock_register(str
+ }
+
+ ptp->clock.ops = ptp_clock_ops;
+- ptp->clock.release = delete_ptp_clock;
+ ptp->info = info;
+ ptp->devid = MKDEV(major, index);
+ ptp->index = index;
+@@ -214,15 +213,6 @@ struct ptp_clock *ptp_clock_register(str
+ if (err)
+ goto no_pin_groups;
+
+- /* Create a new device in our class. */
+- ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid,
+- ptp, ptp->pin_attr_groups,
+- "ptp%d", ptp->index);
+- if (IS_ERR(ptp->dev)) {
+- err = PTR_ERR(ptp->dev);
+- goto no_device;
+- }
+-
+ /* Register a new PPS source. */
+ if (info->pps) {
+ struct pps_source_info pps;
+@@ -238,8 +228,18 @@ struct ptp_clock *ptp_clock_register(str
+ }
+ }
+
+- /* Create a posix clock. */
+- err = posix_clock_register(&ptp->clock, ptp->devid);
++ /* Initialize a new device of our class in our clock structure. */
++ device_initialize(&ptp->dev);
++ ptp->dev.devt = ptp->devid;
++ ptp->dev.class = ptp_class;
++ ptp->dev.parent = parent;
++ ptp->dev.groups = ptp->pin_attr_groups;
++ ptp->dev.release = ptp_clock_release;
++ dev_set_drvdata(&ptp->dev, ptp);
++ dev_set_name(&ptp->dev, "ptp%d", ptp->index);
++
++ /* Create a posix clock and link it to the device. */
++ err = posix_clock_register(&ptp->clock, &ptp->dev);
+ if (err) {
+ pr_err("failed to create posix clock\n");
+ goto no_clock;
+@@ -251,8 +251,6 @@ no_clock:
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+ no_pps:
+- device_destroy(ptp_class, ptp->devid);
+-no_device:
+ ptp_cleanup_pin_groups(ptp);
+ no_pin_groups:
+ mutex_destroy(&ptp->tsevq_mux);
+@@ -273,7 +271,6 @@ int ptp_clock_unregister(struct ptp_cloc
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+
+- device_destroy(ptp_class, ptp->devid);
+ ptp_cleanup_pin_groups(ptp);
+
+ posix_clock_unregister(&ptp->clock);
+--- a/drivers/ptp/ptp_private.h
++++ b/drivers/ptp/ptp_private.h
+@@ -40,7 +40,7 @@ struct timestamp_event_queue {
+
+ struct ptp_clock {
+ struct posix_clock clock;
+- struct device *dev;
++ struct device dev;
+ struct ptp_clock_info *info;
+ dev_t devid;
+ int index; /* index into clocks.map */
+--- a/include/linux/posix-clock.h
++++ b/include/linux/posix-clock.h
+@@ -104,29 +104,32 @@ struct posix_clock_operations {
+ *
+ * @ops: Functional interface to the clock
+ * @cdev: Character device instance for this clock
+- * @kref: Reference count.
++ * @dev: Pointer to the clock's device.
+ * @rwsem: Protects the 'zombie' field from concurrent access.
+ * @zombie: If 'zombie' is true, then the hardware has disappeared.
+- * @release: A function to free the structure when the reference count reaches
+- * zero. May be NULL if structure is statically allocated.
+ *
+ * Drivers should embed their struct posix_clock within a private
+ * structure, obtaining a reference to it during callbacks using
+ * container_of().
++ *
++ * Drivers should supply an initialized but not exposed struct device
++ * to posix_clock_register(). It is used to manage lifetime of the
++ * driver's private structure. It's 'release' field should be set to
++ * a release function for this private structure.
+ */
+ struct posix_clock {
+ struct posix_clock_operations ops;
+ struct cdev cdev;
+- struct kref kref;
++ struct device *dev;
+ struct rw_semaphore rwsem;
+ bool zombie;
+- void (*release)(struct posix_clock *clk);
+ };
+
+ /**
+ * posix_clock_register() - register a new clock
+- * @clk: Pointer to the clock. Caller must provide 'ops' and 'release'
+- * @devid: Allocated device id
++ * @clk: Pointer to the clock. Caller must provide 'ops' field
++ * @dev: Pointer to the initialized device. Caller must provide
++ * 'release' field
+ *
+ * A clock driver calls this function to register itself with the
+ * clock device subsystem. If 'clk' points to dynamically allocated
+@@ -135,7 +138,7 @@ struct posix_clock {
+ *
+ * Returns zero on success, non-zero otherwise.
+ */
+-int posix_clock_register(struct posix_clock *clk, dev_t devid);
++int posix_clock_register(struct posix_clock *clk, struct device *dev);
+
+ /**
+ * posix_clock_unregister() - unregister a clock
+--- a/kernel/time/posix-clock.c
++++ b/kernel/time/posix-clock.c
+@@ -25,8 +25,6 @@
+ #include <linux/syscalls.h>
+ #include <linux/uaccess.h>
+
+-static void delete_clock(struct kref *kref);
+-
+ /*
+ * Returns NULL if the posix_clock instance attached to 'fp' is old and stale.
+ */
+@@ -168,7 +166,7 @@ static int posix_clock_open(struct inode
+ err = 0;
+
+ if (!err) {
+- kref_get(&clk->kref);
++ get_device(clk->dev);
+ fp->private_data = clk;
+ }
+ out:
+@@ -184,7 +182,7 @@ static int posix_clock_release(struct in
+ if (clk->ops.release)
+ err = clk->ops.release(clk);
+
+- kref_put(&clk->kref, delete_clock);
++ put_device(clk->dev);
+
+ fp->private_data = NULL;
+
+@@ -206,38 +204,35 @@ static const struct file_operations posi
+ #endif
+ };
+
+-int posix_clock_register(struct posix_clock *clk, dev_t devid)
++int posix_clock_register(struct posix_clock *clk, struct device *dev)
+ {
+ int err;
+
+- kref_init(&clk->kref);
+ init_rwsem(&clk->rwsem);
+
+ cdev_init(&clk->cdev, &posix_clock_file_operations);
++ err = cdev_device_add(&clk->cdev, dev);
++ if (err) {
++ pr_err("%s unable to add device %d:%d\n",
++ dev_name(dev), MAJOR(dev->devt), MINOR(dev->devt));
++ return err;
++ }
+ clk->cdev.owner = clk->ops.owner;
+- err = cdev_add(&clk->cdev, devid, 1);
++ clk->dev = dev;
+
+- return err;
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(posix_clock_register);
+
+-static void delete_clock(struct kref *kref)
+-{
+- struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
+-
+- if (clk->release)
+- clk->release(clk);
+-}
+-
+ void posix_clock_unregister(struct posix_clock *clk)
+ {
+- cdev_del(&clk->cdev);
++ cdev_device_del(&clk->cdev, clk->dev);
+
+ down_write(&clk->rwsem);
+ clk->zombie = true;
+ up_write(&clk->rwsem);
+
+- kref_put(&clk->kref, delete_clock);
++ put_device(clk->dev);
+ }
+ EXPORT_SYMBOL_GPL(posix_clock_unregister);
+
diff --git a/queue-3.16/ptp-free-ptp-device-pin-descriptors-properly.patch b/queue-3.16/ptp-free-ptp-device-pin-descriptors-properly.patch
new file mode 100644
index 00000000..ab725d54
--- /dev/null
+++ b/queue-3.16/ptp-free-ptp-device-pin-descriptors-properly.patch
@@ -0,0 +1,48 @@
+From: Vladis Dronov <vdronov@redhat.com>
+Date: Mon, 13 Jan 2020 14:00:09 +0100
+Subject: ptp: free ptp device pin descriptors properly
+
+commit 75718584cb3c64e6269109d4d54f888ac5a5fd15 upstream.
+
+There is a bug in ptp_clock_unregister(), where ptp_cleanup_pin_groups()
+first frees ptp->pin_{,dev_}attr, but then posix_clock_unregister() needs
+them to destroy a related sysfs device.
+
+These functions can not be just swapped, as posix_clock_unregister() frees
+ptp which is needed in the ptp_cleanup_pin_groups(). Fix this by calling
+ptp_cleanup_pin_groups() in ptp_clock_release(), right before ptp is freed.
+
+This makes this patch fix an UAF bug in a patch which fixes an UAF bug.
+
+Reported-by: Antti Laakso <antti.laakso@intel.com>
+Fixes: a33121e5487b ("ptp: fix the race between the release of ptp_clock and cdev")
+Link: https://lore.kernel.org/netdev/3d2bd09735dbdaf003585ca376b7c1e5b69a19bd.camel@intel.com/
+Signed-off-by: Vladis Dronov <vdronov@redhat.com>
+Acked-by: Richard Cochran <richardcochran@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/ptp/ptp_clock.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -171,6 +171,7 @@ static void ptp_clock_release(struct dev
+ {
+ struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
+
++ ptp_cleanup_pin_groups(ptp);
+ mutex_destroy(&ptp->tsevq_mux);
+ mutex_destroy(&ptp->pincfg_mux);
+ ida_simple_remove(&ptp_clocks_map, ptp->index);
+@@ -271,9 +272,8 @@ int ptp_clock_unregister(struct ptp_cloc
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+
+- ptp_cleanup_pin_groups(ptp);
+-
+ posix_clock_unregister(&ptp->clock);
++
+ return 0;
+ }
+ EXPORT_SYMBOL(ptp_clock_unregister);
diff --git a/queue-3.16/ptp-use-is_visible-method-to-hide-unused-attributes.patch b/queue-3.16/ptp-use-is_visible-method-to-hide-unused-attributes.patch
new file mode 100644
index 00000000..a559264a
--- /dev/null
+++ b/queue-3.16/ptp-use-is_visible-method-to-hide-unused-attributes.patch
@@ -0,0 +1,206 @@
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Tue, 14 Feb 2017 10:23:33 -0800
+Subject: ptp: use is_visible method to hide unused attributes
+
+commit af59e717d5ff9c8dbf9bcc581c0dfb3b2a9c9030 upstream.
+
+Instead of creating selected attributes after the device is created (and
+after userspace potentially seen uevent), lets use attribute group
+is_visible() method to control which attributes are shown. This will allow
+us to create all attributes (except "pins" group, which will be taken care
+of later) before userspace gets notified about new ptp class device.
+
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/ptp/ptp_sysfs.c | 125 ++++++++++++++++++----------------------
+ 1 file changed, 55 insertions(+), 70 deletions(-)
+
+--- a/drivers/ptp/ptp_sysfs.c
++++ b/drivers/ptp/ptp_sysfs.c
+@@ -46,27 +46,6 @@ PTP_SHOW_INT(n_periodic_outputs, n_per_o
+ PTP_SHOW_INT(n_programmable_pins, n_pins);
+ PTP_SHOW_INT(pps_available, pps);
+
+-static struct attribute *ptp_attrs[] = {
+- &dev_attr_clock_name.attr,
+- &dev_attr_max_adjustment.attr,
+- &dev_attr_n_alarms.attr,
+- &dev_attr_n_external_timestamps.attr,
+- &dev_attr_n_periodic_outputs.attr,
+- &dev_attr_n_programmable_pins.attr,
+- &dev_attr_pps_available.attr,
+- NULL,
+-};
+-
+-static const struct attribute_group ptp_group = {
+- .attrs = ptp_attrs,
+-};
+-
+-const struct attribute_group *ptp_groups[] = {
+- &ptp_group,
+- NULL,
+-};
+-
+-
+ static ssize_t extts_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+@@ -91,6 +70,7 @@ static ssize_t extts_enable_store(struct
+ out:
+ return err;
+ }
++static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
+
+ static ssize_t extts_fifo_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+@@ -124,6 +104,7 @@ out:
+ mutex_unlock(&ptp->tsevq_mux);
+ return cnt;
+ }
++static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
+
+ static ssize_t period_store(struct device *dev,
+ struct device_attribute *attr,
+@@ -151,6 +132,7 @@ static ssize_t period_store(struct devic
+ out:
+ return err;
+ }
++static DEVICE_ATTR(period, 0220, NULL, period_store);
+
+ static ssize_t pps_enable_store(struct device *dev,
+ struct device_attribute *attr,
+@@ -177,6 +159,57 @@ static ssize_t pps_enable_store(struct d
+ out:
+ return err;
+ }
++static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
++
++static struct attribute *ptp_attrs[] = {
++ &dev_attr_clock_name.attr,
++
++ &dev_attr_max_adjustment.attr,
++ &dev_attr_n_alarms.attr,
++ &dev_attr_n_external_timestamps.attr,
++ &dev_attr_n_periodic_outputs.attr,
++ &dev_attr_n_programmable_pins.attr,
++ &dev_attr_pps_available.attr,
++
++ &dev_attr_extts_enable.attr,
++ &dev_attr_fifo.attr,
++ &dev_attr_period.attr,
++ &dev_attr_pps_enable.attr,
++ NULL
++};
++
++static umode_t ptp_is_attribute_visible(struct kobject *kobj,
++ struct attribute *attr, int n)
++{
++ struct device *dev = kobj_to_dev(kobj);
++ struct ptp_clock *ptp = dev_get_drvdata(dev);
++ struct ptp_clock_info *info = ptp->info;
++ umode_t mode = attr->mode;
++
++ if (attr == &dev_attr_extts_enable.attr ||
++ attr == &dev_attr_fifo.attr) {
++ if (!info->n_ext_ts)
++ mode = 0;
++ } else if (attr == &dev_attr_period.attr) {
++ if (!info->n_per_out)
++ mode = 0;
++ } else if (attr == &dev_attr_pps_enable.attr) {
++ if (!info->pps)
++ mode = 0;
++ }
++
++ return mode;
++}
++
++static const struct attribute_group ptp_group = {
++ .is_visible = ptp_is_attribute_visible,
++ .attrs = ptp_attrs,
++};
++
++const struct attribute_group *ptp_groups[] = {
++ &ptp_group,
++ NULL
++};
+
+ static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name)
+ {
+@@ -235,26 +268,11 @@ static ssize_t ptp_pin_store(struct devi
+ return count;
+ }
+
+-static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
+-static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
+-static DEVICE_ATTR(period, 0220, NULL, period_store);
+-static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
+-
+ int ptp_cleanup_sysfs(struct ptp_clock *ptp)
+ {
+ struct device *dev = ptp->dev;
+ struct ptp_clock_info *info = ptp->info;
+
+- if (info->n_ext_ts) {
+- device_remove_file(dev, &dev_attr_extts_enable);
+- device_remove_file(dev, &dev_attr_fifo);
+- }
+- if (info->n_per_out)
+- device_remove_file(dev, &dev_attr_period);
+-
+- if (info->pps)
+- device_remove_file(dev, &dev_attr_pps_enable);
+-
+ if (info->n_pins) {
+ sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group);
+ kfree(ptp->pin_attr);
+@@ -307,46 +325,13 @@ no_dev_attr:
+
+ int ptp_populate_sysfs(struct ptp_clock *ptp)
+ {
+- struct device *dev = ptp->dev;
+ struct ptp_clock_info *info = ptp->info;
+ int err;
+
+- if (info->n_ext_ts) {
+- err = device_create_file(dev, &dev_attr_extts_enable);
+- if (err)
+- goto out1;
+- err = device_create_file(dev, &dev_attr_fifo);
+- if (err)
+- goto out2;
+- }
+- if (info->n_per_out) {
+- err = device_create_file(dev, &dev_attr_period);
+- if (err)
+- goto out3;
+- }
+- if (info->pps) {
+- err = device_create_file(dev, &dev_attr_pps_enable);
+- if (err)
+- goto out4;
+- }
+ if (info->n_pins) {
+ err = ptp_populate_pins(ptp);
+ if (err)
+- goto out5;
++ return err;
+ }
+ return 0;
+-out5:
+- if (info->pps)
+- device_remove_file(dev, &dev_attr_pps_enable);
+-out4:
+- if (info->n_per_out)
+- device_remove_file(dev, &dev_attr_period);
+-out3:
+- if (info->n_ext_ts)
+- device_remove_file(dev, &dev_attr_fifo);
+-out2:
+- if (info->n_ext_ts)
+- device_remove_file(dev, &dev_attr_extts_enable);
+-out1:
+- return err;
+ }
diff --git a/queue-3.16/series b/queue-3.16/series
index dab52b70..a676e4a8 100644
--- a/queue-3.16/series
+++ b/queue-3.16/series
@@ -227,3 +227,19 @@ mm-mempolicy-require-at-least-one-nodeid-for-mpol_preferred.patch
media-ov519-add-missing-endpoint-sanity-checks.patch
media-stv06xx-add-missing-descriptor-sanity-checks.patch
media-xirlink_cit-add-missing-descriptor-sanity-checks.patch
+ptp-do-not-explicitly-set-drvdata-in-ptp_clock_register.patch
+ptp-use-is_visible-method-to-hide-unused-attributes.patch
+ptp-create-pins-together-with-the-rest-of-attributes.patch
+chardev-add-helper-function-to-register-char-devs-with-a-struct.patch
+ptp-fix-pass-zero-to-err_ptr-in-ptp_clock_register.patch
+ptp-fix-the-race-between-the-release-of-ptp_clock-and-cdev.patch
+ptp-free-ptp-device-pin-descriptors-properly.patch
+media-devnode-just-return-0-instead-of-using-a-var.patch
+media-fix-media_open-to-clear-filp-private_data-in-error.patch
+drivers-media-media-devnode-clear-private_data-before.patch
+media-devnode-add-missing-mutex-lock-in-error-handler.patch
+media-devnode-fix-namespace-mess.patch
+media-device-dynamically-allocate-struct-media_devnode.patch
+media-fix-use-after-free-in-cdev_put-when-app-exits-after.patch
+media-fix-media-devnode-ioctl-syscall-and-unregister-race.patch
+slcan-don-t-transmit-uninitialized-stack-data-in-padding.patch
diff --git a/queue-3.16/slcan-don-t-transmit-uninitialized-stack-data-in-padding.patch b/queue-3.16/slcan-don-t-transmit-uninitialized-stack-data-in-padding.patch
new file mode 100644
index 00000000..b858b070
--- /dev/null
+++ b/queue-3.16/slcan-don-t-transmit-uninitialized-stack-data-in-padding.patch
@@ -0,0 +1,48 @@
+From: Richard Palethorpe <rpalethorpe@suse.com>
+Date: Wed, 1 Apr 2020 12:06:39 +0200
+Subject: slcan: Don't transmit uninitialized stack data in padding
+
+commit b9258a2cece4ec1f020715fe3554bc2e360f6264 upstream.
+
+struct can_frame contains some padding which is not explicitly zeroed in
+slc_bump. This uninitialized data will then be transmitted if the stack
+initialization hardening feature is not enabled (CONFIG_INIT_STACK_ALL).
+
+This commit just zeroes the whole struct including the padding.
+
+Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
+Fixes: a1044e36e457 ("can: add slcan driver for serial/USB-serial CAN adapters")
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Cc: linux-can@vger.kernel.org
+Cc: netdev@vger.kernel.org
+Cc: security@kernel.org
+Cc: wg@grandegger.com
+Cc: mkl@pengutronix.de
+Cc: davem@davemloft.net
+Acked-by: Marc Kleine-Budde <mkl@pengutronix.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/net/can/slcan.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/net/can/slcan.c
++++ b/drivers/net/can/slcan.c
+@@ -150,7 +150,7 @@ static void slc_bump(struct slcan *sl)
+ u32 tmpid;
+ char *cmd = sl->rbuff;
+
+- cf.can_id = 0;
++ memset(&cf, 0, sizeof(cf));
+
+ switch (*cmd) {
+ case 'r':
+@@ -189,8 +189,6 @@ static void slc_bump(struct slcan *sl)
+ else
+ return;
+
+- *(u64 *) (&cf.data) = 0; /* clear payload */
+-
+ /* RTR frames may have a dlc > 0 but they never have any data bytes */
+ if (!(cf.can_id & CAN_RTR_FLAG)) {
+ for (i = 0; i < cf.can_dlc; i++) {