Linux filesystem development
 help / color / mirror / Atom feed
* [PATCH] ntfs: prevent write access to $MFT inode
@ 2026-07-02  6:35 Hongling Zeng
  2026-08-13 21:04 ` kernel test robot
  0 siblings, 1 reply; 2+ messages in thread
From: Hongling Zeng @ 2026-07-02  6:35 UTC (permalink / raw)
  To: linkinjeon, hyc.lee, charsyam
  Cc: linux-fsdevel, linux-kernel, zhongling0719, Hongling Zeng, stable

Malicious NTFS images can expose $MFT to userspace and allow write
operations, leading to potential kernel NULL pointer dereference
since ntfs_mft_aops lacks write_begin support.

The vulnerability affects both write_iter and mmap-based write paths:
1. write_iter path: ntfs_file_write_iter()
2. mmap write path: ntfs_filemap_page_mkwrite()

Without protecting both paths, attackers can bypass single-path
protection by using the alternative write method.

Fix by adding write protection in ntfs_file_write_iter() to prevent
any write operations to FILE_MFT.

Fixes: 1e9ea7e04472d ("Revert \"fs: Remove NTFS classic\"")
Cc: stable@vger.kernel.org
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
---
 fs/ntfs/file.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 6a7b638e523d..0d8f11e5ccb7 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -550,6 +550,12 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 	if (NVolShutdown(vol))
 		return -EIO;
 
+	if (ni->mft_no == FILE_MFT) {
+		ntfs_error(vi->i_sb, "Attempt to write to $MFT denied (mft_no: 0x%lx)",
+				ni->mft_no);
+		return -EACCES;
+	}
+
 	if (NInoEncrypted(ni)) {
 		ntfs_error(vi->i_sb, "Writing for %s files is not supported yet",
 			   NInoCompressed(ni) ? "Compressed" : "Encrypted");
@@ -618,8 +624,15 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 static vm_fault_t ntfs_filemap_page_mkwrite(struct vm_fault *vmf)
 {
 	struct inode *inode = file_inode(vmf->vma->vm_file);
+	struct ntfs_inode *ni = NTFS_I(inode);
 	vm_fault_t ret;
 
+	if (ni->mft_no == FILE_MFT) {
+		ntfs_error(inode->i_sb, "Attempt to write to $MFT via mmap denied (mft_no: 0x%lx)",
+				ni->mft_no);
+		return VM_FAULT_SIGBUS;
+	}
+
 	sb_start_pagefault(inode->i_sb);
 	file_update_time(vmf->vma->vm_file);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] ntfs: prevent write access to $MFT inode
  2026-07-02  6:35 [PATCH] ntfs: prevent write access to $MFT inode Hongling Zeng
@ 2026-08-13 21:04 ` kernel test robot
  0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2026-08-13 21:04 UTC (permalink / raw)
  To: Hongling Zeng, linkinjeon, hyc.lee, charsyam
  Cc: oe-kbuild-all, linux-fsdevel, linux-kernel, zhongling0719,
	Hongling Zeng, stable

Hi Hongling,

kernel test robot noticed the following build warnings:

[auto build test WARNING on brauner-vfs/vfs.all]
[also build test WARNING on linus/master v7.2-rc7 next-20260812]
[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#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Hongling-Zeng/ntfs-prevent-write-access-to-MFT-inode/20260814-004837
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/20260702063529.45448-1-zenghongling%40kylinos.cn
patch subject: [PATCH] ntfs: prevent write access to $MFT inode
config: powerpc-allmodconfig (https://download.01.org/0day-ci/archive/20260814/202608140556.ICYSq5Cy-lkp@intel.com/config)
compiler: powerpc64-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260814/202608140556.ICYSq5Cy-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608140556.ICYSq5Cy-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from fs/ntfs/inode.h:13,
                    from fs/ntfs/ntfs.h:26,
                    from fs/ntfs/attrib.h:13,
                    from fs/ntfs/lcnalloc.h:13,
                    from fs/ntfs/file.c:19:
   fs/ntfs/file.c: In function 'ntfs_file_write_iter':
>> fs/ntfs/file.c:554:38: warning: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'u64' {aka 'long long unsigned int'} [-Wformat=]
     554 |                 ntfs_error(vi->i_sb, "Attempt to write to $MFT denied (mft_no: 0x%lx)",
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     555 |                                 ni->mft_no);
         |                                 ~~~~~~~~~~
         |                                   |
         |                                   u64 {aka long long unsigned int}
   fs/ntfs/debug.h:59:68: note: in definition of macro 'ntfs_error'
      59 | #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
         |                                                                    ^
   fs/ntfs/file.c:554:84: note: format string is defined here
     554 |                 ntfs_error(vi->i_sb, "Attempt to write to $MFT denied (mft_no: 0x%lx)",
         |                                                                                  ~~^
         |                                                                                    |
         |                                                                                    long unsigned int
         |                                                                                  %llx
   fs/ntfs/file.c: In function 'ntfs_filemap_page_mkwrite':
   fs/ntfs/file.c:631:41: warning: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'u64' {aka 'long long unsigned int'} [-Wformat=]
     631 |                 ntfs_error(inode->i_sb, "Attempt to write to $MFT via mmap denied (mft_no: 0x%lx)",
         |                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     632 |                                 ni->mft_no);
         |                                 ~~~~~~~~~~
         |                                   |
         |                                   u64 {aka long long unsigned int}
   fs/ntfs/debug.h:59:68: note: in definition of macro 'ntfs_error'
      59 | #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
         |                                                                    ^
   fs/ntfs/file.c:631:96: note: format string is defined here
     631 |                 ntfs_error(inode->i_sb, "Attempt to write to $MFT via mmap denied (mft_no: 0x%lx)",
         |                                                                                              ~~^
         |                                                                                                |
         |                                                                                                long unsigned int
         |                                                                                              %llx


vim +554 fs/ntfs/file.c

   537	
   538	static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
   539	{
   540		struct file *file = iocb->ki_filp;
   541		struct inode *vi = file->f_mapping->host;
   542		struct ntfs_inode *ni = NTFS_I(vi);
   543		struct ntfs_volume *vol = ni->vol;
   544		ssize_t ret;
   545		ssize_t count;
   546		loff_t pos;
   547		int err;
   548		loff_t old_data_size, old_init_size;
   549	
   550		if (NVolShutdown(vol))
   551			return -EIO;
   552	
   553		if (ni->mft_no == FILE_MFT) {
 > 554			ntfs_error(vi->i_sb, "Attempt to write to $MFT denied (mft_no: 0x%lx)",
   555					ni->mft_no);
   556			return -EACCES;
   557		}
   558	
   559		if (NInoEncrypted(ni)) {
   560			ntfs_error(vi->i_sb, "Writing for %s files is not supported yet",
   561				   NInoCompressed(ni) ? "Compressed" : "Encrypted");
   562			return -EOPNOTSUPP;
   563		}
   564	
   565		if (NInoCompressed(ni) && iocb->ki_flags & IOCB_DIRECT)
   566			return -EOPNOTSUPP;
   567	
   568		if (iocb->ki_flags & IOCB_NOWAIT) {
   569			if (!inode_trylock(vi))
   570				return -EAGAIN;
   571		} else
   572			inode_lock(vi);
   573	
   574		ret = generic_write_checks(iocb, from);
   575		if (ret <= 0)
   576			goto out_lock;
   577	
   578		err = file_modified(iocb->ki_filp);
   579		if (err) {
   580			ret = err;
   581			goto out_lock;
   582		}
   583	
   584		if (!(vol->vol_flags & VOLUME_IS_DIRTY))
   585			ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY);
   586	
   587		pos = iocb->ki_pos;
   588		count = ret;
   589	
   590		old_data_size = ni->data_size;
   591		old_init_size = ni->initialized_size;
   592	
   593		if (NInoNonResident(ni) && NInoCompressed(ni)) {
   594			ret = ntfs_compress_write(ni, pos, count, from);
   595			if (ret > 0)
   596				iocb->ki_pos += ret;
   597			goto out;
   598		}
   599	
   600		if (NInoNonResident(ni) && iocb->ki_flags & IOCB_DIRECT)
   601			ret = ntfs_dio_write_iter(iocb, from);
   602		else
   603			ret = iomap_file_buffered_write(iocb, from, &ntfs_write_iomap_ops,
   604					&ntfs_iomap_folio_ops, NULL);
   605	out:
   606		if (ret < 0 && ret != -EIOCBQUEUED) {
   607			if (ni->initialized_size != old_init_size) {
   608				mutex_lock(&ni->mrec_lock);
   609				ntfs_attr_set_initialized_size(ni, old_init_size);
   610				mutex_unlock(&ni->mrec_lock);
   611			}
   612			if (ni->data_size != old_data_size) {
   613				truncate_setsize(vi, old_data_size);
   614				ntfs_attr_truncate(ni, old_data_size);
   615			}
   616		}
   617	out_lock:
   618		inode_unlock(vi);
   619		if (ret > 0)
   620			ret = generic_write_sync(iocb, ret);
   621		return ret;
   622	}
   623	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-13 21:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-02  6:35 [PATCH] ntfs: prevent write access to $MFT inode Hongling Zeng
2026-08-13 21:04 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox