diff mbox series

[V1] fuse: Fix VM_BUG_ON_PAGE issue while accessing zero ref count page

Message ID 1597942555-904-1-git-send-email-ppvk@codeaurora.org (mailing list archive)
State New, archived
Headers show
Series [V1] fuse: Fix VM_BUG_ON_PAGE issue while accessing zero ref count page | expand

Commit Message

Pradeep P V K Aug. 20, 2020, 4:55 p.m. UTC
There is a potential race between fuse_abort_conn() and
fuse_copy_page() as shown below, due to which VM_BUG_ON_PAGE
crash is observed.

context#1:			context#2:
fuse_dev_do_read()		fuse_abort_conn()
->fuse_copy_args()		 ->end_requests()
 ->fuse_copy_pages()		  ->request_end()
  ->fuse_copy_page()		   ->fuse_writepage_end)
   ->fuse_ref_page()		    ->fuse_writepage_free()
				     ->__free_page()
				      ->put_page_testzero()

   ->get_page()
    ->VM_BUG_ON_PAGE()

This results in below crash as when ->put_page_testzero() in context#2
decrease the page reference and get_page() in context#1 accessed it
with zero page reference count.

[  174.391095]  (1)[10406:Thread-6]page dumped because:
VM_BUG_ON_PAGE(((unsigned int) page_ref_count(page) + 127u <= 127u))
[  174.391113]  (1)[10406:Thread-6]page allocated via order 0,
migratetype Unmovable, gfp_mask
0x620042(GFP_NOFS|__GFP_HIGHMEM|__GFP_HARDWALL), pid 261, ts 174390946312 ns
[  174.391135]  (1)[10406:Thread-6] prep_new_page+0x13c/0x210
[  174.391148]  (1)[10406:Thread-6] get_page_from_freelist+0x21ac/0x2370
[  174.391161]  (1)[10406:Thread-6] __alloc_pages_nodemask+0x244/0x14a8
[  174.391176]  (1)[10406:Thread-6] fuse_writepages_fill+0x150/0x708
[  174.391190]  (1)[10406:Thread-6] write_cache_pages+0x3d8/0x550
[  174.391202]  (1)[10406:Thread-6] fuse_writepages+0x94/0x130
[  174.391214]  (1)[10406:Thread-6] do_writepages+0x74/0x140
[  174.391228]  (1)[10406:Thread-6] __writeback_single_inode+0x168/0x788
[  174.391239]  (1)[10406:Thread-6] writeback_sb_inodes+0x56c/0xab8
[  174.391251]  (1)[10406:Thread-6] __writeback_inodes_wb+0x94/0x180
[  174.391262]  (1)[10406:Thread-6] wb_writeback+0x318/0x618
[  174.391274]  (1)[10406:Thread-6] wb_workfn+0x468/0x828
[  174.391290]  (1)[10406:Thread-6] process_one_work+0x3d0/0x720
[  174.391302]  (1)[10406:Thread-6] worker_thread+0x234/0x4c0
[  174.391314]  (1)[10406:Thread-6] kthread+0x144/0x158
[  174.391327]  (1)[10406:Thread-6] ret_from_fork+0x10/0x1c
[  174.391363]  (1)[10406:Thread-6]------------[ cut here ]------------
[  174.391371]  (1)[10406:Thread-6]kernel BUG at include/linux/mm.h:980!
[  174.391381]  (1)[10406:Thread-6]Internal error: Oops - BUG: 0 [#1]
...
[  174.486928]  (1)[10406:Thread-6]pc : fuse_copy_page+0x750/0x790
[  174.493029]  (1)[10406:Thread-6]lr : fuse_copy_page+0x750/0x790
[  174.718831]  (1)[10406:Thread-6] fuse_copy_page+0x750/0x790
[  174.718838]  (1)[10406:Thread-6] fuse_copy_args+0xb4/0x1e8
[  174.718843]  (1)[10406:Thread-6] fuse_dev_do_read+0x424/0x888
[  174.718848]  (1)[10406:Thread-6] fuse_dev_splice_read+0x94/0x200
[  174.718856]  (1)[10406:Thread-6] __arm64_sys_splice+0x874/0xb20
[  174.718864]  (1)[10406:Thread-6] el0_svc_common+0xc8/0x240
[  174.718869]  (1)[10406:Thread-6] el0_svc_handler+0x6c/0x88
[  174.718875]  (1)[10406:Thread-6] el0_svc+0x8/0xc
[  174.778853]  (1)[10406:Thread-6]Kernel panic - not syncing: Fatal

Fix this by protecting fuse_copy_pages() with fc->lock.

Signed-off-by: Pradeep P V K <ppvk@codeaurora.org>
---
 fs/fuse/dev.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

Comments

kernel test robot Aug. 20, 2020, 9:50 p.m. UTC | #1
Hi Pradeep,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on fuse/for-next]
[also build test ERROR on v5.9-rc1 next-20200820]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Pradeep-P-V-K/fuse-Fix-VM_BUG_ON_PAGE-issue-while-accessing-zero-ref-count-page/20200821-005756
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
config: x86_64-randconfig-a003-20200820 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project 4deda57106f7c9b982a49cb907c33e3966c8de7f)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> fs/fuse/dev.c:955:11: error: no member named 'ff' in 'struct fuse_req'
           if (req->ff)
               ~~~  ^
   fs/fuse/dev.c:956:19: error: no member named 'ff' in 'struct fuse_req'
                   spin_lock(&req->ff->fc->lock);
                              ~~~  ^
   fs/fuse/dev.c:968:11: error: no member named 'ff' in 'struct fuse_req'
           if (req->ff)
               ~~~  ^
   fs/fuse/dev.c:969:21: error: no member named 'ff' in 'struct fuse_req'
                   spin_unlock(&req->ff->fc->lock);
                                ~~~  ^
   4 errors generated.

# https://github.com/0day-ci/linux/commit/776d24e60b6fdfbd88fc0cf0bf04859293d42bd6
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pradeep-P-V-K/fuse-Fix-VM_BUG_ON_PAGE-issue-while-accessing-zero-ref-count-page/20200821-005756
git checkout 776d24e60b6fdfbd88fc0cf0bf04859293d42bd6
vim +955 fs/fuse/dev.c

   945	
   946	/* Copy pages in the request to/from userspace buffer */
   947	static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
   948				   int zeroing)
   949	{
   950		unsigned i;
   951		int err = 0;
   952		struct fuse_req *req = cs->req;
   953		struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args);
   954	
 > 955		if (req->ff)
   956			spin_lock(&req->ff->fc->lock);
   957		for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
   958			unsigned int offset = ap->descs[i].offset;
   959			unsigned int count = min(nbytes, ap->descs[i].length);
   960	
   961			err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
   962			if (err)
   963				goto err;
   964	
   965			nbytes -= count;
   966		}
   967	err:
   968		if (req->ff)
   969			spin_unlock(&req->ff->fc->lock);
   970		return err;
   971	}
   972	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 02b3c36..ca4f63c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -948,22 +948,26 @@  static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
 			   int zeroing)
 {
 	unsigned i;
+	int err = 0;
 	struct fuse_req *req = cs->req;
 	struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args);
 
-
+	if (req->ff)
+		spin_lock(&req->ff->fc->lock);
 	for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
-		int err;
 		unsigned int offset = ap->descs[i].offset;
 		unsigned int count = min(nbytes, ap->descs[i].length);
 
 		err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
 		if (err)
-			return err;
+			goto err;
 
 		nbytes -= count;
 	}
-	return 0;
+err:
+	if (req->ff)
+		spin_unlock(&req->ff->fc->lock);
+	return err;
 }
 
 /* Copy a single argument in the request to/from userspace buffer */