linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
@ 2022-08-30 22:53 Chao Yu
  2022-09-08  1:58 ` Chao Yu
  2022-09-08  2:02 ` Jaegeuk Kim
  0 siblings, 2 replies; 9+ messages in thread
From: Chao Yu @ 2022-08-30 22:53 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

From: Chao Yu <chao.yu@oppo.com>

Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
in f2fs_iget() to avoid getting inner inode from external interfaces.

Signed-off-by: Chao Yu <chao.yu@oppo.com>
---
v2:
- don't override errno from f2fs_check_nid_range()
- fix compile error
 fs/f2fs/compress.c |  2 +-
 fs/f2fs/f2fs.h     |  1 +
 fs/f2fs/inode.c    | 13 ++++++++++++-
 fs/f2fs/super.c    |  4 ++--
 4 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 730256732a9e..c38b22bb6432 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1947,7 +1947,7 @@ int f2fs_init_compress_inode(struct f2fs_sb_info *sbi)
 	if (!test_opt(sbi, COMPRESS_CACHE))
 		return 0;
 
-	inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi));
+	inode = f2fs_iget_inner(sbi->sb, F2FS_COMPRESS_INO(sbi));
 	if (IS_ERR(inode))
 		return PTR_ERR(inode);
 	sbi->compress_inode = inode;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 408d8034ed74..35f9e1a6a1bf 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3467,6 +3467,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc);
 void f2fs_set_inode_flags(struct inode *inode);
 bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
 void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
+struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino);
 struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
 struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
 int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 6d11c365d7b4..965f87c1dd63 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -480,7 +480,7 @@ static int do_read_inode(struct inode *inode)
 	return 0;
 }
 
-struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
+struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino)
 {
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
 	struct inode *inode;
@@ -568,6 +568,17 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
 	return ERR_PTR(ret);
 }
 
+struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
+{
+	int ret;
+
+	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return f2fs_iget_inner(sb, ino);
+}
+
 struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino)
 {
 	struct inode *inode;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index b8e5fe244596..a5f5e7483791 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4157,7 +4157,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 		goto free_xattr_cache;
 
 	/* get an inode for meta space */
-	sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
+	sbi->meta_inode = f2fs_iget_inner(sb, F2FS_META_INO(sbi));
 	if (IS_ERR(sbi->meta_inode)) {
 		f2fs_err(sbi, "Failed to read F2FS meta data inode");
 		err = PTR_ERR(sbi->meta_inode);
@@ -4265,7 +4265,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 		goto free_nm;
 
 	/* get an inode for node space */
-	sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
+	sbi->node_inode = f2fs_iget_inner(sb, F2FS_NODE_INO(sbi));
 	if (IS_ERR(sbi->node_inode)) {
 		f2fs_err(sbi, "Failed to read node inode");
 		err = PTR_ERR(sbi->node_inode);
-- 
2.25.1


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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-08-30 22:53 [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget() Chao Yu
@ 2022-09-08  1:58 ` Chao Yu
  2022-09-08  2:02 ` Jaegeuk Kim
  1 sibling, 0 replies; 9+ messages in thread
From: Chao Yu @ 2022-09-08  1:58 UTC (permalink / raw)
  To: Chao Yu, jaegeuk; +Cc: linux-f2fs-devel, linux-kernel

Ping,

On 2022/8/31 6:53, Chao Yu wrote:
> From: Chao Yu <chao.yu@oppo.com>
> 
> Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
> meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
> in f2fs_iget() to avoid getting inner inode from external interfaces.
> 
> Signed-off-by: Chao Yu <chao.yu@oppo.com>
> ---
> v2:
> - don't override errno from f2fs_check_nid_range()
> - fix compile error
>   fs/f2fs/compress.c |  2 +-
>   fs/f2fs/f2fs.h     |  1 +
>   fs/f2fs/inode.c    | 13 ++++++++++++-
>   fs/f2fs/super.c    |  4 ++--
>   4 files changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index 730256732a9e..c38b22bb6432 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1947,7 +1947,7 @@ int f2fs_init_compress_inode(struct f2fs_sb_info *sbi)
>   	if (!test_opt(sbi, COMPRESS_CACHE))
>   		return 0;
>   
> -	inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi));
> +	inode = f2fs_iget_inner(sbi->sb, F2FS_COMPRESS_INO(sbi));
>   	if (IS_ERR(inode))
>   		return PTR_ERR(inode);
>   	sbi->compress_inode = inode;
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 408d8034ed74..35f9e1a6a1bf 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3467,6 +3467,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc);
>   void f2fs_set_inode_flags(struct inode *inode);
>   bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
>   void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
> +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino);
>   struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
>   struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
>   int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
> index 6d11c365d7b4..965f87c1dd63 100644
> --- a/fs/f2fs/inode.c
> +++ b/fs/f2fs/inode.c
> @@ -480,7 +480,7 @@ static int do_read_inode(struct inode *inode)
>   	return 0;
>   }
>   
> -struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino)
>   {
>   	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>   	struct inode *inode;
> @@ -568,6 +568,17 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>   	return ERR_PTR(ret);
>   }
>   
> +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> +{
> +	int ret;
> +
> +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return f2fs_iget_inner(sb, ino);
> +}
> +
>   struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino)
>   {
>   	struct inode *inode;
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index b8e5fe244596..a5f5e7483791 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -4157,7 +4157,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>   		goto free_xattr_cache;
>   
>   	/* get an inode for meta space */
> -	sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
> +	sbi->meta_inode = f2fs_iget_inner(sb, F2FS_META_INO(sbi));
>   	if (IS_ERR(sbi->meta_inode)) {
>   		f2fs_err(sbi, "Failed to read F2FS meta data inode");
>   		err = PTR_ERR(sbi->meta_inode);
> @@ -4265,7 +4265,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>   		goto free_nm;
>   
>   	/* get an inode for node space */
> -	sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
> +	sbi->node_inode = f2fs_iget_inner(sb, F2FS_NODE_INO(sbi));
>   	if (IS_ERR(sbi->node_inode)) {
>   		f2fs_err(sbi, "Failed to read node inode");
>   		err = PTR_ERR(sbi->node_inode);

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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-08-30 22:53 [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget() Chao Yu
  2022-09-08  1:58 ` Chao Yu
@ 2022-09-08  2:02 ` Jaegeuk Kim
  2022-09-08  2:11   ` Chao Yu
  1 sibling, 1 reply; 9+ messages in thread
From: Jaegeuk Kim @ 2022-09-08  2:02 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

On 08/31, Chao Yu wrote:
> From: Chao Yu <chao.yu@oppo.com>
> 
> Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
> meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
> in f2fs_iget() to avoid getting inner inode from external interfaces.

So, we don't want to check the range of inner inode numbers? What'd be the
way to check it's okay?

> 
> Signed-off-by: Chao Yu <chao.yu@oppo.com>
> ---
> v2:
> - don't override errno from f2fs_check_nid_range()
> - fix compile error
>  fs/f2fs/compress.c |  2 +-
>  fs/f2fs/f2fs.h     |  1 +
>  fs/f2fs/inode.c    | 13 ++++++++++++-
>  fs/f2fs/super.c    |  4 ++--
>  4 files changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index 730256732a9e..c38b22bb6432 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1947,7 +1947,7 @@ int f2fs_init_compress_inode(struct f2fs_sb_info *sbi)
>  	if (!test_opt(sbi, COMPRESS_CACHE))
>  		return 0;
>  
> -	inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi));
> +	inode = f2fs_iget_inner(sbi->sb, F2FS_COMPRESS_INO(sbi));
>  	if (IS_ERR(inode))
>  		return PTR_ERR(inode);
>  	sbi->compress_inode = inode;
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 408d8034ed74..35f9e1a6a1bf 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -3467,6 +3467,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc);
>  void f2fs_set_inode_flags(struct inode *inode);
>  bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
>  void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
> +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino);
>  struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
>  struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
>  int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
> index 6d11c365d7b4..965f87c1dd63 100644
> --- a/fs/f2fs/inode.c
> +++ b/fs/f2fs/inode.c
> @@ -480,7 +480,7 @@ static int do_read_inode(struct inode *inode)
>  	return 0;
>  }
>  
> -struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino)
>  {
>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>  	struct inode *inode;
> @@ -568,6 +568,17 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>  	return ERR_PTR(ret);
>  }
>  
> +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> +{
> +	int ret;
> +
> +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return f2fs_iget_inner(sb, ino);
> +}
> +
>  struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino)
>  {
>  	struct inode *inode;
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index b8e5fe244596..a5f5e7483791 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -4157,7 +4157,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  		goto free_xattr_cache;
>  
>  	/* get an inode for meta space */
> -	sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
> +	sbi->meta_inode = f2fs_iget_inner(sb, F2FS_META_INO(sbi));
>  	if (IS_ERR(sbi->meta_inode)) {
>  		f2fs_err(sbi, "Failed to read F2FS meta data inode");
>  		err = PTR_ERR(sbi->meta_inode);
> @@ -4265,7 +4265,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  		goto free_nm;
>  
>  	/* get an inode for node space */
> -	sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
> +	sbi->node_inode = f2fs_iget_inner(sb, F2FS_NODE_INO(sbi));
>  	if (IS_ERR(sbi->node_inode)) {
>  		f2fs_err(sbi, "Failed to read node inode");
>  		err = PTR_ERR(sbi->node_inode);
> -- 
> 2.25.1

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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-09-08  2:02 ` Jaegeuk Kim
@ 2022-09-08  2:11   ` Chao Yu
  2022-09-08  2:19     ` Jaegeuk Kim
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2022-09-08  2:11 UTC (permalink / raw)
  To: Jaegeuk Kim, Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

On 2022/9/8 10:02, Jaegeuk Kim wrote:
> On 08/31, Chao Yu wrote:
>> From: Chao Yu <chao.yu@oppo.com>
>>
>> Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
>> meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
>> in f2fs_iget() to avoid getting inner inode from external interfaces.
> 
> So, we don't want to check the range of inner inode numbers? What'd be the
> way to check it's okay?

For node_ino, meta_ino, root_ino, we have checked them in sanity_check_raw_super()
as below:

	/* check reserved ino info */
	if (le32_to_cpu(raw_super->node_ino) != 1 ||
		le32_to_cpu(raw_super->meta_ino) != 2 ||
		le32_to_cpu(raw_super->root_ino) != 3) {
		f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
			  le32_to_cpu(raw_super->node_ino),
			  le32_to_cpu(raw_super->meta_ino),
			  le32_to_cpu(raw_super->root_ino));
		return -EFSCORRUPTED;
	}

compressed_ino should always be NM_I(sbi)->max_nid, it can be checked in
f2fs_init_compress_inode()?

Thanks,

> 
>>
>> Signed-off-by: Chao Yu <chao.yu@oppo.com>
>> ---
>> v2:
>> - don't override errno from f2fs_check_nid_range()
>> - fix compile error
>>   fs/f2fs/compress.c |  2 +-
>>   fs/f2fs/f2fs.h     |  1 +
>>   fs/f2fs/inode.c    | 13 ++++++++++++-
>>   fs/f2fs/super.c    |  4 ++--
>>   4 files changed, 16 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
>> index 730256732a9e..c38b22bb6432 100644
>> --- a/fs/f2fs/compress.c
>> +++ b/fs/f2fs/compress.c
>> @@ -1947,7 +1947,7 @@ int f2fs_init_compress_inode(struct f2fs_sb_info *sbi)
>>   	if (!test_opt(sbi, COMPRESS_CACHE))
>>   		return 0;
>>   
>> -	inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi));
>> +	inode = f2fs_iget_inner(sbi->sb, F2FS_COMPRESS_INO(sbi));
>>   	if (IS_ERR(inode))
>>   		return PTR_ERR(inode);
>>   	sbi->compress_inode = inode;
>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>> index 408d8034ed74..35f9e1a6a1bf 100644
>> --- a/fs/f2fs/f2fs.h
>> +++ b/fs/f2fs/f2fs.h
>> @@ -3467,6 +3467,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc);
>>   void f2fs_set_inode_flags(struct inode *inode);
>>   bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
>>   void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
>> +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino);
>>   struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
>>   struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
>>   int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
>> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
>> index 6d11c365d7b4..965f87c1dd63 100644
>> --- a/fs/f2fs/inode.c
>> +++ b/fs/f2fs/inode.c
>> @@ -480,7 +480,7 @@ static int do_read_inode(struct inode *inode)
>>   	return 0;
>>   }
>>   
>> -struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>> +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino)
>>   {
>>   	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>>   	struct inode *inode;
>> @@ -568,6 +568,17 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>>   	return ERR_PTR(ret);
>>   }
>>   
>> +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>> +{
>> +	int ret;
>> +
>> +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	return f2fs_iget_inner(sb, ino);
>> +}
>> +
>>   struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino)
>>   {
>>   	struct inode *inode;
>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>> index b8e5fe244596..a5f5e7483791 100644
>> --- a/fs/f2fs/super.c
>> +++ b/fs/f2fs/super.c
>> @@ -4157,7 +4157,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>   		goto free_xattr_cache;
>>   
>>   	/* get an inode for meta space */
>> -	sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
>> +	sbi->meta_inode = f2fs_iget_inner(sb, F2FS_META_INO(sbi));
>>   	if (IS_ERR(sbi->meta_inode)) {
>>   		f2fs_err(sbi, "Failed to read F2FS meta data inode");
>>   		err = PTR_ERR(sbi->meta_inode);
>> @@ -4265,7 +4265,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>   		goto free_nm;
>>   
>>   	/* get an inode for node space */
>> -	sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
>> +	sbi->node_inode = f2fs_iget_inner(sb, F2FS_NODE_INO(sbi));
>>   	if (IS_ERR(sbi->node_inode)) {
>>   		f2fs_err(sbi, "Failed to read node inode");
>>   		err = PTR_ERR(sbi->node_inode);
>> -- 
>> 2.25.1

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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-09-08  2:11   ` Chao Yu
@ 2022-09-08  2:19     ` Jaegeuk Kim
  2022-09-08  4:04       ` Chao Yu
  0 siblings, 1 reply; 9+ messages in thread
From: Jaegeuk Kim @ 2022-09-08  2:19 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

On 09/08, Chao Yu wrote:
> On 2022/9/8 10:02, Jaegeuk Kim wrote:
> > On 08/31, Chao Yu wrote:
> > > From: Chao Yu <chao.yu@oppo.com>
> > > 
> > > Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
> > > meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
> > > in f2fs_iget() to avoid getting inner inode from external interfaces.
> > 
> > So, we don't want to check the range of inner inode numbers? What'd be the
> > way to check it's okay?
> 
> For node_ino, meta_ino, root_ino, we have checked them in sanity_check_raw_super()
> as below:
> 
> 	/* check reserved ino info */
> 	if (le32_to_cpu(raw_super->node_ino) != 1 ||
> 		le32_to_cpu(raw_super->meta_ino) != 2 ||
> 		le32_to_cpu(raw_super->root_ino) != 3) {
> 		f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
> 			  le32_to_cpu(raw_super->node_ino),
> 			  le32_to_cpu(raw_super->meta_ino),
> 			  le32_to_cpu(raw_super->root_ino));
> 		return -EFSCORRUPTED;
> 	}
> 
> compressed_ino should always be NM_I(sbi)->max_nid, it can be checked in
> f2fs_init_compress_inode()?

Hmm, I'm not sure whether we really need this patch, since it'd look better
to handle all the iget with single f2fs_iget?

> 
> Thanks,
> 
> > 
> > > 
> > > Signed-off-by: Chao Yu <chao.yu@oppo.com>
> > > ---
> > > v2:
> > > - don't override errno from f2fs_check_nid_range()
> > > - fix compile error
> > >   fs/f2fs/compress.c |  2 +-
> > >   fs/f2fs/f2fs.h     |  1 +
> > >   fs/f2fs/inode.c    | 13 ++++++++++++-
> > >   fs/f2fs/super.c    |  4 ++--
> > >   4 files changed, 16 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> > > index 730256732a9e..c38b22bb6432 100644
> > > --- a/fs/f2fs/compress.c
> > > +++ b/fs/f2fs/compress.c
> > > @@ -1947,7 +1947,7 @@ int f2fs_init_compress_inode(struct f2fs_sb_info *sbi)
> > >   	if (!test_opt(sbi, COMPRESS_CACHE))
> > >   		return 0;
> > > -	inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi));
> > > +	inode = f2fs_iget_inner(sbi->sb, F2FS_COMPRESS_INO(sbi));
> > >   	if (IS_ERR(inode))
> > >   		return PTR_ERR(inode);
> > >   	sbi->compress_inode = inode;
> > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > > index 408d8034ed74..35f9e1a6a1bf 100644
> > > --- a/fs/f2fs/f2fs.h
> > > +++ b/fs/f2fs/f2fs.h
> > > @@ -3467,6 +3467,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc);
> > >   void f2fs_set_inode_flags(struct inode *inode);
> > >   bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
> > >   void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
> > > +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino);
> > >   struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
> > >   struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
> > >   int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
> > > diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
> > > index 6d11c365d7b4..965f87c1dd63 100644
> > > --- a/fs/f2fs/inode.c
> > > +++ b/fs/f2fs/inode.c
> > > @@ -480,7 +480,7 @@ static int do_read_inode(struct inode *inode)
> > >   	return 0;
> > >   }
> > > -struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> > > +struct inode *f2fs_iget_inner(struct super_block *sb, unsigned long ino)
> > >   {
> > >   	struct f2fs_sb_info *sbi = F2FS_SB(sb);
> > >   	struct inode *inode;
> > > @@ -568,6 +568,17 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> > >   	return ERR_PTR(ret);
> > >   }
> > > +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> > > +{
> > > +	int ret;
> > > +
> > > +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
> > > +	if (ret)
> > > +		return ERR_PTR(ret);
> > > +
> > > +	return f2fs_iget_inner(sb, ino);
> > > +}
> > > +
> > >   struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino)
> > >   {
> > >   	struct inode *inode;
> > > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > > index b8e5fe244596..a5f5e7483791 100644
> > > --- a/fs/f2fs/super.c
> > > +++ b/fs/f2fs/super.c
> > > @@ -4157,7 +4157,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> > >   		goto free_xattr_cache;
> > >   	/* get an inode for meta space */
> > > -	sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
> > > +	sbi->meta_inode = f2fs_iget_inner(sb, F2FS_META_INO(sbi));
> > >   	if (IS_ERR(sbi->meta_inode)) {
> > >   		f2fs_err(sbi, "Failed to read F2FS meta data inode");
> > >   		err = PTR_ERR(sbi->meta_inode);
> > > @@ -4265,7 +4265,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> > >   		goto free_nm;
> > >   	/* get an inode for node space */
> > > -	sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
> > > +	sbi->node_inode = f2fs_iget_inner(sb, F2FS_NODE_INO(sbi));
> > >   	if (IS_ERR(sbi->node_inode)) {
> > >   		f2fs_err(sbi, "Failed to read node inode");
> > >   		err = PTR_ERR(sbi->node_inode);
> > > -- 
> > > 2.25.1

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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-09-08  2:19     ` Jaegeuk Kim
@ 2022-09-08  4:04       ` Chao Yu
  2022-09-12 15:39         ` Jaegeuk Kim
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2022-09-08  4:04 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

On 2022/9/8 10:19, Jaegeuk Kim wrote:
> On 09/08, Chao Yu wrote:
>> On 2022/9/8 10:02, Jaegeuk Kim wrote:
>>> On 08/31, Chao Yu wrote:
>>>> From: Chao Yu <chao.yu@oppo.com>
>>>>
>>>> Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
>>>> meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
>>>> in f2fs_iget() to avoid getting inner inode from external interfaces.
>>>
>>> So, we don't want to check the range of inner inode numbers? What'd be the
>>> way to check it's okay?
>>
>> For node_ino, meta_ino, root_ino, we have checked them in sanity_check_raw_super()
>> as below:
>>
>> 	/* check reserved ino info */
>> 	if (le32_to_cpu(raw_super->node_ino) != 1 ||
>> 		le32_to_cpu(raw_super->meta_ino) != 2 ||
>> 		le32_to_cpu(raw_super->root_ino) != 3) {
>> 		f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
>> 			  le32_to_cpu(raw_super->node_ino),
>> 			  le32_to_cpu(raw_super->meta_ino),
>> 			  le32_to_cpu(raw_super->root_ino));
>> 		return -EFSCORRUPTED;
>> 	}
>>
>> compressed_ino should always be NM_I(sbi)->max_nid, it can be checked in
>> f2fs_init_compress_inode()?
> 
> Hmm, I'm not sure whether we really need this patch, since it'd look better
> to handle all the iget with single f2fs_iget?

Well, the main concern is previously f2fs_iget() won't check validation for inner
inode due to it will skip do_read_inode() - f2fs_check_nid_range(), so that in a
fuzzed image, caller may pass inner ino into f2fs_iget(), result in incorrect use
of inner inode. So I add f2fs_check_nid_range() in prior to f2fs_iget_inner() in
f2fs_iget() as below to detect and avoid this case.

>>>> +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
>>>> +	if (ret)
>>>> +		return ERR_PTR(ret);
>>>> +
>>>> +	return f2fs_iget_inner(sb, ino);


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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-09-08  4:04       ` Chao Yu
@ 2022-09-12 15:39         ` Jaegeuk Kim
  2022-09-13  1:26           ` Chao Yu
  0 siblings, 1 reply; 9+ messages in thread
From: Jaegeuk Kim @ 2022-09-12 15:39 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

On 09/08, Chao Yu wrote:
> On 2022/9/8 10:19, Jaegeuk Kim wrote:
> > On 09/08, Chao Yu wrote:
> > > On 2022/9/8 10:02, Jaegeuk Kim wrote:
> > > > On 08/31, Chao Yu wrote:
> > > > > From: Chao Yu <chao.yu@oppo.com>
> > > > > 
> > > > > Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
> > > > > meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
> > > > > in f2fs_iget() to avoid getting inner inode from external interfaces.
> > > > 
> > > > So, we don't want to check the range of inner inode numbers? What'd be the
> > > > way to check it's okay?
> > > 
> > > For node_ino, meta_ino, root_ino, we have checked them in sanity_check_raw_super()
> > > as below:
> > > 
> > > 	/* check reserved ino info */
> > > 	if (le32_to_cpu(raw_super->node_ino) != 1 ||
> > > 		le32_to_cpu(raw_super->meta_ino) != 2 ||
> > > 		le32_to_cpu(raw_super->root_ino) != 3) {
> > > 		f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
> > > 			  le32_to_cpu(raw_super->node_ino),
> > > 			  le32_to_cpu(raw_super->meta_ino),
> > > 			  le32_to_cpu(raw_super->root_ino));
> > > 		return -EFSCORRUPTED;
> > > 	}
> > > 
> > > compressed_ino should always be NM_I(sbi)->max_nid, it can be checked in
> > > f2fs_init_compress_inode()?
> > 
> > Hmm, I'm not sure whether we really need this patch, since it'd look better
> > to handle all the iget with single f2fs_iget?
> 
> Well, the main concern is previously f2fs_iget() won't check validation for inner
> inode due to it will skip do_read_inode() - f2fs_check_nid_range(), so that in a
> fuzzed image, caller may pass inner ino into f2fs_iget(), result in incorrect use
> of inner inode. So I add f2fs_check_nid_range() in prior to f2fs_iget_inner() in
> f2fs_iget() as below to detect and avoid this case.

FWIW, sanity_check_raw_super() checked the inode numbers.

> 
> > > > > +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
> > > > > +{
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
> > > > > +	if (ret)
> > > > > +		return ERR_PTR(ret);
> > > > > +
> > > > > +	return f2fs_iget_inner(sb, ino);

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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
  2022-09-12 15:39         ` Jaegeuk Kim
@ 2022-09-13  1:26           ` Chao Yu
       [not found]             ` <YyAbBroLzLPaSyCF@google.com>
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2022-09-13  1:26 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

On 2022/9/12 23:39, Jaegeuk Kim wrote:
> On 09/08, Chao Yu wrote:
>> On 2022/9/8 10:19, Jaegeuk Kim wrote:
>>> On 09/08, Chao Yu wrote:
>>>> On 2022/9/8 10:02, Jaegeuk Kim wrote:
>>>>> On 08/31, Chao Yu wrote:
>>>>>> From: Chao Yu <chao.yu@oppo.com>
>>>>>>
>>>>>> Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
>>>>>> meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
>>>>>> in f2fs_iget() to avoid getting inner inode from external interfaces.
>>>>>
>>>>> So, we don't want to check the range of inner inode numbers? What'd be the
>>>>> way to check it's okay?
>>>>
>>>> For node_ino, meta_ino, root_ino, we have checked them in sanity_check_raw_super()
>>>> as below:
>>>>
>>>> 	/* check reserved ino info */
>>>> 	if (le32_to_cpu(raw_super->node_ino) != 1 ||
>>>> 		le32_to_cpu(raw_super->meta_ino) != 2 ||
>>>> 		le32_to_cpu(raw_super->root_ino) != 3) {
>>>> 		f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
>>>> 			  le32_to_cpu(raw_super->node_ino),
>>>> 			  le32_to_cpu(raw_super->meta_ino),
>>>> 			  le32_to_cpu(raw_super->root_ino));
>>>> 		return -EFSCORRUPTED;
>>>> 	}
>>>>
>>>> compressed_ino should always be NM_I(sbi)->max_nid, it can be checked in
>>>> f2fs_init_compress_inode()?
>>>
>>> Hmm, I'm not sure whether we really need this patch, since it'd look better
>>> to handle all the iget with single f2fs_iget?
>>
>> Well, the main concern is previously f2fs_iget() won't check validation for inner
>> inode due to it will skip do_read_inode() - f2fs_check_nid_range(), so that in a
>> fuzzed image, caller may pass inner ino into f2fs_iget(), result in incorrect use
>> of inner inode. So I add f2fs_check_nid_range() in prior to f2fs_iget_inner() in
>> f2fs_iget() as below to detect and avoid this case.
> 
> FWIW, sanity_check_raw_super() checked the inode numbers.

However, previously, f2fs_iget() will return inner inode to caller directly, if caller
passes meta_ino, node_ino or compress_ino to f2fs_iget()?

Thanks,

> 
>>
>>>>>> +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>>>>>> +{
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
>>>>>> +	if (ret)
>>>>>> +		return ERR_PTR(ret);
>>>>>> +
>>>>>> +	return f2fs_iget_inner(sb, ino);

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

* Re: [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget()
       [not found]             ` <YyAbBroLzLPaSyCF@google.com>
@ 2022-09-13  6:44               ` Chao Yu
  0 siblings, 0 replies; 9+ messages in thread
From: Chao Yu @ 2022-09-13  6:44 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel

On 2022/9/13 13:54, Jaegeuk Kim wrote:
> On 09/13, Chao Yu wrote:
>> On 2022/9/12 23:39, Jaegeuk Kim wrote:
>>> On 09/08, Chao Yu wrote:
>>>> On 2022/9/8 10:19, Jaegeuk Kim wrote:
>>>>> On 09/08, Chao Yu wrote:
>>>>>> On 2022/9/8 10:02, Jaegeuk Kim wrote:
>>>>>>> On 08/31, Chao Yu wrote:
>>>>>>>> From: Chao Yu <chao.yu@oppo.com>
>>>>>>>>
>>>>>>>> Introduce f2fs_iget_inner() for f2fs_fill_super() to get inner inode:
>>>>>>>> meta inode, node inode or compressed inode, and add f2fs_check_nid_range()
>>>>>>>> in f2fs_iget() to avoid getting inner inode from external interfaces.
>>>>>>>
>>>>>>> So, we don't want to check the range of inner inode numbers? What'd be the
>>>>>>> way to check it's okay?
>>>>>>
>>>>>> For node_ino, meta_ino, root_ino, we have checked them in sanity_check_raw_super()
>>>>>> as below:
>>>>>>
>>>>>> 	/* check reserved ino info */
>>>>>> 	if (le32_to_cpu(raw_super->node_ino) != 1 ||
>>>>>> 		le32_to_cpu(raw_super->meta_ino) != 2 ||
>>>>>> 		le32_to_cpu(raw_super->root_ino) != 3) {
>>>>>> 		f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
>>>>>> 			  le32_to_cpu(raw_super->node_ino),
>>>>>> 			  le32_to_cpu(raw_super->meta_ino),
>>>>>> 			  le32_to_cpu(raw_super->root_ino));
>>>>>> 		return -EFSCORRUPTED;
>>>>>> 	}
>>>>>>
>>>>>> compressed_ino should always be NM_I(sbi)->max_nid, it can be checked in
>>>>>> f2fs_init_compress_inode()?
>>>>>
>>>>> Hmm, I'm not sure whether we really need this patch, since it'd look better
>>>>> to handle all the iget with single f2fs_iget?
>>>>
>>>> Well, the main concern is previously f2fs_iget() won't check validation for inner
>>>> inode due to it will skip do_read_inode() - f2fs_check_nid_range(), so that in a
>>>> fuzzed image, caller may pass inner ino into f2fs_iget(), result in incorrect use
>>>> of inner inode. So I add f2fs_check_nid_range() in prior to f2fs_iget_inner() in
>>>> f2fs_iget() as below to detect and avoid this case.
>>>
>>> FWIW, sanity_check_raw_super() checked the inode numbers.
>>
>> However, previously, f2fs_iget() will return inner inode to caller directly, if caller
>> passes meta_ino, node_ino or compress_ino to f2fs_iget()?
> 
> Do you want to do sanity check on corrupted dentry? If so, how about checking

Yes, including:

- corrupted ino in dentry
- corrupted ino of orphan inode

As I replied in this thread:

https://lore.kernel.org/lkml/b1c74dc1-8d01-9041-9469-036273c5618d@kernel.org/

> it in f2fs_iget instead?
> 
> 	if (is_meta_ino(ino)) {
> 		if (!(inode->i_state & I_NEW)
> 			return -EFSCORRUPTED;
> 		goto make_now;
> 	}

Fine to me, let me revise in v3.

Thanks,

> 
>>
>> Thanks,
>>
>>>
>>>>
>>>>>>>> +struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
>>>>>>>> +{
>>>>>>>> +	int ret;
>>>>>>>> +
>>>>>>>> +	ret = f2fs_check_nid_range(F2FS_SB(sb), ino);
>>>>>>>> +	if (ret)
>>>>>>>> +		return ERR_PTR(ret);
>>>>>>>> +
>>>>>>>> +	return f2fs_iget_inner(sb, ino);

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

end of thread, other threads:[~2022-09-13  6:44 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-30 22:53 [PATCH v2] f2fs: fix to disallow getting inner inode via f2fs_iget() Chao Yu
2022-09-08  1:58 ` Chao Yu
2022-09-08  2:02 ` Jaegeuk Kim
2022-09-08  2:11   ` Chao Yu
2022-09-08  2:19     ` Jaegeuk Kim
2022-09-08  4:04       ` Chao Yu
2022-09-12 15:39         ` Jaegeuk Kim
2022-09-13  1:26           ` Chao Yu
     [not found]             ` <YyAbBroLzLPaSyCF@google.com>
2022-09-13  6:44               ` Chao Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).