[PATCH v2] squashfs: Add dictionary size range check to prevent shift-out-of-bounds

Ran Hongyun posted 1 patch 1 week, 5 days ago
fs/squashfs/xz_wrapper.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
[PATCH v2] squashfs: Add dictionary size range check to prevent shift-out-of-bounds
Posted by Ran Hongyun 1 week, 5 days ago
When an abnormal SquashFS image (COMP_OPTS flag is 1 but dictionary size
is 0) is mounted, and performs shift operations using dictionarysize, the
shift exponent is -1, causing a shift-out-of-bounds.

Detail as below:
squashfs_comp_opts(msblk, buffer, length)
  squashfs_xz_comp_opts()
    if (comp_opts)
      n = ffs(opts->dict_size) - 1;<----opts->dict_size=0, n=-1
      if (opts->dict_size != (1 << n) && opts->dict_size !=
	  	(1 << n) + (1 << (n + 1))) <----shift-out-of-bounds

Fix it by adding a dictionary size range check before the shift operation.

Fixes: ff750311d30a ("Squashfs: add compression options support to xz decompressor")
Signed-off-by: Ran Hongyun <ranhongyun1@huawei.com>
---
 fs/squashfs/xz_wrapper.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
index 6c49481a2f8c..7d54cd524d6d 100644
--- a/fs/squashfs/xz_wrapper.c
+++ b/fs/squashfs/xz_wrapper.c
@@ -57,10 +57,10 @@ static void *squashfs_xz_comp_opts(struct squashfs_sb_info *msblk,
 
 		opts->dict_size = le32_to_cpu(comp_opts->dictionary_size);
 
-		/* the dictionary size should be 2^n or 2^n+2^(n+1) */
+		/* the dictionary size should be positive and 2^n or 2^n+2^(n+1) */
 		n = ffs(opts->dict_size) - 1;
-		if (opts->dict_size != (1 << n) && opts->dict_size != (1 << n) +
-						(1 << (n + 1))) {
+		if (opts->dict_size <= 0 || (opts->dict_size != (1 << n) &&
+			opts->dict_size != (1 << n) + (1 << (n + 1)))) {
 			err = -EIO;
 			goto out;
 		}
-- 
2.52.0
Re: [PATCH v2] squashfs: Add dictionary size range check to prevent shift-out-of-bounds
Posted by Phillip Lougher 3 days, 14 hours ago

On 13/07/2026 12:55, Ran Hongyun wrote:
> When an abnormal SquashFS image (COMP_OPTS flag is 1 but dictionary size
> is 0) is mounted, and performs shift operations using dictionarysize, the
> shift exponent is -1, causing a shift-out-of-bounds.
> 
> Detail as below:
> squashfs_comp_opts(msblk, buffer, length)
>    squashfs_xz_comp_opts()
>      if (comp_opts)
>        n = ffs(opts->dict_size) - 1;<----opts->dict_size=0, n=-1
>        if (opts->dict_size != (1 << n) && opts->dict_size !=
> 	  	(1 << n) + (1 << (n + 1))) <----shift-out-of-bounds
> 
> Fix it by adding a dictionary size range check before the shift operation.

Reviewed-by: Phillip Lougher <phillip@squashfs.org.uk>

Andrew Morton handles patch submission to Linus for me.  CC'ing him.

Phillip
Re: [PATCH v2] squashfs: Add dictionary size range check to prevent shift-out-of-bounds
Posted by Zhihao Cheng 1 week, 2 days ago
在 2026/7/13 19:55, Ran Hongyun 写道:
> When an abnormal SquashFS image (COMP_OPTS flag is 1 but dictionary size
> is 0) is mounted, and performs shift operations using dictionarysize, the
> shift exponent is -1, causing a shift-out-of-bounds.
> 
> Detail as below:
> squashfs_comp_opts(msblk, buffer, length)
>    squashfs_xz_comp_opts()
>      if (comp_opts)
>        n = ffs(opts->dict_size) - 1;<----opts->dict_size=0, n=-1
>        if (opts->dict_size != (1 << n) && opts->dict_size !=
> 	  	(1 << n) + (1 << (n + 1))) <----shift-out-of-bounds
> 
> Fix it by adding a dictionary size range check before the shift operation.
> 
> Fixes: ff750311d30a ("Squashfs: add compression options support to xz decompressor")
> Signed-off-by: Ran Hongyun <ranhongyun1@huawei.com>
> ---
>   fs/squashfs/xz_wrapper.c | 6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)

Reviewed-by: Zhihao Cheng <chengzhihao1@huawei.com>
> 
> diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
> index 6c49481a2f8c..7d54cd524d6d 100644
> --- a/fs/squashfs/xz_wrapper.c
> +++ b/fs/squashfs/xz_wrapper.c
> @@ -57,10 +57,10 @@ static void *squashfs_xz_comp_opts(struct squashfs_sb_info *msblk,
>   
>   		opts->dict_size = le32_to_cpu(comp_opts->dictionary_size);
>   
> -		/* the dictionary size should be 2^n or 2^n+2^(n+1) */
> +		/* the dictionary size should be positive and 2^n or 2^n+2^(n+1) */
>   		n = ffs(opts->dict_size) - 1;
> -		if (opts->dict_size != (1 << n) && opts->dict_size != (1 << n) +
> -						(1 << (n + 1))) {
> +		if (opts->dict_size <= 0 || (opts->dict_size != (1 << n) &&
> +			opts->dict_size != (1 << n) + (1 << (n + 1)))) {
>   			err = -EIO;
>   			goto out;
>   		}
>