Skip to contentSkip to conversation

mtd: phram: Prevent divide by zero bug in phram_setup()

PATCH Superseded Dan Carpenter 3 participants 4 messages Jan 21, 2022 – Jan 22, 2022

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mtd: phram: Prevent divide by zero bug in phram_setup()

The problem is that "erasesize" is a uint32_t type so it might be non-zero but the truncated "(uint32_t)erasesize" value *is* zero. That would lead to the divide by zero bug.

Avoid the bug by delaying the divide until after we have validated that "erasesize" is reasonable.

Fixes dc2b3e5cbc80 ("mtd: phram: use div_u64_rem to stop overwrite len in phram_setup")
---
 drivers/mtd/devices/phram.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/mtd/devices/phram.c +8 -4
index 6ed6c51fac69..d503821a3e60 100644
@@ -264,16 +264,20 @@ static int phram_setup(const char *val)
 		}
 	}
 
-	if (erasesize)
-		div_u64_rem(len, (uint32_t)erasesize, &rem);
-
 	if (len == 0 || erasesize == 0 || erasesize > len
-	    || erasesize > UINT_MAX || rem) {
+	    || erasesize > UINT_MAX) {
 		parse_err("illegal erasesize or len\n");
 		ret = -EINVAL;
 		goto error;
 	}
 
+	div_u64_rem(len, (uint32_t)erasesize, &rem);
+	if (rem) {
+		parse_err("len is not multiple of erasesize\n");
+		ret = -EINVAL;
+		goto error;
+	}
+
 	ret = register_device(name, start, len, (uint32_t)erasesize);
 	if (ret)
 		goto error;
Signature · 1 line
2.20.1
maintainer
#1 lore raw

Hi Dan,

[email protected] wrote on Fri, 21 Jan 2022 08:38:36 +0300:

Quoted 1 line

The problem is that "erasesize" is a uint32_t type so it might be

Don't you mean uint64_t here? Otherwise I don't get the sentence.

Quoted 1 line

non-zero but the truncated "(uint32_t)erasesize" value *is* zero. That

s/*is*/*can* be/ ? (again, if my understanding is correct).

Quoted 4 lines

would lead to the divide by zero bug.

Avoid the bug by delaying the divide until after we have validated that "erasesize" is reasonable.

I don't really get the fix. If "erasesize" is big enough, then (uint32_t)erasesize can however be zero. But checking if erasesize is zero beforehands does not fix the situation. Or am I missing something?

Quoted 25 lines
Fixes dc2b3e5cbc80 ("mtd: phram: use div_u64_rem to stop overwrite len in phram_setup")
---
 drivers/mtd/devices/phram.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/mtd/devices/phram.c +1 -4
index 6ed6c51fac69..d503821a3e60 100644
@@ -264,16 +264,20 @@ static int phram_setup(const char *val)
 		}
 	}
 
-	if (erasesize)
-		div_u64_rem(len, (uint32_t)erasesize, &rem);
-
 	if (len == 0 || erasesize == 0 || erasesize > len
-	    || erasesize > UINT_MAX || rem) {
+	    || erasesize > UINT_MAX) {
 		parse_err("illegal erasesize or len\n");
 		ret = -EINVAL;
 		goto error;
 	}
 

drivers/mtd/devices/phram.c static int phram_setup(const char *val) · line 283

Quoted 10 lines
drivers/mtd/devices/phram.c +7 -0
+	div_u64_rem(len, (uint32_t)erasesize, &rem);
+	if (rem) {
+		parse_err("len is not multiple of erasesize\n");
+		ret = -EINVAL;
+		goto error;
+	}
+
 	ret = register_device(name, start, len, (uint32_t)erasesize);
 	if (ret)
 		goto error;

Thanks,
Miquèl

#2 lore raw
Quoted 8 lines · Miquel Raynal

Hi Dan,

[email protected] wrote on Fri, 21 Jan 2022 08:38:36 +0300:

Quoted 1 line

The problem is that "erasesize" is a uint32_t type so it might be

Don't you mean uint64_t here? Otherwise I don't get the sentence.

Yeah. I meant uint64_t. Will resend.

Quoted 4 lines
Quoted 1 line

non-zero but the truncated "(uint32_t)erasesize" value *is* zero. That

s/*is*/*can* be/ ? (again, if my understanding is correct).

It might be a situation where "erasesize" is non-zero but after we truncated it "(uint32_t)erasesize" is zero.

Quoted 9 lines
Quoted 4 lines

would lead to the divide by zero bug.

Avoid the bug by delaying the divide until after we have validated that "erasesize" is reasonable.

I don't really get the fix. If "erasesize" is big enough, then (uint32_t)erasesize can however be zero. But checking if erasesize is zero beforehands does not fix the situation. Or am I missing something?

It doesn't just check for zero, it checks a couple other things including if erasesize > UINT_MAX.

regards,
dan carpenter

Reviewed-by on v1 1/1
#3 lore raw
In reply to Dan Carpenter

Thanks for the fix!

Quoted 43 lines · Dan Carpenter

The problem is that "erasesize" is a uint32_t type so it might be non-zero but the truncated "(uint32_t)erasesize" value *is* zero. That would lead to the divide by zero bug.

Avoid the bug by delaying the divide until after we have validated that "erasesize" is reasonable.

Fixes dc2b3e5cbc80 ("mtd: phram: use div_u64_rem to stop overwrite len in phram_setup")
---
  drivers/mtd/devices/phram.c | 12 ++++++++----
  1 file changed, 8 insertions(+), 4 deletions(-)
drivers/mtd/devices/phram.c +8 -4
index 6ed6c51fac69..d503821a3e60 100644
@@ -264,16 +264,20 @@ static int phram_setup(const char *val)
  		}
  	}
 
-	if (erasesize)
-		div_u64_rem(len, (uint32_t)erasesize, &rem);
-
  	if (len == 0 || erasesize == 0 || erasesize > len
-	    || erasesize > UINT_MAX || rem) {
+	    || erasesize > UINT_MAX) {
  		parse_err("illegal erasesize or len\n");
  		ret = -EINVAL;
  		goto error;
  	}
 
+	div_u64_rem(len, (uint32_t)erasesize, &rem);
+	if (rem) {
+		parse_err("len is not multiple of erasesize\n");
+		ret = -EINVAL;
+		goto error;
+	}
+
  	ret = register_device(name, start, len, (uint32_t)erasesize);
  	if (ret)
  		goto error;