[PATCH AUTOSEL 5.15 03/22] fs/ntfs3: Validate data run offset

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Edward Lo <edward.lo@xxxxxxxxxxxxx>

[ Upstream commit 6db620863f8528ed9a9aa5ad323b26554a17881d ]

This adds sanity checks for data run offset. We should make sure data
run offset is legit before trying to unpack them, otherwise we may
encounter use-after-free or some unexpected memory access behaviors.

[   82.940342] BUG: KASAN: use-after-free in run_unpack+0x2e3/0x570
[   82.941180] Read of size 1 at addr ffff888008a8487f by task mount/240
[   82.941670]
[   82.942069] CPU: 0 PID: 240 Comm: mount Not tainted 5.19.0+ #15
[   82.942482] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
[   82.943720] Call Trace:
[   82.944204]  <TASK>
[   82.944471]  dump_stack_lvl+0x49/0x63
[   82.944908]  print_report.cold+0xf5/0x67b
[   82.945141]  ? __wait_on_bit+0x106/0x120
[   82.945750]  ? run_unpack+0x2e3/0x570
[   82.946626]  kasan_report+0xa7/0x120
[   82.947046]  ? run_unpack+0x2e3/0x570
[   82.947280]  __asan_load1+0x51/0x60
[   82.947483]  run_unpack+0x2e3/0x570
[   82.947709]  ? memcpy+0x4e/0x70
[   82.947927]  ? run_pack+0x7a0/0x7a0
[   82.948158]  run_unpack_ex+0xad/0x3f0
[   82.948399]  ? mi_enum_attr+0x14a/0x200
[   82.948717]  ? run_unpack+0x570/0x570
[   82.949072]  ? ni_enum_attr_ex+0x1b2/0x1c0
[   82.949332]  ? ni_fname_type.part.0+0xd0/0xd0
[   82.949611]  ? mi_read+0x262/0x2c0
[   82.949970]  ? ntfs_cmp_names_cpu+0x125/0x180
[   82.950249]  ntfs_iget5+0x632/0x1870
[   82.950621]  ? ntfs_get_block_bmap+0x70/0x70
[   82.951192]  ? evict+0x223/0x280
[   82.951525]  ? iput.part.0+0x286/0x320
[   82.951969]  ntfs_fill_super+0x1321/0x1e20
[   82.952436]  ? put_ntfs+0x1d0/0x1d0
[   82.952822]  ? vsprintf+0x20/0x20
[   82.953188]  ? mutex_unlock+0x81/0xd0
[   82.953379]  ? set_blocksize+0x95/0x150
[   82.954001]  get_tree_bdev+0x232/0x370
[   82.954438]  ? put_ntfs+0x1d0/0x1d0
[   82.954700]  ntfs_fs_get_tree+0x15/0x20
[   82.955049]  vfs_get_tree+0x4c/0x130
[   82.955292]  path_mount+0x645/0xfd0
[   82.955615]  ? putname+0x80/0xa0
[   82.955955]  ? finish_automount+0x2e0/0x2e0
[   82.956310]  ? kmem_cache_free+0x110/0x390
[   82.956723]  ? putname+0x80/0xa0
[   82.957023]  do_mount+0xd6/0xf0
[   82.957411]  ? path_mount+0xfd0/0xfd0
[   82.957638]  ? __kasan_check_write+0x14/0x20
[   82.957948]  __x64_sys_mount+0xca/0x110
[   82.958310]  do_syscall_64+0x3b/0x90
[   82.958719]  entry_SYSCALL_64_after_hwframe+0x63/0xcd
[   82.959341] RIP: 0033:0x7fd0d1ce948a
[   82.960193] Code: 48 8b 0d 11 fa 2a 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 008
[   82.961532] RSP: 002b:00007ffe59ff69a8 EFLAGS: 00000202 ORIG_RAX: 00000000000000a5
[   82.962527] RAX: ffffffffffffffda RBX: 0000564dcc107060 RCX: 00007fd0d1ce948a
[   82.963266] RDX: 0000564dcc107260 RSI: 0000564dcc1072e0 RDI: 0000564dcc10fce0
[   82.963686] RBP: 0000000000000000 R08: 0000564dcc107280 R09: 0000000000000020
[   82.964272] R10: 00000000c0ed0000 R11: 0000000000000202 R12: 0000564dcc10fce0
[   82.964785] R13: 0000564dcc107260 R14: 0000000000000000 R15: 00000000ffffffff

Signed-off-by: Edward Lo <edward.lo@xxxxxxxxxxxxx>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
 fs/ntfs3/attrib.c   | 13 +++++++++++++
 fs/ntfs3/attrlist.c |  5 +++++
 fs/ntfs3/frecord.c  | 14 ++++++++++++++
 fs/ntfs3/fslog.c    |  9 +++++++++
 fs/ntfs3/inode.c    |  5 +++++
 5 files changed, 46 insertions(+)

diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index e8c00dda42ad..43e85c493c05 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -101,6 +101,10 @@ int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
 
 	asize = le32_to_cpu(attr->size);
 	run_off = le16_to_cpu(attr->nres.run_off);
+
+	if (run_off > asize)
+		return -EINVAL;
+
 	err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn,
 			    vcn ? *vcn : svcn, Add2Ptr(attr, run_off),
 			    asize - run_off);
@@ -1157,6 +1161,10 @@ int attr_load_runs_vcn(struct ntfs_inode *ni, enum ATTR_TYPE type,
 	}
 
 	ro = le16_to_cpu(attr->nres.run_off);
+
+	if (ro > le32_to_cpu(attr->size))
+		return -EINVAL;
+
 	err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn, svcn,
 			    Add2Ptr(attr, ro), le32_to_cpu(attr->size) - ro);
 	if (err < 0)
@@ -1832,6 +1840,11 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
 			u16 le_sz;
 			u16 roff = le16_to_cpu(attr->nres.run_off);
 
+			if (roff > le32_to_cpu(attr->size)) {
+				err = -EINVAL;
+				goto out;
+			}
+
 			run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn,
 				      evcn1 - 1, svcn, Add2Ptr(attr, roff),
 				      le32_to_cpu(attr->size) - roff);
diff --git a/fs/ntfs3/attrlist.c b/fs/ntfs3/attrlist.c
index bad6d8a849a2..c0c6bcbc8c05 100644
--- a/fs/ntfs3/attrlist.c
+++ b/fs/ntfs3/attrlist.c
@@ -68,6 +68,11 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
 
 		run_init(&ni->attr_list.run);
 
+		if (run_off > le32_to_cpu(attr->size)) {
+			err = -EINVAL;
+			goto out;
+		}
+
 		err = run_unpack_ex(&ni->attr_list.run, ni->mi.sbi, ni->mi.rno,
 				    0, le64_to_cpu(attr->nres.evcn), 0,
 				    Add2Ptr(attr, run_off),
diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c
index 18842998c8fa..cdeb0b51f0ba 100644
--- a/fs/ntfs3/frecord.c
+++ b/fs/ntfs3/frecord.c
@@ -567,6 +567,12 @@ static int ni_repack(struct ntfs_inode *ni)
 		}
 
 		roff = le16_to_cpu(attr->nres.run_off);
+
+		if (roff > le32_to_cpu(attr->size)) {
+			err = -EINVAL;
+			break;
+		}
+
 		err = run_unpack(&run, sbi, ni->mi.rno, svcn, evcn, svcn,
 				 Add2Ptr(attr, roff),
 				 le32_to_cpu(attr->size) - roff);
@@ -1541,6 +1547,9 @@ int ni_delete_all(struct ntfs_inode *ni)
 		asize = le32_to_cpu(attr->size);
 		roff = le16_to_cpu(attr->nres.run_off);
 
+		if (roff > asize)
+			return -EINVAL;
+
 		/* run==1 means unpack and deallocate. */
 		run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn, evcn, svcn,
 			      Add2Ptr(attr, roff), asize - roff);
@@ -2242,6 +2251,11 @@ int ni_decompress_file(struct ntfs_inode *ni)
 		asize = le32_to_cpu(attr->size);
 		roff = le16_to_cpu(attr->nres.run_off);
 
+		if (roff > asize) {
+			err = -EINVAL;
+			goto out;
+		}
+
 		/*run==1  Means unpack and deallocate. */
 		run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn, evcn, svcn,
 			      Add2Ptr(attr, roff), asize - roff);
diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c
index 614513460b8e..bcdddcd7bc79 100644
--- a/fs/ntfs3/fslog.c
+++ b/fs/ntfs3/fslog.c
@@ -2727,6 +2727,9 @@ static inline bool check_attr(const struct MFT_REC *rec,
 			return false;
 		}
 
+		if (run_off > asize)
+			return false;
+
 		if (run_unpack(NULL, sbi, 0, svcn, evcn, svcn,
 			       Add2Ptr(attr, run_off), asize - run_off) < 0) {
 			return false;
@@ -4769,6 +4772,12 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
 		u16 roff = le16_to_cpu(attr->nres.run_off);
 		CLST svcn = le64_to_cpu(attr->nres.svcn);
 
+		if (roff > t32) {
+			kfree(oa->attr);
+			oa->attr = NULL;
+			goto fake_attr;
+		}
+
 		err = run_unpack(&oa->run0, sbi, inode->i_ino, svcn,
 				 le64_to_cpu(attr->nres.evcn), svcn,
 				 Add2Ptr(attr, roff), t32 - roff);
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 64b4a3c29878..83d4c9f42d9c 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -364,6 +364,11 @@ static struct inode *ntfs_read_mft(struct inode *inode,
 attr_unpack_run:
 	roff = le16_to_cpu(attr->nres.run_off);
 
+	if (roff > asize) {
+		err = -EINVAL;
+		goto out;
+	}
+
 	t64 = le64_to_cpu(attr->nres.svcn);
 	err = run_unpack_ex(run, sbi, ino, t64, le64_to_cpu(attr->nres.evcn),
 			    t64, Add2Ptr(attr, roff), asize - roff);
-- 
2.35.1





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux