diff options
Diffstat (limited to 'fs/sysfs/symlink.c')
| -rw-r--r-- | fs/sysfs/symlink.c | 26 | 
1 files changed, 20 insertions, 6 deletions
| diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index f71246bebfe4..a7ac78f8e67a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -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 *sd = NULL;  	struct sysfs_addrm_cxt acxt; +	enum kobj_ns_type ns_type;  	int error;  	BUG_ON(!name); @@ -58,16 +59,29 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,  	if (!sd)  		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_symlink.target_sd = target_sd;  	target_sd = NULL;	/* reference is now owned by the symlink */  	sysfs_addrm_start(&acxt, parent_sd); -	if (warn) -		error = sysfs_add_one(&acxt, sd); -	else -		error = __sysfs_add_one(&acxt, sd); +	/* Symlinks must be between directories with the same ns_type */ +	if (!ns_type || +	    (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { +		if (warn) +			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);  	if (error) @@ -122,7 +136,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,  {  	const void *ns = NULL;  	spin_lock(&sysfs_assoc_lock); -	if (targ->sd) +	if (targ->sd && sysfs_ns_type(kobj->sd))  		ns = targ->sd->s_ns;  	spin_unlock(&sysfs_assoc_lock);  	sysfs_hash_and_remove(kobj->sd, ns, name); | 
