diff --git a/fs/Makefile b/fs/Makefile
index 293733f61594..738e1a4e4aff 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -12,7 +12,7 @@ obj-y :=	open.o read_write.o file_table.o super.o \
 		attr.o bad_inode.o file.o filesystems.o namespace.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o \
 		pnode.o splice.o sync.o utimes.o d_path.o \
-		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
+		stack.o fs_struct.o statfs.o fs_pin.o nsfs.o readxattr.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=	buffer.o block_dev.o direct-io.o mpage.o
diff --git a/fs/readxattr.c b/fs/readxattr.c
new file mode 100644
index 000000000000..01838f6f1e92
--- /dev/null
+++ b/fs/readxattr.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: readxattr.c
+ *      Read extended attributes from regular files in the initial ram disk
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/xattr.h>
+#include <linux/file.h>
+#include <linux/cred.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+
+#include "internal.h"
+
+#define SETXATTR_FILENAME ".setxattr"
+#define FILENAME_XATTR_SEP ".xattr-"
+
+
+struct readdir_callback {
+	struct dir_context ctx;
+	struct path *path;
+};
+
+LIST_HEAD(dir_list);
+
+struct dir_path {
+	struct list_head next;
+	struct path path;
+};
+
+static int __init read_set_xattr(struct dir_context *__ctx, const char *name,
+				 int namelen, loff_t offset, u64 ino,
+				 unsigned int d_type)
+{
+	struct readdir_callback *ctx = container_of(__ctx, typeof(*ctx), ctx);
+	struct path *dir = ctx->path, source_path, target_path;
+	char filename[NAME_MAX + 1], *xattrname, *separator;
+	struct dir_path *subdir;
+	struct file *file;
+	void *datap;
+	loff_t size;
+	int result;
+
+	if (!strcmp(name, ".") || !strcmp(name, ".."))
+		return 0;
+
+	result = vfs_path_lookup(dir->dentry, dir->mnt, name, 0, &source_path);
+	if (result)
+		return 0;
+
+	size = i_size_read(source_path.dentry->d_inode);
+	if (size > XATTR_SIZE_MAX)
+		goto out;
+
+	if (source_path.dentry->d_inode->i_sb != dir->dentry->d_inode->i_sb)
+		goto out;
+
+	if (!S_ISREG(source_path.dentry->d_inode->i_mode) &&
+	    !S_ISDIR(source_path.dentry->d_inode->i_mode))
+		goto out;
+
+	if (S_ISREG(source_path.dentry->d_inode->i_mode)) {
+		separator = strstr(name, FILENAME_XATTR_SEP);
+		if (!separator)
+			goto out;
+
+		xattrname = separator + sizeof(FILENAME_XATTR_SEP) - 1;
+		if (strlen(xattrname) > XATTR_NAME_MAX)
+			goto out;
+	} else {
+		subdir = kmalloc(sizeof(*subdir), GFP_KERNEL);
+		if (subdir) {
+			subdir->path.dentry = source_path.dentry;
+			subdir->path.mnt = source_path.mnt;
+
+			list_add(&subdir->next, &dir_list);
+		}
+
+		return 0;
+	}
+
+	file = dentry_open(&source_path, O_RDONLY, current_cred());
+	if (IS_ERR(file))
+		goto out;
+
+	result = kernel_read_file(file, &datap, &size, 0, READING_XATTR);
+	if (result)
+		goto out_fput;
+
+	if (separator != name) {
+		snprintf(filename, sizeof(filename), "%.*s",
+			 (int)(namelen - strlen(separator)), name);
+
+		result = vfs_path_lookup(dir->dentry, dir->mnt, filename, 0,
+					&target_path);
+		if (result)
+			goto out_vfree;
+
+		inode_lock(target_path.dentry->d_inode);
+	} else {
+		target_path.dentry = dir->dentry;
+		target_path.mnt = dir->mnt;
+	}
+
+	__vfs_setxattr_noperm(target_path.dentry, xattrname, datap, size, 0);
+
+	if (separator != name) {
+		inode_unlock(target_path.dentry->d_inode);
+		path_put(&target_path);
+	}
+out_vfree:
+	vfree(datap);
+out_fput:
+	fput(file);
+out:
+	path_put(&source_path);
+	return 0;
+}
+
+void __init set_xattrs_initrd(void)
+{
+	struct readdir_callback buf = {
+		.ctx.actor = read_set_xattr,
+	};
+
+	struct dir_path dir, *cur_dir;
+	struct path path;
+	struct file *file;
+	int result;
+
+	result = kern_path(SETXATTR_FILENAME, 0, &path);
+	if (result)
+		return;
+
+	path_put(&path);
+
+	result = kern_path("/", 0, &dir.path);
+	if (result)
+		return;
+
+	list_add(&dir.next, &dir_list);
+
+	while (!list_empty(&dir_list)) {
+		cur_dir = list_first_entry(&dir_list, typeof(*cur_dir), next);
+
+		file = dentry_open(&cur_dir->path, O_RDONLY, current_cred());
+		if (file) {
+			buf.path = &cur_dir->path;
+			iterate_dir(file, &buf.ctx);
+			fput(file);
+		}
+
+		path_put(&cur_dir->path);
+		list_del(&cur_dir->next);
+
+		if (cur_dir != &dir)
+			kfree(cur_dir);
+	}
+}
+EXPORT_SYMBOL_GPL(set_xattrs_initrd);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c95c0807471f..b04edc1c32e9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2894,6 +2894,7 @@ extern int do_pipe_flags(int *, int);
 	id(KEXEC_INITRAMFS, kexec-initramfs)	\
 	id(POLICY, security-policy)		\
 	id(X509_CERTIFICATE, x509-certificate)	\
+	id(XATTR, xattr)	\
 	id(MAX_ID, )
 
 #define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
@@ -3156,6 +3157,7 @@ const char *simple_get_link(struct dentry *, struct inode *,
 extern const struct inode_operations simple_symlink_inode_operations;
 
 extern int iterate_dir(struct file *, struct dir_context *);
+extern void set_xattrs_initrd(void);
 
 extern int vfs_statx(int, const char __user *, int, struct kstat *, u32);
 extern int vfs_statx_fd(unsigned int, struct kstat *, u32, unsigned int);
diff --git a/init/main.c b/init/main.c
index ee147103ba1b..a2f63bc8f9d4 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1180,5 +1180,6 @@ static noinline void __init kernel_init_freeable(void)
 	 */
 
 	integrity_load_keys();
+	set_xattrs_initrd();
 	load_default_modules();
 }
