Commit 96d6523a authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Greg Kroah-Hartman

sysfs: Don't allow the creation of symlinks we can't remove

Recently my tagged sysfs support revealed a flaw in the device core
that a few rare drivers are running into such that we don't always put
network devices in a class subdirectory named net/.

Since we are not creating the class directory the network devices wind
up in a non-tagged directory, but the symlinks to the network devices
from /sys/class/net are in a tagged directory.  All of which works
until we go to remove or rename the symlink.  When we remove or rename
a symlink we look in the namespace of the target of the symlink.
Since the target of the symlink is in a non-tagged sysfs directory we
don't have a namespace to look in, and we fail to remove the symlink.

Detect this problem up front and simply don't create symlinks we won't
be able to remove later.  This prevents symlink leakage and fails in
a much clearer and more understandable way.
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dbbe4649
...@@ -28,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, ...@@ -28,6 +28,7 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
struct sysfs_dirent *target_sd = NULL; struct sysfs_dirent *target_sd = NULL;
struct sysfs_dirent *sd = NULL; struct sysfs_dirent *sd = NULL;
struct sysfs_addrm_cxt acxt; struct sysfs_addrm_cxt acxt;
enum kobj_ns_type ns_type;
int error; int error;
BUG_ON(!name); BUG_ON(!name);
...@@ -58,16 +59,28 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, ...@@ -58,16 +59,28 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
if (!sd) if (!sd)
goto out_put; goto out_put;
if (sysfs_ns_type(parent_sd)) ns_type = sysfs_ns_type(parent_sd);
if (ns_type)
sd->s_ns = target->ktype->namespace(target); sd->s_ns = target->ktype->namespace(target);
sd->s_symlink.target_sd = target_sd; sd->s_symlink.target_sd = target_sd;
target_sd = NULL; /* reference is now owned by the symlink */ target_sd = NULL; /* reference is now owned by the symlink */
sysfs_addrm_start(&acxt, parent_sd); sysfs_addrm_start(&acxt, parent_sd);
if (warn) /* Symlinks must be between directories with the same ns_type */
error = sysfs_add_one(&acxt, sd); if (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent)) {
else if (warn)
error = __sysfs_add_one(&acxt, sd); error = sysfs_add_one(&acxt, sd);
else
error = __sysfs_add_one(&acxt, sd);
} else {
error = -EINVAL;
WARN(1, KERN_WARNING
"sysfs: symlink across ns_types %s/%s -> %s/%s\n",
parent_sd->s_name,
sd->s_name,
sd->s_symlink.target_sd->s_parent->s_name,
sd->s_symlink.target_sd->s_name);
}
sysfs_addrm_finish(&acxt); sysfs_addrm_finish(&acxt);
if (error) if (error)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment