driver core: add uid and gid to devtmpfs
authorKay Sievers <kay@vrfy.org>
Sat, 6 Apr 2013 16:56:00 +0000 (09:56 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Apr 2013 15:21:48 +0000 (08:21 -0700)
Some drivers want to tell userspace what uid and gid should be used for
their device nodes, so allow that information to percolate through the
driver core to userspace in order to make this happen.  This means that
some systems (i.e.  Android and friends) will not need to even run a
udev-like daemon for their device node manager and can just rely in
devtmpfs fully, reducing their footprint even more.

Signed-off-by: Kay Sievers <kay@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
block/genhd.c
drivers/base/core.c
drivers/base/devtmpfs.c
drivers/usb/core/usb.c
include/linux/device.h

index 3c001fba80c76f3f6a22296d07a9f94cc60044a1..dfcec431ceeaa0c0f4232b390d76f170d7120213 100644 (file)
@@ -1111,7 +1111,8 @@ struct class block_class = {
        .name           = "block",
 };
 
-static char *block_devnode(struct device *dev, umode_t *mode)
+static char *block_devnode(struct device *dev, umode_t *mode,
+                          uid_t *uid, gid_t *gid)
 {
        struct gendisk *disk = dev_to_disk(dev);
 
index a7391a30cb294ab7fbc405b6f5b2496654626dc2..8a428b51089df72099733eaf99188d3e4d5ca209 100644 (file)
@@ -283,15 +283,21 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
                const char *tmp;
                const char *name;
                umode_t mode = 0;
+               uid_t uid = 0;
+               gid_t gid = 0;
 
                add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
                add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
-               name = device_get_devnode(dev, &mode, &tmp);
+               name = device_get_devnode(dev, &mode, &uid, &gid, &tmp);
                if (name) {
                        add_uevent_var(env, "DEVNAME=%s", name);
-                       kfree(tmp);
                        if (mode)
                                add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
+                       if (uid)
+                               add_uevent_var(env, "DEVUID=%u", uid);
+                       if (gid)
+                               add_uevent_var(env, "DEVGID=%u", gid);
+                       kfree(tmp);
                }
        }
 
@@ -1281,6 +1287,8 @@ static struct device *next_device(struct klist_iter *i)
  * device_get_devnode - path of device node file
  * @dev: device
  * @mode: returned file access mode
+ * @uid: returned file owner
+ * @gid: returned file group
  * @tmp: possibly allocated string
  *
  * Return the relative path of a possible device node.
@@ -1289,7 +1297,8 @@ static struct device *next_device(struct klist_iter *i)
  * freed by the caller.
  */
 const char *device_get_devnode(struct device *dev,
-                              umode_t *mode, const char **tmp)
+                              umode_t *mode, uid_t *uid, gid_t *gid,
+                              const char **tmp)
 {
        char *s;
 
@@ -1297,7 +1306,7 @@ const char *device_get_devnode(struct device *dev,
 
        /* the device type may provide a specific name */
        if (dev->type && dev->type->devnode)
-               *tmp = dev->type->devnode(dev, mode);
+               *tmp = dev->type->devnode(dev, mode, uid, gid);
        if (*tmp)
                return *tmp;
 
index 01fc5b07f951f81e6521e9c89af797f9838d165b..fda52563677f8712f2ea104ee551977b7fb1625f 100644 (file)
@@ -41,6 +41,8 @@ static struct req {
        int err;
        const char *name;
        umode_t mode;   /* 0 => delete */
+       uid_t uid;
+       gid_t gid;
        struct device *dev;
 } *requests;
 
@@ -85,7 +87,9 @@ int devtmpfs_create_node(struct device *dev)
                return 0;
 
        req.mode = 0;
-       req.name = device_get_devnode(dev, &req.mode, &tmp);
+       req.uid = 0;
+       req.gid = 0;
+       req.name = device_get_devnode(dev, &req.mode, &req.uid, &req.gid, &tmp);
        if (!req.name)
                return -ENOMEM;
 
@@ -121,7 +125,7 @@ int devtmpfs_delete_node(struct device *dev)
        if (!thread)
                return 0;
 
-       req.name = device_get_devnode(dev, NULL, &tmp);
+       req.name = device_get_devnode(dev, NULL, NULL, NULL, &tmp);
        if (!req.name)
                return -ENOMEM;
 
@@ -187,7 +191,8 @@ static int create_path(const char *nodepath)
        return err;
 }
 
-static int handle_create(const char *nodename, umode_t mode, struct device *dev)
+static int handle_create(const char *nodename, umode_t mode, uid_t uid,
+                        gid_t gid, struct device *dev)
 {
        struct dentry *dentry;
        struct path path;
@@ -201,14 +206,14 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
-       err = vfs_mknod(path.dentry->d_inode,
-                       dentry, mode, dev->devt);
+       err = vfs_mknod(path.dentry->d_inode, dentry, mode, dev->devt);
        if (!err) {
                struct iattr newattrs;
 
-               /* fixup possibly umasked mode */
                newattrs.ia_mode = mode;
-               newattrs.ia_valid = ATTR_MODE;
+               newattrs.ia_uid = uid;
+               newattrs.ia_gid = gid;
+               newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
                mutex_lock(&dentry->d_inode->i_mutex);
                notify_change(dentry, &newattrs);
                mutex_unlock(&dentry->d_inode->i_mutex);
@@ -358,10 +363,11 @@ int devtmpfs_mount(const char *mntdir)
 
 static DECLARE_COMPLETION(setup_done);
 
-static int handle(const char *name, umode_t mode, struct device *dev)
+static int handle(const char *name, umode_t mode, uid_t uid, gid_t gid,
+                 struct device *dev)
 {
        if (mode)
-               return handle_create(name, mode, dev);
+               return handle_create(name, mode, uid, gid, dev);
        else
                return handle_remove(name, dev);
 }
@@ -387,7 +393,8 @@ static int devtmpfsd(void *p)
                        spin_unlock(&req_lock);
                        while (req) {
                                struct req *next = req->next;
-                               req->err = handle(req->name, req->mode, req->dev);
+                               req->err = handle(req->name, req->mode,
+                                                 req->uid, req->gid, req->dev);
                                complete(&req->done);
                                req = next;
                        }
index f81b92572735449b53e5c464ca12d38b314e1029..17002832abd9dbe6815120e5118432e39eaaed82 100644 (file)
@@ -317,7 +317,8 @@ static const struct dev_pm_ops usb_device_pm_ops = {
 #endif /* CONFIG_PM */
 
 
-static char *usb_devnode(struct device *dev, umode_t *mode)
+static char *usb_devnode(struct device *dev,
+                        umode_t *mode, uid_t *uid, gid_t *gid)
 {
        struct usb_device *usb_dev;
 
index 4a7c4a84afee76bab4751d81bc724efe5646ccd3..851b85c7101e8412b6eb50d967205838a9b35622 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pm.h>
 #include <linux/atomic.h>
 #include <linux/ratelimit.h>
+#include <linux/uidgid.h>
 #include <asm/device.h>
 
 struct device;
@@ -465,7 +466,8 @@ struct device_type {
        const char *name;
        const struct attribute_group **groups;
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
-       char *(*devnode)(struct device *dev, umode_t *mode);
+       char *(*devnode)(struct device *dev, umode_t *mode,
+                        uid_t *uid, gid_t *gid);
        void (*release)(struct device *dev);
 
        const struct dev_pm_ops *pm;
@@ -843,7 +845,8 @@ extern int device_rename(struct device *dev, const char *new_name);
 extern int device_move(struct device *dev, struct device *new_parent,
                       enum dpm_order dpm_order);
 extern const char *device_get_devnode(struct device *dev,
-                                     umode_t *mode, const char **tmp);
+                                     umode_t *mode, uid_t *uid, gid_t *gid,
+                                     const char **tmp);
 extern void *dev_get_drvdata(const struct device *dev);
 extern int dev_set_drvdata(struct device *dev, void *data);