diff mbox series

[net-next,v2,1/7] kernfs: allow creating kernfs objects with arbitrary uid/gid

Message ID 1531497949-1766-2-git-send-email-tyhicks@canonical.com
State Changes Requested, archived
Delegated to: David Miller
Headers show
Series Make /sys/class/net per net namespace objects belong to container | expand

Commit Message

Tyler Hicks July 13, 2018, 4:05 p.m. UTC
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>

This change allows creating kernfs files and directories with arbitrary
uid/gid instead of always using GLOBAL_ROOT_UID/GID by extending
kernfs_create_dir_ns() and kernfs_create_file_ns() with uid/gid arguments.
The "simple" kernfs_create_file() and kernfs_create_dir() are left alone
and always create objects belonging to the global root.

When creating symlinks ownership (uid/gid) is taken from the target kernfs
object.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
---
 fs/kernfs/dir.c             | 29 ++++++++++++++++++++++++++---
 fs/kernfs/file.c            |  8 ++++++--
 fs/kernfs/inode.c           |  2 +-
 fs/kernfs/kernfs-internal.h |  2 ++
 fs/kernfs/symlink.c         | 11 ++++++++++-
 fs/sysfs/dir.c              |  4 +++-
 fs/sysfs/file.c             |  5 +++--
 include/linux/kernfs.h      | 28 +++++++++++++++++++---------
 kernel/cgroup/cgroup.c      |  4 +++-
 9 files changed, 73 insertions(+), 20 deletions(-)

Comments

kernel test robot July 17, 2018, 1:04 a.m. UTC | #1
Hi Dmitry,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Tyler-Hicks/Make-sys-class-net-per-net-namespace-objects-belong-to-container/20180716-020459
config: x86_64-randconfig-u0-07161309 (attached as .config)
compiler: gcc-5 (Debian 5.5.0-3) 5.4.1 20171010
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 
:::::: branch date: 13 hours ago
:::::: commit date: 13 hours ago

All errors (new ones prefixed by >>):

   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c: In function 'rdtgroup_add_file':
>> arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:149:7: error: incompatible type for argument 4 of '__kernfs_create_file'
          0, rft->kf_ops, rft, NULL, NULL);
          ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: expected 'kuid_t {aka struct <anonymous>}' but argument is of type 'int'
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:149:10: error: incompatible type for argument 5 of '__kernfs_create_file'
          0, rft->kf_ops, rft, NULL, NULL);
             ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: expected 'kgid_t {aka struct <anonymous>}' but argument is of type 'struct kernfs_ops *'
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:149:23: warning: passing argument 6 of '__kernfs_create_file' makes integer from pointer without a cast [-Wint-conversion]
          0, rft->kf_ops, rft, NULL, NULL);
                          ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: expected 'loff_t {aka long long int}' but argument is of type 'struct rftype *'
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
>> arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:148:7: error: too few arguments to function '__kernfs_create_file'
     kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
          ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: declared here
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c: In function 'mon_addfile':
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:1506:51: error: incompatible type for argument 4 of '__kernfs_create_file'
     kn = __kernfs_create_file(parent_kn, name, 0444, 0,
                                                      ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: expected 'kuid_t {aka struct <anonymous>}' but argument is of type 'int'
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:1507:7: error: incompatible type for argument 5 of '__kernfs_create_file'
          &kf_mondata_ops, priv, NULL, NULL);
          ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: expected 'kgid_t {aka struct <anonymous>}' but argument is of type 'struct kernfs_ops *'
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:1507:24: warning: passing argument 6 of '__kernfs_create_file' makes integer from pointer without a cast [-Wint-conversion]
          &kf_mondata_ops, priv, NULL, NULL);
                           ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: expected 'loff_t {aka long long int}' but argument is of type 'void *'
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^
   arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:1506:7: error: too few arguments to function '__kernfs_create_file'
     kn = __kernfs_create_file(parent_kn, name, 0444, 0,
          ^
   In file included from include/linux/sysfs.h:16:0,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:16,
                    from include/linux/node.h:18,
                    from include/linux/cpu.h:17,
                    from arch/x86/kernel/cpu/intel_rdt_rdtgroup.c:23:
   include/linux/kernfs.h:333:21: note: declared here
    struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
                        ^

# https://github.com/0day-ci/linux/commit/d5f7e84e70937f0546d774162a3f9425caec5687
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout d5f7e84e70937f0546d774162a3f9425caec5687
vim +/__kernfs_create_file +149 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c

5ff193fb Fenghua Yu      2016-10-28   22  
12e0110c Tony Luck       2016-10-28  @23  #include <linux/cpu.h>
5ff193fb Fenghua Yu      2016-10-28   24  #include <linux/fs.h>
5ff193fb Fenghua Yu      2016-10-28   25  #include <linux/sysfs.h>
5ff193fb Fenghua Yu      2016-10-28   26  #include <linux/kernfs.h>
9b3a7fd0 Tony Luck       2017-09-25   27  #include <linux/seq_buf.h>
4e978d06 Fenghua Yu      2016-10-28   28  #include <linux/seq_file.h>
3f07c014 Ingo Molnar     2017-02-08   29  #include <linux/sched/signal.h>
29930025 Ingo Molnar     2017-02-08   30  #include <linux/sched/task.h>
5ff193fb Fenghua Yu      2016-10-28   31  #include <linux/slab.h>
e02737d5 Fenghua Yu      2016-10-28   32  #include <linux/task_work.h>
5ff193fb Fenghua Yu      2016-10-28   33  
5ff193fb Fenghua Yu      2016-10-28   34  #include <uapi/linux/magic.h>
5ff193fb Fenghua Yu      2016-10-28   35  
05830204 Vikas Shivappa  2017-07-25   36  #include <asm/intel_rdt_sched.h>
05830204 Vikas Shivappa  2017-07-25   37  #include "intel_rdt.h"
5ff193fb Fenghua Yu      2016-10-28   38  
4af4a88e Vikas Shivappa  2017-07-25   39  DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
4af4a88e Vikas Shivappa  2017-07-25   40  DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
1b5c0b75 Vikas Shivappa  2017-07-25   41  DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
cb2200e9 Reinette Chatre 2017-07-25   42  static struct kernfs_root *rdt_root;
5ff193fb Fenghua Yu      2016-10-28   43  struct rdtgroup rdtgroup_default;
5ff193fb Fenghua Yu      2016-10-28   44  LIST_HEAD(rdt_all_groups);
5ff193fb Fenghua Yu      2016-10-28   45  
4e978d06 Fenghua Yu      2016-10-28   46  /* Kernel fs node for "info" directory under root */
4e978d06 Fenghua Yu      2016-10-28   47  static struct kernfs_node *kn_info;
4e978d06 Fenghua Yu      2016-10-28   48  
4af4a88e Vikas Shivappa  2017-07-25   49  /* Kernel fs node for "mon_groups" directory under root */
4af4a88e Vikas Shivappa  2017-07-25   50  static struct kernfs_node *kn_mongrp;
4af4a88e Vikas Shivappa  2017-07-25   51  
4af4a88e Vikas Shivappa  2017-07-25   52  /* Kernel fs node for "mon_data" directory under root */
4af4a88e Vikas Shivappa  2017-07-25   53  static struct kernfs_node *kn_mondata;
4af4a88e Vikas Shivappa  2017-07-25   54  
9b3a7fd0 Tony Luck       2017-09-25   55  static struct seq_buf last_cmd_status;
9b3a7fd0 Tony Luck       2017-09-25   56  static char last_cmd_status_buf[512];
9b3a7fd0 Tony Luck       2017-09-25   57  
9b3a7fd0 Tony Luck       2017-09-25   58  void rdt_last_cmd_clear(void)
9b3a7fd0 Tony Luck       2017-09-25   59  {
9b3a7fd0 Tony Luck       2017-09-25   60  	lockdep_assert_held(&rdtgroup_mutex);
9b3a7fd0 Tony Luck       2017-09-25   61  	seq_buf_clear(&last_cmd_status);
9b3a7fd0 Tony Luck       2017-09-25   62  }
9b3a7fd0 Tony Luck       2017-09-25   63  
9b3a7fd0 Tony Luck       2017-09-25   64  void rdt_last_cmd_puts(const char *s)
9b3a7fd0 Tony Luck       2017-09-25   65  {
9b3a7fd0 Tony Luck       2017-09-25   66  	lockdep_assert_held(&rdtgroup_mutex);
9b3a7fd0 Tony Luck       2017-09-25   67  	seq_buf_puts(&last_cmd_status, s);
9b3a7fd0 Tony Luck       2017-09-25   68  }
9b3a7fd0 Tony Luck       2017-09-25   69  
9b3a7fd0 Tony Luck       2017-09-25   70  void rdt_last_cmd_printf(const char *fmt, ...)
9b3a7fd0 Tony Luck       2017-09-25   71  {
9b3a7fd0 Tony Luck       2017-09-25   72  	va_list ap;
9b3a7fd0 Tony Luck       2017-09-25   73  
9b3a7fd0 Tony Luck       2017-09-25   74  	va_start(ap, fmt);
9b3a7fd0 Tony Luck       2017-09-25   75  	lockdep_assert_held(&rdtgroup_mutex);
9b3a7fd0 Tony Luck       2017-09-25   76  	seq_buf_vprintf(&last_cmd_status, fmt, ap);
9b3a7fd0 Tony Luck       2017-09-25   77  	va_end(ap);
9b3a7fd0 Tony Luck       2017-09-25   78  }
9b3a7fd0 Tony Luck       2017-09-25   79  
60cf5e10 Fenghua Yu      2016-10-28   80  /*
60cf5e10 Fenghua Yu      2016-10-28   81   * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
60cf5e10 Fenghua Yu      2016-10-28   82   * we can keep a bitmap of free CLOSIDs in a single integer.
60cf5e10 Fenghua Yu      2016-10-28   83   *
60cf5e10 Fenghua Yu      2016-10-28   84   * Using a global CLOSID across all resources has some advantages and
60cf5e10 Fenghua Yu      2016-10-28   85   * some drawbacks:
60cf5e10 Fenghua Yu      2016-10-28   86   * + We can simply set "current->closid" to assign a task to a resource
60cf5e10 Fenghua Yu      2016-10-28   87   *   group.
60cf5e10 Fenghua Yu      2016-10-28   88   * + Context switch code can avoid extra memory references deciding which
60cf5e10 Fenghua Yu      2016-10-28   89   *   CLOSID to load into the PQR_ASSOC MSR
60cf5e10 Fenghua Yu      2016-10-28   90   * - We give up some options in configuring resource groups across multi-socket
60cf5e10 Fenghua Yu      2016-10-28   91   *   systems.
60cf5e10 Fenghua Yu      2016-10-28   92   * - Our choices on how to configure each resource become progressively more
60cf5e10 Fenghua Yu      2016-10-28   93   *   limited as the number of resources grows.
60cf5e10 Fenghua Yu      2016-10-28   94   */
60cf5e10 Fenghua Yu      2016-10-28   95  static int closid_free_map;
60cf5e10 Fenghua Yu      2016-10-28   96  
60cf5e10 Fenghua Yu      2016-10-28   97  static void closid_init(void)
60cf5e10 Fenghua Yu      2016-10-28   98  {
60cf5e10 Fenghua Yu      2016-10-28   99  	struct rdt_resource *r;
60cf5e10 Fenghua Yu      2016-10-28  100  	int rdt_min_closid = 32;
60cf5e10 Fenghua Yu      2016-10-28  101  
60cf5e10 Fenghua Yu      2016-10-28  102  	/* Compute rdt_min_closid across all resources */
1b5c0b75 Vikas Shivappa  2017-07-25  103  	for_each_alloc_enabled_rdt_resource(r)
60cf5e10 Fenghua Yu      2016-10-28  104  		rdt_min_closid = min(rdt_min_closid, r->num_closid);
60cf5e10 Fenghua Yu      2016-10-28  105  
60cf5e10 Fenghua Yu      2016-10-28  106  	closid_free_map = BIT_MASK(rdt_min_closid) - 1;
60cf5e10 Fenghua Yu      2016-10-28  107  
60cf5e10 Fenghua Yu      2016-10-28  108  	/* CLOSID 0 is always reserved for the default group */
60cf5e10 Fenghua Yu      2016-10-28  109  	closid_free_map &= ~1;
60cf5e10 Fenghua Yu      2016-10-28  110  }
60cf5e10 Fenghua Yu      2016-10-28  111  
cb2200e9 Reinette Chatre 2017-07-25  112  static int closid_alloc(void)
60cf5e10 Fenghua Yu      2016-10-28  113  {
0734ded1 Vikas Shivappa  2017-07-25  114  	u32 closid = ffs(closid_free_map);
60cf5e10 Fenghua Yu      2016-10-28  115  
60cf5e10 Fenghua Yu      2016-10-28  116  	if (closid == 0)
60cf5e10 Fenghua Yu      2016-10-28  117  		return -ENOSPC;
60cf5e10 Fenghua Yu      2016-10-28  118  	closid--;
60cf5e10 Fenghua Yu      2016-10-28  119  	closid_free_map &= ~(1 << closid);
60cf5e10 Fenghua Yu      2016-10-28  120  
60cf5e10 Fenghua Yu      2016-10-28  121  	return closid;
60cf5e10 Fenghua Yu      2016-10-28  122  }
60cf5e10 Fenghua Yu      2016-10-28  123  
60cf5e10 Fenghua Yu      2016-10-28  124  static void closid_free(int closid)
60cf5e10 Fenghua Yu      2016-10-28  125  {
60cf5e10 Fenghua Yu      2016-10-28  126  	closid_free_map |= 1 << closid;
60cf5e10 Fenghua Yu      2016-10-28  127  }
60cf5e10 Fenghua Yu      2016-10-28  128  
4e978d06 Fenghua Yu      2016-10-28  129  /* set uid and gid of rdtgroup dirs and files to that of the creator */
4e978d06 Fenghua Yu      2016-10-28  130  static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
4e978d06 Fenghua Yu      2016-10-28  131  {
4e978d06 Fenghua Yu      2016-10-28  132  	struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
4e978d06 Fenghua Yu      2016-10-28  133  				.ia_uid = current_fsuid(),
4e978d06 Fenghua Yu      2016-10-28  134  				.ia_gid = current_fsgid(), };
4e978d06 Fenghua Yu      2016-10-28  135  
4e978d06 Fenghua Yu      2016-10-28  136  	if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
4e978d06 Fenghua Yu      2016-10-28  137  	    gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
4e978d06 Fenghua Yu      2016-10-28  138  		return 0;
4e978d06 Fenghua Yu      2016-10-28  139  
4e978d06 Fenghua Yu      2016-10-28  140  	return kernfs_setattr(kn, &iattr);
4e978d06 Fenghua Yu      2016-10-28  141  }
4e978d06 Fenghua Yu      2016-10-28  142  
4e978d06 Fenghua Yu      2016-10-28  143  static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
4e978d06 Fenghua Yu      2016-10-28  144  {
4e978d06 Fenghua Yu      2016-10-28  145  	struct kernfs_node *kn;
4e978d06 Fenghua Yu      2016-10-28  146  	int ret;
4e978d06 Fenghua Yu      2016-10-28  147  
4e978d06 Fenghua Yu      2016-10-28 @148  	kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
4e978d06 Fenghua Yu      2016-10-28 @149  				  0, rft->kf_ops, rft, NULL, NULL);
4e978d06 Fenghua Yu      2016-10-28  150  	if (IS_ERR(kn))
4e978d06 Fenghua Yu      2016-10-28  151  		return PTR_ERR(kn);
4e978d06 Fenghua Yu      2016-10-28  152  
4e978d06 Fenghua Yu      2016-10-28  153  	ret = rdtgroup_kn_set_ugid(kn);
4e978d06 Fenghua Yu      2016-10-28  154  	if (ret) {
4e978d06 Fenghua Yu      2016-10-28  155  		kernfs_remove(kn);
4e978d06 Fenghua Yu      2016-10-28  156  		return ret;
4e978d06 Fenghua Yu      2016-10-28  157  	}
4e978d06 Fenghua Yu      2016-10-28  158  
4e978d06 Fenghua Yu      2016-10-28  159  	return 0;
4e978d06 Fenghua Yu      2016-10-28  160  }
4e978d06 Fenghua Yu      2016-10-28  161  

:::::: The code at line 149 was first introduced by commit
:::::: 4e978d06dedb8207b298a5a8a49fce4b2ab80d12 x86/intel_rdt: Add "info" files to resctrl file system

:::::: TO: Fenghua Yu <fenghua.yu@intel.com>
:::::: CC: Thomas Gleixner <tglx@linutronix.de>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox series

Patch

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index d66cc0777303..4ca0b5c18192 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -619,6 +619,7 @@  struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
 
 static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 					     const char *name, umode_t mode,
+					     kuid_t uid, kgid_t gid,
 					     unsigned flags)
 {
 	struct kernfs_node *kn;
@@ -661,8 +662,22 @@  static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 	kn->mode = mode;
 	kn->flags = flags;
 
+	if (!uid_eq(uid, GLOBAL_ROOT_UID) || !gid_eq(gid, GLOBAL_ROOT_GID)) {
+		struct iattr iattr = {
+			.ia_valid = ATTR_UID | ATTR_GID,
+			.ia_uid = uid,
+			.ia_gid = gid,
+		};
+
+		ret = __kernfs_setattr(kn, &iattr);
+		if (ret < 0)
+			goto err_out3;
+	}
+
 	return kn;
 
+ err_out3:
+	idr_remove(&root->ino_idr, kn->id.ino);
  err_out2:
 	kmem_cache_free(kernfs_node_cache, kn);
  err_out1:
@@ -672,11 +687,13 @@  static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 
 struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 				    const char *name, umode_t mode,
+				    kuid_t uid, kgid_t gid,
 				    unsigned flags)
 {
 	struct kernfs_node *kn;
 
-	kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags);
+	kn = __kernfs_new_node(kernfs_root(parent),
+			       name, mode, uid, gid, flags);
 	if (kn) {
 		kernfs_get(parent);
 		kn->parent = parent;
@@ -946,6 +963,7 @@  struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
 	root->next_generation = 1;
 
 	kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
+			       GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
 			       KERNFS_DIR);
 	if (!kn) {
 		idr_destroy(&root->ino_idr);
@@ -984,6 +1002,8 @@  void kernfs_destroy_root(struct kernfs_root *root)
  * @parent: parent in which to create a new directory
  * @name: name of the new directory
  * @mode: mode of the new directory
+ * @uid: uid of the new directory
+ * @gid: gid of the new directory
  * @priv: opaque data associated with the new directory
  * @ns: optional namespace tag of the directory
  *
@@ -991,13 +1011,15 @@  void kernfs_destroy_root(struct kernfs_root *root)
  */
 struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 					 const char *name, umode_t mode,
+					 kuid_t uid, kgid_t gid,
 					 void *priv, const void *ns)
 {
 	struct kernfs_node *kn;
 	int rc;
 
 	/* allocate */
-	kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR);
+	kn = kernfs_new_node(parent, name, mode | S_IFDIR,
+			     uid, gid, KERNFS_DIR);
 	if (!kn)
 		return ERR_PTR(-ENOMEM);
 
@@ -1028,7 +1050,8 @@  struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
 	int rc;
 
 	/* allocate */
-	kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR);
+	kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR,
+			     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, KERNFS_DIR);
 	if (!kn)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 2015d8c45e4a..dbf5bc250bfd 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -965,6 +965,8 @@  const struct file_operations kernfs_file_fops = {
  * @parent: directory to create the file in
  * @name: name of the file
  * @mode: mode of the file
+ * @uid: uid of the file
+ * @gid: gid of the file
  * @size: size of the file
  * @ops: kernfs operations for the file
  * @priv: private data for the file
@@ -975,7 +977,8 @@  const struct file_operations kernfs_file_fops = {
  */
 struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 					 const char *name,
-					 umode_t mode, loff_t size,
+					 umode_t mode, kuid_t uid, kgid_t gid,
+					 loff_t size,
 					 const struct kernfs_ops *ops,
 					 void *priv, const void *ns,
 					 struct lock_class_key *key)
@@ -986,7 +989,8 @@  struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 
 	flags = KERNFS_FILE;
 
-	kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG, flags);
+	kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG,
+			     uid, gid, flags);
 	if (!kn)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 3d73fe9d56e2..80cebcd94c90 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -63,7 +63,7 @@  static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
 	return ret;
 }
 
-static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
+int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
 {
 	struct kernfs_iattrs *attrs;
 	struct iattr *iattrs;
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 0f260dcca177..3d83b114bb08 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -90,6 +90,7 @@  int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr);
 int kernfs_iop_getattr(const struct path *path, struct kstat *stat,
 		       u32 request_mask, unsigned int query_flags);
 ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size);
+int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr);
 
 /*
  * dir.c
@@ -104,6 +105,7 @@  void kernfs_put_active(struct kernfs_node *kn);
 int kernfs_add_one(struct kernfs_node *kn);
 struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 				    const char *name, umode_t mode,
+				    kuid_t uid, kgid_t gid,
 				    unsigned flags);
 struct kernfs_node *kernfs_find_and_get_node_by_ino(struct kernfs_root *root,
 						    unsigned int ino);
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 08ccabd7047f..5ffed48f3d0e 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -21,6 +21,7 @@ 
  * @target: target node for the symlink to point to
  *
  * Returns the created node on success, ERR_PTR() value on error.
+ * Ownership of the link matches ownership of the target.
  */
 struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
 				       const char *name,
@@ -28,8 +29,16 @@  struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
 {
 	struct kernfs_node *kn;
 	int error;
+	kuid_t uid = GLOBAL_ROOT_UID;
+	kgid_t gid = GLOBAL_ROOT_GID;
 
-	kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, KERNFS_LINK);
+	if (target->iattr) {
+		uid = target->iattr->ia_iattr.ia_uid;
+		gid = target->iattr->ia_iattr.ia_gid;
+	}
+
+	kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, uid, gid,
+			     KERNFS_LINK);
 	if (!kn)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 58eba92a0e41..e39b884f0867 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -52,7 +52,9 @@  int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
 		return -ENOENT;
 
 	kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
-				  S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns);
+				  S_IRWXU | S_IRUGO | S_IXUGO,
+				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+				  kobj, ns);
 	if (IS_ERR(kn)) {
 		if (PTR_ERR(kn) == -EEXIST)
 			sysfs_warn_dup(parent, kobject_name(kobj));
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 5c13f29bfcdb..513fa691ecbd 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -302,8 +302,9 @@  int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 	if (!attr->ignore_lockdep)
 		key = attr->key ?: (struct lock_class_key *)&attr->skey;
 #endif
-	kn = __kernfs_create_file(parent, attr->name, mode & 0777, size, ops,
-				  (void *)attr, ns, key);
+	kn = __kernfs_create_file(parent, attr->name,
+				  mode & 0777, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+				  size, ops, (void *)attr, ns, key);
 	if (IS_ERR(kn)) {
 		if (PTR_ERR(kn) == -EEXIST)
 			sysfs_warn_dup(parent, attr->name);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index ab25c8b6d9e3..814643f7ee52 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -15,6 +15,7 @@ 
 #include <linux/lockdep.h>
 #include <linux/rbtree.h>
 #include <linux/atomic.h>
+#include <linux/uidgid.h>
 #include <linux/wait.h>
 
 struct file;
@@ -325,12 +326,14 @@  void kernfs_destroy_root(struct kernfs_root *root);
 
 struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 					 const char *name, umode_t mode,
+					 kuid_t uid, kgid_t gid,
 					 void *priv, const void *ns);
 struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
 					    const char *name);
 struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
-					 const char *name,
-					 umode_t mode, loff_t size,
+					 const char *name, umode_t mode,
+					 kuid_t uid, kgid_t gid,
+					 loff_t size,
 					 const struct kernfs_ops *ops,
 					 void *priv, const void *ns,
 					 struct lock_class_key *key);
@@ -415,12 +418,14 @@  static inline void kernfs_destroy_root(struct kernfs_root *root) { }
 
 static inline struct kernfs_node *
 kernfs_create_dir_ns(struct kernfs_node *parent, const char *name,
-		     umode_t mode, void *priv, const void *ns)
+		     umode_t mode, kuid_t uid, kgid_t gid,
+		     void *priv, const void *ns)
 { return ERR_PTR(-ENOSYS); }
 
 static inline struct kernfs_node *
 __kernfs_create_file(struct kernfs_node *parent, const char *name,
-		     umode_t mode, loff_t size, const struct kernfs_ops *ops,
+		     umode_t mode, kuid_t uid, kgid_t gid,
+		     loff_t size, const struct kernfs_ops *ops,
 		     void *priv, const void *ns, struct lock_class_key *key)
 { return ERR_PTR(-ENOSYS); }
 
@@ -498,12 +503,15 @@  static inline struct kernfs_node *
 kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
 		  void *priv)
 {
-	return kernfs_create_dir_ns(parent, name, mode, priv, NULL);
+	return kernfs_create_dir_ns(parent, name, mode,
+				    GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+				    priv, NULL);
 }
 
 static inline struct kernfs_node *
 kernfs_create_file_ns(struct kernfs_node *parent, const char *name,
-		      umode_t mode, loff_t size, const struct kernfs_ops *ops,
+		      umode_t mode, kuid_t uid, kgid_t gid,
+		      loff_t size, const struct kernfs_ops *ops,
 		      void *priv, const void *ns)
 {
 	struct lock_class_key *key = NULL;
@@ -511,15 +519,17 @@  kernfs_create_file_ns(struct kernfs_node *parent, const char *name,
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 	key = (struct lock_class_key *)&ops->lockdep_key;
 #endif
-	return __kernfs_create_file(parent, name, mode, size, ops, priv, ns,
-				    key);
+	return __kernfs_create_file(parent, name, mode, uid, gid,
+				    size, ops, priv, ns, key);
 }
 
 static inline struct kernfs_node *
 kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode,
 		   loff_t size, const struct kernfs_ops *ops, void *priv)
 {
-	return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL);
+	return kernfs_create_file_ns(parent, name, mode,
+				     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+				     size, ops, priv, NULL);
 }
 
 static inline int kernfs_remove_by_name(struct kernfs_node *parent,
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 077370bf8964..35cf3d71f8aa 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3557,7 +3557,9 @@  static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp,
 	key = &cft->lockdep_key;
 #endif
 	kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
-				  cgroup_file_mode(cft), 0, cft->kf_ops, cft,
+				  cgroup_file_mode(cft),
+				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+				  0, cft->kf_ops, cft,
 				  NULL, key);
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);