[PATCH] provide temporary device node for callouts to access the device

%N will create a temporary node for a callout a be sustituted with the
name of the node.
This commit is contained in:
kay.sievers@vrfy.org 2005-02-09 04:37:32 +01:00 committed by Greg KH
parent bce52be81e
commit c1ab046124
8 changed files with 80 additions and 40 deletions

View file

@ -201,6 +201,12 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
switch (c) {
case 'p':
if (strlen(udev->devpath) == 0)
break;
strfieldcatmax(string, udev->devpath, maxsize);
dbg("substitute kernel name '%s'", udev->kernel_name);
break;
case 'b':
if (strlen(udev->bus_id) == 0)
break;
@ -290,6 +296,15 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
strfieldcatmax(string, temp2, maxsize);
}
break;
case 'N':
if (udev->tmp_node[0] == '\0') {
dbg("create temporary device node for callout");
snprintf(udev->tmp_node, NAME_SIZE-1, "%s/.tmp-%u-%u", udev_root, udev->major, udev->minor);
udev_make_node(udev, udev->tmp_node, udev->major, udev->minor, 0600, 0, 0);
}
strfieldcatmax(string, udev->tmp_node, maxsize);
dbg("substitute temporary device node name '%s'", udev->tmp_node);
break;
default:
dbg("unknown substitution type '%%%c'", c);
break;
@ -787,5 +802,11 @@ int namedev_name_device(struct udevice *udev, struct sysfs_class_device *class_d
dbg("no rule found, use kernel name '%s'", udev->name);
exit:
if (udev->tmp_node[0] != '\0') {
dbg("removing temporary device node");
unlink_secure(udev->tmp_node);
udev->tmp_node[0] = '\0';
}
return 0;
}

View file

@ -1066,6 +1066,24 @@ EOF
conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="should_not_match", DRIVER="sd-wrong"
BUS="scsi", KERNEL="sda", NAME="node", DRIVER="sd"
EOF
},
{
desc => "temporary node creation test",
subsys => "block",
devpath => "/block/sda",
exp_name => "sda",
conf => <<EOF
BUS="scsi", KERNEL="sda", PROGRAM="/usr/bin/test -b %N" NAME="%N"
EOF
},
{
desc => "devpath substitution test",
subsys => "block",
devpath => "/block/sda",
exp_name => "sda",
conf => <<EOF
BUS="scsi", KERNEL="sda", PROGRAM="/bin/echo %p", RESULT="/block/sda" NAME="%k"
EOF
},
);

View file

@ -188,6 +188,9 @@ For example, 'sda3' has a "kernel number" of '3'.
.B %k
The "kernel name" for the device.
.TP
.B %p
The devpath for the device.
.TP
.B %M
The kernel major number for the device.
.TP
@ -211,6 +214,10 @@ If the number is followed by the + char this part plus
all remaining parts of the result string are substituted:
.BI %c{ N+ }
.TP
.B %N
The name of a created temporary device node to provide access to the
device from a external program.
.TP
.BI %s{ filename }
The content of a sysfs attribute.
.TP

3
udev.h
View file

@ -23,6 +23,7 @@
#ifndef _UDEV_H_
#define _UDEV_H_
#include <sys/types.h>
#include <sys/param.h>
#include "libsysfs/sysfs/libsysfs.h"
@ -59,6 +60,7 @@ struct udevice {
int minor;
char devname[NAME_SIZE];
char tmp_node[NAME_SIZE];
int partitions;
int ignore_remove;
int config_line;
@ -75,6 +77,7 @@ extern int udev_remove_device(struct udevice *udev);
extern void udev_init_config(void);
extern int udev_start(void);
extern void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix);
extern int udev_make_node(struct udevice *udev, const char *file, int major, int minor, mode_t mode, uid_t uid, gid_t gid);
extern char sysfs_path[SYSFS_PATH_MAX];
extern char udev_root[PATH_MAX];

View file

@ -67,7 +67,7 @@ error:
return -1;
}
static int make_node(struct udevice *udev, char *file, int major, int minor, unsigned int mode, uid_t uid, gid_t gid)
int udev_make_node(struct udevice *udev, const char *file, int major, int minor, mode_t mode, uid_t uid, gid_t gid)
{
struct stat stats;
int retval = 0;
@ -183,7 +183,7 @@ static int create_node(struct udevice *udev)
if (!udev->test_run) {
info("creating device node '%s'", filename);
if (make_node(udev, filename, udev->major, udev->minor, udev->mode, uid, gid) != 0)
if (udev_make_node(udev, filename, udev->major, udev->minor, udev->mode, uid, gid) != 0)
goto error;
} else {
info("creating device node '%s', major = '%d', minor = '%d', "
@ -198,7 +198,7 @@ static int create_node(struct udevice *udev)
for (i = 1; i <= udev->partitions; i++) {
strfieldcpy(partitionname, filename);
strintcat(partitionname, i);
make_node(udev, partitionname, udev->major, udev->minor + i, udev->mode, uid, gid);
udev_make_node(udev, partitionname, udev->major, udev->minor + i, udev->mode, uid, gid);
}
}
}

View file

@ -67,41 +67,6 @@ static int delete_path(const char *path)
return 0;
}
/** Remove all permissions on the device node, before
* unlinking it. This fixes a security issue.
* If the user created a hard-link to the device node,
* he can't use it any longer, because he lost permission
* to do so.
*/
static int secure_unlink(const char *filename)
{
int retval;
retval = chown(filename, 0, 0);
if (retval) {
dbg("chown(%s, 0, 0) failed with error '%s'",
filename, strerror(errno));
/* We continue nevertheless.
* I think it's very unlikely for chown
* to fail here, if the file exists.
*/
}
retval = chmod(filename, 0000);
if (retval) {
dbg("chmod(%s, 0000) failed with error '%s'",
filename, strerror(errno));
/* We continue nevertheless. */
}
retval = unlink(filename);
if (errno == ENOENT)
retval = 0;
if (retval) {
dbg("unlink(%s) failed with error '%s'",
filename, strerror(errno));
}
return retval;
}
static int delete_node(struct udevice *udev)
{
char filename[NAME_SIZE];
@ -116,7 +81,7 @@ static int delete_node(struct udevice *udev)
filename[NAME_SIZE-1] = '\0';
info("removing device node '%s'", filename);
retval = secure_unlink(filename);
retval = unlink_secure(filename);
if (retval)
return retval;
@ -131,7 +96,7 @@ static int delete_node(struct udevice *udev)
for (i = 1; i <= num; i++) {
strfieldcpy(partitionname, filename);
strintcat(partitionname, i);
secure_unlink(partitionname);
unlink_secure(partitionname);
}
}

View file

@ -112,6 +112,31 @@ int create_path(const char *path)
return mkdir(p, 0755);
}
/* Reset permissions on the device node, before unlinking it to make sure,
* that permisions of possible hard links will be removed to.
*/
int unlink_secure(const char *filename)
{
int retval;
retval = chown(filename, 0, 0);
if (retval)
dbg("chown(%s, 0, 0) failed with error '%s'", filename, strerror(errno));
retval = chmod(filename, 0000);
if (retval)
dbg("chmod(%s, 0000) failed with error '%s'", filename, strerror(errno));
retval = unlink(filename);
if (errno == ENOENT)
retval = 0;
if (retval)
dbg("unlink(%s) failed with error '%s'", filename, strerror(errno));
return retval;
}
int parse_get_pair(char **orig_string, char **left, char **right)
{
char *temp;

View file

@ -80,6 +80,7 @@ extern void udev_init_device(struct udevice *udev, const char* devpath, const ch
extern int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel);
extern int create_path(const char *path);
extern int parse_get_pair(char **orig_string, char **left, char **right);
extern int unlink_secure(const char *filename);
extern int file_map(const char *filename, char **buf, size_t *bufsize);
extern void file_unmap(char *buf, size_t bufsize);
extern size_t buf_get_line(const char *buf, size_t buflen, size_t cur);