Skip to content

Commit

Permalink
driver core: add uid and gid to devtmpfs
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
kaysievers authored and gregkh committed Apr 8, 2013
1 parent bb2b005 commit 3c2670e
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 18 deletions.
3 changes: 2 additions & 1 deletion block/genhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
17 changes: 13 additions & 4 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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.
Expand All @@ -1289,15 +1297,16 @@ 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;

*tmp = NULL;

/* 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;

Expand Down
27 changes: 17 additions & 10 deletions drivers/base/devtmpfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
7 changes: 5 additions & 2 deletions include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 3c2670e

Please sign in to comment.