[10/10] pstore: Remove filesystem records when backend is unregistered
diff mbox series

Message ID 20200506152114.50375-11-keescook@chromium.org
State In Next
Commit 455041156af8c9fe9ae575310942f6f5e3d789e1
Headers show
Series
  • pstore: Remove filesystem records when backend is unregistered
Related show

Commit Message

Kees Cook May 6, 2020, 3:21 p.m. UTC
If a backend was unloaded without having first removed all its
associated records in pstorefs, subsequent removals would crash while
attempting to call into the now missing backend. Add automatic removal
from the tree in pstore_unregister(), so that no references to the
backend remain.

Reported-by: Luis Henriques <lhenriques@suse.com>
Link: https://lore.kernel.org/lkml/87o8yrmv69.fsf@suse.com
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 fs/pstore/inode.c    | 30 ++++++++++++++++++++++++++++++
 fs/pstore/internal.h |  1 +
 fs/pstore/platform.c |  3 +++
 3 files changed, 34 insertions(+)

Patch
diff mbox series

diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index e13482c8e180..499d91a669bb 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -36,6 +36,7 @@  static struct super_block *pstore_sb;
 
 struct pstore_private {
 	struct list_head list;
+	struct dentry *dentry;
 	struct pstore_record *record;
 	size_t total_size;
 };
@@ -306,6 +307,34 @@  struct dentry *psinfo_lock_root(void)
 	return root;
 }
 
+int pstore_put_backend_records(struct pstore_info *psi)
+{
+	struct pstore_private *pos, *tmp;
+	struct dentry *root;
+	int rc = 0;
+
+	root = psinfo_lock_root();
+	if (!root)
+		return 0;
+
+	mutex_lock(&records_list_lock);
+	list_for_each_entry_safe(pos, tmp, &records_list, list) {
+		if (pos->record->psi == psi) {
+			list_del_init(&pos->list);
+			rc = simple_unlink(d_inode(root), pos->dentry);
+			if (WARN_ON(rc))
+				break;
+			d_delete(pos->dentry);
+			dput(pos->dentry);
+		}
+	}
+	mutex_unlock(&records_list_lock);
+
+	inode_unlock(d_inode(root));
+
+	return rc;
+}
+
 /*
  * Make a regular file in the root directory of our file system.
  * Load it up with "size" bytes of data from "buf".
@@ -352,6 +381,7 @@  int pstore_mkfile(struct dentry *root, struct pstore_record *record)
 	if (!dentry)
 		goto fail_private;
 
+	private->dentry = dentry;
 	private->record = record;
 	inode->i_size = private->total_size = size;
 	inode->i_private = private;
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index fe5f7ef7323f..8efd72d93b10 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -31,6 +31,7 @@  extern void	pstore_set_kmsg_bytes(int);
 extern void	pstore_get_records(int);
 extern void	pstore_get_backend_records(struct pstore_info *psi,
 					   struct dentry *root, int quiet);
+extern int	pstore_put_backend_records(struct pstore_info *psi);
 extern int	pstore_mkfile(struct dentry *root,
 			      struct pstore_record *record);
 extern void	pstore_record_init(struct pstore_record *record,
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 03a17b401533..6fb526187953 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -658,6 +658,9 @@  void pstore_unregister(struct pstore_info *psi)
 	del_timer_sync(&pstore_timer);
 	flush_work(&pstore_work);
 
+	/* Remove all backend records from filesystem tree. */
+	pstore_put_backend_records(psi);
+
 	free_buf_for_compression();
 
 	psinfo = NULL;