X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev-remove.c;h=7ad7c2402a8e05f77d23a1451ab9b891372a8116;hp=98c45d6c333650ff4ebb381ad6508e49568cad7b;hb=8372907752159970c86c3f7cc565c35cf2fa1ef9;hpb=f61d732a02c8a5e11c39651a70e3e3fd00529495 diff --git a/udev-remove.c b/udev-remove.c index 98c45d6c3..7ad7c2402 100644 --- a/udev-remove.c +++ b/udev-remove.c @@ -65,6 +65,41 @@ static int delete_path(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 *dev) { char filename[NAME_SIZE]; @@ -79,14 +114,9 @@ static int delete_node(struct udevice *dev) strfieldcat(filename, dev->name); info("removing device node '%s'", filename); - retval = unlink(filename); - if (errno == ENOENT) - retval = 0; - if (retval) { - dbg("unlink(%s) failed with error '%s'", - filename, strerror(errno)); + retval = secure_unlink(filename); + if (retval) return retval; - } /* remove partition nodes */ if (dev->partitions > 0) { @@ -94,7 +124,7 @@ static int delete_node(struct udevice *dev) for (i = 1; i <= dev->partitions; i++) { strfieldcpy(partitionname, filename); strintcat(partitionname, i); - unlink(partitionname); + secure_unlink(partitionname); } } @@ -129,7 +159,7 @@ static int delete_node(struct udevice *dev) * something different from the kernel name. If we have, us it. If not, use * the default kernel name for lack of anything else to know to do. */ -int udev_remove_device(char *path, char *subsystem) +int udev_remove_device(const char *path, const char *subsystem) { struct udevice dev; char *temp; @@ -137,36 +167,24 @@ int udev_remove_device(char *path, char *subsystem) memset(&dev, 0x00, sizeof(dev)); - dev.type = get_device_type(path, subsystem); - - switch (dev.type) { - case 'b': - case 'c': - retval = udevdb_get_dev(path, &dev); - if (retval) { - dbg("'%s' not found in database, falling back on default name", path); - temp = strrchr(path, '/'); - if (temp == NULL) - return -ENODEV; - strfieldcpy(dev.name, &temp[1]); - } - - dbg("name='%s'", dev.name); - udevdb_delete_dev(path); + retval = udevdb_get_dev(path, &dev); + if (retval != 0) { + dbg("'%s' not found in database, falling back on default name", path); + temp = strrchr(path, '/'); + if (temp == NULL) + return -ENODEV; + strfieldcpy(dev.name, &temp[1]); + } + dbg("name='%s'", dev.name); - dev_d_send(&dev, subsystem); + dev.type = get_device_type(path, subsystem); + dev_d_send(&dev, subsystem, path); + udevdb_delete_dev(path); + if (dev.type == 'b' || dev.type == 'c') retval = delete_node(&dev); - break; - - case 'n': + else if (dev.type == 'n') retval = 0; - break; - - default: - dbg("unknown device type '%c'", dev.type); - retval = -EINVAL; - } return retval; }