All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-13  5:59 ` Manas Ghandat
  0 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-13  5:59 UTC (permalink / raw)
  To: gregkh
  Cc: Manas Ghandat, Linux-kernel-mentees, anton, linkinjeon,
	linux-fsdevel, linux-kernel, linux-ntfs-dev,
	syzbot+4768a8f039aa677897d0

Currently there is not check for ni->itype.compressed.block_size when
a->data.non_resident.compression_unit is present and NInoSparse(ni) is
true. Added the required check to calculation of block size.

Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
---
V3 -> V4: Fix description
V2 -> V3: Fix patching issue.
V1 -> V2: Cleaned up coding style.

 fs/ntfs/inode.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 6c3f38d66579..a657322874ed 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1077,6 +1077,15 @@ static int ntfs_read_locked_inode(struct inode *vi)
 					goto unm_err_out;
 				}
 				if (a->data.non_resident.compression_unit) {
+					if (a->data.non_resident.compression_unit +
+					vol->cluster_size_bits > 32) {
+						ntfs_error(vi->i_sb,
+						"Found non-standard compression unit (%u).   Cannot handle this.",
+						a->data.non_resident.compression_unit
+						);
+						err = -EOPNOTSUPP;
+						goto unm_err_out;
+					}
 					ni->itype.compressed.block_size = 1U <<
 							(a->data.non_resident.
 							compression_unit +
-- 
2.37.2


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

* [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-13  5:59 ` Manas Ghandat
  0 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-13  5:59 UTC (permalink / raw)
  To: gregkh
  Cc: Manas Ghandat, linux-ntfs-dev, linux-kernel,
	syzbot+4768a8f039aa677897d0, linux-fsdevel, Linux-kernel-mentees,
	linkinjeon, anton

Currently there is not check for ni->itype.compressed.block_size when
a->data.non_resident.compression_unit is present and NInoSparse(ni) is
true. Added the required check to calculation of block size.

Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
---
V3 -> V4: Fix description
V2 -> V3: Fix patching issue.
V1 -> V2: Cleaned up coding style.

 fs/ntfs/inode.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 6c3f38d66579..a657322874ed 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1077,6 +1077,15 @@ static int ntfs_read_locked_inode(struct inode *vi)
 					goto unm_err_out;
 				}
 				if (a->data.non_resident.compression_unit) {
+					if (a->data.non_resident.compression_unit +
+					vol->cluster_size_bits > 32) {
+						ntfs_error(vi->i_sb,
+						"Found non-standard compression unit (%u).   Cannot handle this.",
+						a->data.non_resident.compression_unit
+						);
+						err = -EOPNOTSUPP;
+						goto unm_err_out;
+					}
 					ni->itype.compressed.block_size = 1U <<
 							(a->data.non_resident.
 							compression_unit +
-- 
2.37.2

_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-13  5:59 ` Manas Ghandat
@ 2023-08-14  1:02   ` Namjae Jeon
  -1 siblings, 0 replies; 21+ messages in thread
From: Namjae Jeon @ 2023-08-14  1:02 UTC (permalink / raw)
  To: Manas Ghandat, anton
  Cc: linux-ntfs-dev, linux-kernel, syzbot+4768a8f039aa677897d0,
	linux-fsdevel, Linux-kernel-mentees

2023-08-13 14:59 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com>:
Hi,
> Currently there is not check for ni->itype.compressed.block_size when
> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
> true. Added the required check to calculation of block size.
>
> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
> ---
> V3 -> V4: Fix description
> V2 -> V3: Fix patching issue.
> V1 -> V2: Cleaned up coding style.
>
>  fs/ntfs/inode.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
> index 6c3f38d66579..a657322874ed 100644
> --- a/fs/ntfs/inode.c
> +++ b/fs/ntfs/inode.c
> @@ -1077,6 +1077,15 @@ static int ntfs_read_locked_inode(struct inode *vi)
>  					goto unm_err_out;
>  				}
>  				if (a->data.non_resident.compression_unit) {
> +					if (a->data.non_resident.compression_unit +
> +					vol->cluster_size_bits > 32) {
> +						ntfs_error(vi->i_sb,
> +						"Found non-standard compression unit (%u).   Cannot handle this.",
> +						a->data.non_resident.compression_unit
> +						);
> +						err = -EOPNOTSUPP;
> +						goto unm_err_out;
> +					}
compression_unit seems to be used when the ntfs inode is compressed.
And it should be either 0 or 4 value. So, I think we can set related
compression block variables of ntfs inode only when ni is
NInoCompressed like this... Anton, Am I missing something ?

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index efe0602b4e51..e5a7d81d575b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1076,7 +1076,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
                                        err = -EOPNOTSUPP;
                                        goto unm_err_out;
                                }
-                               if (a->data.non_resident.compression_unit) {
+                               if (NInoCompressed(ni) &&
+                                   a->data.non_resident.compression_unit) {
                                        ni->itype.compressed.block_size = 1U <<
                                                        (a->data.non_resident.
                                                        compression_unit +

>  					ni->itype.compressed.block_size = 1U <<
>  							(a->data.non_resident.
>  							compression_unit +
> --
> 2.37.2
>
>
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-14  1:02   ` Namjae Jeon
  0 siblings, 0 replies; 21+ messages in thread
From: Namjae Jeon @ 2023-08-14  1:02 UTC (permalink / raw)
  To: Manas Ghandat, anton
  Cc: gregkh, Linux-kernel-mentees, linux-fsdevel, linux-kernel,
	linux-ntfs-dev, syzbot+4768a8f039aa677897d0

2023-08-13 14:59 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com>:
Hi,
> Currently there is not check for ni->itype.compressed.block_size when
> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
> true. Added the required check to calculation of block size.
>
> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
> ---
> V3 -> V4: Fix description
> V2 -> V3: Fix patching issue.
> V1 -> V2: Cleaned up coding style.
>
>  fs/ntfs/inode.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
> index 6c3f38d66579..a657322874ed 100644
> --- a/fs/ntfs/inode.c
> +++ b/fs/ntfs/inode.c
> @@ -1077,6 +1077,15 @@ static int ntfs_read_locked_inode(struct inode *vi)
>  					goto unm_err_out;
>  				}
>  				if (a->data.non_resident.compression_unit) {
> +					if (a->data.non_resident.compression_unit +
> +					vol->cluster_size_bits > 32) {
> +						ntfs_error(vi->i_sb,
> +						"Found non-standard compression unit (%u).   Cannot handle this.",
> +						a->data.non_resident.compression_unit
> +						);
> +						err = -EOPNOTSUPP;
> +						goto unm_err_out;
> +					}
compression_unit seems to be used when the ntfs inode is compressed.
And it should be either 0 or 4 value. So, I think we can set related
compression block variables of ntfs inode only when ni is
NInoCompressed like this... Anton, Am I missing something ?

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index efe0602b4e51..e5a7d81d575b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1076,7 +1076,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
                                        err = -EOPNOTSUPP;
                                        goto unm_err_out;
                                }
-                               if (a->data.non_resident.compression_unit) {
+                               if (NInoCompressed(ni) &&
+                                   a->data.non_resident.compression_unit) {
                                        ni->itype.compressed.block_size = 1U <<
                                                        (a->data.non_resident.
                                                        compression_unit +

>  					ni->itype.compressed.block_size = 1U <<
>  							(a->data.non_resident.
>  							compression_unit +
> --
> 2.37.2
>
>

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-14  1:02   ` Namjae Jeon
  (?)
@ 2023-08-14  9:29   ` Anton Altaparmakov via Linux-kernel-mentees
  2023-08-15  5:22       ` Manas Ghandat
  -1 siblings, 1 reply; 21+ messages in thread
From: Anton Altaparmakov via Linux-kernel-mentees @ 2023-08-14  9:29 UTC (permalink / raw)
  To: Namjae Jeon
  Cc: Manas Ghandat, linux-ntfs-dev, Linux Kernel,
	syzbot+4768a8f039aa677897d0, Linux FS-devel Mailing List,
	Linux-kernel-mentees


[-- Attachment #1.1: Type: text/plain, Size: 5552 bytes --]

Hi Namjae,

The compression unit is not only used for compressed files.  It is also used for sparse files.  This is from some internal documentation I wrote:

The compression unit expressed as the log to the base 2 of the number of clusters in a compression unit.  0 means not compressed.  (This effectively limits the compression unit size to be a power of two clusters.)  WinNT4 only uses a value of 4.  Sparse files have this set to 0 on XPSP2.  On Windows 7, sparse files have this set to 4 for cluster size <= 4096, to 3 for cluster size 8192, to 2 for cluster size 16384, to 1 for cluster size 32768 and to 0 for cluster size 65536, i.e. for cluster size >= 4096, the compression unit is set such that 2^compression unit * cluster_size = 65536 bytes, i.e. so that the compression block size is 65536 bytes thus for cluster size >= 4096, the compression unit can be calculated as compression_unit = log2(65536 / cluster_size).  And the closest we we can get to approximating Windows behaviour is to use compression_unit 4 and only allow it for cluster size <= 4096 when NTFS version is < 3.0, use compression_unit 0 and only allow it for cluster size <= 4096 when NTFS version is = 3.0 and use the correct number as described above for Windows 7 when NTFS version is >= 3.1.  This is not ideal as XP has NTFS version 3.1, too but XP is already out of support so it is better to be aligning ourselves with current Windows versions like 7 and 8.  Finally, note that even Windows 7 disabled compressed files when cluster size > 4096 thus the new compression unit only applies to sparse files and nothing changes for compressed files (unless Windows 8 or later changes this behaviour which is as yet untested).

The correct check that is missing here is:

if (NInoSparse(ni) && a->data.non_resident.compression_unit && a->data.non_resident.compression_unit != vol->sparse_compression_unit) {
ntfs_error(vi->i_sb, "Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
a->data.non_resident.compression_unit, vol->sparse_compression_unit);
err = -EOPNOTSUPP;
goto unm_err_out;
}

And vol->sparse_compression_unit is set at mount time like this:

        vol->sparse_compression_unit = 4;
        if (vol->cluster_size > 4096) {
                switch (vol->cluster_size) {
                case 65536:
                        vol->sparse_compression_unit = 0;
                        break;
                case 32768:
                        vol->sparse_compression_unit = 1;
                        break;
                case 16384:
                        vol->sparse_compression_unit = 2;
                        break;
                case 8192:
                        vol->sparse_compression_unit = 3;
                        break;
                }
        }

Best regards,

Anton

On 14 Aug 2023, at 02:02, Namjae Jeon <linkinjeon@kernel.org> wrote:

2023-08-13 14:59 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com<mailto:ghandatmanas@gmail.com>>:
Hi,
Currently there is not check for ni->itype.compressed.block_size when
a->data.non_resident.compression_unit is present and NInoSparse(ni) is
true. Added the required check to calculation of block size.

Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
---
V3 -> V4: Fix description
V2 -> V3: Fix patching issue.
V1 -> V2: Cleaned up coding style.

fs/ntfs/inode.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 6c3f38d66579..a657322874ed 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1077,6 +1077,15 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto unm_err_out;
}
if (a->data.non_resident.compression_unit) {
+ if (a->data.non_resident.compression_unit +
+ vol->cluster_size_bits > 32) {
+ ntfs_error(vi->i_sb,
+ "Found non-standard compression unit (%u).   Cannot handle this.",
+ a->data.non_resident.compression_unit
+ );
+ err = -EOPNOTSUPP;
+ goto unm_err_out;
+ }
compression_unit seems to be used when the ntfs inode is compressed.
And it should be either 0 or 4 value. So, I think we can set related
compression block variables of ntfs inode only when ni is
NInoCompressed like this... Anton, Am I missing something ?

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index efe0602b4e51..e5a7d81d575b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1076,7 +1076,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
                                       err = -EOPNOTSUPP;
                                       goto unm_err_out;
                               }
-                               if (a->data.non_resident.compression_unit) {
+                               if (NInoCompressed(ni) &&
+                                   a->data.non_resident.compression_unit) {
                                       ni->itype.compressed.block_size = 1U <<
                                                       (a->data.non_resident.
                                                       compression_unit +

ni->itype.compressed.block_size = 1U <<
(a->data.non_resident.
compression_unit +
--
2.37.2

--
Anton Altaparmakov <anton at tuxera.com> (replace at with @)
Lead in File System Development, Tuxera Inc., http://www.tuxera.com/
Linux NTFS maintainer


[-- Attachment #1.2: Type: text/html, Size: 31338 bytes --]

[-- Attachment #2: Type: text/plain, Size: 201 bytes --]

_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-14  9:29   ` Anton Altaparmakov via Linux-kernel-mentees
@ 2023-08-15  5:22       ` Manas Ghandat
  0 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-15  5:22 UTC (permalink / raw)
  To: anton, linkinjeon
  Cc: Manas Ghandat, linux-ntfs-dev, linux-kernel,
	syzbot+4768a8f039aa677897d0, linux-fsdevel, Linux-kernel-mentees

Currently there is not check for ni->itype.compressed.block_size when
a->data.non_resident.compression_unit is present and NInoSparse(ni) is
true. Added the correct check to the compression unit.

Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
---
V4 -> V5: Add recommended check to compression_unit
V3 -> V4: Fix description
V2 -> V3: Fix patching issue.
V1 -> V2: Cleaned up coding style.

 fs/ntfs/inode.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 6c3f38d66579..d8ac221f212b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1076,6 +1076,16 @@ static int ntfs_read_locked_inode(struct inode *vi)
 					err = -EOPNOTSUPP;
 					goto unm_err_out;
 				}
+				if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
+				a->data.non_resident.compression_unit !=
+				vol->sparse_compression_unit) {
+					ntfs_error(vi->i_sb,
+					"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
+					a->data.non_resident.compression_unit,
+					vol->sparse_compression_unit);
+					err = -EOPNOTSUPP;
+					goto unm_err_out;
+				}
 				if (a->data.non_resident.compression_unit) {
 					ni->itype.compressed.block_size = 1U <<
 							(a->data.non_resident.
-- 
2.37.2

_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-15  5:22       ` Manas Ghandat
  0 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-15  5:22 UTC (permalink / raw)
  To: anton, linkinjeon
  Cc: Manas Ghandat, Linux-kernel-mentees, gregkh, linux-fsdevel,
	linux-kernel, linux-ntfs-dev, syzbot+4768a8f039aa677897d0

Currently there is not check for ni->itype.compressed.block_size when
a->data.non_resident.compression_unit is present and NInoSparse(ni) is
true. Added the correct check to the compression unit.

Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
---
V4 -> V5: Add recommended check to compression_unit
V3 -> V4: Fix description
V2 -> V3: Fix patching issue.
V1 -> V2: Cleaned up coding style.

 fs/ntfs/inode.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 6c3f38d66579..d8ac221f212b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1076,6 +1076,16 @@ static int ntfs_read_locked_inode(struct inode *vi)
 					err = -EOPNOTSUPP;
 					goto unm_err_out;
 				}
+				if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
+				a->data.non_resident.compression_unit !=
+				vol->sparse_compression_unit) {
+					ntfs_error(vi->i_sb,
+					"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
+					a->data.non_resident.compression_unit,
+					vol->sparse_compression_unit);
+					err = -EOPNOTSUPP;
+					goto unm_err_out;
+				}
 				if (a->data.non_resident.compression_unit) {
 					ni->itype.compressed.block_size = 1U <<
 							(a->data.non_resident.
-- 
2.37.2


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

* Re: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-15  5:22       ` Manas Ghandat
@ 2023-08-15  7:16         ` kernel test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2023-08-15  7:16 UTC (permalink / raw)
  To: Manas Ghandat, anton, linkinjeon
  Cc: oe-kbuild-all, Manas Ghandat, Linux-kernel-mentees, gregkh,
	linux-fsdevel, linux-kernel, linux-ntfs-dev,
	syzbot+4768a8f039aa677897d0

Hi Manas,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.5-rc6 next-20230809]
[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/Manas-Ghandat/ntfs-fix-shift-out-of-bounds-in-ntfs_iget/20230815-132656
base:   linus/master
patch link:    https://lore.kernel.org/r/20230815052251.107732-1-ghandatmanas%40gmail.com
patch subject: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
config: mips-randconfig-r002-20230815 (https://download.01.org/0day-ci/archive/20230815/202308151536.ErfTUJ9J-lkp@intel.com/config)
compiler: mipsel-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230815/202308151536.ErfTUJ9J-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/202308151536.ErfTUJ9J-lkp@intel.com/

All errors (new ones prefixed by >>):

   fs/ntfs/inode.c: In function 'ntfs_read_locked_inode':
>> fs/ntfs/inode.c:1081:36: error: 'ntfs_volume' has no member named 'sparse_compression_unit'
    1081 |                                 vol->sparse_compression_unit) {
         |                                    ^~
   In file included from fs/ntfs/inode.h:25,
                    from fs/ntfs/aops.h:18,
                    from fs/ntfs/inode.c:18:
   fs/ntfs/inode.c:1085:44: error: 'ntfs_volume' has no member named 'sparse_compression_unit'
    1085 |                                         vol->sparse_compression_unit);
         |                                            ^~
   fs/ntfs/debug.h:55:73: note: in definition of macro 'ntfs_error'
      55 | #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
         |                                                                         ^


vim +1081 fs/ntfs/inode.c

   497	
   498	/**
   499	 * ntfs_read_locked_inode - read an inode from its device
   500	 * @vi:		inode to read
   501	 *
   502	 * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
   503	 * described by @vi into memory from the device.
   504	 *
   505	 * The only fields in @vi that we need to/can look at when the function is
   506	 * called are i_sb, pointing to the mounted device's super block, and i_ino,
   507	 * the number of the inode to load.
   508	 *
   509	 * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
   510	 * for reading and sets up the necessary @vi fields as well as initializing
   511	 * the ntfs inode.
   512	 *
   513	 * Q: What locks are held when the function is called?
   514	 * A: i_state has I_NEW set, hence the inode is locked, also
   515	 *    i_count is set to 1, so it is not going to go away
   516	 *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
   517	 *    is allowed to write to them. We should of course be honouring them but
   518	 *    we need to do that using the IS_* macros defined in include/linux/fs.h.
   519	 *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
   520	 *
   521	 * Return 0 on success and -errno on error.  In the error case, the inode will
   522	 * have had make_bad_inode() executed on it.
   523	 */
   524	static int ntfs_read_locked_inode(struct inode *vi)
   525	{
   526		ntfs_volume *vol = NTFS_SB(vi->i_sb);
   527		ntfs_inode *ni;
   528		struct inode *bvi;
   529		MFT_RECORD *m;
   530		ATTR_RECORD *a;
   531		STANDARD_INFORMATION *si;
   532		ntfs_attr_search_ctx *ctx;
   533		int err = 0;
   534	
   535		ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
   536	
   537		/* Setup the generic vfs inode parts now. */
   538		vi->i_uid = vol->uid;
   539		vi->i_gid = vol->gid;
   540		vi->i_mode = 0;
   541	
   542		/*
   543		 * Initialize the ntfs specific part of @vi special casing
   544		 * FILE_MFT which we need to do at mount time.
   545		 */
   546		if (vi->i_ino != FILE_MFT)
   547			ntfs_init_big_inode(vi);
   548		ni = NTFS_I(vi);
   549	
   550		m = map_mft_record(ni);
   551		if (IS_ERR(m)) {
   552			err = PTR_ERR(m);
   553			goto err_out;
   554		}
   555		ctx = ntfs_attr_get_search_ctx(ni, m);
   556		if (!ctx) {
   557			err = -ENOMEM;
   558			goto unm_err_out;
   559		}
   560	
   561		if (!(m->flags & MFT_RECORD_IN_USE)) {
   562			ntfs_error(vi->i_sb, "Inode is not in use!");
   563			goto unm_err_out;
   564		}
   565		if (m->base_mft_record) {
   566			ntfs_error(vi->i_sb, "Inode is an extent inode!");
   567			goto unm_err_out;
   568		}
   569	
   570		/* Transfer information from mft record into vfs and ntfs inodes. */
   571		vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
   572	
   573		/*
   574		 * FIXME: Keep in mind that link_count is two for files which have both
   575		 * a long file name and a short file name as separate entries, so if
   576		 * we are hiding short file names this will be too high. Either we need
   577		 * to account for the short file names by subtracting them or we need
   578		 * to make sure we delete files even though i_nlink is not zero which
   579		 * might be tricky due to vfs interactions. Need to think about this
   580		 * some more when implementing the unlink command.
   581		 */
   582		set_nlink(vi, le16_to_cpu(m->link_count));
   583		/*
   584		 * FIXME: Reparse points can have the directory bit set even though
   585		 * they would be S_IFLNK. Need to deal with this further below when we
   586		 * implement reparse points / symbolic links but it will do for now.
   587		 * Also if not a directory, it could be something else, rather than
   588		 * a regular file. But again, will do for now.
   589		 */
   590		/* Everyone gets all permissions. */
   591		vi->i_mode |= S_IRWXUGO;
   592		/* If read-only, no one gets write permissions. */
   593		if (IS_RDONLY(vi))
   594			vi->i_mode &= ~S_IWUGO;
   595		if (m->flags & MFT_RECORD_IS_DIRECTORY) {
   596			vi->i_mode |= S_IFDIR;
   597			/*
   598			 * Apply the directory permissions mask set in the mount
   599			 * options.
   600			 */
   601			vi->i_mode &= ~vol->dmask;
   602			/* Things break without this kludge! */
   603			if (vi->i_nlink > 1)
   604				set_nlink(vi, 1);
   605		} else {
   606			vi->i_mode |= S_IFREG;
   607			/* Apply the file permissions mask set in the mount options. */
   608			vi->i_mode &= ~vol->fmask;
   609		}
   610		/*
   611		 * Find the standard information attribute in the mft record. At this
   612		 * stage we haven't setup the attribute list stuff yet, so this could
   613		 * in fact fail if the standard information is in an extent record, but
   614		 * I don't think this actually ever happens.
   615		 */
   616		err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
   617				ctx);
   618		if (unlikely(err)) {
   619			if (err == -ENOENT) {
   620				/*
   621				 * TODO: We should be performing a hot fix here (if the
   622				 * recover mount option is set) by creating a new
   623				 * attribute.
   624				 */
   625				ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
   626						"is missing.");
   627			}
   628			goto unm_err_out;
   629		}
   630		a = ctx->attr;
   631		/* Get the standard information attribute value. */
   632		if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
   633				+ le32_to_cpu(a->data.resident.value_length) >
   634				(u8 *)ctx->mrec + vol->mft_record_size) {
   635			ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
   636			goto unm_err_out;
   637		}
   638		si = (STANDARD_INFORMATION*)((u8*)a +
   639				le16_to_cpu(a->data.resident.value_offset));
   640	
   641		/* Transfer information from the standard information into vi. */
   642		/*
   643		 * Note: The i_?times do not quite map perfectly onto the NTFS times,
   644		 * but they are close enough, and in the end it doesn't really matter
   645		 * that much...
   646		 */
   647		/*
   648		 * mtime is the last change of the data within the file. Not changed
   649		 * when only metadata is changed, e.g. a rename doesn't affect mtime.
   650		 */
   651		vi->i_mtime = ntfs2utc(si->last_data_change_time);
   652		/*
   653		 * ctime is the last change of the metadata of the file. This obviously
   654		 * always changes, when mtime is changed. ctime can be changed on its
   655		 * own, mtime is then not changed, e.g. when a file is renamed.
   656		 */
   657		vi->i_ctime = ntfs2utc(si->last_mft_change_time);
   658		/*
   659		 * Last access to the data within the file. Not changed during a rename
   660		 * for example but changed whenever the file is written to.
   661		 */
   662		vi->i_atime = ntfs2utc(si->last_access_time);
   663	
   664		/* Find the attribute list attribute if present. */
   665		ntfs_attr_reinit_search_ctx(ctx);
   666		err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
   667		if (err) {
   668			if (unlikely(err != -ENOENT)) {
   669				ntfs_error(vi->i_sb, "Failed to lookup attribute list "
   670						"attribute.");
   671				goto unm_err_out;
   672			}
   673		} else /* if (!err) */ {
   674			if (vi->i_ino == FILE_MFT)
   675				goto skip_attr_list_load;
   676			ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
   677			NInoSetAttrList(ni);
   678			a = ctx->attr;
   679			if (a->flags & ATTR_COMPRESSION_MASK) {
   680				ntfs_error(vi->i_sb, "Attribute list attribute is "
   681						"compressed.");
   682				goto unm_err_out;
   683			}
   684			if (a->flags & ATTR_IS_ENCRYPTED ||
   685					a->flags & ATTR_IS_SPARSE) {
   686				if (a->non_resident) {
   687					ntfs_error(vi->i_sb, "Non-resident attribute "
   688							"list attribute is encrypted/"
   689							"sparse.");
   690					goto unm_err_out;
   691				}
   692				ntfs_warning(vi->i_sb, "Resident attribute list "
   693						"attribute in inode 0x%lx is marked "
   694						"encrypted/sparse which is not true.  "
   695						"However, Windows allows this and "
   696						"chkdsk does not detect or correct it "
   697						"so we will just ignore the invalid "
   698						"flags and pretend they are not set.",
   699						vi->i_ino);
   700			}
   701			/* Now allocate memory for the attribute list. */
   702			ni->attr_list_size = (u32)ntfs_attr_size(a);
   703			ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
   704			if (!ni->attr_list) {
   705				ntfs_error(vi->i_sb, "Not enough memory to allocate "
   706						"buffer for attribute list.");
   707				err = -ENOMEM;
   708				goto unm_err_out;
   709			}
   710			if (a->non_resident) {
   711				NInoSetAttrListNonResident(ni);
   712				if (a->data.non_resident.lowest_vcn) {
   713					ntfs_error(vi->i_sb, "Attribute list has non "
   714							"zero lowest_vcn.");
   715					goto unm_err_out;
   716				}
   717				/*
   718				 * Setup the runlist. No need for locking as we have
   719				 * exclusive access to the inode at this time.
   720				 */
   721				ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
   722						a, NULL);
   723				if (IS_ERR(ni->attr_list_rl.rl)) {
   724					err = PTR_ERR(ni->attr_list_rl.rl);
   725					ni->attr_list_rl.rl = NULL;
   726					ntfs_error(vi->i_sb, "Mapping pairs "
   727							"decompression failed.");
   728					goto unm_err_out;
   729				}
   730				/* Now load the attribute list. */
   731				if ((err = load_attribute_list(vol, &ni->attr_list_rl,
   732						ni->attr_list, ni->attr_list_size,
   733						sle64_to_cpu(a->data.non_resident.
   734						initialized_size)))) {
   735					ntfs_error(vi->i_sb, "Failed to load "
   736							"attribute list attribute.");
   737					goto unm_err_out;
   738				}
   739			} else /* if (!a->non_resident) */ {
   740				if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
   741						+ le32_to_cpu(
   742						a->data.resident.value_length) >
   743						(u8*)ctx->mrec + vol->mft_record_size) {
   744					ntfs_error(vi->i_sb, "Corrupt attribute list "
   745							"in inode.");
   746					goto unm_err_out;
   747				}
   748				/* Now copy the attribute list. */
   749				memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
   750						a->data.resident.value_offset),
   751						le32_to_cpu(
   752						a->data.resident.value_length));
   753			}
   754		}
   755	skip_attr_list_load:
   756		/*
   757		 * If an attribute list is present we now have the attribute list value
   758		 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
   759		 */
   760		if (S_ISDIR(vi->i_mode)) {
   761			loff_t bvi_size;
   762			ntfs_inode *bni;
   763			INDEX_ROOT *ir;
   764			u8 *ir_end, *index_end;
   765	
   766			/* It is a directory, find index root attribute. */
   767			ntfs_attr_reinit_search_ctx(ctx);
   768			err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
   769					0, NULL, 0, ctx);
   770			if (unlikely(err)) {
   771				if (err == -ENOENT) {
   772					// FIXME: File is corrupt! Hot-fix with empty
   773					// index root attribute if recovery option is
   774					// set.
   775					ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
   776							"is missing.");
   777				}
   778				goto unm_err_out;
   779			}
   780			a = ctx->attr;
   781			/* Set up the state. */
   782			if (unlikely(a->non_resident)) {
   783				ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
   784						"resident.");
   785				goto unm_err_out;
   786			}
   787			/* Ensure the attribute name is placed before the value. */
   788			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   789					le16_to_cpu(a->data.resident.value_offset)))) {
   790				ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
   791						"placed after the attribute value.");
   792				goto unm_err_out;
   793			}
   794			/*
   795			 * Compressed/encrypted index root just means that the newly
   796			 * created files in that directory should be created compressed/
   797			 * encrypted. However index root cannot be both compressed and
   798			 * encrypted.
   799			 */
   800			if (a->flags & ATTR_COMPRESSION_MASK)
   801				NInoSetCompressed(ni);
   802			if (a->flags & ATTR_IS_ENCRYPTED) {
   803				if (a->flags & ATTR_COMPRESSION_MASK) {
   804					ntfs_error(vi->i_sb, "Found encrypted and "
   805							"compressed attribute.");
   806					goto unm_err_out;
   807				}
   808				NInoSetEncrypted(ni);
   809			}
   810			if (a->flags & ATTR_IS_SPARSE)
   811				NInoSetSparse(ni);
   812			ir = (INDEX_ROOT*)((u8*)a +
   813					le16_to_cpu(a->data.resident.value_offset));
   814			ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
   815			if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
   816				ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
   817						"corrupt.");
   818				goto unm_err_out;
   819			}
   820			index_end = (u8*)&ir->index +
   821					le32_to_cpu(ir->index.index_length);
   822			if (index_end > ir_end) {
   823				ntfs_error(vi->i_sb, "Directory index is corrupt.");
   824				goto unm_err_out;
   825			}
   826			if (ir->type != AT_FILE_NAME) {
   827				ntfs_error(vi->i_sb, "Indexed attribute is not "
   828						"$FILE_NAME.");
   829				goto unm_err_out;
   830			}
   831			if (ir->collation_rule != COLLATION_FILE_NAME) {
   832				ntfs_error(vi->i_sb, "Index collation rule is not "
   833						"COLLATION_FILE_NAME.");
   834				goto unm_err_out;
   835			}
   836			ni->itype.index.collation_rule = ir->collation_rule;
   837			ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
   838			if (ni->itype.index.block_size &
   839					(ni->itype.index.block_size - 1)) {
   840				ntfs_error(vi->i_sb, "Index block size (%u) is not a "
   841						"power of two.",
   842						ni->itype.index.block_size);
   843				goto unm_err_out;
   844			}
   845			if (ni->itype.index.block_size > PAGE_SIZE) {
   846				ntfs_error(vi->i_sb, "Index block size (%u) > "
   847						"PAGE_SIZE (%ld) is not "
   848						"supported.  Sorry.",
   849						ni->itype.index.block_size,
   850						PAGE_SIZE);
   851				err = -EOPNOTSUPP;
   852				goto unm_err_out;
   853			}
   854			if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
   855				ntfs_error(vi->i_sb, "Index block size (%u) < "
   856						"NTFS_BLOCK_SIZE (%i) is not "
   857						"supported.  Sorry.",
   858						ni->itype.index.block_size,
   859						NTFS_BLOCK_SIZE);
   860				err = -EOPNOTSUPP;
   861				goto unm_err_out;
   862			}
   863			ni->itype.index.block_size_bits =
   864					ffs(ni->itype.index.block_size) - 1;
   865			/* Determine the size of a vcn in the directory index. */
   866			if (vol->cluster_size <= ni->itype.index.block_size) {
   867				ni->itype.index.vcn_size = vol->cluster_size;
   868				ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
   869			} else {
   870				ni->itype.index.vcn_size = vol->sector_size;
   871				ni->itype.index.vcn_size_bits = vol->sector_size_bits;
   872			}
   873	
   874			/* Setup the index allocation attribute, even if not present. */
   875			NInoSetMstProtected(ni);
   876			ni->type = AT_INDEX_ALLOCATION;
   877			ni->name = I30;
   878			ni->name_len = 4;
   879	
   880			if (!(ir->index.flags & LARGE_INDEX)) {
   881				/* No index allocation. */
   882				vi->i_size = ni->initialized_size =
   883						ni->allocated_size = 0;
   884				/* We are done with the mft record, so we release it. */
   885				ntfs_attr_put_search_ctx(ctx);
   886				unmap_mft_record(ni);
   887				m = NULL;
   888				ctx = NULL;
   889				goto skip_large_dir_stuff;
   890			} /* LARGE_INDEX: Index allocation present. Setup state. */
   891			NInoSetIndexAllocPresent(ni);
   892			/* Find index allocation attribute. */
   893			ntfs_attr_reinit_search_ctx(ctx);
   894			err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
   895					CASE_SENSITIVE, 0, NULL, 0, ctx);
   896			if (unlikely(err)) {
   897				if (err == -ENOENT)
   898					ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
   899							"attribute is not present but "
   900							"$INDEX_ROOT indicated it is.");
   901				else
   902					ntfs_error(vi->i_sb, "Failed to lookup "
   903							"$INDEX_ALLOCATION "
   904							"attribute.");
   905				goto unm_err_out;
   906			}
   907			a = ctx->attr;
   908			if (!a->non_resident) {
   909				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   910						"is resident.");
   911				goto unm_err_out;
   912			}
   913			/*
   914			 * Ensure the attribute name is placed before the mapping pairs
   915			 * array.
   916			 */
   917			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   918					le16_to_cpu(
   919					a->data.non_resident.mapping_pairs_offset)))) {
   920				ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
   921						"is placed after the mapping pairs "
   922						"array.");
   923				goto unm_err_out;
   924			}
   925			if (a->flags & ATTR_IS_ENCRYPTED) {
   926				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   927						"is encrypted.");
   928				goto unm_err_out;
   929			}
   930			if (a->flags & ATTR_IS_SPARSE) {
   931				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   932						"is sparse.");
   933				goto unm_err_out;
   934			}
   935			if (a->flags & ATTR_COMPRESSION_MASK) {
   936				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   937						"is compressed.");
   938				goto unm_err_out;
   939			}
   940			if (a->data.non_resident.lowest_vcn) {
   941				ntfs_error(vi->i_sb, "First extent of "
   942						"$INDEX_ALLOCATION attribute has non "
   943						"zero lowest_vcn.");
   944				goto unm_err_out;
   945			}
   946			vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
   947			ni->initialized_size = sle64_to_cpu(
   948					a->data.non_resident.initialized_size);
   949			ni->allocated_size = sle64_to_cpu(
   950					a->data.non_resident.allocated_size);
   951			/*
   952			 * We are done with the mft record, so we release it. Otherwise
   953			 * we would deadlock in ntfs_attr_iget().
   954			 */
   955			ntfs_attr_put_search_ctx(ctx);
   956			unmap_mft_record(ni);
   957			m = NULL;
   958			ctx = NULL;
   959			/* Get the index bitmap attribute inode. */
   960			bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
   961			if (IS_ERR(bvi)) {
   962				ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
   963				err = PTR_ERR(bvi);
   964				goto unm_err_out;
   965			}
   966			bni = NTFS_I(bvi);
   967			if (NInoCompressed(bni) || NInoEncrypted(bni) ||
   968					NInoSparse(bni)) {
   969				ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
   970						"and/or encrypted and/or sparse.");
   971				goto iput_unm_err_out;
   972			}
   973			/* Consistency check bitmap size vs. index allocation size. */
   974			bvi_size = i_size_read(bvi);
   975			if ((bvi_size << 3) < (vi->i_size >>
   976					ni->itype.index.block_size_bits)) {
   977				ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
   978						"for index allocation (0x%llx).",
   979						bvi_size << 3, vi->i_size);
   980				goto iput_unm_err_out;
   981			}
   982			/* No longer need the bitmap attribute inode. */
   983			iput(bvi);
   984	skip_large_dir_stuff:
   985			/* Setup the operations for this inode. */
   986			vi->i_op = &ntfs_dir_inode_ops;
   987			vi->i_fop = &ntfs_dir_ops;
   988			vi->i_mapping->a_ops = &ntfs_mst_aops;
   989		} else {
   990			/* It is a file. */
   991			ntfs_attr_reinit_search_ctx(ctx);
   992	
   993			/* Setup the data attribute, even if not present. */
   994			ni->type = AT_DATA;
   995			ni->name = NULL;
   996			ni->name_len = 0;
   997	
   998			/* Find first extent of the unnamed data attribute. */
   999			err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
  1000			if (unlikely(err)) {
  1001				vi->i_size = ni->initialized_size =
  1002						ni->allocated_size = 0;
  1003				if (err != -ENOENT) {
  1004					ntfs_error(vi->i_sb, "Failed to lookup $DATA "
  1005							"attribute.");
  1006					goto unm_err_out;
  1007				}
  1008				/*
  1009				 * FILE_Secure does not have an unnamed $DATA
  1010				 * attribute, so we special case it here.
  1011				 */
  1012				if (vi->i_ino == FILE_Secure)
  1013					goto no_data_attr_special_case;
  1014				/*
  1015				 * Most if not all the system files in the $Extend
  1016				 * system directory do not have unnamed data
  1017				 * attributes so we need to check if the parent
  1018				 * directory of the file is FILE_Extend and if it is
  1019				 * ignore this error. To do this we need to get the
  1020				 * name of this inode from the mft record as the name
  1021				 * contains the back reference to the parent directory.
  1022				 */
  1023				if (ntfs_is_extended_system_file(ctx) > 0)
  1024					goto no_data_attr_special_case;
  1025				// FIXME: File is corrupt! Hot-fix with empty data
  1026				// attribute if recovery option is set.
  1027				ntfs_error(vi->i_sb, "$DATA attribute is missing.");
  1028				goto unm_err_out;
  1029			}
  1030			a = ctx->attr;
  1031			/* Setup the state. */
  1032			if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
  1033				if (a->flags & ATTR_COMPRESSION_MASK) {
  1034					NInoSetCompressed(ni);
  1035					if (vol->cluster_size > 4096) {
  1036						ntfs_error(vi->i_sb, "Found "
  1037								"compressed data but "
  1038								"compression is "
  1039								"disabled due to "
  1040								"cluster size (%i) > "
  1041								"4kiB.",
  1042								vol->cluster_size);
  1043						goto unm_err_out;
  1044					}
  1045					if ((a->flags & ATTR_COMPRESSION_MASK)
  1046							!= ATTR_IS_COMPRESSED) {
  1047						ntfs_error(vi->i_sb, "Found unknown "
  1048								"compression method "
  1049								"or corrupt file.");
  1050						goto unm_err_out;
  1051					}
  1052				}
  1053				if (a->flags & ATTR_IS_SPARSE)
  1054					NInoSetSparse(ni);
  1055			}
  1056			if (a->flags & ATTR_IS_ENCRYPTED) {
  1057				if (NInoCompressed(ni)) {
  1058					ntfs_error(vi->i_sb, "Found encrypted and "
  1059							"compressed data.");
  1060					goto unm_err_out;
  1061				}
  1062				NInoSetEncrypted(ni);
  1063			}
  1064			if (a->non_resident) {
  1065				NInoSetNonResident(ni);
  1066				if (NInoCompressed(ni) || NInoSparse(ni)) {
  1067					if (NInoCompressed(ni) && a->data.non_resident.
  1068							compression_unit != 4) {
  1069						ntfs_error(vi->i_sb, "Found "
  1070								"non-standard "
  1071								"compression unit (%u "
  1072								"instead of 4).  "
  1073								"Cannot handle this.",
  1074								a->data.non_resident.
  1075								compression_unit);
  1076						err = -EOPNOTSUPP;
  1077						goto unm_err_out;
  1078					}
  1079					if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
  1080					a->data.non_resident.compression_unit !=
> 1081					vol->sparse_compression_unit) {
  1082						ntfs_error(vi->i_sb,
  1083						"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
  1084						a->data.non_resident.compression_unit,
  1085						vol->sparse_compression_unit);
  1086						err = -EOPNOTSUPP;
  1087						goto unm_err_out;
  1088					}
  1089					if (a->data.non_resident.compression_unit) {
  1090						ni->itype.compressed.block_size = 1U <<
  1091								(a->data.non_resident.
  1092								compression_unit +
  1093								vol->cluster_size_bits);
  1094						ni->itype.compressed.block_size_bits =
  1095								ffs(ni->itype.
  1096								compressed.
  1097								block_size) - 1;
  1098						ni->itype.compressed.block_clusters =
  1099								1U << a->data.
  1100								non_resident.
  1101								compression_unit;
  1102					} else {
  1103						ni->itype.compressed.block_size = 0;
  1104						ni->itype.compressed.block_size_bits =
  1105								0;
  1106						ni->itype.compressed.block_clusters =
  1107								0;
  1108					}
  1109					ni->itype.compressed.size = sle64_to_cpu(
  1110							a->data.non_resident.
  1111							compressed_size);
  1112				}
  1113				if (a->data.non_resident.lowest_vcn) {
  1114					ntfs_error(vi->i_sb, "First extent of $DATA "
  1115							"attribute has non zero "
  1116							"lowest_vcn.");
  1117					goto unm_err_out;
  1118				}
  1119				vi->i_size = sle64_to_cpu(
  1120						a->data.non_resident.data_size);
  1121				ni->initialized_size = sle64_to_cpu(
  1122						a->data.non_resident.initialized_size);
  1123				ni->allocated_size = sle64_to_cpu(
  1124						a->data.non_resident.allocated_size);
  1125			} else { /* Resident attribute. */
  1126				vi->i_size = ni->initialized_size = le32_to_cpu(
  1127						a->data.resident.value_length);
  1128				ni->allocated_size = le32_to_cpu(a->length) -
  1129						le16_to_cpu(
  1130						a->data.resident.value_offset);
  1131				if (vi->i_size > ni->allocated_size) {
  1132					ntfs_error(vi->i_sb, "Resident data attribute "
  1133							"is corrupt (size exceeds "
  1134							"allocation).");
  1135					goto unm_err_out;
  1136				}
  1137			}
  1138	no_data_attr_special_case:
  1139			/* We are done with the mft record, so we release it. */
  1140			ntfs_attr_put_search_ctx(ctx);
  1141			unmap_mft_record(ni);
  1142			m = NULL;
  1143			ctx = NULL;
  1144			/* Setup the operations for this inode. */
  1145			vi->i_op = &ntfs_file_inode_ops;
  1146			vi->i_fop = &ntfs_file_ops;
  1147			vi->i_mapping->a_ops = &ntfs_normal_aops;
  1148			if (NInoMstProtected(ni))
  1149				vi->i_mapping->a_ops = &ntfs_mst_aops;
  1150			else if (NInoCompressed(ni))
  1151				vi->i_mapping->a_ops = &ntfs_compressed_aops;
  1152		}
  1153		/*
  1154		 * The number of 512-byte blocks used on disk (for stat). This is in so
  1155		 * far inaccurate as it doesn't account for any named streams or other
  1156		 * special non-resident attributes, but that is how Windows works, too,
  1157		 * so we are at least consistent with Windows, if not entirely
  1158		 * consistent with the Linux Way. Doing it the Linux Way would cause a
  1159		 * significant slowdown as it would involve iterating over all
  1160		 * attributes in the mft record and adding the allocated/compressed
  1161		 * sizes of all non-resident attributes present to give us the Linux
  1162		 * correct size that should go into i_blocks (after division by 512).
  1163		 */
  1164		if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
  1165			vi->i_blocks = ni->itype.compressed.size >> 9;
  1166		else
  1167			vi->i_blocks = ni->allocated_size >> 9;
  1168		ntfs_debug("Done.");
  1169		return 0;
  1170	iput_unm_err_out:
  1171		iput(bvi);
  1172	unm_err_out:
  1173		if (!err)
  1174			err = -EIO;
  1175		if (ctx)
  1176			ntfs_attr_put_search_ctx(ctx);
  1177		if (m)
  1178			unmap_mft_record(ni);
  1179	err_out:
  1180		ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
  1181				"inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
  1182		make_bad_inode(vi);
  1183		if (err != -EOPNOTSUPP && err != -ENOMEM)
  1184			NVolSetErrors(vol);
  1185		return err;
  1186	}
  1187	

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

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

* Re: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-15  7:16         ` kernel test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2023-08-15  7:16 UTC (permalink / raw)
  To: Manas Ghandat, anton, linkinjeon
  Cc: Manas Ghandat, linux-ntfs-dev, linux-kernel,
	syzbot+4768a8f039aa677897d0, oe-kbuild-all, linux-fsdevel,
	Linux-kernel-mentees

Hi Manas,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.5-rc6 next-20230809]
[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/Manas-Ghandat/ntfs-fix-shift-out-of-bounds-in-ntfs_iget/20230815-132656
base:   linus/master
patch link:    https://lore.kernel.org/r/20230815052251.107732-1-ghandatmanas%40gmail.com
patch subject: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
config: mips-randconfig-r002-20230815 (https://download.01.org/0day-ci/archive/20230815/202308151536.ErfTUJ9J-lkp@intel.com/config)
compiler: mipsel-linux-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230815/202308151536.ErfTUJ9J-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/202308151536.ErfTUJ9J-lkp@intel.com/

All errors (new ones prefixed by >>):

   fs/ntfs/inode.c: In function 'ntfs_read_locked_inode':
>> fs/ntfs/inode.c:1081:36: error: 'ntfs_volume' has no member named 'sparse_compression_unit'
    1081 |                                 vol->sparse_compression_unit) {
         |                                    ^~
   In file included from fs/ntfs/inode.h:25,
                    from fs/ntfs/aops.h:18,
                    from fs/ntfs/inode.c:18:
   fs/ntfs/inode.c:1085:44: error: 'ntfs_volume' has no member named 'sparse_compression_unit'
    1085 |                                         vol->sparse_compression_unit);
         |                                            ^~
   fs/ntfs/debug.h:55:73: note: in definition of macro 'ntfs_error'
      55 | #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
         |                                                                         ^


vim +1081 fs/ntfs/inode.c

   497	
   498	/**
   499	 * ntfs_read_locked_inode - read an inode from its device
   500	 * @vi:		inode to read
   501	 *
   502	 * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
   503	 * described by @vi into memory from the device.
   504	 *
   505	 * The only fields in @vi that we need to/can look at when the function is
   506	 * called are i_sb, pointing to the mounted device's super block, and i_ino,
   507	 * the number of the inode to load.
   508	 *
   509	 * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
   510	 * for reading and sets up the necessary @vi fields as well as initializing
   511	 * the ntfs inode.
   512	 *
   513	 * Q: What locks are held when the function is called?
   514	 * A: i_state has I_NEW set, hence the inode is locked, also
   515	 *    i_count is set to 1, so it is not going to go away
   516	 *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
   517	 *    is allowed to write to them. We should of course be honouring them but
   518	 *    we need to do that using the IS_* macros defined in include/linux/fs.h.
   519	 *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
   520	 *
   521	 * Return 0 on success and -errno on error.  In the error case, the inode will
   522	 * have had make_bad_inode() executed on it.
   523	 */
   524	static int ntfs_read_locked_inode(struct inode *vi)
   525	{
   526		ntfs_volume *vol = NTFS_SB(vi->i_sb);
   527		ntfs_inode *ni;
   528		struct inode *bvi;
   529		MFT_RECORD *m;
   530		ATTR_RECORD *a;
   531		STANDARD_INFORMATION *si;
   532		ntfs_attr_search_ctx *ctx;
   533		int err = 0;
   534	
   535		ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
   536	
   537		/* Setup the generic vfs inode parts now. */
   538		vi->i_uid = vol->uid;
   539		vi->i_gid = vol->gid;
   540		vi->i_mode = 0;
   541	
   542		/*
   543		 * Initialize the ntfs specific part of @vi special casing
   544		 * FILE_MFT which we need to do at mount time.
   545		 */
   546		if (vi->i_ino != FILE_MFT)
   547			ntfs_init_big_inode(vi);
   548		ni = NTFS_I(vi);
   549	
   550		m = map_mft_record(ni);
   551		if (IS_ERR(m)) {
   552			err = PTR_ERR(m);
   553			goto err_out;
   554		}
   555		ctx = ntfs_attr_get_search_ctx(ni, m);
   556		if (!ctx) {
   557			err = -ENOMEM;
   558			goto unm_err_out;
   559		}
   560	
   561		if (!(m->flags & MFT_RECORD_IN_USE)) {
   562			ntfs_error(vi->i_sb, "Inode is not in use!");
   563			goto unm_err_out;
   564		}
   565		if (m->base_mft_record) {
   566			ntfs_error(vi->i_sb, "Inode is an extent inode!");
   567			goto unm_err_out;
   568		}
   569	
   570		/* Transfer information from mft record into vfs and ntfs inodes. */
   571		vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
   572	
   573		/*
   574		 * FIXME: Keep in mind that link_count is two for files which have both
   575		 * a long file name and a short file name as separate entries, so if
   576		 * we are hiding short file names this will be too high. Either we need
   577		 * to account for the short file names by subtracting them or we need
   578		 * to make sure we delete files even though i_nlink is not zero which
   579		 * might be tricky due to vfs interactions. Need to think about this
   580		 * some more when implementing the unlink command.
   581		 */
   582		set_nlink(vi, le16_to_cpu(m->link_count));
   583		/*
   584		 * FIXME: Reparse points can have the directory bit set even though
   585		 * they would be S_IFLNK. Need to deal with this further below when we
   586		 * implement reparse points / symbolic links but it will do for now.
   587		 * Also if not a directory, it could be something else, rather than
   588		 * a regular file. But again, will do for now.
   589		 */
   590		/* Everyone gets all permissions. */
   591		vi->i_mode |= S_IRWXUGO;
   592		/* If read-only, no one gets write permissions. */
   593		if (IS_RDONLY(vi))
   594			vi->i_mode &= ~S_IWUGO;
   595		if (m->flags & MFT_RECORD_IS_DIRECTORY) {
   596			vi->i_mode |= S_IFDIR;
   597			/*
   598			 * Apply the directory permissions mask set in the mount
   599			 * options.
   600			 */
   601			vi->i_mode &= ~vol->dmask;
   602			/* Things break without this kludge! */
   603			if (vi->i_nlink > 1)
   604				set_nlink(vi, 1);
   605		} else {
   606			vi->i_mode |= S_IFREG;
   607			/* Apply the file permissions mask set in the mount options. */
   608			vi->i_mode &= ~vol->fmask;
   609		}
   610		/*
   611		 * Find the standard information attribute in the mft record. At this
   612		 * stage we haven't setup the attribute list stuff yet, so this could
   613		 * in fact fail if the standard information is in an extent record, but
   614		 * I don't think this actually ever happens.
   615		 */
   616		err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
   617				ctx);
   618		if (unlikely(err)) {
   619			if (err == -ENOENT) {
   620				/*
   621				 * TODO: We should be performing a hot fix here (if the
   622				 * recover mount option is set) by creating a new
   623				 * attribute.
   624				 */
   625				ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
   626						"is missing.");
   627			}
   628			goto unm_err_out;
   629		}
   630		a = ctx->attr;
   631		/* Get the standard information attribute value. */
   632		if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
   633				+ le32_to_cpu(a->data.resident.value_length) >
   634				(u8 *)ctx->mrec + vol->mft_record_size) {
   635			ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
   636			goto unm_err_out;
   637		}
   638		si = (STANDARD_INFORMATION*)((u8*)a +
   639				le16_to_cpu(a->data.resident.value_offset));
   640	
   641		/* Transfer information from the standard information into vi. */
   642		/*
   643		 * Note: The i_?times do not quite map perfectly onto the NTFS times,
   644		 * but they are close enough, and in the end it doesn't really matter
   645		 * that much...
   646		 */
   647		/*
   648		 * mtime is the last change of the data within the file. Not changed
   649		 * when only metadata is changed, e.g. a rename doesn't affect mtime.
   650		 */
   651		vi->i_mtime = ntfs2utc(si->last_data_change_time);
   652		/*
   653		 * ctime is the last change of the metadata of the file. This obviously
   654		 * always changes, when mtime is changed. ctime can be changed on its
   655		 * own, mtime is then not changed, e.g. when a file is renamed.
   656		 */
   657		vi->i_ctime = ntfs2utc(si->last_mft_change_time);
   658		/*
   659		 * Last access to the data within the file. Not changed during a rename
   660		 * for example but changed whenever the file is written to.
   661		 */
   662		vi->i_atime = ntfs2utc(si->last_access_time);
   663	
   664		/* Find the attribute list attribute if present. */
   665		ntfs_attr_reinit_search_ctx(ctx);
   666		err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
   667		if (err) {
   668			if (unlikely(err != -ENOENT)) {
   669				ntfs_error(vi->i_sb, "Failed to lookup attribute list "
   670						"attribute.");
   671				goto unm_err_out;
   672			}
   673		} else /* if (!err) */ {
   674			if (vi->i_ino == FILE_MFT)
   675				goto skip_attr_list_load;
   676			ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
   677			NInoSetAttrList(ni);
   678			a = ctx->attr;
   679			if (a->flags & ATTR_COMPRESSION_MASK) {
   680				ntfs_error(vi->i_sb, "Attribute list attribute is "
   681						"compressed.");
   682				goto unm_err_out;
   683			}
   684			if (a->flags & ATTR_IS_ENCRYPTED ||
   685					a->flags & ATTR_IS_SPARSE) {
   686				if (a->non_resident) {
   687					ntfs_error(vi->i_sb, "Non-resident attribute "
   688							"list attribute is encrypted/"
   689							"sparse.");
   690					goto unm_err_out;
   691				}
   692				ntfs_warning(vi->i_sb, "Resident attribute list "
   693						"attribute in inode 0x%lx is marked "
   694						"encrypted/sparse which is not true.  "
   695						"However, Windows allows this and "
   696						"chkdsk does not detect or correct it "
   697						"so we will just ignore the invalid "
   698						"flags and pretend they are not set.",
   699						vi->i_ino);
   700			}
   701			/* Now allocate memory for the attribute list. */
   702			ni->attr_list_size = (u32)ntfs_attr_size(a);
   703			ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
   704			if (!ni->attr_list) {
   705				ntfs_error(vi->i_sb, "Not enough memory to allocate "
   706						"buffer for attribute list.");
   707				err = -ENOMEM;
   708				goto unm_err_out;
   709			}
   710			if (a->non_resident) {
   711				NInoSetAttrListNonResident(ni);
   712				if (a->data.non_resident.lowest_vcn) {
   713					ntfs_error(vi->i_sb, "Attribute list has non "
   714							"zero lowest_vcn.");
   715					goto unm_err_out;
   716				}
   717				/*
   718				 * Setup the runlist. No need for locking as we have
   719				 * exclusive access to the inode at this time.
   720				 */
   721				ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
   722						a, NULL);
   723				if (IS_ERR(ni->attr_list_rl.rl)) {
   724					err = PTR_ERR(ni->attr_list_rl.rl);
   725					ni->attr_list_rl.rl = NULL;
   726					ntfs_error(vi->i_sb, "Mapping pairs "
   727							"decompression failed.");
   728					goto unm_err_out;
   729				}
   730				/* Now load the attribute list. */
   731				if ((err = load_attribute_list(vol, &ni->attr_list_rl,
   732						ni->attr_list, ni->attr_list_size,
   733						sle64_to_cpu(a->data.non_resident.
   734						initialized_size)))) {
   735					ntfs_error(vi->i_sb, "Failed to load "
   736							"attribute list attribute.");
   737					goto unm_err_out;
   738				}
   739			} else /* if (!a->non_resident) */ {
   740				if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
   741						+ le32_to_cpu(
   742						a->data.resident.value_length) >
   743						(u8*)ctx->mrec + vol->mft_record_size) {
   744					ntfs_error(vi->i_sb, "Corrupt attribute list "
   745							"in inode.");
   746					goto unm_err_out;
   747				}
   748				/* Now copy the attribute list. */
   749				memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
   750						a->data.resident.value_offset),
   751						le32_to_cpu(
   752						a->data.resident.value_length));
   753			}
   754		}
   755	skip_attr_list_load:
   756		/*
   757		 * If an attribute list is present we now have the attribute list value
   758		 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
   759		 */
   760		if (S_ISDIR(vi->i_mode)) {
   761			loff_t bvi_size;
   762			ntfs_inode *bni;
   763			INDEX_ROOT *ir;
   764			u8 *ir_end, *index_end;
   765	
   766			/* It is a directory, find index root attribute. */
   767			ntfs_attr_reinit_search_ctx(ctx);
   768			err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
   769					0, NULL, 0, ctx);
   770			if (unlikely(err)) {
   771				if (err == -ENOENT) {
   772					// FIXME: File is corrupt! Hot-fix with empty
   773					// index root attribute if recovery option is
   774					// set.
   775					ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
   776							"is missing.");
   777				}
   778				goto unm_err_out;
   779			}
   780			a = ctx->attr;
   781			/* Set up the state. */
   782			if (unlikely(a->non_resident)) {
   783				ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
   784						"resident.");
   785				goto unm_err_out;
   786			}
   787			/* Ensure the attribute name is placed before the value. */
   788			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   789					le16_to_cpu(a->data.resident.value_offset)))) {
   790				ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
   791						"placed after the attribute value.");
   792				goto unm_err_out;
   793			}
   794			/*
   795			 * Compressed/encrypted index root just means that the newly
   796			 * created files in that directory should be created compressed/
   797			 * encrypted. However index root cannot be both compressed and
   798			 * encrypted.
   799			 */
   800			if (a->flags & ATTR_COMPRESSION_MASK)
   801				NInoSetCompressed(ni);
   802			if (a->flags & ATTR_IS_ENCRYPTED) {
   803				if (a->flags & ATTR_COMPRESSION_MASK) {
   804					ntfs_error(vi->i_sb, "Found encrypted and "
   805							"compressed attribute.");
   806					goto unm_err_out;
   807				}
   808				NInoSetEncrypted(ni);
   809			}
   810			if (a->flags & ATTR_IS_SPARSE)
   811				NInoSetSparse(ni);
   812			ir = (INDEX_ROOT*)((u8*)a +
   813					le16_to_cpu(a->data.resident.value_offset));
   814			ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
   815			if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
   816				ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
   817						"corrupt.");
   818				goto unm_err_out;
   819			}
   820			index_end = (u8*)&ir->index +
   821					le32_to_cpu(ir->index.index_length);
   822			if (index_end > ir_end) {
   823				ntfs_error(vi->i_sb, "Directory index is corrupt.");
   824				goto unm_err_out;
   825			}
   826			if (ir->type != AT_FILE_NAME) {
   827				ntfs_error(vi->i_sb, "Indexed attribute is not "
   828						"$FILE_NAME.");
   829				goto unm_err_out;
   830			}
   831			if (ir->collation_rule != COLLATION_FILE_NAME) {
   832				ntfs_error(vi->i_sb, "Index collation rule is not "
   833						"COLLATION_FILE_NAME.");
   834				goto unm_err_out;
   835			}
   836			ni->itype.index.collation_rule = ir->collation_rule;
   837			ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
   838			if (ni->itype.index.block_size &
   839					(ni->itype.index.block_size - 1)) {
   840				ntfs_error(vi->i_sb, "Index block size (%u) is not a "
   841						"power of two.",
   842						ni->itype.index.block_size);
   843				goto unm_err_out;
   844			}
   845			if (ni->itype.index.block_size > PAGE_SIZE) {
   846				ntfs_error(vi->i_sb, "Index block size (%u) > "
   847						"PAGE_SIZE (%ld) is not "
   848						"supported.  Sorry.",
   849						ni->itype.index.block_size,
   850						PAGE_SIZE);
   851				err = -EOPNOTSUPP;
   852				goto unm_err_out;
   853			}
   854			if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
   855				ntfs_error(vi->i_sb, "Index block size (%u) < "
   856						"NTFS_BLOCK_SIZE (%i) is not "
   857						"supported.  Sorry.",
   858						ni->itype.index.block_size,
   859						NTFS_BLOCK_SIZE);
   860				err = -EOPNOTSUPP;
   861				goto unm_err_out;
   862			}
   863			ni->itype.index.block_size_bits =
   864					ffs(ni->itype.index.block_size) - 1;
   865			/* Determine the size of a vcn in the directory index. */
   866			if (vol->cluster_size <= ni->itype.index.block_size) {
   867				ni->itype.index.vcn_size = vol->cluster_size;
   868				ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
   869			} else {
   870				ni->itype.index.vcn_size = vol->sector_size;
   871				ni->itype.index.vcn_size_bits = vol->sector_size_bits;
   872			}
   873	
   874			/* Setup the index allocation attribute, even if not present. */
   875			NInoSetMstProtected(ni);
   876			ni->type = AT_INDEX_ALLOCATION;
   877			ni->name = I30;
   878			ni->name_len = 4;
   879	
   880			if (!(ir->index.flags & LARGE_INDEX)) {
   881				/* No index allocation. */
   882				vi->i_size = ni->initialized_size =
   883						ni->allocated_size = 0;
   884				/* We are done with the mft record, so we release it. */
   885				ntfs_attr_put_search_ctx(ctx);
   886				unmap_mft_record(ni);
   887				m = NULL;
   888				ctx = NULL;
   889				goto skip_large_dir_stuff;
   890			} /* LARGE_INDEX: Index allocation present. Setup state. */
   891			NInoSetIndexAllocPresent(ni);
   892			/* Find index allocation attribute. */
   893			ntfs_attr_reinit_search_ctx(ctx);
   894			err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
   895					CASE_SENSITIVE, 0, NULL, 0, ctx);
   896			if (unlikely(err)) {
   897				if (err == -ENOENT)
   898					ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
   899							"attribute is not present but "
   900							"$INDEX_ROOT indicated it is.");
   901				else
   902					ntfs_error(vi->i_sb, "Failed to lookup "
   903							"$INDEX_ALLOCATION "
   904							"attribute.");
   905				goto unm_err_out;
   906			}
   907			a = ctx->attr;
   908			if (!a->non_resident) {
   909				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   910						"is resident.");
   911				goto unm_err_out;
   912			}
   913			/*
   914			 * Ensure the attribute name is placed before the mapping pairs
   915			 * array.
   916			 */
   917			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   918					le16_to_cpu(
   919					a->data.non_resident.mapping_pairs_offset)))) {
   920				ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
   921						"is placed after the mapping pairs "
   922						"array.");
   923				goto unm_err_out;
   924			}
   925			if (a->flags & ATTR_IS_ENCRYPTED) {
   926				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   927						"is encrypted.");
   928				goto unm_err_out;
   929			}
   930			if (a->flags & ATTR_IS_SPARSE) {
   931				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   932						"is sparse.");
   933				goto unm_err_out;
   934			}
   935			if (a->flags & ATTR_COMPRESSION_MASK) {
   936				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   937						"is compressed.");
   938				goto unm_err_out;
   939			}
   940			if (a->data.non_resident.lowest_vcn) {
   941				ntfs_error(vi->i_sb, "First extent of "
   942						"$INDEX_ALLOCATION attribute has non "
   943						"zero lowest_vcn.");
   944				goto unm_err_out;
   945			}
   946			vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
   947			ni->initialized_size = sle64_to_cpu(
   948					a->data.non_resident.initialized_size);
   949			ni->allocated_size = sle64_to_cpu(
   950					a->data.non_resident.allocated_size);
   951			/*
   952			 * We are done with the mft record, so we release it. Otherwise
   953			 * we would deadlock in ntfs_attr_iget().
   954			 */
   955			ntfs_attr_put_search_ctx(ctx);
   956			unmap_mft_record(ni);
   957			m = NULL;
   958			ctx = NULL;
   959			/* Get the index bitmap attribute inode. */
   960			bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
   961			if (IS_ERR(bvi)) {
   962				ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
   963				err = PTR_ERR(bvi);
   964				goto unm_err_out;
   965			}
   966			bni = NTFS_I(bvi);
   967			if (NInoCompressed(bni) || NInoEncrypted(bni) ||
   968					NInoSparse(bni)) {
   969				ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
   970						"and/or encrypted and/or sparse.");
   971				goto iput_unm_err_out;
   972			}
   973			/* Consistency check bitmap size vs. index allocation size. */
   974			bvi_size = i_size_read(bvi);
   975			if ((bvi_size << 3) < (vi->i_size >>
   976					ni->itype.index.block_size_bits)) {
   977				ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
   978						"for index allocation (0x%llx).",
   979						bvi_size << 3, vi->i_size);
   980				goto iput_unm_err_out;
   981			}
   982			/* No longer need the bitmap attribute inode. */
   983			iput(bvi);
   984	skip_large_dir_stuff:
   985			/* Setup the operations for this inode. */
   986			vi->i_op = &ntfs_dir_inode_ops;
   987			vi->i_fop = &ntfs_dir_ops;
   988			vi->i_mapping->a_ops = &ntfs_mst_aops;
   989		} else {
   990			/* It is a file. */
   991			ntfs_attr_reinit_search_ctx(ctx);
   992	
   993			/* Setup the data attribute, even if not present. */
   994			ni->type = AT_DATA;
   995			ni->name = NULL;
   996			ni->name_len = 0;
   997	
   998			/* Find first extent of the unnamed data attribute. */
   999			err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
  1000			if (unlikely(err)) {
  1001				vi->i_size = ni->initialized_size =
  1002						ni->allocated_size = 0;
  1003				if (err != -ENOENT) {
  1004					ntfs_error(vi->i_sb, "Failed to lookup $DATA "
  1005							"attribute.");
  1006					goto unm_err_out;
  1007				}
  1008				/*
  1009				 * FILE_Secure does not have an unnamed $DATA
  1010				 * attribute, so we special case it here.
  1011				 */
  1012				if (vi->i_ino == FILE_Secure)
  1013					goto no_data_attr_special_case;
  1014				/*
  1015				 * Most if not all the system files in the $Extend
  1016				 * system directory do not have unnamed data
  1017				 * attributes so we need to check if the parent
  1018				 * directory of the file is FILE_Extend and if it is
  1019				 * ignore this error. To do this we need to get the
  1020				 * name of this inode from the mft record as the name
  1021				 * contains the back reference to the parent directory.
  1022				 */
  1023				if (ntfs_is_extended_system_file(ctx) > 0)
  1024					goto no_data_attr_special_case;
  1025				// FIXME: File is corrupt! Hot-fix with empty data
  1026				// attribute if recovery option is set.
  1027				ntfs_error(vi->i_sb, "$DATA attribute is missing.");
  1028				goto unm_err_out;
  1029			}
  1030			a = ctx->attr;
  1031			/* Setup the state. */
  1032			if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
  1033				if (a->flags & ATTR_COMPRESSION_MASK) {
  1034					NInoSetCompressed(ni);
  1035					if (vol->cluster_size > 4096) {
  1036						ntfs_error(vi->i_sb, "Found "
  1037								"compressed data but "
  1038								"compression is "
  1039								"disabled due to "
  1040								"cluster size (%i) > "
  1041								"4kiB.",
  1042								vol->cluster_size);
  1043						goto unm_err_out;
  1044					}
  1045					if ((a->flags & ATTR_COMPRESSION_MASK)
  1046							!= ATTR_IS_COMPRESSED) {
  1047						ntfs_error(vi->i_sb, "Found unknown "
  1048								"compression method "
  1049								"or corrupt file.");
  1050						goto unm_err_out;
  1051					}
  1052				}
  1053				if (a->flags & ATTR_IS_SPARSE)
  1054					NInoSetSparse(ni);
  1055			}
  1056			if (a->flags & ATTR_IS_ENCRYPTED) {
  1057				if (NInoCompressed(ni)) {
  1058					ntfs_error(vi->i_sb, "Found encrypted and "
  1059							"compressed data.");
  1060					goto unm_err_out;
  1061				}
  1062				NInoSetEncrypted(ni);
  1063			}
  1064			if (a->non_resident) {
  1065				NInoSetNonResident(ni);
  1066				if (NInoCompressed(ni) || NInoSparse(ni)) {
  1067					if (NInoCompressed(ni) && a->data.non_resident.
  1068							compression_unit != 4) {
  1069						ntfs_error(vi->i_sb, "Found "
  1070								"non-standard "
  1071								"compression unit (%u "
  1072								"instead of 4).  "
  1073								"Cannot handle this.",
  1074								a->data.non_resident.
  1075								compression_unit);
  1076						err = -EOPNOTSUPP;
  1077						goto unm_err_out;
  1078					}
  1079					if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
  1080					a->data.non_resident.compression_unit !=
> 1081					vol->sparse_compression_unit) {
  1082						ntfs_error(vi->i_sb,
  1083						"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
  1084						a->data.non_resident.compression_unit,
  1085						vol->sparse_compression_unit);
  1086						err = -EOPNOTSUPP;
  1087						goto unm_err_out;
  1088					}
  1089					if (a->data.non_resident.compression_unit) {
  1090						ni->itype.compressed.block_size = 1U <<
  1091								(a->data.non_resident.
  1092								compression_unit +
  1093								vol->cluster_size_bits);
  1094						ni->itype.compressed.block_size_bits =
  1095								ffs(ni->itype.
  1096								compressed.
  1097								block_size) - 1;
  1098						ni->itype.compressed.block_clusters =
  1099								1U << a->data.
  1100								non_resident.
  1101								compression_unit;
  1102					} else {
  1103						ni->itype.compressed.block_size = 0;
  1104						ni->itype.compressed.block_size_bits =
  1105								0;
  1106						ni->itype.compressed.block_clusters =
  1107								0;
  1108					}
  1109					ni->itype.compressed.size = sle64_to_cpu(
  1110							a->data.non_resident.
  1111							compressed_size);
  1112				}
  1113				if (a->data.non_resident.lowest_vcn) {
  1114					ntfs_error(vi->i_sb, "First extent of $DATA "
  1115							"attribute has non zero "
  1116							"lowest_vcn.");
  1117					goto unm_err_out;
  1118				}
  1119				vi->i_size = sle64_to_cpu(
  1120						a->data.non_resident.data_size);
  1121				ni->initialized_size = sle64_to_cpu(
  1122						a->data.non_resident.initialized_size);
  1123				ni->allocated_size = sle64_to_cpu(
  1124						a->data.non_resident.allocated_size);
  1125			} else { /* Resident attribute. */
  1126				vi->i_size = ni->initialized_size = le32_to_cpu(
  1127						a->data.resident.value_length);
  1128				ni->allocated_size = le32_to_cpu(a->length) -
  1129						le16_to_cpu(
  1130						a->data.resident.value_offset);
  1131				if (vi->i_size > ni->allocated_size) {
  1132					ntfs_error(vi->i_sb, "Resident data attribute "
  1133							"is corrupt (size exceeds "
  1134							"allocation).");
  1135					goto unm_err_out;
  1136				}
  1137			}
  1138	no_data_attr_special_case:
  1139			/* We are done with the mft record, so we release it. */
  1140			ntfs_attr_put_search_ctx(ctx);
  1141			unmap_mft_record(ni);
  1142			m = NULL;
  1143			ctx = NULL;
  1144			/* Setup the operations for this inode. */
  1145			vi->i_op = &ntfs_file_inode_ops;
  1146			vi->i_fop = &ntfs_file_ops;
  1147			vi->i_mapping->a_ops = &ntfs_normal_aops;
  1148			if (NInoMstProtected(ni))
  1149				vi->i_mapping->a_ops = &ntfs_mst_aops;
  1150			else if (NInoCompressed(ni))
  1151				vi->i_mapping->a_ops = &ntfs_compressed_aops;
  1152		}
  1153		/*
  1154		 * The number of 512-byte blocks used on disk (for stat). This is in so
  1155		 * far inaccurate as it doesn't account for any named streams or other
  1156		 * special non-resident attributes, but that is how Windows works, too,
  1157		 * so we are at least consistent with Windows, if not entirely
  1158		 * consistent with the Linux Way. Doing it the Linux Way would cause a
  1159		 * significant slowdown as it would involve iterating over all
  1160		 * attributes in the mft record and adding the allocated/compressed
  1161		 * sizes of all non-resident attributes present to give us the Linux
  1162		 * correct size that should go into i_blocks (after division by 512).
  1163		 */
  1164		if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
  1165			vi->i_blocks = ni->itype.compressed.size >> 9;
  1166		else
  1167			vi->i_blocks = ni->allocated_size >> 9;
  1168		ntfs_debug("Done.");
  1169		return 0;
  1170	iput_unm_err_out:
  1171		iput(bvi);
  1172	unm_err_out:
  1173		if (!err)
  1174			err = -EIO;
  1175		if (ctx)
  1176			ntfs_attr_put_search_ctx(ctx);
  1177		if (m)
  1178			unmap_mft_record(ni);
  1179	err_out:
  1180		ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
  1181				"inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
  1182		make_bad_inode(vi);
  1183		if (err != -EOPNOTSUPP && err != -ENOMEM)
  1184			NVolSetErrors(vol);
  1185		return err;
  1186	}
  1187	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-15  5:22       ` Manas Ghandat
@ 2023-08-15  8:52         ` kernel test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2023-08-15  8:52 UTC (permalink / raw)
  To: Manas Ghandat, anton, linkinjeon
  Cc: llvm, oe-kbuild-all, Manas Ghandat, Linux-kernel-mentees, gregkh,
	linux-fsdevel, linux-kernel, linux-ntfs-dev,
	syzbot+4768a8f039aa677897d0

Hi Manas,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.5-rc6 next-20230809]
[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/Manas-Ghandat/ntfs-fix-shift-out-of-bounds-in-ntfs_iget/20230815-132656
base:   linus/master
patch link:    https://lore.kernel.org/r/20230815052251.107732-1-ghandatmanas%40gmail.com
patch subject: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
config: i386-randconfig-i002-20230815 (https://download.01.org/0day-ci/archive/20230815/202308151606.3Xy20wzx-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce: (https://download.01.org/0day-ci/archive/20230815/202308151606.3Xy20wzx-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/202308151606.3Xy20wzx-lkp@intel.com/

All errors (new ones prefixed by >>):

>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
                                   vol->sparse_compression_unit) {
                                   ~~~  ^
   fs/ntfs/inode.c:1085:11: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
                                           vol->sparse_compression_unit);
                                           ~~~  ^
   fs/ntfs/debug.h:55:66: note: expanded from macro 'ntfs_error'
   #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
                                                                           ^
   2 errors generated.


vim +1081 fs/ntfs/inode.c

   497	
   498	/**
   499	 * ntfs_read_locked_inode - read an inode from its device
   500	 * @vi:		inode to read
   501	 *
   502	 * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
   503	 * described by @vi into memory from the device.
   504	 *
   505	 * The only fields in @vi that we need to/can look at when the function is
   506	 * called are i_sb, pointing to the mounted device's super block, and i_ino,
   507	 * the number of the inode to load.
   508	 *
   509	 * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
   510	 * for reading and sets up the necessary @vi fields as well as initializing
   511	 * the ntfs inode.
   512	 *
   513	 * Q: What locks are held when the function is called?
   514	 * A: i_state has I_NEW set, hence the inode is locked, also
   515	 *    i_count is set to 1, so it is not going to go away
   516	 *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
   517	 *    is allowed to write to them. We should of course be honouring them but
   518	 *    we need to do that using the IS_* macros defined in include/linux/fs.h.
   519	 *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
   520	 *
   521	 * Return 0 on success and -errno on error.  In the error case, the inode will
   522	 * have had make_bad_inode() executed on it.
   523	 */
   524	static int ntfs_read_locked_inode(struct inode *vi)
   525	{
   526		ntfs_volume *vol = NTFS_SB(vi->i_sb);
   527		ntfs_inode *ni;
   528		struct inode *bvi;
   529		MFT_RECORD *m;
   530		ATTR_RECORD *a;
   531		STANDARD_INFORMATION *si;
   532		ntfs_attr_search_ctx *ctx;
   533		int err = 0;
   534	
   535		ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
   536	
   537		/* Setup the generic vfs inode parts now. */
   538		vi->i_uid = vol->uid;
   539		vi->i_gid = vol->gid;
   540		vi->i_mode = 0;
   541	
   542		/*
   543		 * Initialize the ntfs specific part of @vi special casing
   544		 * FILE_MFT which we need to do at mount time.
   545		 */
   546		if (vi->i_ino != FILE_MFT)
   547			ntfs_init_big_inode(vi);
   548		ni = NTFS_I(vi);
   549	
   550		m = map_mft_record(ni);
   551		if (IS_ERR(m)) {
   552			err = PTR_ERR(m);
   553			goto err_out;
   554		}
   555		ctx = ntfs_attr_get_search_ctx(ni, m);
   556		if (!ctx) {
   557			err = -ENOMEM;
   558			goto unm_err_out;
   559		}
   560	
   561		if (!(m->flags & MFT_RECORD_IN_USE)) {
   562			ntfs_error(vi->i_sb, "Inode is not in use!");
   563			goto unm_err_out;
   564		}
   565		if (m->base_mft_record) {
   566			ntfs_error(vi->i_sb, "Inode is an extent inode!");
   567			goto unm_err_out;
   568		}
   569	
   570		/* Transfer information from mft record into vfs and ntfs inodes. */
   571		vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
   572	
   573		/*
   574		 * FIXME: Keep in mind that link_count is two for files which have both
   575		 * a long file name and a short file name as separate entries, so if
   576		 * we are hiding short file names this will be too high. Either we need
   577		 * to account for the short file names by subtracting them or we need
   578		 * to make sure we delete files even though i_nlink is not zero which
   579		 * might be tricky due to vfs interactions. Need to think about this
   580		 * some more when implementing the unlink command.
   581		 */
   582		set_nlink(vi, le16_to_cpu(m->link_count));
   583		/*
   584		 * FIXME: Reparse points can have the directory bit set even though
   585		 * they would be S_IFLNK. Need to deal with this further below when we
   586		 * implement reparse points / symbolic links but it will do for now.
   587		 * Also if not a directory, it could be something else, rather than
   588		 * a regular file. But again, will do for now.
   589		 */
   590		/* Everyone gets all permissions. */
   591		vi->i_mode |= S_IRWXUGO;
   592		/* If read-only, no one gets write permissions. */
   593		if (IS_RDONLY(vi))
   594			vi->i_mode &= ~S_IWUGO;
   595		if (m->flags & MFT_RECORD_IS_DIRECTORY) {
   596			vi->i_mode |= S_IFDIR;
   597			/*
   598			 * Apply the directory permissions mask set in the mount
   599			 * options.
   600			 */
   601			vi->i_mode &= ~vol->dmask;
   602			/* Things break without this kludge! */
   603			if (vi->i_nlink > 1)
   604				set_nlink(vi, 1);
   605		} else {
   606			vi->i_mode |= S_IFREG;
   607			/* Apply the file permissions mask set in the mount options. */
   608			vi->i_mode &= ~vol->fmask;
   609		}
   610		/*
   611		 * Find the standard information attribute in the mft record. At this
   612		 * stage we haven't setup the attribute list stuff yet, so this could
   613		 * in fact fail if the standard information is in an extent record, but
   614		 * I don't think this actually ever happens.
   615		 */
   616		err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
   617				ctx);
   618		if (unlikely(err)) {
   619			if (err == -ENOENT) {
   620				/*
   621				 * TODO: We should be performing a hot fix here (if the
   622				 * recover mount option is set) by creating a new
   623				 * attribute.
   624				 */
   625				ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
   626						"is missing.");
   627			}
   628			goto unm_err_out;
   629		}
   630		a = ctx->attr;
   631		/* Get the standard information attribute value. */
   632		if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
   633				+ le32_to_cpu(a->data.resident.value_length) >
   634				(u8 *)ctx->mrec + vol->mft_record_size) {
   635			ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
   636			goto unm_err_out;
   637		}
   638		si = (STANDARD_INFORMATION*)((u8*)a +
   639				le16_to_cpu(a->data.resident.value_offset));
   640	
   641		/* Transfer information from the standard information into vi. */
   642		/*
   643		 * Note: The i_?times do not quite map perfectly onto the NTFS times,
   644		 * but they are close enough, and in the end it doesn't really matter
   645		 * that much...
   646		 */
   647		/*
   648		 * mtime is the last change of the data within the file. Not changed
   649		 * when only metadata is changed, e.g. a rename doesn't affect mtime.
   650		 */
   651		vi->i_mtime = ntfs2utc(si->last_data_change_time);
   652		/*
   653		 * ctime is the last change of the metadata of the file. This obviously
   654		 * always changes, when mtime is changed. ctime can be changed on its
   655		 * own, mtime is then not changed, e.g. when a file is renamed.
   656		 */
   657		vi->i_ctime = ntfs2utc(si->last_mft_change_time);
   658		/*
   659		 * Last access to the data within the file. Not changed during a rename
   660		 * for example but changed whenever the file is written to.
   661		 */
   662		vi->i_atime = ntfs2utc(si->last_access_time);
   663	
   664		/* Find the attribute list attribute if present. */
   665		ntfs_attr_reinit_search_ctx(ctx);
   666		err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
   667		if (err) {
   668			if (unlikely(err != -ENOENT)) {
   669				ntfs_error(vi->i_sb, "Failed to lookup attribute list "
   670						"attribute.");
   671				goto unm_err_out;
   672			}
   673		} else /* if (!err) */ {
   674			if (vi->i_ino == FILE_MFT)
   675				goto skip_attr_list_load;
   676			ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
   677			NInoSetAttrList(ni);
   678			a = ctx->attr;
   679			if (a->flags & ATTR_COMPRESSION_MASK) {
   680				ntfs_error(vi->i_sb, "Attribute list attribute is "
   681						"compressed.");
   682				goto unm_err_out;
   683			}
   684			if (a->flags & ATTR_IS_ENCRYPTED ||
   685					a->flags & ATTR_IS_SPARSE) {
   686				if (a->non_resident) {
   687					ntfs_error(vi->i_sb, "Non-resident attribute "
   688							"list attribute is encrypted/"
   689							"sparse.");
   690					goto unm_err_out;
   691				}
   692				ntfs_warning(vi->i_sb, "Resident attribute list "
   693						"attribute in inode 0x%lx is marked "
   694						"encrypted/sparse which is not true.  "
   695						"However, Windows allows this and "
   696						"chkdsk does not detect or correct it "
   697						"so we will just ignore the invalid "
   698						"flags and pretend they are not set.",
   699						vi->i_ino);
   700			}
   701			/* Now allocate memory for the attribute list. */
   702			ni->attr_list_size = (u32)ntfs_attr_size(a);
   703			ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
   704			if (!ni->attr_list) {
   705				ntfs_error(vi->i_sb, "Not enough memory to allocate "
   706						"buffer for attribute list.");
   707				err = -ENOMEM;
   708				goto unm_err_out;
   709			}
   710			if (a->non_resident) {
   711				NInoSetAttrListNonResident(ni);
   712				if (a->data.non_resident.lowest_vcn) {
   713					ntfs_error(vi->i_sb, "Attribute list has non "
   714							"zero lowest_vcn.");
   715					goto unm_err_out;
   716				}
   717				/*
   718				 * Setup the runlist. No need for locking as we have
   719				 * exclusive access to the inode at this time.
   720				 */
   721				ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
   722						a, NULL);
   723				if (IS_ERR(ni->attr_list_rl.rl)) {
   724					err = PTR_ERR(ni->attr_list_rl.rl);
   725					ni->attr_list_rl.rl = NULL;
   726					ntfs_error(vi->i_sb, "Mapping pairs "
   727							"decompression failed.");
   728					goto unm_err_out;
   729				}
   730				/* Now load the attribute list. */
   731				if ((err = load_attribute_list(vol, &ni->attr_list_rl,
   732						ni->attr_list, ni->attr_list_size,
   733						sle64_to_cpu(a->data.non_resident.
   734						initialized_size)))) {
   735					ntfs_error(vi->i_sb, "Failed to load "
   736							"attribute list attribute.");
   737					goto unm_err_out;
   738				}
   739			} else /* if (!a->non_resident) */ {
   740				if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
   741						+ le32_to_cpu(
   742						a->data.resident.value_length) >
   743						(u8*)ctx->mrec + vol->mft_record_size) {
   744					ntfs_error(vi->i_sb, "Corrupt attribute list "
   745							"in inode.");
   746					goto unm_err_out;
   747				}
   748				/* Now copy the attribute list. */
   749				memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
   750						a->data.resident.value_offset),
   751						le32_to_cpu(
   752						a->data.resident.value_length));
   753			}
   754		}
   755	skip_attr_list_load:
   756		/*
   757		 * If an attribute list is present we now have the attribute list value
   758		 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
   759		 */
   760		if (S_ISDIR(vi->i_mode)) {
   761			loff_t bvi_size;
   762			ntfs_inode *bni;
   763			INDEX_ROOT *ir;
   764			u8 *ir_end, *index_end;
   765	
   766			/* It is a directory, find index root attribute. */
   767			ntfs_attr_reinit_search_ctx(ctx);
   768			err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
   769					0, NULL, 0, ctx);
   770			if (unlikely(err)) {
   771				if (err == -ENOENT) {
   772					// FIXME: File is corrupt! Hot-fix with empty
   773					// index root attribute if recovery option is
   774					// set.
   775					ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
   776							"is missing.");
   777				}
   778				goto unm_err_out;
   779			}
   780			a = ctx->attr;
   781			/* Set up the state. */
   782			if (unlikely(a->non_resident)) {
   783				ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
   784						"resident.");
   785				goto unm_err_out;
   786			}
   787			/* Ensure the attribute name is placed before the value. */
   788			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   789					le16_to_cpu(a->data.resident.value_offset)))) {
   790				ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
   791						"placed after the attribute value.");
   792				goto unm_err_out;
   793			}
   794			/*
   795			 * Compressed/encrypted index root just means that the newly
   796			 * created files in that directory should be created compressed/
   797			 * encrypted. However index root cannot be both compressed and
   798			 * encrypted.
   799			 */
   800			if (a->flags & ATTR_COMPRESSION_MASK)
   801				NInoSetCompressed(ni);
   802			if (a->flags & ATTR_IS_ENCRYPTED) {
   803				if (a->flags & ATTR_COMPRESSION_MASK) {
   804					ntfs_error(vi->i_sb, "Found encrypted and "
   805							"compressed attribute.");
   806					goto unm_err_out;
   807				}
   808				NInoSetEncrypted(ni);
   809			}
   810			if (a->flags & ATTR_IS_SPARSE)
   811				NInoSetSparse(ni);
   812			ir = (INDEX_ROOT*)((u8*)a +
   813					le16_to_cpu(a->data.resident.value_offset));
   814			ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
   815			if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
   816				ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
   817						"corrupt.");
   818				goto unm_err_out;
   819			}
   820			index_end = (u8*)&ir->index +
   821					le32_to_cpu(ir->index.index_length);
   822			if (index_end > ir_end) {
   823				ntfs_error(vi->i_sb, "Directory index is corrupt.");
   824				goto unm_err_out;
   825			}
   826			if (ir->type != AT_FILE_NAME) {
   827				ntfs_error(vi->i_sb, "Indexed attribute is not "
   828						"$FILE_NAME.");
   829				goto unm_err_out;
   830			}
   831			if (ir->collation_rule != COLLATION_FILE_NAME) {
   832				ntfs_error(vi->i_sb, "Index collation rule is not "
   833						"COLLATION_FILE_NAME.");
   834				goto unm_err_out;
   835			}
   836			ni->itype.index.collation_rule = ir->collation_rule;
   837			ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
   838			if (ni->itype.index.block_size &
   839					(ni->itype.index.block_size - 1)) {
   840				ntfs_error(vi->i_sb, "Index block size (%u) is not a "
   841						"power of two.",
   842						ni->itype.index.block_size);
   843				goto unm_err_out;
   844			}
   845			if (ni->itype.index.block_size > PAGE_SIZE) {
   846				ntfs_error(vi->i_sb, "Index block size (%u) > "
   847						"PAGE_SIZE (%ld) is not "
   848						"supported.  Sorry.",
   849						ni->itype.index.block_size,
   850						PAGE_SIZE);
   851				err = -EOPNOTSUPP;
   852				goto unm_err_out;
   853			}
   854			if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
   855				ntfs_error(vi->i_sb, "Index block size (%u) < "
   856						"NTFS_BLOCK_SIZE (%i) is not "
   857						"supported.  Sorry.",
   858						ni->itype.index.block_size,
   859						NTFS_BLOCK_SIZE);
   860				err = -EOPNOTSUPP;
   861				goto unm_err_out;
   862			}
   863			ni->itype.index.block_size_bits =
   864					ffs(ni->itype.index.block_size) - 1;
   865			/* Determine the size of a vcn in the directory index. */
   866			if (vol->cluster_size <= ni->itype.index.block_size) {
   867				ni->itype.index.vcn_size = vol->cluster_size;
   868				ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
   869			} else {
   870				ni->itype.index.vcn_size = vol->sector_size;
   871				ni->itype.index.vcn_size_bits = vol->sector_size_bits;
   872			}
   873	
   874			/* Setup the index allocation attribute, even if not present. */
   875			NInoSetMstProtected(ni);
   876			ni->type = AT_INDEX_ALLOCATION;
   877			ni->name = I30;
   878			ni->name_len = 4;
   879	
   880			if (!(ir->index.flags & LARGE_INDEX)) {
   881				/* No index allocation. */
   882				vi->i_size = ni->initialized_size =
   883						ni->allocated_size = 0;
   884				/* We are done with the mft record, so we release it. */
   885				ntfs_attr_put_search_ctx(ctx);
   886				unmap_mft_record(ni);
   887				m = NULL;
   888				ctx = NULL;
   889				goto skip_large_dir_stuff;
   890			} /* LARGE_INDEX: Index allocation present. Setup state. */
   891			NInoSetIndexAllocPresent(ni);
   892			/* Find index allocation attribute. */
   893			ntfs_attr_reinit_search_ctx(ctx);
   894			err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
   895					CASE_SENSITIVE, 0, NULL, 0, ctx);
   896			if (unlikely(err)) {
   897				if (err == -ENOENT)
   898					ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
   899							"attribute is not present but "
   900							"$INDEX_ROOT indicated it is.");
   901				else
   902					ntfs_error(vi->i_sb, "Failed to lookup "
   903							"$INDEX_ALLOCATION "
   904							"attribute.");
   905				goto unm_err_out;
   906			}
   907			a = ctx->attr;
   908			if (!a->non_resident) {
   909				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   910						"is resident.");
   911				goto unm_err_out;
   912			}
   913			/*
   914			 * Ensure the attribute name is placed before the mapping pairs
   915			 * array.
   916			 */
   917			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   918					le16_to_cpu(
   919					a->data.non_resident.mapping_pairs_offset)))) {
   920				ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
   921						"is placed after the mapping pairs "
   922						"array.");
   923				goto unm_err_out;
   924			}
   925			if (a->flags & ATTR_IS_ENCRYPTED) {
   926				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   927						"is encrypted.");
   928				goto unm_err_out;
   929			}
   930			if (a->flags & ATTR_IS_SPARSE) {
   931				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   932						"is sparse.");
   933				goto unm_err_out;
   934			}
   935			if (a->flags & ATTR_COMPRESSION_MASK) {
   936				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   937						"is compressed.");
   938				goto unm_err_out;
   939			}
   940			if (a->data.non_resident.lowest_vcn) {
   941				ntfs_error(vi->i_sb, "First extent of "
   942						"$INDEX_ALLOCATION attribute has non "
   943						"zero lowest_vcn.");
   944				goto unm_err_out;
   945			}
   946			vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
   947			ni->initialized_size = sle64_to_cpu(
   948					a->data.non_resident.initialized_size);
   949			ni->allocated_size = sle64_to_cpu(
   950					a->data.non_resident.allocated_size);
   951			/*
   952			 * We are done with the mft record, so we release it. Otherwise
   953			 * we would deadlock in ntfs_attr_iget().
   954			 */
   955			ntfs_attr_put_search_ctx(ctx);
   956			unmap_mft_record(ni);
   957			m = NULL;
   958			ctx = NULL;
   959			/* Get the index bitmap attribute inode. */
   960			bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
   961			if (IS_ERR(bvi)) {
   962				ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
   963				err = PTR_ERR(bvi);
   964				goto unm_err_out;
   965			}
   966			bni = NTFS_I(bvi);
   967			if (NInoCompressed(bni) || NInoEncrypted(bni) ||
   968					NInoSparse(bni)) {
   969				ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
   970						"and/or encrypted and/or sparse.");
   971				goto iput_unm_err_out;
   972			}
   973			/* Consistency check bitmap size vs. index allocation size. */
   974			bvi_size = i_size_read(bvi);
   975			if ((bvi_size << 3) < (vi->i_size >>
   976					ni->itype.index.block_size_bits)) {
   977				ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
   978						"for index allocation (0x%llx).",
   979						bvi_size << 3, vi->i_size);
   980				goto iput_unm_err_out;
   981			}
   982			/* No longer need the bitmap attribute inode. */
   983			iput(bvi);
   984	skip_large_dir_stuff:
   985			/* Setup the operations for this inode. */
   986			vi->i_op = &ntfs_dir_inode_ops;
   987			vi->i_fop = &ntfs_dir_ops;
   988			vi->i_mapping->a_ops = &ntfs_mst_aops;
   989		} else {
   990			/* It is a file. */
   991			ntfs_attr_reinit_search_ctx(ctx);
   992	
   993			/* Setup the data attribute, even if not present. */
   994			ni->type = AT_DATA;
   995			ni->name = NULL;
   996			ni->name_len = 0;
   997	
   998			/* Find first extent of the unnamed data attribute. */
   999			err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
  1000			if (unlikely(err)) {
  1001				vi->i_size = ni->initialized_size =
  1002						ni->allocated_size = 0;
  1003				if (err != -ENOENT) {
  1004					ntfs_error(vi->i_sb, "Failed to lookup $DATA "
  1005							"attribute.");
  1006					goto unm_err_out;
  1007				}
  1008				/*
  1009				 * FILE_Secure does not have an unnamed $DATA
  1010				 * attribute, so we special case it here.
  1011				 */
  1012				if (vi->i_ino == FILE_Secure)
  1013					goto no_data_attr_special_case;
  1014				/*
  1015				 * Most if not all the system files in the $Extend
  1016				 * system directory do not have unnamed data
  1017				 * attributes so we need to check if the parent
  1018				 * directory of the file is FILE_Extend and if it is
  1019				 * ignore this error. To do this we need to get the
  1020				 * name of this inode from the mft record as the name
  1021				 * contains the back reference to the parent directory.
  1022				 */
  1023				if (ntfs_is_extended_system_file(ctx) > 0)
  1024					goto no_data_attr_special_case;
  1025				// FIXME: File is corrupt! Hot-fix with empty data
  1026				// attribute if recovery option is set.
  1027				ntfs_error(vi->i_sb, "$DATA attribute is missing.");
  1028				goto unm_err_out;
  1029			}
  1030			a = ctx->attr;
  1031			/* Setup the state. */
  1032			if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
  1033				if (a->flags & ATTR_COMPRESSION_MASK) {
  1034					NInoSetCompressed(ni);
  1035					if (vol->cluster_size > 4096) {
  1036						ntfs_error(vi->i_sb, "Found "
  1037								"compressed data but "
  1038								"compression is "
  1039								"disabled due to "
  1040								"cluster size (%i) > "
  1041								"4kiB.",
  1042								vol->cluster_size);
  1043						goto unm_err_out;
  1044					}
  1045					if ((a->flags & ATTR_COMPRESSION_MASK)
  1046							!= ATTR_IS_COMPRESSED) {
  1047						ntfs_error(vi->i_sb, "Found unknown "
  1048								"compression method "
  1049								"or corrupt file.");
  1050						goto unm_err_out;
  1051					}
  1052				}
  1053				if (a->flags & ATTR_IS_SPARSE)
  1054					NInoSetSparse(ni);
  1055			}
  1056			if (a->flags & ATTR_IS_ENCRYPTED) {
  1057				if (NInoCompressed(ni)) {
  1058					ntfs_error(vi->i_sb, "Found encrypted and "
  1059							"compressed data.");
  1060					goto unm_err_out;
  1061				}
  1062				NInoSetEncrypted(ni);
  1063			}
  1064			if (a->non_resident) {
  1065				NInoSetNonResident(ni);
  1066				if (NInoCompressed(ni) || NInoSparse(ni)) {
  1067					if (NInoCompressed(ni) && a->data.non_resident.
  1068							compression_unit != 4) {
  1069						ntfs_error(vi->i_sb, "Found "
  1070								"non-standard "
  1071								"compression unit (%u "
  1072								"instead of 4).  "
  1073								"Cannot handle this.",
  1074								a->data.non_resident.
  1075								compression_unit);
  1076						err = -EOPNOTSUPP;
  1077						goto unm_err_out;
  1078					}
  1079					if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
  1080					a->data.non_resident.compression_unit !=
> 1081					vol->sparse_compression_unit) {
  1082						ntfs_error(vi->i_sb,
  1083						"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
  1084						a->data.non_resident.compression_unit,
  1085						vol->sparse_compression_unit);
  1086						err = -EOPNOTSUPP;
  1087						goto unm_err_out;
  1088					}
  1089					if (a->data.non_resident.compression_unit) {
  1090						ni->itype.compressed.block_size = 1U <<
  1091								(a->data.non_resident.
  1092								compression_unit +
  1093								vol->cluster_size_bits);
  1094						ni->itype.compressed.block_size_bits =
  1095								ffs(ni->itype.
  1096								compressed.
  1097								block_size) - 1;
  1098						ni->itype.compressed.block_clusters =
  1099								1U << a->data.
  1100								non_resident.
  1101								compression_unit;
  1102					} else {
  1103						ni->itype.compressed.block_size = 0;
  1104						ni->itype.compressed.block_size_bits =
  1105								0;
  1106						ni->itype.compressed.block_clusters =
  1107								0;
  1108					}
  1109					ni->itype.compressed.size = sle64_to_cpu(
  1110							a->data.non_resident.
  1111							compressed_size);
  1112				}
  1113				if (a->data.non_resident.lowest_vcn) {
  1114					ntfs_error(vi->i_sb, "First extent of $DATA "
  1115							"attribute has non zero "
  1116							"lowest_vcn.");
  1117					goto unm_err_out;
  1118				}
  1119				vi->i_size = sle64_to_cpu(
  1120						a->data.non_resident.data_size);
  1121				ni->initialized_size = sle64_to_cpu(
  1122						a->data.non_resident.initialized_size);
  1123				ni->allocated_size = sle64_to_cpu(
  1124						a->data.non_resident.allocated_size);
  1125			} else { /* Resident attribute. */
  1126				vi->i_size = ni->initialized_size = le32_to_cpu(
  1127						a->data.resident.value_length);
  1128				ni->allocated_size = le32_to_cpu(a->length) -
  1129						le16_to_cpu(
  1130						a->data.resident.value_offset);
  1131				if (vi->i_size > ni->allocated_size) {
  1132					ntfs_error(vi->i_sb, "Resident data attribute "
  1133							"is corrupt (size exceeds "
  1134							"allocation).");
  1135					goto unm_err_out;
  1136				}
  1137			}
  1138	no_data_attr_special_case:
  1139			/* We are done with the mft record, so we release it. */
  1140			ntfs_attr_put_search_ctx(ctx);
  1141			unmap_mft_record(ni);
  1142			m = NULL;
  1143			ctx = NULL;
  1144			/* Setup the operations for this inode. */
  1145			vi->i_op = &ntfs_file_inode_ops;
  1146			vi->i_fop = &ntfs_file_ops;
  1147			vi->i_mapping->a_ops = &ntfs_normal_aops;
  1148			if (NInoMstProtected(ni))
  1149				vi->i_mapping->a_ops = &ntfs_mst_aops;
  1150			else if (NInoCompressed(ni))
  1151				vi->i_mapping->a_ops = &ntfs_compressed_aops;
  1152		}
  1153		/*
  1154		 * The number of 512-byte blocks used on disk (for stat). This is in so
  1155		 * far inaccurate as it doesn't account for any named streams or other
  1156		 * special non-resident attributes, but that is how Windows works, too,
  1157		 * so we are at least consistent with Windows, if not entirely
  1158		 * consistent with the Linux Way. Doing it the Linux Way would cause a
  1159		 * significant slowdown as it would involve iterating over all
  1160		 * attributes in the mft record and adding the allocated/compressed
  1161		 * sizes of all non-resident attributes present to give us the Linux
  1162		 * correct size that should go into i_blocks (after division by 512).
  1163		 */
  1164		if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
  1165			vi->i_blocks = ni->itype.compressed.size >> 9;
  1166		else
  1167			vi->i_blocks = ni->allocated_size >> 9;
  1168		ntfs_debug("Done.");
  1169		return 0;
  1170	iput_unm_err_out:
  1171		iput(bvi);
  1172	unm_err_out:
  1173		if (!err)
  1174			err = -EIO;
  1175		if (ctx)
  1176			ntfs_attr_put_search_ctx(ctx);
  1177		if (m)
  1178			unmap_mft_record(ni);
  1179	err_out:
  1180		ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
  1181				"inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
  1182		make_bad_inode(vi);
  1183		if (err != -EOPNOTSUPP && err != -ENOMEM)
  1184			NVolSetErrors(vol);
  1185		return err;
  1186	}
  1187	

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

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

* Re: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-15  5:22       ` Manas Ghandat
@ 2023-08-15  8:52         ` kernel test robot
  -1 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2023-08-15  8:52 UTC (permalink / raw)
  To: Manas Ghandat, anton, linkinjeon
  Cc: llvm, oe-kbuild-all, Manas Ghandat, Linux-kernel-mentees, gregkh,
	linux-fsdevel, linux-kernel, linux-ntfs-dev,
	syzbot+4768a8f039aa677897d0

Hi Manas,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.5-rc6 next-20230809]
[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/Manas-Ghandat/ntfs-fix-shift-out-of-bounds-in-ntfs_iget/20230815-132656
base:   linus/master
patch link:    https://lore.kernel.org/r/20230815052251.107732-1-ghandatmanas%40gmail.com
patch subject: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
config: hexagon-randconfig-r045-20230815 (https://download.01.org/0day-ci/archive/20230815/202308151601.LQ3EIAQF-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230815/202308151601.LQ3EIAQF-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/202308151601.LQ3EIAQF-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from fs/ntfs/inode.c:8:
   In file included from include/linux/buffer_head.h:12:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:334:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     547 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     560 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from fs/ntfs/inode.c:8:
   In file included from include/linux/buffer_head.h:12:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:334:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     573 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from fs/ntfs/inode.c:8:
   In file included from include/linux/buffer_head.h:12:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:334:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     584 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     594 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     604 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1081 |                                 vol->sparse_compression_unit) {
         |                                 ~~~  ^
   include/linux/compiler.h:55:47: note: expanded from macro 'if'
      55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
         |                                               ^~~~
   include/linux/compiler.h:57:52: note: expanded from macro '__trace_if_var'
      57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
         |                                                    ^~~~
>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1081 |                                 vol->sparse_compression_unit) {
         |                                 ~~~  ^
   include/linux/compiler.h:55:47: note: expanded from macro 'if'
      55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
         |                                               ^~~~
   include/linux/compiler.h:57:61: note: expanded from macro '__trace_if_var'
      57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
         |                                                             ^~~~
>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1081 |                                 vol->sparse_compression_unit) {
         |                                 ~~~  ^
   include/linux/compiler.h:55:47: note: expanded from macro 'if'
      55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
         |                                               ^~~~
   include/linux/compiler.h:57:86: note: expanded from macro '__trace_if_var'
      57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
         |                                                                                      ^~~~
   include/linux/compiler.h:68:3: note: expanded from macro '__trace_if_value'
      68 |         (cond) ?                                        \
         |          ^~~~
   fs/ntfs/inode.c:1085:11: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1085 |                                         vol->sparse_compression_unit);
         |                                         ~~~  ^
   fs/ntfs/debug.h:55:66: note: expanded from macro 'ntfs_error'
      55 | #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
         |                                                                         ^
   6 warnings and 4 errors generated.


vim +1081 fs/ntfs/inode.c

   497	
   498	/**
   499	 * ntfs_read_locked_inode - read an inode from its device
   500	 * @vi:		inode to read
   501	 *
   502	 * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
   503	 * described by @vi into memory from the device.
   504	 *
   505	 * The only fields in @vi that we need to/can look at when the function is
   506	 * called are i_sb, pointing to the mounted device's super block, and i_ino,
   507	 * the number of the inode to load.
   508	 *
   509	 * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
   510	 * for reading and sets up the necessary @vi fields as well as initializing
   511	 * the ntfs inode.
   512	 *
   513	 * Q: What locks are held when the function is called?
   514	 * A: i_state has I_NEW set, hence the inode is locked, also
   515	 *    i_count is set to 1, so it is not going to go away
   516	 *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
   517	 *    is allowed to write to them. We should of course be honouring them but
   518	 *    we need to do that using the IS_* macros defined in include/linux/fs.h.
   519	 *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
   520	 *
   521	 * Return 0 on success and -errno on error.  In the error case, the inode will
   522	 * have had make_bad_inode() executed on it.
   523	 */
   524	static int ntfs_read_locked_inode(struct inode *vi)
   525	{
   526		ntfs_volume *vol = NTFS_SB(vi->i_sb);
   527		ntfs_inode *ni;
   528		struct inode *bvi;
   529		MFT_RECORD *m;
   530		ATTR_RECORD *a;
   531		STANDARD_INFORMATION *si;
   532		ntfs_attr_search_ctx *ctx;
   533		int err = 0;
   534	
   535		ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
   536	
   537		/* Setup the generic vfs inode parts now. */
   538		vi->i_uid = vol->uid;
   539		vi->i_gid = vol->gid;
   540		vi->i_mode = 0;
   541	
   542		/*
   543		 * Initialize the ntfs specific part of @vi special casing
   544		 * FILE_MFT which we need to do at mount time.
   545		 */
   546		if (vi->i_ino != FILE_MFT)
   547			ntfs_init_big_inode(vi);
   548		ni = NTFS_I(vi);
   549	
   550		m = map_mft_record(ni);
   551		if (IS_ERR(m)) {
   552			err = PTR_ERR(m);
   553			goto err_out;
   554		}
   555		ctx = ntfs_attr_get_search_ctx(ni, m);
   556		if (!ctx) {
   557			err = -ENOMEM;
   558			goto unm_err_out;
   559		}
   560	
   561		if (!(m->flags & MFT_RECORD_IN_USE)) {
   562			ntfs_error(vi->i_sb, "Inode is not in use!");
   563			goto unm_err_out;
   564		}
   565		if (m->base_mft_record) {
   566			ntfs_error(vi->i_sb, "Inode is an extent inode!");
   567			goto unm_err_out;
   568		}
   569	
   570		/* Transfer information from mft record into vfs and ntfs inodes. */
   571		vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
   572	
   573		/*
   574		 * FIXME: Keep in mind that link_count is two for files which have both
   575		 * a long file name and a short file name as separate entries, so if
   576		 * we are hiding short file names this will be too high. Either we need
   577		 * to account for the short file names by subtracting them or we need
   578		 * to make sure we delete files even though i_nlink is not zero which
   579		 * might be tricky due to vfs interactions. Need to think about this
   580		 * some more when implementing the unlink command.
   581		 */
   582		set_nlink(vi, le16_to_cpu(m->link_count));
   583		/*
   584		 * FIXME: Reparse points can have the directory bit set even though
   585		 * they would be S_IFLNK. Need to deal with this further below when we
   586		 * implement reparse points / symbolic links but it will do for now.
   587		 * Also if not a directory, it could be something else, rather than
   588		 * a regular file. But again, will do for now.
   589		 */
   590		/* Everyone gets all permissions. */
   591		vi->i_mode |= S_IRWXUGO;
   592		/* If read-only, no one gets write permissions. */
   593		if (IS_RDONLY(vi))
   594			vi->i_mode &= ~S_IWUGO;
   595		if (m->flags & MFT_RECORD_IS_DIRECTORY) {
   596			vi->i_mode |= S_IFDIR;
   597			/*
   598			 * Apply the directory permissions mask set in the mount
   599			 * options.
   600			 */
   601			vi->i_mode &= ~vol->dmask;
   602			/* Things break without this kludge! */
   603			if (vi->i_nlink > 1)
   604				set_nlink(vi, 1);
   605		} else {
   606			vi->i_mode |= S_IFREG;
   607			/* Apply the file permissions mask set in the mount options. */
   608			vi->i_mode &= ~vol->fmask;
   609		}
   610		/*
   611		 * Find the standard information attribute in the mft record. At this
   612		 * stage we haven't setup the attribute list stuff yet, so this could
   613		 * in fact fail if the standard information is in an extent record, but
   614		 * I don't think this actually ever happens.
   615		 */
   616		err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
   617				ctx);
   618		if (unlikely(err)) {
   619			if (err == -ENOENT) {
   620				/*
   621				 * TODO: We should be performing a hot fix here (if the
   622				 * recover mount option is set) by creating a new
   623				 * attribute.
   624				 */
   625				ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
   626						"is missing.");
   627			}
   628			goto unm_err_out;
   629		}
   630		a = ctx->attr;
   631		/* Get the standard information attribute value. */
   632		if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
   633				+ le32_to_cpu(a->data.resident.value_length) >
   634				(u8 *)ctx->mrec + vol->mft_record_size) {
   635			ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
   636			goto unm_err_out;
   637		}
   638		si = (STANDARD_INFORMATION*)((u8*)a +
   639				le16_to_cpu(a->data.resident.value_offset));
   640	
   641		/* Transfer information from the standard information into vi. */
   642		/*
   643		 * Note: The i_?times do not quite map perfectly onto the NTFS times,
   644		 * but they are close enough, and in the end it doesn't really matter
   645		 * that much...
   646		 */
   647		/*
   648		 * mtime is the last change of the data within the file. Not changed
   649		 * when only metadata is changed, e.g. a rename doesn't affect mtime.
   650		 */
   651		vi->i_mtime = ntfs2utc(si->last_data_change_time);
   652		/*
   653		 * ctime is the last change of the metadata of the file. This obviously
   654		 * always changes, when mtime is changed. ctime can be changed on its
   655		 * own, mtime is then not changed, e.g. when a file is renamed.
   656		 */
   657		vi->i_ctime = ntfs2utc(si->last_mft_change_time);
   658		/*
   659		 * Last access to the data within the file. Not changed during a rename
   660		 * for example but changed whenever the file is written to.
   661		 */
   662		vi->i_atime = ntfs2utc(si->last_access_time);
   663	
   664		/* Find the attribute list attribute if present. */
   665		ntfs_attr_reinit_search_ctx(ctx);
   666		err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
   667		if (err) {
   668			if (unlikely(err != -ENOENT)) {
   669				ntfs_error(vi->i_sb, "Failed to lookup attribute list "
   670						"attribute.");
   671				goto unm_err_out;
   672			}
   673		} else /* if (!err) */ {
   674			if (vi->i_ino == FILE_MFT)
   675				goto skip_attr_list_load;
   676			ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
   677			NInoSetAttrList(ni);
   678			a = ctx->attr;
   679			if (a->flags & ATTR_COMPRESSION_MASK) {
   680				ntfs_error(vi->i_sb, "Attribute list attribute is "
   681						"compressed.");
   682				goto unm_err_out;
   683			}
   684			if (a->flags & ATTR_IS_ENCRYPTED ||
   685					a->flags & ATTR_IS_SPARSE) {
   686				if (a->non_resident) {
   687					ntfs_error(vi->i_sb, "Non-resident attribute "
   688							"list attribute is encrypted/"
   689							"sparse.");
   690					goto unm_err_out;
   691				}
   692				ntfs_warning(vi->i_sb, "Resident attribute list "
   693						"attribute in inode 0x%lx is marked "
   694						"encrypted/sparse which is not true.  "
   695						"However, Windows allows this and "
   696						"chkdsk does not detect or correct it "
   697						"so we will just ignore the invalid "
   698						"flags and pretend they are not set.",
   699						vi->i_ino);
   700			}
   701			/* Now allocate memory for the attribute list. */
   702			ni->attr_list_size = (u32)ntfs_attr_size(a);
   703			ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
   704			if (!ni->attr_list) {
   705				ntfs_error(vi->i_sb, "Not enough memory to allocate "
   706						"buffer for attribute list.");
   707				err = -ENOMEM;
   708				goto unm_err_out;
   709			}
   710			if (a->non_resident) {
   711				NInoSetAttrListNonResident(ni);
   712				if (a->data.non_resident.lowest_vcn) {
   713					ntfs_error(vi->i_sb, "Attribute list has non "
   714							"zero lowest_vcn.");
   715					goto unm_err_out;
   716				}
   717				/*
   718				 * Setup the runlist. No need for locking as we have
   719				 * exclusive access to the inode at this time.
   720				 */
   721				ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
   722						a, NULL);
   723				if (IS_ERR(ni->attr_list_rl.rl)) {
   724					err = PTR_ERR(ni->attr_list_rl.rl);
   725					ni->attr_list_rl.rl = NULL;
   726					ntfs_error(vi->i_sb, "Mapping pairs "
   727							"decompression failed.");
   728					goto unm_err_out;
   729				}
   730				/* Now load the attribute list. */
   731				if ((err = load_attribute_list(vol, &ni->attr_list_rl,
   732						ni->attr_list, ni->attr_list_size,
   733						sle64_to_cpu(a->data.non_resident.
   734						initialized_size)))) {
   735					ntfs_error(vi->i_sb, "Failed to load "
   736							"attribute list attribute.");
   737					goto unm_err_out;
   738				}
   739			} else /* if (!a->non_resident) */ {
   740				if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
   741						+ le32_to_cpu(
   742						a->data.resident.value_length) >
   743						(u8*)ctx->mrec + vol->mft_record_size) {
   744					ntfs_error(vi->i_sb, "Corrupt attribute list "
   745							"in inode.");
   746					goto unm_err_out;
   747				}
   748				/* Now copy the attribute list. */
   749				memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
   750						a->data.resident.value_offset),
   751						le32_to_cpu(
   752						a->data.resident.value_length));
   753			}
   754		}
   755	skip_attr_list_load:
   756		/*
   757		 * If an attribute list is present we now have the attribute list value
   758		 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
   759		 */
   760		if (S_ISDIR(vi->i_mode)) {
   761			loff_t bvi_size;
   762			ntfs_inode *bni;
   763			INDEX_ROOT *ir;
   764			u8 *ir_end, *index_end;
   765	
   766			/* It is a directory, find index root attribute. */
   767			ntfs_attr_reinit_search_ctx(ctx);
   768			err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
   769					0, NULL, 0, ctx);
   770			if (unlikely(err)) {
   771				if (err == -ENOENT) {
   772					// FIXME: File is corrupt! Hot-fix with empty
   773					// index root attribute if recovery option is
   774					// set.
   775					ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
   776							"is missing.");
   777				}
   778				goto unm_err_out;
   779			}
   780			a = ctx->attr;
   781			/* Set up the state. */
   782			if (unlikely(a->non_resident)) {
   783				ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
   784						"resident.");
   785				goto unm_err_out;
   786			}
   787			/* Ensure the attribute name is placed before the value. */
   788			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   789					le16_to_cpu(a->data.resident.value_offset)))) {
   790				ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
   791						"placed after the attribute value.");
   792				goto unm_err_out;
   793			}
   794			/*
   795			 * Compressed/encrypted index root just means that the newly
   796			 * created files in that directory should be created compressed/
   797			 * encrypted. However index root cannot be both compressed and
   798			 * encrypted.
   799			 */
   800			if (a->flags & ATTR_COMPRESSION_MASK)
   801				NInoSetCompressed(ni);
   802			if (a->flags & ATTR_IS_ENCRYPTED) {
   803				if (a->flags & ATTR_COMPRESSION_MASK) {
   804					ntfs_error(vi->i_sb, "Found encrypted and "
   805							"compressed attribute.");
   806					goto unm_err_out;
   807				}
   808				NInoSetEncrypted(ni);
   809			}
   810			if (a->flags & ATTR_IS_SPARSE)
   811				NInoSetSparse(ni);
   812			ir = (INDEX_ROOT*)((u8*)a +
   813					le16_to_cpu(a->data.resident.value_offset));
   814			ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
   815			if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
   816				ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
   817						"corrupt.");
   818				goto unm_err_out;
   819			}
   820			index_end = (u8*)&ir->index +
   821					le32_to_cpu(ir->index.index_length);
   822			if (index_end > ir_end) {
   823				ntfs_error(vi->i_sb, "Directory index is corrupt.");
   824				goto unm_err_out;
   825			}
   826			if (ir->type != AT_FILE_NAME) {
   827				ntfs_error(vi->i_sb, "Indexed attribute is not "
   828						"$FILE_NAME.");
   829				goto unm_err_out;
   830			}
   831			if (ir->collation_rule != COLLATION_FILE_NAME) {
   832				ntfs_error(vi->i_sb, "Index collation rule is not "
   833						"COLLATION_FILE_NAME.");
   834				goto unm_err_out;
   835			}
   836			ni->itype.index.collation_rule = ir->collation_rule;
   837			ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
   838			if (ni->itype.index.block_size &
   839					(ni->itype.index.block_size - 1)) {
   840				ntfs_error(vi->i_sb, "Index block size (%u) is not a "
   841						"power of two.",
   842						ni->itype.index.block_size);
   843				goto unm_err_out;
   844			}
   845			if (ni->itype.index.block_size > PAGE_SIZE) {
   846				ntfs_error(vi->i_sb, "Index block size (%u) > "
   847						"PAGE_SIZE (%ld) is not "
   848						"supported.  Sorry.",
   849						ni->itype.index.block_size,
   850						PAGE_SIZE);
   851				err = -EOPNOTSUPP;
   852				goto unm_err_out;
   853			}
   854			if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
   855				ntfs_error(vi->i_sb, "Index block size (%u) < "
   856						"NTFS_BLOCK_SIZE (%i) is not "
   857						"supported.  Sorry.",
   858						ni->itype.index.block_size,
   859						NTFS_BLOCK_SIZE);
   860				err = -EOPNOTSUPP;
   861				goto unm_err_out;
   862			}
   863			ni->itype.index.block_size_bits =
   864					ffs(ni->itype.index.block_size) - 1;
   865			/* Determine the size of a vcn in the directory index. */
   866			if (vol->cluster_size <= ni->itype.index.block_size) {
   867				ni->itype.index.vcn_size = vol->cluster_size;
   868				ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
   869			} else {
   870				ni->itype.index.vcn_size = vol->sector_size;
   871				ni->itype.index.vcn_size_bits = vol->sector_size_bits;
   872			}
   873	
   874			/* Setup the index allocation attribute, even if not present. */
   875			NInoSetMstProtected(ni);
   876			ni->type = AT_INDEX_ALLOCATION;
   877			ni->name = I30;
   878			ni->name_len = 4;
   879	
   880			if (!(ir->index.flags & LARGE_INDEX)) {
   881				/* No index allocation. */
   882				vi->i_size = ni->initialized_size =
   883						ni->allocated_size = 0;
   884				/* We are done with the mft record, so we release it. */
   885				ntfs_attr_put_search_ctx(ctx);
   886				unmap_mft_record(ni);
   887				m = NULL;
   888				ctx = NULL;
   889				goto skip_large_dir_stuff;
   890			} /* LARGE_INDEX: Index allocation present. Setup state. */
   891			NInoSetIndexAllocPresent(ni);
   892			/* Find index allocation attribute. */
   893			ntfs_attr_reinit_search_ctx(ctx);
   894			err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
   895					CASE_SENSITIVE, 0, NULL, 0, ctx);
   896			if (unlikely(err)) {
   897				if (err == -ENOENT)
   898					ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
   899							"attribute is not present but "
   900							"$INDEX_ROOT indicated it is.");
   901				else
   902					ntfs_error(vi->i_sb, "Failed to lookup "
   903							"$INDEX_ALLOCATION "
   904							"attribute.");
   905				goto unm_err_out;
   906			}
   907			a = ctx->attr;
   908			if (!a->non_resident) {
   909				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   910						"is resident.");
   911				goto unm_err_out;
   912			}
   913			/*
   914			 * Ensure the attribute name is placed before the mapping pairs
   915			 * array.
   916			 */
   917			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   918					le16_to_cpu(
   919					a->data.non_resident.mapping_pairs_offset)))) {
   920				ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
   921						"is placed after the mapping pairs "
   922						"array.");
   923				goto unm_err_out;
   924			}
   925			if (a->flags & ATTR_IS_ENCRYPTED) {
   926				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   927						"is encrypted.");
   928				goto unm_err_out;
   929			}
   930			if (a->flags & ATTR_IS_SPARSE) {
   931				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   932						"is sparse.");
   933				goto unm_err_out;
   934			}
   935			if (a->flags & ATTR_COMPRESSION_MASK) {
   936				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   937						"is compressed.");
   938				goto unm_err_out;
   939			}
   940			if (a->data.non_resident.lowest_vcn) {
   941				ntfs_error(vi->i_sb, "First extent of "
   942						"$INDEX_ALLOCATION attribute has non "
   943						"zero lowest_vcn.");
   944				goto unm_err_out;
   945			}
   946			vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
   947			ni->initialized_size = sle64_to_cpu(
   948					a->data.non_resident.initialized_size);
   949			ni->allocated_size = sle64_to_cpu(
   950					a->data.non_resident.allocated_size);
   951			/*
   952			 * We are done with the mft record, so we release it. Otherwise
   953			 * we would deadlock in ntfs_attr_iget().
   954			 */
   955			ntfs_attr_put_search_ctx(ctx);
   956			unmap_mft_record(ni);
   957			m = NULL;
   958			ctx = NULL;
   959			/* Get the index bitmap attribute inode. */
   960			bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
   961			if (IS_ERR(bvi)) {
   962				ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
   963				err = PTR_ERR(bvi);
   964				goto unm_err_out;
   965			}
   966			bni = NTFS_I(bvi);
   967			if (NInoCompressed(bni) || NInoEncrypted(bni) ||
   968					NInoSparse(bni)) {
   969				ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
   970						"and/or encrypted and/or sparse.");
   971				goto iput_unm_err_out;
   972			}
   973			/* Consistency check bitmap size vs. index allocation size. */
   974			bvi_size = i_size_read(bvi);
   975			if ((bvi_size << 3) < (vi->i_size >>
   976					ni->itype.index.block_size_bits)) {
   977				ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
   978						"for index allocation (0x%llx).",
   979						bvi_size << 3, vi->i_size);
   980				goto iput_unm_err_out;
   981			}
   982			/* No longer need the bitmap attribute inode. */
   983			iput(bvi);
   984	skip_large_dir_stuff:
   985			/* Setup the operations for this inode. */
   986			vi->i_op = &ntfs_dir_inode_ops;
   987			vi->i_fop = &ntfs_dir_ops;
   988			vi->i_mapping->a_ops = &ntfs_mst_aops;
   989		} else {
   990			/* It is a file. */
   991			ntfs_attr_reinit_search_ctx(ctx);
   992	
   993			/* Setup the data attribute, even if not present. */
   994			ni->type = AT_DATA;
   995			ni->name = NULL;
   996			ni->name_len = 0;
   997	
   998			/* Find first extent of the unnamed data attribute. */
   999			err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
  1000			if (unlikely(err)) {
  1001				vi->i_size = ni->initialized_size =
  1002						ni->allocated_size = 0;
  1003				if (err != -ENOENT) {
  1004					ntfs_error(vi->i_sb, "Failed to lookup $DATA "
  1005							"attribute.");
  1006					goto unm_err_out;
  1007				}
  1008				/*
  1009				 * FILE_Secure does not have an unnamed $DATA
  1010				 * attribute, so we special case it here.
  1011				 */
  1012				if (vi->i_ino == FILE_Secure)
  1013					goto no_data_attr_special_case;
  1014				/*
  1015				 * Most if not all the system files in the $Extend
  1016				 * system directory do not have unnamed data
  1017				 * attributes so we need to check if the parent
  1018				 * directory of the file is FILE_Extend and if it is
  1019				 * ignore this error. To do this we need to get the
  1020				 * name of this inode from the mft record as the name
  1021				 * contains the back reference to the parent directory.
  1022				 */
  1023				if (ntfs_is_extended_system_file(ctx) > 0)
  1024					goto no_data_attr_special_case;
  1025				// FIXME: File is corrupt! Hot-fix with empty data
  1026				// attribute if recovery option is set.
  1027				ntfs_error(vi->i_sb, "$DATA attribute is missing.");
  1028				goto unm_err_out;
  1029			}
  1030			a = ctx->attr;
  1031			/* Setup the state. */
  1032			if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
  1033				if (a->flags & ATTR_COMPRESSION_MASK) {
  1034					NInoSetCompressed(ni);
  1035					if (vol->cluster_size > 4096) {
  1036						ntfs_error(vi->i_sb, "Found "
  1037								"compressed data but "
  1038								"compression is "
  1039								"disabled due to "
  1040								"cluster size (%i) > "
  1041								"4kiB.",
  1042								vol->cluster_size);
  1043						goto unm_err_out;
  1044					}
  1045					if ((a->flags & ATTR_COMPRESSION_MASK)
  1046							!= ATTR_IS_COMPRESSED) {
  1047						ntfs_error(vi->i_sb, "Found unknown "
  1048								"compression method "
  1049								"or corrupt file.");
  1050						goto unm_err_out;
  1051					}
  1052				}
  1053				if (a->flags & ATTR_IS_SPARSE)
  1054					NInoSetSparse(ni);
  1055			}
  1056			if (a->flags & ATTR_IS_ENCRYPTED) {
  1057				if (NInoCompressed(ni)) {
  1058					ntfs_error(vi->i_sb, "Found encrypted and "
  1059							"compressed data.");
  1060					goto unm_err_out;
  1061				}
  1062				NInoSetEncrypted(ni);
  1063			}
  1064			if (a->non_resident) {
  1065				NInoSetNonResident(ni);
  1066				if (NInoCompressed(ni) || NInoSparse(ni)) {
  1067					if (NInoCompressed(ni) && a->data.non_resident.
  1068							compression_unit != 4) {
  1069						ntfs_error(vi->i_sb, "Found "
  1070								"non-standard "
  1071								"compression unit (%u "
  1072								"instead of 4).  "
  1073								"Cannot handle this.",
  1074								a->data.non_resident.
  1075								compression_unit);
  1076						err = -EOPNOTSUPP;
  1077						goto unm_err_out;
  1078					}
  1079					if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
  1080					a->data.non_resident.compression_unit !=
> 1081					vol->sparse_compression_unit) {
  1082						ntfs_error(vi->i_sb,
  1083						"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
  1084						a->data.non_resident.compression_unit,
  1085						vol->sparse_compression_unit);
  1086						err = -EOPNOTSUPP;
  1087						goto unm_err_out;
  1088					}
  1089					if (a->data.non_resident.compression_unit) {
  1090						ni->itype.compressed.block_size = 1U <<
  1091								(a->data.non_resident.
  1092								compression_unit +
  1093								vol->cluster_size_bits);
  1094						ni->itype.compressed.block_size_bits =
  1095								ffs(ni->itype.
  1096								compressed.
  1097								block_size) - 1;
  1098						ni->itype.compressed.block_clusters =
  1099								1U << a->data.
  1100								non_resident.
  1101								compression_unit;
  1102					} else {
  1103						ni->itype.compressed.block_size = 0;
  1104						ni->itype.compressed.block_size_bits =
  1105								0;
  1106						ni->itype.compressed.block_clusters =
  1107								0;
  1108					}
  1109					ni->itype.compressed.size = sle64_to_cpu(
  1110							a->data.non_resident.
  1111							compressed_size);
  1112				}
  1113				if (a->data.non_resident.lowest_vcn) {
  1114					ntfs_error(vi->i_sb, "First extent of $DATA "
  1115							"attribute has non zero "
  1116							"lowest_vcn.");
  1117					goto unm_err_out;
  1118				}
  1119				vi->i_size = sle64_to_cpu(
  1120						a->data.non_resident.data_size);
  1121				ni->initialized_size = sle64_to_cpu(
  1122						a->data.non_resident.initialized_size);
  1123				ni->allocated_size = sle64_to_cpu(
  1124						a->data.non_resident.allocated_size);
  1125			} else { /* Resident attribute. */
  1126				vi->i_size = ni->initialized_size = le32_to_cpu(
  1127						a->data.resident.value_length);
  1128				ni->allocated_size = le32_to_cpu(a->length) -
  1129						le16_to_cpu(
  1130						a->data.resident.value_offset);
  1131				if (vi->i_size > ni->allocated_size) {
  1132					ntfs_error(vi->i_sb, "Resident data attribute "
  1133							"is corrupt (size exceeds "
  1134							"allocation).");
  1135					goto unm_err_out;
  1136				}
  1137			}
  1138	no_data_attr_special_case:
  1139			/* We are done with the mft record, so we release it. */
  1140			ntfs_attr_put_search_ctx(ctx);
  1141			unmap_mft_record(ni);
  1142			m = NULL;
  1143			ctx = NULL;
  1144			/* Setup the operations for this inode. */
  1145			vi->i_op = &ntfs_file_inode_ops;
  1146			vi->i_fop = &ntfs_file_ops;
  1147			vi->i_mapping->a_ops = &ntfs_normal_aops;
  1148			if (NInoMstProtected(ni))
  1149				vi->i_mapping->a_ops = &ntfs_mst_aops;
  1150			else if (NInoCompressed(ni))
  1151				vi->i_mapping->a_ops = &ntfs_compressed_aops;
  1152		}
  1153		/*
  1154		 * The number of 512-byte blocks used on disk (for stat). This is in so
  1155		 * far inaccurate as it doesn't account for any named streams or other
  1156		 * special non-resident attributes, but that is how Windows works, too,
  1157		 * so we are at least consistent with Windows, if not entirely
  1158		 * consistent with the Linux Way. Doing it the Linux Way would cause a
  1159		 * significant slowdown as it would involve iterating over all
  1160		 * attributes in the mft record and adding the allocated/compressed
  1161		 * sizes of all non-resident attributes present to give us the Linux
  1162		 * correct size that should go into i_blocks (after division by 512).
  1163		 */
  1164		if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
  1165			vi->i_blocks = ni->itype.compressed.size >> 9;
  1166		else
  1167			vi->i_blocks = ni->allocated_size >> 9;
  1168		ntfs_debug("Done.");
  1169		return 0;
  1170	iput_unm_err_out:
  1171		iput(bvi);
  1172	unm_err_out:
  1173		if (!err)
  1174			err = -EIO;
  1175		if (ctx)
  1176			ntfs_attr_put_search_ctx(ctx);
  1177		if (m)
  1178			unmap_mft_record(ni);
  1179	err_out:
  1180		ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
  1181				"inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
  1182		make_bad_inode(vi);
  1183		if (err != -EOPNOTSUPP && err != -ENOMEM)
  1184			NVolSetErrors(vol);
  1185		return err;
  1186	}
  1187	

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

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

* Re: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-15  8:52         ` kernel test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2023-08-15  8:52 UTC (permalink / raw)
  To: Manas Ghandat, anton, linkinjeon
  Cc: Manas Ghandat, linux-ntfs-dev, llvm, linux-kernel,
	syzbot+4768a8f039aa677897d0, oe-kbuild-all, linux-fsdevel,
	Linux-kernel-mentees

Hi Manas,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.5-rc6 next-20230809]
[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/Manas-Ghandat/ntfs-fix-shift-out-of-bounds-in-ntfs_iget/20230815-132656
base:   linus/master
patch link:    https://lore.kernel.org/r/20230815052251.107732-1-ghandatmanas%40gmail.com
patch subject: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
config: i386-randconfig-i002-20230815 (https://download.01.org/0day-ci/archive/20230815/202308151606.3Xy20wzx-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce: (https://download.01.org/0day-ci/archive/20230815/202308151606.3Xy20wzx-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/202308151606.3Xy20wzx-lkp@intel.com/

All errors (new ones prefixed by >>):

>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
                                   vol->sparse_compression_unit) {
                                   ~~~  ^
   fs/ntfs/inode.c:1085:11: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
                                           vol->sparse_compression_unit);
                                           ~~~  ^
   fs/ntfs/debug.h:55:66: note: expanded from macro 'ntfs_error'
   #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
                                                                           ^
   2 errors generated.


vim +1081 fs/ntfs/inode.c

   497	
   498	/**
   499	 * ntfs_read_locked_inode - read an inode from its device
   500	 * @vi:		inode to read
   501	 *
   502	 * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
   503	 * described by @vi into memory from the device.
   504	 *
   505	 * The only fields in @vi that we need to/can look at when the function is
   506	 * called are i_sb, pointing to the mounted device's super block, and i_ino,
   507	 * the number of the inode to load.
   508	 *
   509	 * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
   510	 * for reading and sets up the necessary @vi fields as well as initializing
   511	 * the ntfs inode.
   512	 *
   513	 * Q: What locks are held when the function is called?
   514	 * A: i_state has I_NEW set, hence the inode is locked, also
   515	 *    i_count is set to 1, so it is not going to go away
   516	 *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
   517	 *    is allowed to write to them. We should of course be honouring them but
   518	 *    we need to do that using the IS_* macros defined in include/linux/fs.h.
   519	 *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
   520	 *
   521	 * Return 0 on success and -errno on error.  In the error case, the inode will
   522	 * have had make_bad_inode() executed on it.
   523	 */
   524	static int ntfs_read_locked_inode(struct inode *vi)
   525	{
   526		ntfs_volume *vol = NTFS_SB(vi->i_sb);
   527		ntfs_inode *ni;
   528		struct inode *bvi;
   529		MFT_RECORD *m;
   530		ATTR_RECORD *a;
   531		STANDARD_INFORMATION *si;
   532		ntfs_attr_search_ctx *ctx;
   533		int err = 0;
   534	
   535		ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
   536	
   537		/* Setup the generic vfs inode parts now. */
   538		vi->i_uid = vol->uid;
   539		vi->i_gid = vol->gid;
   540		vi->i_mode = 0;
   541	
   542		/*
   543		 * Initialize the ntfs specific part of @vi special casing
   544		 * FILE_MFT which we need to do at mount time.
   545		 */
   546		if (vi->i_ino != FILE_MFT)
   547			ntfs_init_big_inode(vi);
   548		ni = NTFS_I(vi);
   549	
   550		m = map_mft_record(ni);
   551		if (IS_ERR(m)) {
   552			err = PTR_ERR(m);
   553			goto err_out;
   554		}
   555		ctx = ntfs_attr_get_search_ctx(ni, m);
   556		if (!ctx) {
   557			err = -ENOMEM;
   558			goto unm_err_out;
   559		}
   560	
   561		if (!(m->flags & MFT_RECORD_IN_USE)) {
   562			ntfs_error(vi->i_sb, "Inode is not in use!");
   563			goto unm_err_out;
   564		}
   565		if (m->base_mft_record) {
   566			ntfs_error(vi->i_sb, "Inode is an extent inode!");
   567			goto unm_err_out;
   568		}
   569	
   570		/* Transfer information from mft record into vfs and ntfs inodes. */
   571		vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
   572	
   573		/*
   574		 * FIXME: Keep in mind that link_count is two for files which have both
   575		 * a long file name and a short file name as separate entries, so if
   576		 * we are hiding short file names this will be too high. Either we need
   577		 * to account for the short file names by subtracting them or we need
   578		 * to make sure we delete files even though i_nlink is not zero which
   579		 * might be tricky due to vfs interactions. Need to think about this
   580		 * some more when implementing the unlink command.
   581		 */
   582		set_nlink(vi, le16_to_cpu(m->link_count));
   583		/*
   584		 * FIXME: Reparse points can have the directory bit set even though
   585		 * they would be S_IFLNK. Need to deal with this further below when we
   586		 * implement reparse points / symbolic links but it will do for now.
   587		 * Also if not a directory, it could be something else, rather than
   588		 * a regular file. But again, will do for now.
   589		 */
   590		/* Everyone gets all permissions. */
   591		vi->i_mode |= S_IRWXUGO;
   592		/* If read-only, no one gets write permissions. */
   593		if (IS_RDONLY(vi))
   594			vi->i_mode &= ~S_IWUGO;
   595		if (m->flags & MFT_RECORD_IS_DIRECTORY) {
   596			vi->i_mode |= S_IFDIR;
   597			/*
   598			 * Apply the directory permissions mask set in the mount
   599			 * options.
   600			 */
   601			vi->i_mode &= ~vol->dmask;
   602			/* Things break without this kludge! */
   603			if (vi->i_nlink > 1)
   604				set_nlink(vi, 1);
   605		} else {
   606			vi->i_mode |= S_IFREG;
   607			/* Apply the file permissions mask set in the mount options. */
   608			vi->i_mode &= ~vol->fmask;
   609		}
   610		/*
   611		 * Find the standard information attribute in the mft record. At this
   612		 * stage we haven't setup the attribute list stuff yet, so this could
   613		 * in fact fail if the standard information is in an extent record, but
   614		 * I don't think this actually ever happens.
   615		 */
   616		err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
   617				ctx);
   618		if (unlikely(err)) {
   619			if (err == -ENOENT) {
   620				/*
   621				 * TODO: We should be performing a hot fix here (if the
   622				 * recover mount option is set) by creating a new
   623				 * attribute.
   624				 */
   625				ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
   626						"is missing.");
   627			}
   628			goto unm_err_out;
   629		}
   630		a = ctx->attr;
   631		/* Get the standard information attribute value. */
   632		if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
   633				+ le32_to_cpu(a->data.resident.value_length) >
   634				(u8 *)ctx->mrec + vol->mft_record_size) {
   635			ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
   636			goto unm_err_out;
   637		}
   638		si = (STANDARD_INFORMATION*)((u8*)a +
   639				le16_to_cpu(a->data.resident.value_offset));
   640	
   641		/* Transfer information from the standard information into vi. */
   642		/*
   643		 * Note: The i_?times do not quite map perfectly onto the NTFS times,
   644		 * but they are close enough, and in the end it doesn't really matter
   645		 * that much...
   646		 */
   647		/*
   648		 * mtime is the last change of the data within the file. Not changed
   649		 * when only metadata is changed, e.g. a rename doesn't affect mtime.
   650		 */
   651		vi->i_mtime = ntfs2utc(si->last_data_change_time);
   652		/*
   653		 * ctime is the last change of the metadata of the file. This obviously
   654		 * always changes, when mtime is changed. ctime can be changed on its
   655		 * own, mtime is then not changed, e.g. when a file is renamed.
   656		 */
   657		vi->i_ctime = ntfs2utc(si->last_mft_change_time);
   658		/*
   659		 * Last access to the data within the file. Not changed during a rename
   660		 * for example but changed whenever the file is written to.
   661		 */
   662		vi->i_atime = ntfs2utc(si->last_access_time);
   663	
   664		/* Find the attribute list attribute if present. */
   665		ntfs_attr_reinit_search_ctx(ctx);
   666		err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
   667		if (err) {
   668			if (unlikely(err != -ENOENT)) {
   669				ntfs_error(vi->i_sb, "Failed to lookup attribute list "
   670						"attribute.");
   671				goto unm_err_out;
   672			}
   673		} else /* if (!err) */ {
   674			if (vi->i_ino == FILE_MFT)
   675				goto skip_attr_list_load;
   676			ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
   677			NInoSetAttrList(ni);
   678			a = ctx->attr;
   679			if (a->flags & ATTR_COMPRESSION_MASK) {
   680				ntfs_error(vi->i_sb, "Attribute list attribute is "
   681						"compressed.");
   682				goto unm_err_out;
   683			}
   684			if (a->flags & ATTR_IS_ENCRYPTED ||
   685					a->flags & ATTR_IS_SPARSE) {
   686				if (a->non_resident) {
   687					ntfs_error(vi->i_sb, "Non-resident attribute "
   688							"list attribute is encrypted/"
   689							"sparse.");
   690					goto unm_err_out;
   691				}
   692				ntfs_warning(vi->i_sb, "Resident attribute list "
   693						"attribute in inode 0x%lx is marked "
   694						"encrypted/sparse which is not true.  "
   695						"However, Windows allows this and "
   696						"chkdsk does not detect or correct it "
   697						"so we will just ignore the invalid "
   698						"flags and pretend they are not set.",
   699						vi->i_ino);
   700			}
   701			/* Now allocate memory for the attribute list. */
   702			ni->attr_list_size = (u32)ntfs_attr_size(a);
   703			ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
   704			if (!ni->attr_list) {
   705				ntfs_error(vi->i_sb, "Not enough memory to allocate "
   706						"buffer for attribute list.");
   707				err = -ENOMEM;
   708				goto unm_err_out;
   709			}
   710			if (a->non_resident) {
   711				NInoSetAttrListNonResident(ni);
   712				if (a->data.non_resident.lowest_vcn) {
   713					ntfs_error(vi->i_sb, "Attribute list has non "
   714							"zero lowest_vcn.");
   715					goto unm_err_out;
   716				}
   717				/*
   718				 * Setup the runlist. No need for locking as we have
   719				 * exclusive access to the inode at this time.
   720				 */
   721				ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
   722						a, NULL);
   723				if (IS_ERR(ni->attr_list_rl.rl)) {
   724					err = PTR_ERR(ni->attr_list_rl.rl);
   725					ni->attr_list_rl.rl = NULL;
   726					ntfs_error(vi->i_sb, "Mapping pairs "
   727							"decompression failed.");
   728					goto unm_err_out;
   729				}
   730				/* Now load the attribute list. */
   731				if ((err = load_attribute_list(vol, &ni->attr_list_rl,
   732						ni->attr_list, ni->attr_list_size,
   733						sle64_to_cpu(a->data.non_resident.
   734						initialized_size)))) {
   735					ntfs_error(vi->i_sb, "Failed to load "
   736							"attribute list attribute.");
   737					goto unm_err_out;
   738				}
   739			} else /* if (!a->non_resident) */ {
   740				if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
   741						+ le32_to_cpu(
   742						a->data.resident.value_length) >
   743						(u8*)ctx->mrec + vol->mft_record_size) {
   744					ntfs_error(vi->i_sb, "Corrupt attribute list "
   745							"in inode.");
   746					goto unm_err_out;
   747				}
   748				/* Now copy the attribute list. */
   749				memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
   750						a->data.resident.value_offset),
   751						le32_to_cpu(
   752						a->data.resident.value_length));
   753			}
   754		}
   755	skip_attr_list_load:
   756		/*
   757		 * If an attribute list is present we now have the attribute list value
   758		 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
   759		 */
   760		if (S_ISDIR(vi->i_mode)) {
   761			loff_t bvi_size;
   762			ntfs_inode *bni;
   763			INDEX_ROOT *ir;
   764			u8 *ir_end, *index_end;
   765	
   766			/* It is a directory, find index root attribute. */
   767			ntfs_attr_reinit_search_ctx(ctx);
   768			err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
   769					0, NULL, 0, ctx);
   770			if (unlikely(err)) {
   771				if (err == -ENOENT) {
   772					// FIXME: File is corrupt! Hot-fix with empty
   773					// index root attribute if recovery option is
   774					// set.
   775					ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
   776							"is missing.");
   777				}
   778				goto unm_err_out;
   779			}
   780			a = ctx->attr;
   781			/* Set up the state. */
   782			if (unlikely(a->non_resident)) {
   783				ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
   784						"resident.");
   785				goto unm_err_out;
   786			}
   787			/* Ensure the attribute name is placed before the value. */
   788			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   789					le16_to_cpu(a->data.resident.value_offset)))) {
   790				ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
   791						"placed after the attribute value.");
   792				goto unm_err_out;
   793			}
   794			/*
   795			 * Compressed/encrypted index root just means that the newly
   796			 * created files in that directory should be created compressed/
   797			 * encrypted. However index root cannot be both compressed and
   798			 * encrypted.
   799			 */
   800			if (a->flags & ATTR_COMPRESSION_MASK)
   801				NInoSetCompressed(ni);
   802			if (a->flags & ATTR_IS_ENCRYPTED) {
   803				if (a->flags & ATTR_COMPRESSION_MASK) {
   804					ntfs_error(vi->i_sb, "Found encrypted and "
   805							"compressed attribute.");
   806					goto unm_err_out;
   807				}
   808				NInoSetEncrypted(ni);
   809			}
   810			if (a->flags & ATTR_IS_SPARSE)
   811				NInoSetSparse(ni);
   812			ir = (INDEX_ROOT*)((u8*)a +
   813					le16_to_cpu(a->data.resident.value_offset));
   814			ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
   815			if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
   816				ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
   817						"corrupt.");
   818				goto unm_err_out;
   819			}
   820			index_end = (u8*)&ir->index +
   821					le32_to_cpu(ir->index.index_length);
   822			if (index_end > ir_end) {
   823				ntfs_error(vi->i_sb, "Directory index is corrupt.");
   824				goto unm_err_out;
   825			}
   826			if (ir->type != AT_FILE_NAME) {
   827				ntfs_error(vi->i_sb, "Indexed attribute is not "
   828						"$FILE_NAME.");
   829				goto unm_err_out;
   830			}
   831			if (ir->collation_rule != COLLATION_FILE_NAME) {
   832				ntfs_error(vi->i_sb, "Index collation rule is not "
   833						"COLLATION_FILE_NAME.");
   834				goto unm_err_out;
   835			}
   836			ni->itype.index.collation_rule = ir->collation_rule;
   837			ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
   838			if (ni->itype.index.block_size &
   839					(ni->itype.index.block_size - 1)) {
   840				ntfs_error(vi->i_sb, "Index block size (%u) is not a "
   841						"power of two.",
   842						ni->itype.index.block_size);
   843				goto unm_err_out;
   844			}
   845			if (ni->itype.index.block_size > PAGE_SIZE) {
   846				ntfs_error(vi->i_sb, "Index block size (%u) > "
   847						"PAGE_SIZE (%ld) is not "
   848						"supported.  Sorry.",
   849						ni->itype.index.block_size,
   850						PAGE_SIZE);
   851				err = -EOPNOTSUPP;
   852				goto unm_err_out;
   853			}
   854			if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
   855				ntfs_error(vi->i_sb, "Index block size (%u) < "
   856						"NTFS_BLOCK_SIZE (%i) is not "
   857						"supported.  Sorry.",
   858						ni->itype.index.block_size,
   859						NTFS_BLOCK_SIZE);
   860				err = -EOPNOTSUPP;
   861				goto unm_err_out;
   862			}
   863			ni->itype.index.block_size_bits =
   864					ffs(ni->itype.index.block_size) - 1;
   865			/* Determine the size of a vcn in the directory index. */
   866			if (vol->cluster_size <= ni->itype.index.block_size) {
   867				ni->itype.index.vcn_size = vol->cluster_size;
   868				ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
   869			} else {
   870				ni->itype.index.vcn_size = vol->sector_size;
   871				ni->itype.index.vcn_size_bits = vol->sector_size_bits;
   872			}
   873	
   874			/* Setup the index allocation attribute, even if not present. */
   875			NInoSetMstProtected(ni);
   876			ni->type = AT_INDEX_ALLOCATION;
   877			ni->name = I30;
   878			ni->name_len = 4;
   879	
   880			if (!(ir->index.flags & LARGE_INDEX)) {
   881				/* No index allocation. */
   882				vi->i_size = ni->initialized_size =
   883						ni->allocated_size = 0;
   884				/* We are done with the mft record, so we release it. */
   885				ntfs_attr_put_search_ctx(ctx);
   886				unmap_mft_record(ni);
   887				m = NULL;
   888				ctx = NULL;
   889				goto skip_large_dir_stuff;
   890			} /* LARGE_INDEX: Index allocation present. Setup state. */
   891			NInoSetIndexAllocPresent(ni);
   892			/* Find index allocation attribute. */
   893			ntfs_attr_reinit_search_ctx(ctx);
   894			err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
   895					CASE_SENSITIVE, 0, NULL, 0, ctx);
   896			if (unlikely(err)) {
   897				if (err == -ENOENT)
   898					ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
   899							"attribute is not present but "
   900							"$INDEX_ROOT indicated it is.");
   901				else
   902					ntfs_error(vi->i_sb, "Failed to lookup "
   903							"$INDEX_ALLOCATION "
   904							"attribute.");
   905				goto unm_err_out;
   906			}
   907			a = ctx->attr;
   908			if (!a->non_resident) {
   909				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   910						"is resident.");
   911				goto unm_err_out;
   912			}
   913			/*
   914			 * Ensure the attribute name is placed before the mapping pairs
   915			 * array.
   916			 */
   917			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   918					le16_to_cpu(
   919					a->data.non_resident.mapping_pairs_offset)))) {
   920				ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
   921						"is placed after the mapping pairs "
   922						"array.");
   923				goto unm_err_out;
   924			}
   925			if (a->flags & ATTR_IS_ENCRYPTED) {
   926				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   927						"is encrypted.");
   928				goto unm_err_out;
   929			}
   930			if (a->flags & ATTR_IS_SPARSE) {
   931				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   932						"is sparse.");
   933				goto unm_err_out;
   934			}
   935			if (a->flags & ATTR_COMPRESSION_MASK) {
   936				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   937						"is compressed.");
   938				goto unm_err_out;
   939			}
   940			if (a->data.non_resident.lowest_vcn) {
   941				ntfs_error(vi->i_sb, "First extent of "
   942						"$INDEX_ALLOCATION attribute has non "
   943						"zero lowest_vcn.");
   944				goto unm_err_out;
   945			}
   946			vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
   947			ni->initialized_size = sle64_to_cpu(
   948					a->data.non_resident.initialized_size);
   949			ni->allocated_size = sle64_to_cpu(
   950					a->data.non_resident.allocated_size);
   951			/*
   952			 * We are done with the mft record, so we release it. Otherwise
   953			 * we would deadlock in ntfs_attr_iget().
   954			 */
   955			ntfs_attr_put_search_ctx(ctx);
   956			unmap_mft_record(ni);
   957			m = NULL;
   958			ctx = NULL;
   959			/* Get the index bitmap attribute inode. */
   960			bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
   961			if (IS_ERR(bvi)) {
   962				ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
   963				err = PTR_ERR(bvi);
   964				goto unm_err_out;
   965			}
   966			bni = NTFS_I(bvi);
   967			if (NInoCompressed(bni) || NInoEncrypted(bni) ||
   968					NInoSparse(bni)) {
   969				ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
   970						"and/or encrypted and/or sparse.");
   971				goto iput_unm_err_out;
   972			}
   973			/* Consistency check bitmap size vs. index allocation size. */
   974			bvi_size = i_size_read(bvi);
   975			if ((bvi_size << 3) < (vi->i_size >>
   976					ni->itype.index.block_size_bits)) {
   977				ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
   978						"for index allocation (0x%llx).",
   979						bvi_size << 3, vi->i_size);
   980				goto iput_unm_err_out;
   981			}
   982			/* No longer need the bitmap attribute inode. */
   983			iput(bvi);
   984	skip_large_dir_stuff:
   985			/* Setup the operations for this inode. */
   986			vi->i_op = &ntfs_dir_inode_ops;
   987			vi->i_fop = &ntfs_dir_ops;
   988			vi->i_mapping->a_ops = &ntfs_mst_aops;
   989		} else {
   990			/* It is a file. */
   991			ntfs_attr_reinit_search_ctx(ctx);
   992	
   993			/* Setup the data attribute, even if not present. */
   994			ni->type = AT_DATA;
   995			ni->name = NULL;
   996			ni->name_len = 0;
   997	
   998			/* Find first extent of the unnamed data attribute. */
   999			err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
  1000			if (unlikely(err)) {
  1001				vi->i_size = ni->initialized_size =
  1002						ni->allocated_size = 0;
  1003				if (err != -ENOENT) {
  1004					ntfs_error(vi->i_sb, "Failed to lookup $DATA "
  1005							"attribute.");
  1006					goto unm_err_out;
  1007				}
  1008				/*
  1009				 * FILE_Secure does not have an unnamed $DATA
  1010				 * attribute, so we special case it here.
  1011				 */
  1012				if (vi->i_ino == FILE_Secure)
  1013					goto no_data_attr_special_case;
  1014				/*
  1015				 * Most if not all the system files in the $Extend
  1016				 * system directory do not have unnamed data
  1017				 * attributes so we need to check if the parent
  1018				 * directory of the file is FILE_Extend and if it is
  1019				 * ignore this error. To do this we need to get the
  1020				 * name of this inode from the mft record as the name
  1021				 * contains the back reference to the parent directory.
  1022				 */
  1023				if (ntfs_is_extended_system_file(ctx) > 0)
  1024					goto no_data_attr_special_case;
  1025				// FIXME: File is corrupt! Hot-fix with empty data
  1026				// attribute if recovery option is set.
  1027				ntfs_error(vi->i_sb, "$DATA attribute is missing.");
  1028				goto unm_err_out;
  1029			}
  1030			a = ctx->attr;
  1031			/* Setup the state. */
  1032			if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
  1033				if (a->flags & ATTR_COMPRESSION_MASK) {
  1034					NInoSetCompressed(ni);
  1035					if (vol->cluster_size > 4096) {
  1036						ntfs_error(vi->i_sb, "Found "
  1037								"compressed data but "
  1038								"compression is "
  1039								"disabled due to "
  1040								"cluster size (%i) > "
  1041								"4kiB.",
  1042								vol->cluster_size);
  1043						goto unm_err_out;
  1044					}
  1045					if ((a->flags & ATTR_COMPRESSION_MASK)
  1046							!= ATTR_IS_COMPRESSED) {
  1047						ntfs_error(vi->i_sb, "Found unknown "
  1048								"compression method "
  1049								"or corrupt file.");
  1050						goto unm_err_out;
  1051					}
  1052				}
  1053				if (a->flags & ATTR_IS_SPARSE)
  1054					NInoSetSparse(ni);
  1055			}
  1056			if (a->flags & ATTR_IS_ENCRYPTED) {
  1057				if (NInoCompressed(ni)) {
  1058					ntfs_error(vi->i_sb, "Found encrypted and "
  1059							"compressed data.");
  1060					goto unm_err_out;
  1061				}
  1062				NInoSetEncrypted(ni);
  1063			}
  1064			if (a->non_resident) {
  1065				NInoSetNonResident(ni);
  1066				if (NInoCompressed(ni) || NInoSparse(ni)) {
  1067					if (NInoCompressed(ni) && a->data.non_resident.
  1068							compression_unit != 4) {
  1069						ntfs_error(vi->i_sb, "Found "
  1070								"non-standard "
  1071								"compression unit (%u "
  1072								"instead of 4).  "
  1073								"Cannot handle this.",
  1074								a->data.non_resident.
  1075								compression_unit);
  1076						err = -EOPNOTSUPP;
  1077						goto unm_err_out;
  1078					}
  1079					if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
  1080					a->data.non_resident.compression_unit !=
> 1081					vol->sparse_compression_unit) {
  1082						ntfs_error(vi->i_sb,
  1083						"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
  1084						a->data.non_resident.compression_unit,
  1085						vol->sparse_compression_unit);
  1086						err = -EOPNOTSUPP;
  1087						goto unm_err_out;
  1088					}
  1089					if (a->data.non_resident.compression_unit) {
  1090						ni->itype.compressed.block_size = 1U <<
  1091								(a->data.non_resident.
  1092								compression_unit +
  1093								vol->cluster_size_bits);
  1094						ni->itype.compressed.block_size_bits =
  1095								ffs(ni->itype.
  1096								compressed.
  1097								block_size) - 1;
  1098						ni->itype.compressed.block_clusters =
  1099								1U << a->data.
  1100								non_resident.
  1101								compression_unit;
  1102					} else {
  1103						ni->itype.compressed.block_size = 0;
  1104						ni->itype.compressed.block_size_bits =
  1105								0;
  1106						ni->itype.compressed.block_clusters =
  1107								0;
  1108					}
  1109					ni->itype.compressed.size = sle64_to_cpu(
  1110							a->data.non_resident.
  1111							compressed_size);
  1112				}
  1113				if (a->data.non_resident.lowest_vcn) {
  1114					ntfs_error(vi->i_sb, "First extent of $DATA "
  1115							"attribute has non zero "
  1116							"lowest_vcn.");
  1117					goto unm_err_out;
  1118				}
  1119				vi->i_size = sle64_to_cpu(
  1120						a->data.non_resident.data_size);
  1121				ni->initialized_size = sle64_to_cpu(
  1122						a->data.non_resident.initialized_size);
  1123				ni->allocated_size = sle64_to_cpu(
  1124						a->data.non_resident.allocated_size);
  1125			} else { /* Resident attribute. */
  1126				vi->i_size = ni->initialized_size = le32_to_cpu(
  1127						a->data.resident.value_length);
  1128				ni->allocated_size = le32_to_cpu(a->length) -
  1129						le16_to_cpu(
  1130						a->data.resident.value_offset);
  1131				if (vi->i_size > ni->allocated_size) {
  1132					ntfs_error(vi->i_sb, "Resident data attribute "
  1133							"is corrupt (size exceeds "
  1134							"allocation).");
  1135					goto unm_err_out;
  1136				}
  1137			}
  1138	no_data_attr_special_case:
  1139			/* We are done with the mft record, so we release it. */
  1140			ntfs_attr_put_search_ctx(ctx);
  1141			unmap_mft_record(ni);
  1142			m = NULL;
  1143			ctx = NULL;
  1144			/* Setup the operations for this inode. */
  1145			vi->i_op = &ntfs_file_inode_ops;
  1146			vi->i_fop = &ntfs_file_ops;
  1147			vi->i_mapping->a_ops = &ntfs_normal_aops;
  1148			if (NInoMstProtected(ni))
  1149				vi->i_mapping->a_ops = &ntfs_mst_aops;
  1150			else if (NInoCompressed(ni))
  1151				vi->i_mapping->a_ops = &ntfs_compressed_aops;
  1152		}
  1153		/*
  1154		 * The number of 512-byte blocks used on disk (for stat). This is in so
  1155		 * far inaccurate as it doesn't account for any named streams or other
  1156		 * special non-resident attributes, but that is how Windows works, too,
  1157		 * so we are at least consistent with Windows, if not entirely
  1158		 * consistent with the Linux Way. Doing it the Linux Way would cause a
  1159		 * significant slowdown as it would involve iterating over all
  1160		 * attributes in the mft record and adding the allocated/compressed
  1161		 * sizes of all non-resident attributes present to give us the Linux
  1162		 * correct size that should go into i_blocks (after division by 512).
  1163		 */
  1164		if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
  1165			vi->i_blocks = ni->itype.compressed.size >> 9;
  1166		else
  1167			vi->i_blocks = ni->allocated_size >> 9;
  1168		ntfs_debug("Done.");
  1169		return 0;
  1170	iput_unm_err_out:
  1171		iput(bvi);
  1172	unm_err_out:
  1173		if (!err)
  1174			err = -EIO;
  1175		if (ctx)
  1176			ntfs_attr_put_search_ctx(ctx);
  1177		if (m)
  1178			unmap_mft_record(ni);
  1179	err_out:
  1180		ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
  1181				"inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
  1182		make_bad_inode(vi);
  1183		if (err != -EOPNOTSUPP && err != -ENOMEM)
  1184			NVolSetErrors(vol);
  1185		return err;
  1186	}
  1187	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-15  8:52         ` kernel test robot
  0 siblings, 0 replies; 21+ messages in thread
From: kernel test robot @ 2023-08-15  8:52 UTC (permalink / raw)
  To: Manas Ghandat, anton, linkinjeon
  Cc: Manas Ghandat, linux-ntfs-dev, llvm, linux-kernel,
	syzbot+4768a8f039aa677897d0, oe-kbuild-all, linux-fsdevel,
	Linux-kernel-mentees

Hi Manas,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.5-rc6 next-20230809]
[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/Manas-Ghandat/ntfs-fix-shift-out-of-bounds-in-ntfs_iget/20230815-132656
base:   linus/master
patch link:    https://lore.kernel.org/r/20230815052251.107732-1-ghandatmanas%40gmail.com
patch subject: [PATCH v5] ntfs : fix shift-out-of-bounds in ntfs_iget
config: hexagon-randconfig-r045-20230815 (https://download.01.org/0day-ci/archive/20230815/202308151601.LQ3EIAQF-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230815/202308151601.LQ3EIAQF-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/202308151601.LQ3EIAQF-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from fs/ntfs/inode.c:8:
   In file included from include/linux/buffer_head.h:12:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:334:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     547 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     560 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from fs/ntfs/inode.c:8:
   In file included from include/linux/buffer_head.h:12:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:334:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     573 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from fs/ntfs/inode.c:8:
   In file included from include/linux/buffer_head.h:12:
   In file included from include/linux/blk_types.h:10:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:12:
   In file included from include/linux/hardirq.h:11:
   In file included from ./arch/hexagon/include/generated/asm/hardirq.h:1:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/hexagon/include/asm/io.h:334:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     584 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     594 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     604 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1081 |                                 vol->sparse_compression_unit) {
         |                                 ~~~  ^
   include/linux/compiler.h:55:47: note: expanded from macro 'if'
      55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
         |                                               ^~~~
   include/linux/compiler.h:57:52: note: expanded from macro '__trace_if_var'
      57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
         |                                                    ^~~~
>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1081 |                                 vol->sparse_compression_unit) {
         |                                 ~~~  ^
   include/linux/compiler.h:55:47: note: expanded from macro 'if'
      55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
         |                                               ^~~~
   include/linux/compiler.h:57:61: note: expanded from macro '__trace_if_var'
      57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
         |                                                             ^~~~
>> fs/ntfs/inode.c:1081:10: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1081 |                                 vol->sparse_compression_unit) {
         |                                 ~~~  ^
   include/linux/compiler.h:55:47: note: expanded from macro 'if'
      55 | #define if(cond, ...) if ( __trace_if_var( !!(cond , ## __VA_ARGS__) ) )
         |                                               ^~~~
   include/linux/compiler.h:57:86: note: expanded from macro '__trace_if_var'
      57 | #define __trace_if_var(cond) (__builtin_constant_p(cond) ? (cond) : __trace_if_value(cond))
         |                                                                                      ^~~~
   include/linux/compiler.h:68:3: note: expanded from macro '__trace_if_value'
      68 |         (cond) ?                                        \
         |          ^~~~
   fs/ntfs/inode.c:1085:11: error: no member named 'sparse_compression_unit' in 'ntfs_volume'
    1085 |                                         vol->sparse_compression_unit);
         |                                         ~~~  ^
   fs/ntfs/debug.h:55:66: note: expanded from macro 'ntfs_error'
      55 | #define ntfs_error(sb, f, a...)         __ntfs_error(__func__, sb, f, ##a)
         |                                                                         ^
   6 warnings and 4 errors generated.


vim +1081 fs/ntfs/inode.c

   497	
   498	/**
   499	 * ntfs_read_locked_inode - read an inode from its device
   500	 * @vi:		inode to read
   501	 *
   502	 * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode
   503	 * described by @vi into memory from the device.
   504	 *
   505	 * The only fields in @vi that we need to/can look at when the function is
   506	 * called are i_sb, pointing to the mounted device's super block, and i_ino,
   507	 * the number of the inode to load.
   508	 *
   509	 * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino
   510	 * for reading and sets up the necessary @vi fields as well as initializing
   511	 * the ntfs inode.
   512	 *
   513	 * Q: What locks are held when the function is called?
   514	 * A: i_state has I_NEW set, hence the inode is locked, also
   515	 *    i_count is set to 1, so it is not going to go away
   516	 *    i_flags is set to 0 and we have no business touching it.  Only an ioctl()
   517	 *    is allowed to write to them. We should of course be honouring them but
   518	 *    we need to do that using the IS_* macros defined in include/linux/fs.h.
   519	 *    In any case ntfs_read_locked_inode() has nothing to do with i_flags.
   520	 *
   521	 * Return 0 on success and -errno on error.  In the error case, the inode will
   522	 * have had make_bad_inode() executed on it.
   523	 */
   524	static int ntfs_read_locked_inode(struct inode *vi)
   525	{
   526		ntfs_volume *vol = NTFS_SB(vi->i_sb);
   527		ntfs_inode *ni;
   528		struct inode *bvi;
   529		MFT_RECORD *m;
   530		ATTR_RECORD *a;
   531		STANDARD_INFORMATION *si;
   532		ntfs_attr_search_ctx *ctx;
   533		int err = 0;
   534	
   535		ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino);
   536	
   537		/* Setup the generic vfs inode parts now. */
   538		vi->i_uid = vol->uid;
   539		vi->i_gid = vol->gid;
   540		vi->i_mode = 0;
   541	
   542		/*
   543		 * Initialize the ntfs specific part of @vi special casing
   544		 * FILE_MFT which we need to do at mount time.
   545		 */
   546		if (vi->i_ino != FILE_MFT)
   547			ntfs_init_big_inode(vi);
   548		ni = NTFS_I(vi);
   549	
   550		m = map_mft_record(ni);
   551		if (IS_ERR(m)) {
   552			err = PTR_ERR(m);
   553			goto err_out;
   554		}
   555		ctx = ntfs_attr_get_search_ctx(ni, m);
   556		if (!ctx) {
   557			err = -ENOMEM;
   558			goto unm_err_out;
   559		}
   560	
   561		if (!(m->flags & MFT_RECORD_IN_USE)) {
   562			ntfs_error(vi->i_sb, "Inode is not in use!");
   563			goto unm_err_out;
   564		}
   565		if (m->base_mft_record) {
   566			ntfs_error(vi->i_sb, "Inode is an extent inode!");
   567			goto unm_err_out;
   568		}
   569	
   570		/* Transfer information from mft record into vfs and ntfs inodes. */
   571		vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
   572	
   573		/*
   574		 * FIXME: Keep in mind that link_count is two for files which have both
   575		 * a long file name and a short file name as separate entries, so if
   576		 * we are hiding short file names this will be too high. Either we need
   577		 * to account for the short file names by subtracting them or we need
   578		 * to make sure we delete files even though i_nlink is not zero which
   579		 * might be tricky due to vfs interactions. Need to think about this
   580		 * some more when implementing the unlink command.
   581		 */
   582		set_nlink(vi, le16_to_cpu(m->link_count));
   583		/*
   584		 * FIXME: Reparse points can have the directory bit set even though
   585		 * they would be S_IFLNK. Need to deal with this further below when we
   586		 * implement reparse points / symbolic links but it will do for now.
   587		 * Also if not a directory, it could be something else, rather than
   588		 * a regular file. But again, will do for now.
   589		 */
   590		/* Everyone gets all permissions. */
   591		vi->i_mode |= S_IRWXUGO;
   592		/* If read-only, no one gets write permissions. */
   593		if (IS_RDONLY(vi))
   594			vi->i_mode &= ~S_IWUGO;
   595		if (m->flags & MFT_RECORD_IS_DIRECTORY) {
   596			vi->i_mode |= S_IFDIR;
   597			/*
   598			 * Apply the directory permissions mask set in the mount
   599			 * options.
   600			 */
   601			vi->i_mode &= ~vol->dmask;
   602			/* Things break without this kludge! */
   603			if (vi->i_nlink > 1)
   604				set_nlink(vi, 1);
   605		} else {
   606			vi->i_mode |= S_IFREG;
   607			/* Apply the file permissions mask set in the mount options. */
   608			vi->i_mode &= ~vol->fmask;
   609		}
   610		/*
   611		 * Find the standard information attribute in the mft record. At this
   612		 * stage we haven't setup the attribute list stuff yet, so this could
   613		 * in fact fail if the standard information is in an extent record, but
   614		 * I don't think this actually ever happens.
   615		 */
   616		err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0,
   617				ctx);
   618		if (unlikely(err)) {
   619			if (err == -ENOENT) {
   620				/*
   621				 * TODO: We should be performing a hot fix here (if the
   622				 * recover mount option is set) by creating a new
   623				 * attribute.
   624				 */
   625				ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute "
   626						"is missing.");
   627			}
   628			goto unm_err_out;
   629		}
   630		a = ctx->attr;
   631		/* Get the standard information attribute value. */
   632		if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset)
   633				+ le32_to_cpu(a->data.resident.value_length) >
   634				(u8 *)ctx->mrec + vol->mft_record_size) {
   635			ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode.");
   636			goto unm_err_out;
   637		}
   638		si = (STANDARD_INFORMATION*)((u8*)a +
   639				le16_to_cpu(a->data.resident.value_offset));
   640	
   641		/* Transfer information from the standard information into vi. */
   642		/*
   643		 * Note: The i_?times do not quite map perfectly onto the NTFS times,
   644		 * but they are close enough, and in the end it doesn't really matter
   645		 * that much...
   646		 */
   647		/*
   648		 * mtime is the last change of the data within the file. Not changed
   649		 * when only metadata is changed, e.g. a rename doesn't affect mtime.
   650		 */
   651		vi->i_mtime = ntfs2utc(si->last_data_change_time);
   652		/*
   653		 * ctime is the last change of the metadata of the file. This obviously
   654		 * always changes, when mtime is changed. ctime can be changed on its
   655		 * own, mtime is then not changed, e.g. when a file is renamed.
   656		 */
   657		vi->i_ctime = ntfs2utc(si->last_mft_change_time);
   658		/*
   659		 * Last access to the data within the file. Not changed during a rename
   660		 * for example but changed whenever the file is written to.
   661		 */
   662		vi->i_atime = ntfs2utc(si->last_access_time);
   663	
   664		/* Find the attribute list attribute if present. */
   665		ntfs_attr_reinit_search_ctx(ctx);
   666		err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);
   667		if (err) {
   668			if (unlikely(err != -ENOENT)) {
   669				ntfs_error(vi->i_sb, "Failed to lookup attribute list "
   670						"attribute.");
   671				goto unm_err_out;
   672			}
   673		} else /* if (!err) */ {
   674			if (vi->i_ino == FILE_MFT)
   675				goto skip_attr_list_load;
   676			ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino);
   677			NInoSetAttrList(ni);
   678			a = ctx->attr;
   679			if (a->flags & ATTR_COMPRESSION_MASK) {
   680				ntfs_error(vi->i_sb, "Attribute list attribute is "
   681						"compressed.");
   682				goto unm_err_out;
   683			}
   684			if (a->flags & ATTR_IS_ENCRYPTED ||
   685					a->flags & ATTR_IS_SPARSE) {
   686				if (a->non_resident) {
   687					ntfs_error(vi->i_sb, "Non-resident attribute "
   688							"list attribute is encrypted/"
   689							"sparse.");
   690					goto unm_err_out;
   691				}
   692				ntfs_warning(vi->i_sb, "Resident attribute list "
   693						"attribute in inode 0x%lx is marked "
   694						"encrypted/sparse which is not true.  "
   695						"However, Windows allows this and "
   696						"chkdsk does not detect or correct it "
   697						"so we will just ignore the invalid "
   698						"flags and pretend they are not set.",
   699						vi->i_ino);
   700			}
   701			/* Now allocate memory for the attribute list. */
   702			ni->attr_list_size = (u32)ntfs_attr_size(a);
   703			ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);
   704			if (!ni->attr_list) {
   705				ntfs_error(vi->i_sb, "Not enough memory to allocate "
   706						"buffer for attribute list.");
   707				err = -ENOMEM;
   708				goto unm_err_out;
   709			}
   710			if (a->non_resident) {
   711				NInoSetAttrListNonResident(ni);
   712				if (a->data.non_resident.lowest_vcn) {
   713					ntfs_error(vi->i_sb, "Attribute list has non "
   714							"zero lowest_vcn.");
   715					goto unm_err_out;
   716				}
   717				/*
   718				 * Setup the runlist. No need for locking as we have
   719				 * exclusive access to the inode at this time.
   720				 */
   721				ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol,
   722						a, NULL);
   723				if (IS_ERR(ni->attr_list_rl.rl)) {
   724					err = PTR_ERR(ni->attr_list_rl.rl);
   725					ni->attr_list_rl.rl = NULL;
   726					ntfs_error(vi->i_sb, "Mapping pairs "
   727							"decompression failed.");
   728					goto unm_err_out;
   729				}
   730				/* Now load the attribute list. */
   731				if ((err = load_attribute_list(vol, &ni->attr_list_rl,
   732						ni->attr_list, ni->attr_list_size,
   733						sle64_to_cpu(a->data.non_resident.
   734						initialized_size)))) {
   735					ntfs_error(vi->i_sb, "Failed to load "
   736							"attribute list attribute.");
   737					goto unm_err_out;
   738				}
   739			} else /* if (!a->non_resident) */ {
   740				if ((u8*)a + le16_to_cpu(a->data.resident.value_offset)
   741						+ le32_to_cpu(
   742						a->data.resident.value_length) >
   743						(u8*)ctx->mrec + vol->mft_record_size) {
   744					ntfs_error(vi->i_sb, "Corrupt attribute list "
   745							"in inode.");
   746					goto unm_err_out;
   747				}
   748				/* Now copy the attribute list. */
   749				memcpy(ni->attr_list, (u8*)a + le16_to_cpu(
   750						a->data.resident.value_offset),
   751						le32_to_cpu(
   752						a->data.resident.value_length));
   753			}
   754		}
   755	skip_attr_list_load:
   756		/*
   757		 * If an attribute list is present we now have the attribute list value
   758		 * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes.
   759		 */
   760		if (S_ISDIR(vi->i_mode)) {
   761			loff_t bvi_size;
   762			ntfs_inode *bni;
   763			INDEX_ROOT *ir;
   764			u8 *ir_end, *index_end;
   765	
   766			/* It is a directory, find index root attribute. */
   767			ntfs_attr_reinit_search_ctx(ctx);
   768			err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE,
   769					0, NULL, 0, ctx);
   770			if (unlikely(err)) {
   771				if (err == -ENOENT) {
   772					// FIXME: File is corrupt! Hot-fix with empty
   773					// index root attribute if recovery option is
   774					// set.
   775					ntfs_error(vi->i_sb, "$INDEX_ROOT attribute "
   776							"is missing.");
   777				}
   778				goto unm_err_out;
   779			}
   780			a = ctx->attr;
   781			/* Set up the state. */
   782			if (unlikely(a->non_resident)) {
   783				ntfs_error(vol->sb, "$INDEX_ROOT attribute is not "
   784						"resident.");
   785				goto unm_err_out;
   786			}
   787			/* Ensure the attribute name is placed before the value. */
   788			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   789					le16_to_cpu(a->data.resident.value_offset)))) {
   790				ntfs_error(vol->sb, "$INDEX_ROOT attribute name is "
   791						"placed after the attribute value.");
   792				goto unm_err_out;
   793			}
   794			/*
   795			 * Compressed/encrypted index root just means that the newly
   796			 * created files in that directory should be created compressed/
   797			 * encrypted. However index root cannot be both compressed and
   798			 * encrypted.
   799			 */
   800			if (a->flags & ATTR_COMPRESSION_MASK)
   801				NInoSetCompressed(ni);
   802			if (a->flags & ATTR_IS_ENCRYPTED) {
   803				if (a->flags & ATTR_COMPRESSION_MASK) {
   804					ntfs_error(vi->i_sb, "Found encrypted and "
   805							"compressed attribute.");
   806					goto unm_err_out;
   807				}
   808				NInoSetEncrypted(ni);
   809			}
   810			if (a->flags & ATTR_IS_SPARSE)
   811				NInoSetSparse(ni);
   812			ir = (INDEX_ROOT*)((u8*)a +
   813					le16_to_cpu(a->data.resident.value_offset));
   814			ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length);
   815			if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) {
   816				ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
   817						"corrupt.");
   818				goto unm_err_out;
   819			}
   820			index_end = (u8*)&ir->index +
   821					le32_to_cpu(ir->index.index_length);
   822			if (index_end > ir_end) {
   823				ntfs_error(vi->i_sb, "Directory index is corrupt.");
   824				goto unm_err_out;
   825			}
   826			if (ir->type != AT_FILE_NAME) {
   827				ntfs_error(vi->i_sb, "Indexed attribute is not "
   828						"$FILE_NAME.");
   829				goto unm_err_out;
   830			}
   831			if (ir->collation_rule != COLLATION_FILE_NAME) {
   832				ntfs_error(vi->i_sb, "Index collation rule is not "
   833						"COLLATION_FILE_NAME.");
   834				goto unm_err_out;
   835			}
   836			ni->itype.index.collation_rule = ir->collation_rule;
   837			ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
   838			if (ni->itype.index.block_size &
   839					(ni->itype.index.block_size - 1)) {
   840				ntfs_error(vi->i_sb, "Index block size (%u) is not a "
   841						"power of two.",
   842						ni->itype.index.block_size);
   843				goto unm_err_out;
   844			}
   845			if (ni->itype.index.block_size > PAGE_SIZE) {
   846				ntfs_error(vi->i_sb, "Index block size (%u) > "
   847						"PAGE_SIZE (%ld) is not "
   848						"supported.  Sorry.",
   849						ni->itype.index.block_size,
   850						PAGE_SIZE);
   851				err = -EOPNOTSUPP;
   852				goto unm_err_out;
   853			}
   854			if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
   855				ntfs_error(vi->i_sb, "Index block size (%u) < "
   856						"NTFS_BLOCK_SIZE (%i) is not "
   857						"supported.  Sorry.",
   858						ni->itype.index.block_size,
   859						NTFS_BLOCK_SIZE);
   860				err = -EOPNOTSUPP;
   861				goto unm_err_out;
   862			}
   863			ni->itype.index.block_size_bits =
   864					ffs(ni->itype.index.block_size) - 1;
   865			/* Determine the size of a vcn in the directory index. */
   866			if (vol->cluster_size <= ni->itype.index.block_size) {
   867				ni->itype.index.vcn_size = vol->cluster_size;
   868				ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
   869			} else {
   870				ni->itype.index.vcn_size = vol->sector_size;
   871				ni->itype.index.vcn_size_bits = vol->sector_size_bits;
   872			}
   873	
   874			/* Setup the index allocation attribute, even if not present. */
   875			NInoSetMstProtected(ni);
   876			ni->type = AT_INDEX_ALLOCATION;
   877			ni->name = I30;
   878			ni->name_len = 4;
   879	
   880			if (!(ir->index.flags & LARGE_INDEX)) {
   881				/* No index allocation. */
   882				vi->i_size = ni->initialized_size =
   883						ni->allocated_size = 0;
   884				/* We are done with the mft record, so we release it. */
   885				ntfs_attr_put_search_ctx(ctx);
   886				unmap_mft_record(ni);
   887				m = NULL;
   888				ctx = NULL;
   889				goto skip_large_dir_stuff;
   890			} /* LARGE_INDEX: Index allocation present. Setup state. */
   891			NInoSetIndexAllocPresent(ni);
   892			/* Find index allocation attribute. */
   893			ntfs_attr_reinit_search_ctx(ctx);
   894			err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4,
   895					CASE_SENSITIVE, 0, NULL, 0, ctx);
   896			if (unlikely(err)) {
   897				if (err == -ENOENT)
   898					ntfs_error(vi->i_sb, "$INDEX_ALLOCATION "
   899							"attribute is not present but "
   900							"$INDEX_ROOT indicated it is.");
   901				else
   902					ntfs_error(vi->i_sb, "Failed to lookup "
   903							"$INDEX_ALLOCATION "
   904							"attribute.");
   905				goto unm_err_out;
   906			}
   907			a = ctx->attr;
   908			if (!a->non_resident) {
   909				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   910						"is resident.");
   911				goto unm_err_out;
   912			}
   913			/*
   914			 * Ensure the attribute name is placed before the mapping pairs
   915			 * array.
   916			 */
   917			if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >=
   918					le16_to_cpu(
   919					a->data.non_resident.mapping_pairs_offset)))) {
   920				ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name "
   921						"is placed after the mapping pairs "
   922						"array.");
   923				goto unm_err_out;
   924			}
   925			if (a->flags & ATTR_IS_ENCRYPTED) {
   926				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   927						"is encrypted.");
   928				goto unm_err_out;
   929			}
   930			if (a->flags & ATTR_IS_SPARSE) {
   931				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   932						"is sparse.");
   933				goto unm_err_out;
   934			}
   935			if (a->flags & ATTR_COMPRESSION_MASK) {
   936				ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute "
   937						"is compressed.");
   938				goto unm_err_out;
   939			}
   940			if (a->data.non_resident.lowest_vcn) {
   941				ntfs_error(vi->i_sb, "First extent of "
   942						"$INDEX_ALLOCATION attribute has non "
   943						"zero lowest_vcn.");
   944				goto unm_err_out;
   945			}
   946			vi->i_size = sle64_to_cpu(a->data.non_resident.data_size);
   947			ni->initialized_size = sle64_to_cpu(
   948					a->data.non_resident.initialized_size);
   949			ni->allocated_size = sle64_to_cpu(
   950					a->data.non_resident.allocated_size);
   951			/*
   952			 * We are done with the mft record, so we release it. Otherwise
   953			 * we would deadlock in ntfs_attr_iget().
   954			 */
   955			ntfs_attr_put_search_ctx(ctx);
   956			unmap_mft_record(ni);
   957			m = NULL;
   958			ctx = NULL;
   959			/* Get the index bitmap attribute inode. */
   960			bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4);
   961			if (IS_ERR(bvi)) {
   962				ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
   963				err = PTR_ERR(bvi);
   964				goto unm_err_out;
   965			}
   966			bni = NTFS_I(bvi);
   967			if (NInoCompressed(bni) || NInoEncrypted(bni) ||
   968					NInoSparse(bni)) {
   969				ntfs_error(vi->i_sb, "$BITMAP attribute is compressed "
   970						"and/or encrypted and/or sparse.");
   971				goto iput_unm_err_out;
   972			}
   973			/* Consistency check bitmap size vs. index allocation size. */
   974			bvi_size = i_size_read(bvi);
   975			if ((bvi_size << 3) < (vi->i_size >>
   976					ni->itype.index.block_size_bits)) {
   977				ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) "
   978						"for index allocation (0x%llx).",
   979						bvi_size << 3, vi->i_size);
   980				goto iput_unm_err_out;
   981			}
   982			/* No longer need the bitmap attribute inode. */
   983			iput(bvi);
   984	skip_large_dir_stuff:
   985			/* Setup the operations for this inode. */
   986			vi->i_op = &ntfs_dir_inode_ops;
   987			vi->i_fop = &ntfs_dir_ops;
   988			vi->i_mapping->a_ops = &ntfs_mst_aops;
   989		} else {
   990			/* It is a file. */
   991			ntfs_attr_reinit_search_ctx(ctx);
   992	
   993			/* Setup the data attribute, even if not present. */
   994			ni->type = AT_DATA;
   995			ni->name = NULL;
   996			ni->name_len = 0;
   997	
   998			/* Find first extent of the unnamed data attribute. */
   999			err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx);
  1000			if (unlikely(err)) {
  1001				vi->i_size = ni->initialized_size =
  1002						ni->allocated_size = 0;
  1003				if (err != -ENOENT) {
  1004					ntfs_error(vi->i_sb, "Failed to lookup $DATA "
  1005							"attribute.");
  1006					goto unm_err_out;
  1007				}
  1008				/*
  1009				 * FILE_Secure does not have an unnamed $DATA
  1010				 * attribute, so we special case it here.
  1011				 */
  1012				if (vi->i_ino == FILE_Secure)
  1013					goto no_data_attr_special_case;
  1014				/*
  1015				 * Most if not all the system files in the $Extend
  1016				 * system directory do not have unnamed data
  1017				 * attributes so we need to check if the parent
  1018				 * directory of the file is FILE_Extend and if it is
  1019				 * ignore this error. To do this we need to get the
  1020				 * name of this inode from the mft record as the name
  1021				 * contains the back reference to the parent directory.
  1022				 */
  1023				if (ntfs_is_extended_system_file(ctx) > 0)
  1024					goto no_data_attr_special_case;
  1025				// FIXME: File is corrupt! Hot-fix with empty data
  1026				// attribute if recovery option is set.
  1027				ntfs_error(vi->i_sb, "$DATA attribute is missing.");
  1028				goto unm_err_out;
  1029			}
  1030			a = ctx->attr;
  1031			/* Setup the state. */
  1032			if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) {
  1033				if (a->flags & ATTR_COMPRESSION_MASK) {
  1034					NInoSetCompressed(ni);
  1035					if (vol->cluster_size > 4096) {
  1036						ntfs_error(vi->i_sb, "Found "
  1037								"compressed data but "
  1038								"compression is "
  1039								"disabled due to "
  1040								"cluster size (%i) > "
  1041								"4kiB.",
  1042								vol->cluster_size);
  1043						goto unm_err_out;
  1044					}
  1045					if ((a->flags & ATTR_COMPRESSION_MASK)
  1046							!= ATTR_IS_COMPRESSED) {
  1047						ntfs_error(vi->i_sb, "Found unknown "
  1048								"compression method "
  1049								"or corrupt file.");
  1050						goto unm_err_out;
  1051					}
  1052				}
  1053				if (a->flags & ATTR_IS_SPARSE)
  1054					NInoSetSparse(ni);
  1055			}
  1056			if (a->flags & ATTR_IS_ENCRYPTED) {
  1057				if (NInoCompressed(ni)) {
  1058					ntfs_error(vi->i_sb, "Found encrypted and "
  1059							"compressed data.");
  1060					goto unm_err_out;
  1061				}
  1062				NInoSetEncrypted(ni);
  1063			}
  1064			if (a->non_resident) {
  1065				NInoSetNonResident(ni);
  1066				if (NInoCompressed(ni) || NInoSparse(ni)) {
  1067					if (NInoCompressed(ni) && a->data.non_resident.
  1068							compression_unit != 4) {
  1069						ntfs_error(vi->i_sb, "Found "
  1070								"non-standard "
  1071								"compression unit (%u "
  1072								"instead of 4).  "
  1073								"Cannot handle this.",
  1074								a->data.non_resident.
  1075								compression_unit);
  1076						err = -EOPNOTSUPP;
  1077						goto unm_err_out;
  1078					}
  1079					if (NInoSparse(ni) && a->data.non_resident.compression_unit &&
  1080					a->data.non_resident.compression_unit !=
> 1081					vol->sparse_compression_unit) {
  1082						ntfs_error(vi->i_sb,
  1083						"Found non-standard compression unit (%u instead of 0 or %d).  Cannot handle this.",
  1084						a->data.non_resident.compression_unit,
  1085						vol->sparse_compression_unit);
  1086						err = -EOPNOTSUPP;
  1087						goto unm_err_out;
  1088					}
  1089					if (a->data.non_resident.compression_unit) {
  1090						ni->itype.compressed.block_size = 1U <<
  1091								(a->data.non_resident.
  1092								compression_unit +
  1093								vol->cluster_size_bits);
  1094						ni->itype.compressed.block_size_bits =
  1095								ffs(ni->itype.
  1096								compressed.
  1097								block_size) - 1;
  1098						ni->itype.compressed.block_clusters =
  1099								1U << a->data.
  1100								non_resident.
  1101								compression_unit;
  1102					} else {
  1103						ni->itype.compressed.block_size = 0;
  1104						ni->itype.compressed.block_size_bits =
  1105								0;
  1106						ni->itype.compressed.block_clusters =
  1107								0;
  1108					}
  1109					ni->itype.compressed.size = sle64_to_cpu(
  1110							a->data.non_resident.
  1111							compressed_size);
  1112				}
  1113				if (a->data.non_resident.lowest_vcn) {
  1114					ntfs_error(vi->i_sb, "First extent of $DATA "
  1115							"attribute has non zero "
  1116							"lowest_vcn.");
  1117					goto unm_err_out;
  1118				}
  1119				vi->i_size = sle64_to_cpu(
  1120						a->data.non_resident.data_size);
  1121				ni->initialized_size = sle64_to_cpu(
  1122						a->data.non_resident.initialized_size);
  1123				ni->allocated_size = sle64_to_cpu(
  1124						a->data.non_resident.allocated_size);
  1125			} else { /* Resident attribute. */
  1126				vi->i_size = ni->initialized_size = le32_to_cpu(
  1127						a->data.resident.value_length);
  1128				ni->allocated_size = le32_to_cpu(a->length) -
  1129						le16_to_cpu(
  1130						a->data.resident.value_offset);
  1131				if (vi->i_size > ni->allocated_size) {
  1132					ntfs_error(vi->i_sb, "Resident data attribute "
  1133							"is corrupt (size exceeds "
  1134							"allocation).");
  1135					goto unm_err_out;
  1136				}
  1137			}
  1138	no_data_attr_special_case:
  1139			/* We are done with the mft record, so we release it. */
  1140			ntfs_attr_put_search_ctx(ctx);
  1141			unmap_mft_record(ni);
  1142			m = NULL;
  1143			ctx = NULL;
  1144			/* Setup the operations for this inode. */
  1145			vi->i_op = &ntfs_file_inode_ops;
  1146			vi->i_fop = &ntfs_file_ops;
  1147			vi->i_mapping->a_ops = &ntfs_normal_aops;
  1148			if (NInoMstProtected(ni))
  1149				vi->i_mapping->a_ops = &ntfs_mst_aops;
  1150			else if (NInoCompressed(ni))
  1151				vi->i_mapping->a_ops = &ntfs_compressed_aops;
  1152		}
  1153		/*
  1154		 * The number of 512-byte blocks used on disk (for stat). This is in so
  1155		 * far inaccurate as it doesn't account for any named streams or other
  1156		 * special non-resident attributes, but that is how Windows works, too,
  1157		 * so we are at least consistent with Windows, if not entirely
  1158		 * consistent with the Linux Way. Doing it the Linux Way would cause a
  1159		 * significant slowdown as it would involve iterating over all
  1160		 * attributes in the mft record and adding the allocated/compressed
  1161		 * sizes of all non-resident attributes present to give us the Linux
  1162		 * correct size that should go into i_blocks (after division by 512).
  1163		 */
  1164		if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni)))
  1165			vi->i_blocks = ni->itype.compressed.size >> 9;
  1166		else
  1167			vi->i_blocks = ni->allocated_size >> 9;
  1168		ntfs_debug("Done.");
  1169		return 0;
  1170	iput_unm_err_out:
  1171		iput(bvi);
  1172	unm_err_out:
  1173		if (!err)
  1174			err = -EIO;
  1175		if (ctx)
  1176			ntfs_attr_put_search_ctx(ctx);
  1177		if (m)
  1178			unmap_mft_record(ni);
  1179	err_out:
  1180		ntfs_error(vol->sb, "Failed with error code %i.  Marking corrupt "
  1181				"inode 0x%lx as bad.  Run chkdsk.", err, vi->i_ino);
  1182		make_bad_inode(vi);
  1183		if (err != -EOPNOTSUPP && err != -ENOMEM)
  1184			NVolSetErrors(vol);
  1185		return err;
  1186	}
  1187	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees


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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-13  5:59 ` Manas Ghandat
@ 2023-08-16 19:15   ` Greg KH
  -1 siblings, 0 replies; 21+ messages in thread
From: Greg KH @ 2023-08-16 19:15 UTC (permalink / raw)
  To: Manas Ghandat
  Cc: linux-ntfs-dev, linux-kernel, syzbot+4768a8f039aa677897d0,
	linux-fsdevel, Linux-kernel-mentees, linkinjeon, anton

On Sun, Aug 13, 2023 at 11:29:49AM +0530, Manas Ghandat wrote:
> Currently there is not check for ni->itype.compressed.block_size when
> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
> true. Added the required check to calculation of block size.
> 
> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b

What is this last tag for?  That's a kernel release version, what can be
done with that?

confused,

greg k-h
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-16 19:15   ` Greg KH
  0 siblings, 0 replies; 21+ messages in thread
From: Greg KH @ 2023-08-16 19:15 UTC (permalink / raw)
  To: Manas Ghandat
  Cc: Linux-kernel-mentees, anton, linkinjeon, linux-fsdevel,
	linux-kernel, linux-ntfs-dev, syzbot+4768a8f039aa677897d0

On Sun, Aug 13, 2023 at 11:29:49AM +0530, Manas Ghandat wrote:
> Currently there is not check for ni->itype.compressed.block_size when
> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
> true. Added the required check to calculation of block size.
> 
> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b

What is this last tag for?  That's a kernel release version, what can be
done with that?

confused,

greg k-h

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-16 19:15   ` Greg KH
@ 2023-08-18  6:34     ` Manas Ghandat
  -1 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-18  6:34 UTC (permalink / raw)
  To: Greg KH
  Cc: Linux-kernel-mentees, anton, linkinjeon, linux-fsdevel,
	linux-kernel, linux-ntfs-dev, syzbot+4768a8f039aa677897d0

Sorry for the last reply Greg. The last tag specifies the commit id. 
Also, I have sent the v5 of the patch in which I have made some critical 
changes. Please take a look at that.

On 17/08/23 00:45, Greg KH wrote:
> On Sun, Aug 13, 2023 at 11:29:49AM +0530, Manas Ghandat wrote:
>> Currently there is not check for ni->itype.compressed.block_size when
>> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
>> true. Added the required check to calculation of block size.
>>
>> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
>> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
>> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
>> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
> What is this last tag for?  That's a kernel release version, what can be
> done with that?
>
> confused,
>
> greg k-h

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-18  6:34     ` Manas Ghandat
  0 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-18  6:34 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-ntfs-dev, linux-kernel, syzbot+4768a8f039aa677897d0,
	linux-fsdevel, Linux-kernel-mentees, linkinjeon, anton

Sorry for the last reply Greg. The last tag specifies the commit id. 
Also, I have sent the v5 of the patch in which I have made some critical 
changes. Please take a look at that.

On 17/08/23 00:45, Greg KH wrote:
> On Sun, Aug 13, 2023 at 11:29:49AM +0530, Manas Ghandat wrote:
>> Currently there is not check for ni->itype.compressed.block_size when
>> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
>> true. Added the required check to calculation of block size.
>>
>> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
>> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
>> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
>> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
> What is this last tag for?  That's a kernel release version, what can be
> done with that?
>
> confused,
>
> greg k-h
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-18  6:34     ` Manas Ghandat
@ 2023-08-28  3:00       ` Namjae Jeon
  -1 siblings, 0 replies; 21+ messages in thread
From: Namjae Jeon @ 2023-08-28  3:00 UTC (permalink / raw)
  To: Manas Ghandat
  Cc: Greg KH, Linux-kernel-mentees, anton, linux-fsdevel,
	linux-kernel, linux-ntfs-dev, syzbot+4768a8f039aa677897d0

2023-08-18 15:34 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com>:
> Sorry for the last reply Greg. The last tag specifies the commit id.
> Also, I have sent the v5 of the patch in which I have made some critical
> changes. Please take a look at that.
Have you checked build error report from kernel test robot ?

>
> On 17/08/23 00:45, Greg KH wrote:
>> On Sun, Aug 13, 2023 at 11:29:49AM +0530, Manas Ghandat wrote:
>>> Currently there is not check for ni->itype.compressed.block_size when
>>> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
>>> true. Added the required check to calculation of block size.
>>>
>>> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
>>> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
>>> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
>> What is this last tag for?  That's a kernel release version, what can be
>> done with that?
>>
>> confused,
>>
>> greg k-h
>

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-28  3:00       ` Namjae Jeon
  0 siblings, 0 replies; 21+ messages in thread
From: Namjae Jeon @ 2023-08-28  3:00 UTC (permalink / raw)
  To: Manas Ghandat
  Cc: linux-ntfs-dev, linux-kernel, syzbot+4768a8f039aa677897d0,
	linux-fsdevel, Linux-kernel-mentees, anton

2023-08-18 15:34 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com>:
> Sorry for the last reply Greg. The last tag specifies the commit id.
> Also, I have sent the v5 of the patch in which I have made some critical
> changes. Please take a look at that.
Have you checked build error report from kernel test robot ?

>
> On 17/08/23 00:45, Greg KH wrote:
>> On Sun, Aug 13, 2023 at 11:29:49AM +0530, Manas Ghandat wrote:
>>> Currently there is not check for ni->itype.compressed.block_size when
>>> a->data.non_resident.compression_unit is present and NInoSparse(ni) is
>>> true. Added the required check to calculation of block size.
>>>
>>> Signed-off-by: Manas Ghandat <ghandatmanas@gmail.com>
>>> Reported-by: syzbot+4768a8f039aa677897d0@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=4768a8f039aa677897d0
>>> Fix-commit-ID: upstream f40ddce88593482919761f74910f42f4b84c004b
>> What is this last tag for?  That's a kernel release version, what can be
>> done with that?
>>
>> confused,
>>
>> greg k-h
>
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
  2023-08-28  3:00       ` Namjae Jeon
@ 2023-08-28 16:52         ` Manas Ghandat
  -1 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-28 16:52 UTC (permalink / raw)
  To: Namjae Jeon
  Cc: linux-ntfs-dev, linux-kernel, syzbot+4768a8f039aa677897d0,
	linux-fsdevel, Linux-kernel-mentees, anton

I was looking at this issue for some time now. As suggested by Anton, 
that the vol->sparse_compression_unit is set at the mount. I cannot seem 
to find the code for that part. It seems that the ntfs_inode struct does 
not have any sparse_compression_unit. So I am stuck at that part of the 
problem.

On 28/08/23 08:30, Namjae Jeon wrote:
> 2023-08-18 15:34 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com>:
>> Sorry for the last reply Greg. The last tag specifies the commit id.
>> Also, I have sent the v5 of the patch in which I have made some critical
>> changes. Please take a look at that.
> Have you checked build error report from kernel test robot ?
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees

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

* Re: [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget
@ 2023-08-28 16:52         ` Manas Ghandat
  0 siblings, 0 replies; 21+ messages in thread
From: Manas Ghandat @ 2023-08-28 16:52 UTC (permalink / raw)
  To: Namjae Jeon
  Cc: Greg KH, Linux-kernel-mentees, anton, linux-fsdevel,
	linux-kernel, linux-ntfs-dev, syzbot+4768a8f039aa677897d0

I was looking at this issue for some time now. As suggested by Anton, 
that the vol->sparse_compression_unit is set at the mount. I cannot seem 
to find the code for that part. It seems that the ntfs_inode struct does 
not have any sparse_compression_unit. So I am stuck at that part of the 
problem.

On 28/08/23 08:30, Namjae Jeon wrote:
> 2023-08-18 15:34 GMT+09:00, Manas Ghandat <ghandatmanas@gmail.com>:
>> Sorry for the last reply Greg. The last tag specifies the commit id.
>> Also, I have sent the v5 of the patch in which I have made some critical
>> changes. Please take a look at that.
> Have you checked build error report from kernel test robot ?

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

end of thread, other threads:[~2023-08-28 16:54 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-13  5:59 [PATCH v4] ntfs : fix shift-out-of-bounds in ntfs_iget Manas Ghandat
2023-08-13  5:59 ` Manas Ghandat
2023-08-14  1:02 ` Namjae Jeon
2023-08-14  1:02   ` Namjae Jeon
2023-08-14  9:29   ` Anton Altaparmakov via Linux-kernel-mentees
2023-08-15  5:22     ` [PATCH v5] " Manas Ghandat
2023-08-15  5:22       ` Manas Ghandat
2023-08-15  7:16       ` kernel test robot
2023-08-15  7:16         ` kernel test robot
2023-08-15  8:52       ` kernel test robot
2023-08-15  8:52         ` kernel test robot
2023-08-15  8:52       ` kernel test robot
2023-08-15  8:52         ` kernel test robot
2023-08-16 19:15 ` [PATCH v4] " Greg KH
2023-08-16 19:15   ` Greg KH
2023-08-18  6:34   ` Manas Ghandat
2023-08-18  6:34     ` Manas Ghandat
2023-08-28  3:00     ` Namjae Jeon
2023-08-28  3:00       ` Namjae Jeon
2023-08-28 16:52       ` Manas Ghandat
2023-08-28 16:52         ` Manas Ghandat

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.