From: Kees Cook Date: Tue, 5 May 2020 02:46:53 +0000 (-0700) Subject: pstore: Remove filesystem records when backend is unregistered X-Git-Tag: v5.10.7~2539^2~25 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=609e28bb139e53621521130f0d4aea27a725d465;p=platform%2Fkernel%2Flinux-rpi.git pstore: Remove filesystem records when backend is unregistered 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 Link: https://lore.kernel.org/lkml/87o8yrmv69.fsf@suse.com Link: https://lore.kernel.org/lkml/20200506152114.50375-11-keescook@chromium.org/ Signed-off-by: Kees Cook --- diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 0e76e12..c331efe 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; }; @@ -191,6 +192,7 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry) list_del_init(&p->list); else rc = -ENOENT; + p->dentry = NULL; mutex_unlock(&records_list_lock); if (rc) return rc; @@ -306,6 +308,35 @@ static 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_drop(pos->dentry); + dput(pos->dentry); + pos->dentry = NULL; + } + } + 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 +383,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 fe5f7ef..8efd72d 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 327ee70..398785a 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -657,6 +657,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;