Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7eff2e7a authored by Kay Sievers's avatar Kay Sievers Committed by Greg Kroah-Hartman
Browse files

Driver core: change add_uevent_var to use a struct



This changes the uevent buffer functions to use a struct instead of a
long list of parameters. It does no longer require the caller to do the
proper buffer termination and size accounting, which is currently wrong
in some places. It fixes a known bug where parts of the uevent
environment are overwritten because of wrong index calculations.

Many thanks to Mathieu Desnoyers for finding bugs and improving the
error handling.

Signed-off-by: default avatarKay Sievers <kay.sievers@vrfy.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8380770c
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -66,8 +66,7 @@ static int tiocx_match(struct device *dev, struct device_driver *drv)


}
}


static int tiocx_uevent(struct device *dev, char **envp, int num_envp,
static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
			 char *buffer, int buffer_size)
{
{
	return -ENODEV;
	return -ENODEV;
}
}
+11 −26
Original line number Original line Diff line number Diff line
@@ -57,26 +57,21 @@ ssize_t of_device_get_modalias(struct of_device *ofdev,
	return tsize;
	return tsize;
}
}


int of_device_uevent(struct device *dev,
int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
		char **envp, int num_envp, char *buffer, int buffer_size)
{
{
	struct of_device *ofdev;
	struct of_device *ofdev;
	const char *compat;
	const char *compat;
	int i = 0, length = 0, seen = 0, cplen, sl;
	int seen = 0, cplen, sl;


	if (!dev)
	if (!dev)
		return -ENODEV;
		return -ENODEV;


	ofdev = to_of_device(dev);
	ofdev = to_of_device(dev);


	if (add_uevent_var(envp, num_envp, &i,
	if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
			   buffer, buffer_size, &length,
			   "OF_NAME=%s", ofdev->node->name))
		return -ENOMEM;
		return -ENOMEM;


	if (add_uevent_var(envp, num_envp, &i,
	if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
			   buffer, buffer_size, &length,
			   "OF_TYPE=%s", ofdev->node->type))
		return -ENOMEM;
		return -ENOMEM;


        /* Since the compatible field can contain pretty much anything
        /* Since the compatible field can contain pretty much anything
@@ -85,9 +80,7 @@ int of_device_uevent(struct device *dev,


	compat = of_get_property(ofdev->node, "compatible", &cplen);
	compat = of_get_property(ofdev->node, "compatible", &cplen);
	while (compat && *compat && cplen > 0) {
	while (compat && *compat && cplen > 0) {
		if (add_uevent_var(envp, num_envp, &i,
		if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
				   buffer, buffer_size, &length,
				   "OF_COMPATIBLE_%d=%s", seen, compat))
			return -ENOMEM;
			return -ENOMEM;


		sl = strlen (compat) + 1;
		sl = strlen (compat) + 1;
@@ -96,25 +89,17 @@ int of_device_uevent(struct device *dev,
		seen++;
		seen++;
	}
	}


	if (add_uevent_var(envp, num_envp, &i,
	if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
			   buffer, buffer_size, &length,
			   "OF_COMPATIBLE_N=%d", seen))
		return -ENOMEM;
		return -ENOMEM;


	/* modalias is trickier, we add it in 2 steps */
	/* modalias is trickier, we add it in 2 steps */
	if (add_uevent_var(envp, num_envp, &i,
	if (add_uevent_var(env, "MODALIAS="))
			   buffer, buffer_size, &length,
			   "MODALIAS="))
		return -ENOMEM;
		return -ENOMEM;

	sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
	sl = of_device_get_modalias(ofdev, &buffer[length-1],
				    sizeof(env->buf) - env->buflen);
					buffer_size-length);
	if (sl >= (sizeof(env->buf) - env->buflen))
	if (sl >= (buffer_size-length))
		return -ENOMEM;
		return -ENOMEM;

	env->buflen += sl;
	length += sl;

	envp[i] = NULL;


	return 0;
	return 0;
}
}
+3 −13
Original line number Original line Diff line number Diff line
@@ -317,30 +317,20 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
	return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
	return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
}
}


static int vio_hotplug(struct device *dev, char **envp, int num_envp,
static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
			char *buffer, int buffer_size)
{
{
	const struct vio_dev *vio_dev = to_vio_dev(dev);
	const struct vio_dev *vio_dev = to_vio_dev(dev);
	struct device_node *dn;
	struct device_node *dn;
	const char *cp;
	const char *cp;
	int length;

	if (!num_envp)
		return -ENOMEM;


	dn = dev->archdata.of_node;
	dn = dev->archdata.of_node;
	if (!dn)
	if (!dn)
		return -ENODEV;
		return -ENODEV;
	cp = of_get_property(dn, "compatible", &length);
	cp = of_get_property(dn, "compatible", NULL);
	if (!cp)
	if (!cp)
		return -ENODEV;
		return -ENODEV;


	envp[0] = buffer;
	add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp);
	length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
				vio_dev->type, cp);
	if ((buffer_size - length) <= 0)
		return -ENOMEM;
	envp[1] = NULL;
	return 0;
	return 0;
}
}


+2 −7
Original line number Original line Diff line number Diff line
@@ -437,18 +437,13 @@ static void ps3_system_bus_shutdown(struct device *_dev)
	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
}
}


static int ps3_system_bus_uevent(struct device *_dev, char **envp,
static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
				 int num_envp, char *buffer, int buffer_size)
{
{
	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
	int i = 0, length = 0;
	int i = 0, length = 0;


	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
	if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
			   &length, "MODALIAS=ps3:%d",
			   dev->match_id))
		return -ENOMEM;
		return -ENOMEM;

	envp[i] = NULL;
	return 0;
	return 0;
}
}


+8 −27
Original line number Original line Diff line number Diff line
@@ -540,60 +540,41 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
	return ((ktype == &ktype_block) || (ktype == &ktype_part));
	return ((ktype == &ktype_block) || (ktype == &ktype_part));
}
}


static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
static int block_uevent(struct kset *kset, struct kobject *kobj,
			 int num_envp, char *buffer, int buffer_size)
			struct kobj_uevent_env *env)
{
{
	struct kobj_type *ktype = get_ktype(kobj);
	struct kobj_type *ktype = get_ktype(kobj);
	struct device *physdev;
	struct device *physdev;
	struct gendisk *disk;
	struct gendisk *disk;
	struct hd_struct *part;
	struct hd_struct *part;
	int length = 0;
	int i = 0;


	if (ktype == &ktype_block) {
	if (ktype == &ktype_block) {
		disk = container_of(kobj, struct gendisk, kobj);
		disk = container_of(kobj, struct gendisk, kobj);
		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
		add_uevent_var(env, "MINOR=%u", disk->first_minor);
			       &length, "MINOR=%u", disk->first_minor);
	} else if (ktype == &ktype_part) {
	} else if (ktype == &ktype_part) {
		disk = container_of(kobj->parent, struct gendisk, kobj);
		disk = container_of(kobj->parent, struct gendisk, kobj);
		part = container_of(kobj, struct hd_struct, kobj);
		part = container_of(kobj, struct hd_struct, kobj);
		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
		add_uevent_var(env, "MINOR=%u",
			       &length, "MINOR=%u",
			       disk->first_minor + part->partno);
			       disk->first_minor + part->partno);
	} else
	} else
		return 0;
		return 0;


	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
	add_uevent_var(env, "MAJOR=%u", disk->major);
		       "MAJOR=%u", disk->major);


	/* add physical device, backing this device  */
	/* add physical device, backing this device  */
	physdev = disk->driverfs_dev;
	physdev = disk->driverfs_dev;
	if (physdev) {
	if (physdev) {
		char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
		char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);


		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
		add_uevent_var(env, "PHYSDEVPATH=%s", path);
			       &length, "PHYSDEVPATH=%s", path);
		kfree(path);
		kfree(path);


		if (physdev->bus)
		if (physdev->bus)
			add_uevent_var(envp, num_envp, &i,
			add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);
				       buffer, buffer_size, &length,
				       "PHYSDEVBUS=%s",
				       physdev->bus->name);


		if (physdev->driver)
		if (physdev->driver)
			add_uevent_var(envp, num_envp, &i,
			add_uevent_var(env, physdev->driver->name);
				       buffer, buffer_size, &length,
	}
				       "PHYSDEVDRIVER=%s",
				       physdev->driver->name);
	}

	/* terminate, set to next free slot, shrink available space */
	envp[i] = NULL;
	envp = &envp[i];
	num_envp -= i;
	buffer = &buffer[length];
	buffer_size -= length;


	return 0;
	return 0;
}
}
Loading