Skip to content

Commit

Permalink
Driver-Core: extend devnode callbacks to provide permissions
Browse files Browse the repository at this point in the history
This allows subsytems to provide devtmpfs with non-default permissions
for the device node. Instead of the default mode of 0600, null, zero,
random, urandom, full, tty, ptmx now have a mode of 0666, which allows
non-privileged processes to access standard device nodes in case no
other userspace process applies the expected permissions.

This also fixes a wrong assignment in pktcdvd and a checkpatch.pl complain.

Signed-off-by: Kay Sievers <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
kaysievers authored and Live-CD User committed Sep 19, 2009
1 parent 78f28b7 commit e454cea
Show file tree
Hide file tree
Showing 30 changed files with 116 additions and 79 deletions.
4 changes: 2 additions & 2 deletions arch/x86/kernel/cpuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ static struct notifier_block __refdata cpuid_class_cpu_notifier =
.notifier_call = cpuid_class_cpu_callback,
};

static char *cpuid_nodename(struct device *dev)
static char *cpuid_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
}
Expand All @@ -203,7 +203,7 @@ static int __init cpuid_init(void)
err = PTR_ERR(cpuid_class);
goto out_chrdev;
}
cpuid_class->nodename = cpuid_nodename;
cpuid_class->devnode = cpuid_devnode;
for_each_online_cpu(i) {
err = cpuid_device_create(i);
if (err != 0)
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kernel/microcode_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static const struct file_operations microcode_fops = {
static struct miscdevice microcode_dev = {
.minor = MICROCODE_MINOR,
.name = "microcode",
.devnode = "cpu/microcode",
.nodename = "cpu/microcode",
.fops = &microcode_fops,
};

Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/msr.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ static struct notifier_block __refdata msr_class_cpu_notifier = {
.notifier_call = msr_class_cpu_callback,
};

static char *msr_nodename(struct device *dev)
static char *msr_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
}
Expand All @@ -262,7 +262,7 @@ static int __init msr_init(void)
err = PTR_ERR(msr_class);
goto out_chrdev;
}
msr_class->nodename = msr_nodename;
msr_class->devnode = msr_devnode;
for_each_online_cpu(i) {
err = msr_device_create(i);
if (err != 0)
Expand Down
4 changes: 2 additions & 2 deletions block/bsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ EXPORT_SYMBOL_GPL(bsg_register_queue);

static struct cdev bsg_cdev;

static char *bsg_nodename(struct device *dev)
static char *bsg_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev));
}
Expand All @@ -1087,7 +1087,7 @@ static int __init bsg_init(void)
ret = PTR_ERR(bsg_class);
goto destroy_kmemcache;
}
bsg_class->nodename = bsg_nodename;
bsg_class->devnode = bsg_devnode;

ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg");
if (ret)
Expand Down
8 changes: 4 additions & 4 deletions block/genhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -998,20 +998,20 @@ struct class block_class = {
.name = "block",
};

static char *block_nodename(struct device *dev)
static char *block_devnode(struct device *dev, mode_t *mode)
{
struct gendisk *disk = dev_to_disk(dev);

if (disk->nodename)
return disk->nodename(disk);
if (disk->devnode)
return disk->devnode(disk, mode);
return NULL;
}

static struct device_type disk_type = {
.name = "disk",
.groups = disk_attr_groups,
.release = disk_release,
.nodename = block_nodename,
.devnode = block_devnode,
};

#ifdef CONFIG_PROC_FS
Expand Down
19 changes: 12 additions & 7 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
if (MAJOR(dev->devt)) {
const char *tmp;
const char *name;
mode_t mode = 0;

add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
name = device_get_nodename(dev, &tmp);
name = device_get_devnode(dev, &mode, &tmp);
if (name) {
add_uevent_var(env, "DEVNAME=%s", name);
kfree(tmp);
if (mode)
add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
}
}

Expand Down Expand Up @@ -1148,30 +1151,32 @@ static struct device *next_device(struct klist_iter *i)
}

/**
* device_get_nodename - path of device node file
* device_get_devnode - path of device node file
* @dev: device
* @mode: returned file access mode
* @tmp: possibly allocated string
*
* Return the relative path of a possible device node.
* Non-default names may need to allocate a memory to compose
* a name. This memory is returned in tmp and needs to be
* freed by the caller.
*/
const char *device_get_nodename(struct device *dev, const char **tmp)
const char *device_get_devnode(struct device *dev,
mode_t *mode, const char **tmp)
{
char *s;

*tmp = NULL;

/* the device type may provide a specific name */
if (dev->type && dev->type->nodename)
*tmp = dev->type->nodename(dev);
if (dev->type && dev->type->devnode)
*tmp = dev->type->devnode(dev, mode);
if (*tmp)
return *tmp;

/* the class may provide a specific name */
if (dev->class && dev->class->nodename)
*tmp = dev->class->nodename(dev);
if (dev->class && dev->class->devnode)
*tmp = dev->class->devnode(dev, mode);
if (*tmp)
return *tmp;

Expand Down
24 changes: 16 additions & 8 deletions drivers/base/devtmpfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
* During bootup, before any driver core device is registered,
* devtmpfs, a tmpfs-based filesystem is created. Every driver-core
* device which requests a device node, will add a node in this
* filesystem. The node is named after the the name of the device,
* or the susbsytem can provide a custom name. All devices are
* owned by root and have a mode of 0600.
* filesystem.
* By default, all devices are named after the the name of the
* device, owned by root and have a default mode of 0600. Subsystems
* can overwrite the default setting if needed.
*/

#include <linux/kernel.h>
Expand All @@ -20,6 +21,7 @@
#include <linux/fs.h>
#include <linux/shmem_fs.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/init_task.h>

static struct vfsmount *dev_mnt;
Expand Down Expand Up @@ -134,22 +136,24 @@ int devtmpfs_create_node(struct device *dev)
const char *tmp = NULL;
const char *nodename;
const struct cred *curr_cred;
mode_t mode;
mode_t mode = 0;
struct nameidata nd;
struct dentry *dentry;
int err;

if (!dev_mnt)
return 0;

nodename = device_get_nodename(dev, &tmp);
nodename = device_get_devnode(dev, &mode, &tmp);
if (!nodename)
return -ENOMEM;

if (mode == 0)
mode = 0600;
if (is_blockdev(dev))
mode = S_IFBLK|0600;
mode |= S_IFBLK;
else
mode = S_IFCHR|0600;
mode |= S_IFCHR;

curr_cred = override_creds(&init_cred);
err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
Expand All @@ -165,8 +169,12 @@ int devtmpfs_create_node(struct device *dev)

dentry = lookup_create(&nd, 0);
if (!IS_ERR(dentry)) {
int umask;

umask = sys_umask(0000);
err = vfs_mknod(nd.path.dentry->d_inode,
dentry, mode, dev->devt);
sys_umask(umask);
/* mark as kernel created inode */
if (!err)
dentry->d_inode->i_private = &dev_mnt;
Expand Down Expand Up @@ -271,7 +279,7 @@ int devtmpfs_delete_node(struct device *dev)
if (!dev_mnt)
return 0;

nodename = device_get_nodename(dev, &tmp);
nodename = device_get_devnode(dev, NULL, &tmp);
if (!nodename)
return -ENOMEM;

Expand Down
4 changes: 2 additions & 2 deletions drivers/block/aoe/aoechr.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ static const struct file_operations aoe_fops = {
.owner = THIS_MODULE,
};

static char *aoe_nodename(struct device *dev)
static char *aoe_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
}
Expand All @@ -288,7 +288,7 @@ aoechr_init(void)
unregister_chrdev(AOE_MAJOR, "aoechr");
return PTR_ERR(aoe_class);
}
aoe_class->nodename = aoe_nodename;
aoe_class->devnode = aoe_devnode;

for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
device_create(aoe_class, NULL,
Expand Down
6 changes: 3 additions & 3 deletions drivers/block/pktcdvd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2857,7 +2857,7 @@ static struct block_device_operations pktcdvd_ops = {
.media_changed = pkt_media_changed,
};

static char *pktcdvd_nodename(struct gendisk *gd)
static char *pktcdvd_devnode(struct gendisk *gd, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name);
}
Expand Down Expand Up @@ -2914,7 +2914,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
strcpy(disk->disk_name, pd->name);
disk->nodename = pktcdvd_nodename;
disk->devnode = pktcdvd_devnode;
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
Expand Down Expand Up @@ -3070,7 +3070,7 @@ static const struct file_operations pkt_ctl_fops = {
static struct miscdevice pkt_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DRIVER_NAME,
.name = "pktcdvd/control",
.nodename = "pktcdvd/control",
.fops = &pkt_ctl_fops
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/char/hw_random/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ static const struct file_operations rng_chrdev_ops = {
static struct miscdevice rng_miscdev = {
.minor = RNG_MISCDEV_MINOR,
.name = RNG_MODULE_NAME,
.devnode = "hwrng",
.nodename = "hwrng",
.fops = &rng_chrdev_ops,
};

Expand Down
29 changes: 19 additions & 10 deletions drivers/char/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -866,24 +866,25 @@ static const struct file_operations kmsg_fops = {

static const struct memdev {
const char *name;
mode_t mode;
const struct file_operations *fops;
struct backing_dev_info *dev_info;
} devlist[] = {
[ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
[1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
#ifdef CONFIG_DEVKMEM
[ 2] = { "kmem", &kmem_fops, &directly_mappable_cdev_bdi },
[2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
#endif
[ 3] = {"null", &null_fops, NULL },
[3] = { "null", 0666, &null_fops, NULL },
#ifdef CONFIG_DEVPORT
[ 4] = { "port", &port_fops, NULL },
[4] = { "port", 0, &port_fops, NULL },
#endif
[ 5] = { "zero", &zero_fops, &zero_bdi },
[ 7] = { "full", &full_fops, NULL },
[ 8] = { "random", &random_fops, NULL },
[ 9] = { "urandom", &urandom_fops, NULL },
[11] = { "kmsg", &kmsg_fops, NULL },
[5] = { "zero", 0666, &zero_fops, &zero_bdi },
[7] = { "full", 0666, &full_fops, NULL },
[8] = { "random", 0666, &random_fops, NULL },
[9] = { "urandom", 0666, &urandom_fops, NULL },
[11] = { "kmsg", 0, &kmsg_fops, NULL },
#ifdef CONFIG_CRASH_DUMP
[12] = { "oldmem", &oldmem_fops, NULL },
[12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
};

Expand Down Expand Up @@ -920,6 +921,13 @@ static const struct file_operations memory_fops = {
.open = memory_open,
};

static char *mem_devnode(struct device *dev, mode_t *mode)
{
if (mode && devlist[MINOR(dev->devt)].mode)
*mode = devlist[MINOR(dev->devt)].mode;
return NULL;
}

static struct class *mem_class;

static int __init chr_dev_init(void)
Expand All @@ -935,6 +943,7 @@ static int __init chr_dev_init(void)
printk("unable to get major %d for memory devs\n", MEM_MAJOR);

mem_class = class_create(THIS_MODULE, "mem");
mem_class->devnode = mem_devnode;
for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
if (!devlist[minor].name)
continue;
Expand Down
10 changes: 6 additions & 4 deletions drivers/char/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,14 @@ int misc_deregister(struct miscdevice *misc)
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);

static char *misc_nodename(struct device *dev)
static char *misc_devnode(struct device *dev, mode_t *mode)
{
struct miscdevice *c = dev_get_drvdata(dev);

if (c->devnode)
return kstrdup(c->devnode, GFP_KERNEL);
if (mode && c->mode)
*mode = c->mode;
if (c->nodename)
return kstrdup(c->nodename, GFP_KERNEL);
return NULL;
}

Expand All @@ -287,7 +289,7 @@ static int __init misc_init(void)
err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
goto fail_printk;
misc_class->nodename = misc_nodename;
misc_class->devnode = misc_devnode;
return 0;

fail_printk:
Expand Down
4 changes: 2 additions & 2 deletions drivers/char/raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ static const struct file_operations raw_ctl_fops = {

static struct cdev raw_cdev;

static char *raw_nodename(struct device *dev)
static char *raw_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
}
Expand Down Expand Up @@ -289,7 +289,7 @@ static int __init raw_init(void)
ret = PTR_ERR(raw_class);
goto error_region;
}
raw_class->nodename = raw_nodename;
raw_class->devnode = raw_devnode;
device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");

return 0;
Expand Down
11 changes: 11 additions & 0 deletions drivers/char/tty_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -3056,11 +3056,22 @@ void __init console_init(void)
}
}

static char *tty_devnode(struct device *dev, mode_t *mode)
{
if (!mode)
return NULL;
if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
dev->devt == MKDEV(TTYAUX_MAJOR, 2))
*mode = 0666;
return NULL;
}

static int __init tty_class_init(void)
{
tty_class = class_create(THIS_MODULE, "tty");
if (IS_ERR(tty_class))
return PTR_ERR(tty_class);
tty_class->devnode = tty_devnode;
return 0;
}

Expand Down
Loading

0 comments on commit e454cea

Please sign in to comment.