sysfs: add sysfs_link_change_owner()
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 27 Feb 2020 03:37:12 +0000 (04:37 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Feb 2020 04:07:25 +0000 (20:07 -0800)
Add a helper to change the owner of a sysfs link.
This function will be used to correctly account for kobject ownership
changes, e.g. when moving network devices between network namespaces.

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
fs/sysfs/file.c
include/linux/sysfs.h

index 4ca936ca3ba4475ddeaea3749d82b881ededb7d1..332cd69b378c72b79baab454d9730abcdaff9094 100644 (file)
@@ -570,6 +570,47 @@ static int internal_change_owner(struct kernfs_node *kn, kuid_t kuid,
        return kernfs_setattr(kn, &newattrs);
 }
 
+/**
+ *     sysfs_link_change_owner - change owner of a sysfs file.
+ *     @kobj:  object of the kernfs_node the symlink is located in.
+ *     @targ:  object of the kernfs_node the symlink points to.
+ *     @name:  name of the link.
+ *     @kuid:  new owner's kuid
+ *     @kgid:  new owner's kgid
+ *
+ * This function looks up the sysfs symlink entry @name under @kobj and changes
+ * the ownership to @kuid/@kgid. The symlink is looked up in the namespace of
+ * @targ.
+ *
+ * Returns 0 on success or error code on failure.
+ */
+int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
+                           const char *name, kuid_t kuid, kgid_t kgid)
+{
+       struct kernfs_node *kn = NULL;
+       int error;
+
+       if (!name || !kobj->state_in_sysfs || !targ->state_in_sysfs)
+               return -EINVAL;
+
+       error = -ENOENT;
+       kn = kernfs_find_and_get_ns(kobj->sd, name, targ->sd->ns);
+       if (!kn)
+               goto out;
+
+       error = -EINVAL;
+       if (kernfs_type(kn) != KERNFS_LINK)
+               goto out;
+       if (kn->symlink.target_kn->priv != targ)
+               goto out;
+
+       error = internal_change_owner(kn, kuid, kgid);
+
+out:
+       kernfs_put(kn);
+       return error;
+}
+
 /**
  *     sysfs_file_change_owner - change owner of a sysfs file.
  *     @kobj:  object.
index a7884024a91189686d218016ade7dca96891c23a..7e15ebfd750e5e9a90b0356734b1688ddc3fe21f 100644 (file)
@@ -312,6 +312,8 @@ static inline void sysfs_enable_ns(struct kernfs_node *kn)
 
 int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
                            kgid_t kgid);
+int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
+                           const char *name, kuid_t kuid, kgid_t kgid);
 
 #else /* CONFIG_SYSFS */
 
@@ -532,6 +534,14 @@ static inline int sysfs_file_change_owner(struct kobject *kobj,
        return 0;
 }
 
+static inline int sysfs_link_change_owner(struct kobject *kobj,
+                                         struct kobject *targ,
+                                         const char *name, kuid_t kuid,
+                                         kgid_t kgid)
+{
+       return 0;
+}
+
 #endif /* CONFIG_SYSFS */
 
 static inline int __must_check sysfs_create_file(struct kobject *kobj,