diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index a365088caa3c2f1dd356911d54f7f68dc5340396..673ef598d97d3c362a04dcb0799817b9515a5041 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -288,12 +288,11 @@ int kernfs_iop_permission(struct inode *inode, int mask)
 	return generic_permission(inode, mask);
 }
 
-static int kernfs_xattr_get(const struct xattr_handler *handler,
-			    struct dentry *unused, struct inode *inode,
-			    const char *suffix, void *value, size_t size)
+static int kernfs_node_xattr_get(const struct xattr_handler *handler,
+				 struct kernfs_node *kn, const char *suffix,
+				 void *value, size_t size)
 {
 	const char *name = xattr_full_name(handler, suffix);
-	struct kernfs_node *kn = inode->i_private;
 	struct kernfs_iattrs *attrs;
 
 	attrs = kernfs_iattrs_noalloc(kn);
@@ -303,13 +302,11 @@ static int kernfs_xattr_get(const struct xattr_handler *handler,
 	return simple_xattr_get(&attrs->xattrs, name, value, size);
 }
 
-static int kernfs_xattr_set(const struct xattr_handler *handler,
-			    struct dentry *unused, struct inode *inode,
-			    const char *suffix, const void *value,
-			    size_t size, int flags)
+static int kernfs_node_xattr_set(const struct xattr_handler *handler,
+				 struct kernfs_node *kn, const char *suffix,
+				 const void *value, size_t size, int flags)
 {
 	const char *name = xattr_full_name(handler, suffix);
-	struct kernfs_node *kn = inode->i_private;
 	struct kernfs_iattrs *attrs;
 
 	attrs = kernfs_iattrs(kn);
@@ -319,6 +316,25 @@ static int kernfs_xattr_set(const struct xattr_handler *handler,
 	return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
 }
 
+static int kernfs_xattr_get(const struct xattr_handler *handler,
+			    struct dentry *unused, struct inode *inode,
+			    const char *suffix, void *value, size_t size)
+{
+	struct kernfs_node *kn = inode->i_private;
+
+	return kernfs_node_xattr_get(handler, kn, suffix, value, size);
+}
+
+static int kernfs_xattr_set(const struct xattr_handler *handler,
+			    struct dentry *unused, struct inode *inode,
+			    const char *suffix, const void *value,
+			    size_t size, int flags)
+{
+	struct kernfs_node *kn = inode->i_private;
+
+	return kernfs_node_xattr_set(handler, kn, suffix, value, size, flags);
+}
+
 static const struct xattr_handler kernfs_trusted_xattr_handler = {
 	.prefix = XATTR_TRUSTED_PREFIX,
 	.get = kernfs_xattr_get,
@@ -336,3 +352,17 @@ const struct xattr_handler *kernfs_xattr_handlers[] = {
 	&kernfs_security_xattr_handler,
 	NULL
 };
+
+int kernfs_security_xattr_get(struct kernfs_node *kn, const char *suffix,
+			      void *value, size_t size)
+{
+	return kernfs_node_xattr_get(&kernfs_security_xattr_handler,
+				     kn, suffix, value, size);
+}
+
+int kernfs_security_xattr_set(struct kernfs_node *kn, const char *suffix,
+			      void *value, size_t size, int flags)
+{
+	return kernfs_node_xattr_set(&kernfs_security_xattr_handler,
+				     kn, suffix, value, size, flags);
+}
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index c8893f6634705eb8da4795455ce67820ae98d7e4..39eea07c2900b15ee9d1a3f8d3b9655feb2cc3b3 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -371,6 +371,11 @@ __poll_t kernfs_generic_poll(struct kernfs_open_file *of,
 			     struct poll_table_struct *pt);
 void kernfs_notify(struct kernfs_node *kn);
 
+int kernfs_security_xattr_get(struct kernfs_node *kn, const char *suffix,
+			      void *value, size_t size);
+int kernfs_security_xattr_set(struct kernfs_node *kn, const char *suffix,
+			      void *value, size_t size, int flags);
+
 const void *kernfs_super_ns(struct super_block *sb);
 int kernfs_get_tree(struct fs_context *fc);
 void kernfs_free_fs_context(struct fs_context *fc);
@@ -473,6 +478,16 @@ static inline int kernfs_setattr(struct kernfs_node *kn,
 
 static inline void kernfs_notify(struct kernfs_node *kn) { }
 
+static inline int kernfs_security_xattr_get(struct kernfs_node *kn,
+					    const char *suffix, void *value,
+					    size_t size)
+{ return -ENOSYS; }
+
+static inline int kernfs_security_xattr_set(struct kernfs_node *kn,
+					    const char *suffix, void *value,
+					    size_t size, int flags)
+{ return -ENOSYS; }
+
 static inline const void *kernfs_super_ns(struct super_block *sb)
 { return NULL; }
 
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index a9b8ff578b6b3e4571c606fb8b3705778ce62ebb..0dd5bda719e69adaa63b0d83b6a2df8465f2f7f5 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -445,6 +445,15 @@
  *	to abort the copy up. Note that the caller is responsible for reading
  *	and writing the xattrs as this hook is merely a filter.
  *
+ * Security hooks for kernfs node operations
+ *
+ * @kernfs_init_security
+ *	Initialize the security context of a newly created kernfs node based
+ *	on its own and its parent's attributes.
+ *
+ *	@kn_dir the parent kernfs node
+ *	@kn the new child kernfs node
+ *
  * Security hooks for file operations
  *
  * @file_permission:
@@ -1578,6 +1587,9 @@ union security_list_options {
 	int (*inode_copy_up)(struct dentry *src, struct cred **new);
 	int (*inode_copy_up_xattr)(const char *name);
 
+	int (*kernfs_init_security)(struct kernfs_node *kn_dir,
+				    struct kernfs_node *kn);
+
 	int (*file_permission)(struct file *file, int mask);
 	int (*file_alloc_security)(struct file *file);
 	void (*file_free_security)(struct file *file);
@@ -1879,6 +1891,7 @@ struct security_hook_heads {
 	struct hlist_head inode_getsecid;
 	struct hlist_head inode_copy_up;
 	struct hlist_head inode_copy_up_xattr;
+	struct hlist_head kernfs_init_security;
 	struct hlist_head file_permission;
 	struct hlist_head file_alloc_security;
 	struct hlist_head file_free_security;
diff --git a/include/linux/security.h b/include/linux/security.h
index 49f2685324b09eae63640838dc7cfe83dd2463f3..d543293216b974adfef7465696590336c66b11c4 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -51,6 +51,7 @@ struct fown_struct;
 struct file_operations;
 struct msg_msg;
 struct xattr;
+struct kernfs_node;
 struct xfrm_sec_ctx;
 struct mm_struct;
 struct fs_context;
@@ -299,6 +300,8 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
 void security_inode_getsecid(struct inode *inode, u32 *secid);
 int security_inode_copy_up(struct dentry *src, struct cred **new);
 int security_inode_copy_up_xattr(const char *name);
+int security_kernfs_init_security(struct kernfs_node *kn_dir,
+				  struct kernfs_node *kn);
 int security_file_permission(struct file *file, int mask);
 int security_file_alloc(struct file *file);
 void security_file_free(struct file *file);
@@ -801,6 +804,12 @@ static inline int security_inode_copy_up(struct dentry *src, struct cred **new)
 	return 0;
 }
 
+static inline int security_kernfs_init_security(struct kernfs_node *kn_dir,
+						struct kernfs_node *kn)
+{
+	return 0;
+}
+
 static inline int security_inode_copy_up_xattr(const char *name)
 {
 	return -EOPNOTSUPP;
diff --git a/security/security.c b/security/security.c
index 23cbb1a295a361a6be204e6bf5aec4d8971f152a..8d6ef9da94eb836244dc834bd827ddd4573bd763 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1318,6 +1318,12 @@ int security_inode_copy_up_xattr(const char *name)
 }
 EXPORT_SYMBOL(security_inode_copy_up_xattr);
 
+int security_kernfs_init_security(struct kernfs_node *kn_dir,
+				  struct kernfs_node *kn)
+{
+	return call_int_hook(kernfs_init_security, 0, kn_dir, kn);
+}
+
 int security_file_permission(struct file *file, int mask)
 {
 	int ret;