public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
@ 2015-09-04 12:56 Vitaly Kuznetsov
  2015-09-10 23:08 ` Andrew Morton
  2015-09-11  1:22 ` James Bottomley
  0 siblings, 2 replies; 9+ messages in thread
From: Vitaly Kuznetsov @ 2015-09-04 12:56 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Andy Shevchenko, Rasmus Villemoes, James Bottomley, linux-kernel,
	K. Y. Srinivasan

string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
problem is that if size == 0 when we start calculating sf_cap this loop
will never end.

The caller causing the issue is sd_read_capacity(), the problem was noticed
on Hyper-V.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 lib/string_helpers.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index c98ae81..a155c7b 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -76,7 +76,7 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
 		i++;
 	}
 
-	sf_cap = size;
+	sf_cap = size ? size : 1;
 	for (j = 0; sf_cap*10 < 1000; j++)
 		sf_cap *= 10;
 
-- 
2.4.3


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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-04 12:56 [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size() Vitaly Kuznetsov
@ 2015-09-10 23:08 ` Andrew Morton
  2015-09-11 18:31   ` James Bottomley
  2015-09-11  1:22 ` James Bottomley
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2015-09-10 23:08 UTC (permalink / raw)
  To: Vitaly Kuznetsov
  Cc: Andy Shevchenko, Rasmus Villemoes, James Bottomley, linux-kernel,
	K. Y. Srinivasan

On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <vkuznets@redhat.com> wrote:

> string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
> problem is that if size == 0 when we start calculating sf_cap this loop
> will never end.
> 
> The caller causing the issue is sd_read_capacity(), the problem was noticed
> on Hyper-V.

When fixing bugs, please provide enough info for others to be able to
understand which kernel version(s) need the fix.  In this case: what
end-user action triggers this bug?  (iow, how does sdkp->capacity
become zero?)





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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-04 12:56 [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size() Vitaly Kuznetsov
  2015-09-10 23:08 ` Andrew Morton
@ 2015-09-11  1:22 ` James Bottomley
  2015-09-14  9:19   ` Vitaly Kuznetsov
  1 sibling, 1 reply; 9+ messages in thread
From: James Bottomley @ 2015-09-11  1:22 UTC (permalink / raw)
  To: vkuznets@redhat.com
  Cc: linux@rasmusvillemoes.dk, andriy.shevchenko@linux.intel.com,
	linux-kernel@vger.kernel.org, akpm@linux-foundation.org,
	kys@microsoft.com

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1305 bytes --]

On Fri, 2015-09-04 at 14:56 +0200, Vitaly Kuznetsov wrote:
> string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
> problem is that if size == 0 when we start calculating sf_cap this loop
> will never end.
> 
> The caller causing the issue is sd_read_capacity(), the problem was noticed
> on Hyper-V.
> 
> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> ---
>  lib/string_helpers.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/string_helpers.c b/lib/string_helpers.c
> index c98ae81..a155c7b 100644
> --- a/lib/string_helpers.c
> +++ b/lib/string_helpers.c
> @@ -76,7 +76,7 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
>  		i++;
>  	}
>  
> -	sf_cap = size;
> +	sf_cap = size ? size : 1;

If size can become zero after the scale adjustment, then there's a fault
in the algorithm, and this probably isn't the right fix.  However, I did
a brief calculation, and I can't see how size becomes zero ... it might
be that I haven't looked at this long enough (I am on holiday).

James

>  	for (j = 0; sf_cap*10 < 1000; j++)
>  		sf_cap *= 10;
>  


ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-10 23:08 ` Andrew Morton
@ 2015-09-11 18:31   ` James Bottomley
  2015-09-14  9:06     ` Andy Shevchenko
  2015-09-14  9:16     ` Vitaly Kuznetsov
  0 siblings, 2 replies; 9+ messages in thread
From: James Bottomley @ 2015-09-11 18:31 UTC (permalink / raw)
  To: akpm@linux-foundation.org
  Cc: linux@rasmusvillemoes.dk, andriy.shevchenko@linux.intel.com,
	vkuznets@redhat.com, linux-kernel@vger.kernel.org,
	kys@microsoft.com

[-- Attachment #1: Type: text/plain, Size: 975 bytes --]

On Thu, 2015-09-10 at 16:08 -0700, Andrew Morton wrote:
> On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> 
> > string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
> > problem is that if size == 0 when we start calculating sf_cap this loop
> > will never end.
> > 
> > The caller causing the issue is sd_read_capacity(), the problem was noticed
> > on Hyper-V.
> 
> When fixing bugs, please provide enough info for others to be able to
> understand which kernel version(s) need the fix.  In this case: what
> end-user action triggers this bug?  (iow, how does sdkp->capacity
> become zero?)

Any more details.  The attached programme, which is cut straight out of
the algorithm in string_helpers.c and modified for a C environment
slightly (only in do_div and the typedefs) produces this

hello
STRING IS 512 B

With your input, so I don't think the problem is where you think it is.

James


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: test.c --]
[-- Type: text/x-csrc; name="test.c", Size: 2502 bytes --]

#include <sys/types.h>
#include <string.h>
#include <stdio.h>

# define do_div(n,base) ({					\
	u32 __base = (base);				\
	u32 __rem;						\
	__rem = ((u64)(n)) % __base;			\
	(n) = ((u64)(n)) / __base;				\
	__rem;							\
 })

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

typedef unsigned long long u64;
typedef unsigned int u32;

enum string_size_units {
  STRING_UNITS_2,
  STRING_UNITS_10,
};

/**
 * string_get_size - get the size in the specified units
 * @size:	The size to be converted in blocks
 * @blk_size:	Size of the block (use 1 for size in bytes)
 * @units:	units to use (powers of 1000 or 1024)
 * @buf:	buffer to format to
 * @len:	length of buffer
 *
 * This function returns a string formatted to 3 significant figures
 * giving the size in the required units.  @buf should have room for
 * at least 9 bytes and will always be zero terminated.
 *
 */
void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
		     char *buf, int len)
{
	static const char *const units_10[] = {
		"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
	};
	static const char *const units_2[] = {
		"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
	};
	static const char *const *const units_str[] = {
		[STRING_UNITS_10] = units_10,
		[STRING_UNITS_2] = units_2,
	};
	static const unsigned int divisor[] = {
		[STRING_UNITS_10] = 1000,
		[STRING_UNITS_2] = 1024,
	};
	int i, j;
	u32 remainder = 0, sf_cap, exp;
	char tmp[8];
	const char *unit;

	tmp[0] = '\0';
	i = 0;
	if (!size)
		goto out;

	while (blk_size >= divisor[units]) {
		remainder = do_div(blk_size, divisor[units]);
		i++;
	}

	exp = divisor[units] / (u32)blk_size;
	if (size >= exp) {
		remainder = do_div(size, divisor[units]);
		remainder *= blk_size;
		i++;
	} else {
		remainder *= size;
	}

	size *= blk_size;
	size += remainder / divisor[units];
	remainder %= divisor[units];

	while (size >= divisor[units]) {
		remainder = do_div(size, divisor[units]);
		i++;
	}

	sf_cap = size;
	for (j = 0; sf_cap*10 < 1000; j++)
		sf_cap *= 10;

	if (j) {
		remainder *= 1000;
		remainder /= divisor[units];
		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
		tmp[j+1] = '\0';
	}

 out:
	if (i >= ARRAY_SIZE(units_2))
		unit = "UNK";
	else
		unit = units_str[units][i];

	snprintf(buf, len, "%u%s %s", (u32)size,
		 tmp, unit);
}

int main(char *argc[], int argv)
{
char buf[512];

printf("hello\n");
string_get_size(1, 512, STRING_UNITS_2, buf, sizeof(buf));
printf("STRING IS %s\n", buf);

}

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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-11 18:31   ` James Bottomley
@ 2015-09-14  9:06     ` Andy Shevchenko
  2015-09-14 12:43       ` Vitaly Kuznetsov
  2015-09-14  9:16     ` Vitaly Kuznetsov
  1 sibling, 1 reply; 9+ messages in thread
From: Andy Shevchenko @ 2015-09-14  9:06 UTC (permalink / raw)
  To: James Bottomley, akpm@linux-foundation.org
  Cc: linux@rasmusvillemoes.dk, vkuznets@redhat.com,
	linux-kernel@vger.kernel.org, kys@microsoft.com

On Fri, 2015-09-11 at 18:31 +0000, James Bottomley wrote:
> On Thu, 2015-09-10 at 16:08 -0700, Andrew Morton wrote:
> > On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <
> > vkuznets@redhat.com> wrote:
> > 
> > > string_get_size(1, 512, 0, ..., ...) call results in an infinite 
> > > loop. The
> > > problem is that if size == 0 when we start calculating sf_cap 
> > > this loop
> > > will never end.
> > > 
> > > The caller causing the issue is sd_read_capacity(), the problem 
> > > was noticed
> > > on Hyper-V.
> > 
> > When fixing bugs, please provide enough info for others to be able 
> > to
> > understand which kernel version(s) need the fix.  In this case: 
> > what
> > end-user action triggers this bug?  (iow, how does sdkp->capacity
> > become zero?)
> 
> Any more details.  The attached programme, which is cut straight out 
> of
> the algorithm in string_helpers.c and modified for a C environment
> slightly (only in do_div and the typedefs) produces this
> 
> hello
> STRING IS 512 B
> 
> With your input, so I don't think the problem is where you think it 
> is.
> 
> James
> 

Vitaly, it might make sense to extend test-string_helpers.c to what you
are trying to do right.


-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-11 18:31   ` James Bottomley
  2015-09-14  9:06     ` Andy Shevchenko
@ 2015-09-14  9:16     ` Vitaly Kuznetsov
  1 sibling, 0 replies; 9+ messages in thread
From: Vitaly Kuznetsov @ 2015-09-14  9:16 UTC (permalink / raw)
  To: James Bottomley
  Cc: akpm@linux-foundation.org, linux@rasmusvillemoes.dk,
	andriy.shevchenko@linux.intel.com, linux-kernel@vger.kernel.org,
	kys@microsoft.com

James Bottomley <jbottomley@odin.com> writes:

> On Thu, 2015-09-10 at 16:08 -0700, Andrew Morton wrote:
>> On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>> 
>> > string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
>> > problem is that if size == 0 when we start calculating sf_cap this loop
>> > will never end.
>> > 
>> > The caller causing the issue is sd_read_capacity(), the problem was noticed
>> > on Hyper-V.
>> 
>> When fixing bugs, please provide enough info for others to be able to
>> understand which kernel version(s) need the fix.  In this case: what
>> end-user action triggers this bug?  (iow, how does sdkp->capacity
>> become zero?)
>
> Any more details.  The attached programme, which is cut straight out of
> the algorithm in string_helpers.c and modified for a C environment
> slightly (only in do_div and the typedefs) produces this
>
> hello
> STRING IS 512 B
>
> With your input, so I don't think the problem is where you think it
> is.

Sorry for delayed reply, I was traveling.

Please change
string_get_size(1, 512, STRING_UNITS_2, buf, sizeof(buf));

to
string_get_size(1, 512, STRING_UNITS_10, buf, sizeof(buf));

in your test.c program to see the issue, it will enter the infinite loop
as well.

Regardless to Hyper-V I think such library function shouldn't do such
nasty things (but I'll try to investigate why such small size was
reported).

-- 
  Vitaly

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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-11  1:22 ` James Bottomley
@ 2015-09-14  9:19   ` Vitaly Kuznetsov
  0 siblings, 0 replies; 9+ messages in thread
From: Vitaly Kuznetsov @ 2015-09-14  9:19 UTC (permalink / raw)
  To: James Bottomley
  Cc: linux@rasmusvillemoes.dk, andriy.shevchenko@linux.intel.com,
	linux-kernel@vger.kernel.org, akpm@linux-foundation.org,
	kys@microsoft.com

James Bottomley <jbottomley@odin.com> writes:

> On Fri, 2015-09-04 at 14:56 +0200, Vitaly Kuznetsov wrote:
>> string_get_size(1, 512, 0, ..., ...) call results in an infinite loop. The
>> problem is that if size == 0 when we start calculating sf_cap this loop
>> will never end.
>> 
>> The caller causing the issue is sd_read_capacity(), the problem was noticed
>> on Hyper-V.
>> 
>> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
>> ---
>>  lib/string_helpers.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/lib/string_helpers.c b/lib/string_helpers.c
>> index c98ae81..a155c7b 100644
>> --- a/lib/string_helpers.c
>> +++ b/lib/string_helpers.c
>> @@ -76,7 +76,7 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
>>  		i++;
>>  	}
>>  
>> -	sf_cap = size;
>> +	sf_cap = size ? size : 1;
>
> If size can become zero after the scale adjustment, then there's a fault
> in the algorithm, and this probably isn't the right fix.  However, I did
> a brief calculation, and I can't see how size becomes zero ...

... but it does ...

> it might be that I haven't looked at this long enough (I am on holiday).

The function itself looks over complicated to me but you're probably
right and I'll try to find the root cause of the issue in the algorythm.

Thanks,

>
> James
>
>>  	for (j = 0; sf_cap*10 < 1000; j++)
>>  		sf_cap *= 10;
>>  

-- 
  Vitaly

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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-14  9:06     ` Andy Shevchenko
@ 2015-09-14 12:43       ` Vitaly Kuznetsov
  2015-09-14 14:33         ` Andy Shevchenko
  0 siblings, 1 reply; 9+ messages in thread
From: Vitaly Kuznetsov @ 2015-09-14 12:43 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: James Bottomley, akpm@linux-foundation.org,
	linux@rasmusvillemoes.dk, linux-kernel@vger.kernel.org,
	kys@microsoft.com

Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:

> On Fri, 2015-09-11 at 18:31 +0000, James Bottomley wrote:
>> On Thu, 2015-09-10 at 16:08 -0700, Andrew Morton wrote:
>> > On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <
>> > vkuznets@redhat.com> wrote:
>> > 
>> > > string_get_size(1, 512, 0, ..., ...) call results in an infinite 
>> > > loop. The
>> > > problem is that if size == 0 when we start calculating sf_cap 
>> > > this loop
>> > > will never end.
>> > > 
>> > > The caller causing the issue is sd_read_capacity(), the problem 
>> > > was noticed
>> > > on Hyper-V.
>> > 
>> > When fixing bugs, please provide enough info for others to be able 
>> > to
>> > understand which kernel version(s) need the fix.  In this case: 
>> > what
>> > end-user action triggers this bug?  (iow, how does sdkp->capacity
>> > become zero?)
>> 
>> Any more details.  The attached programme, which is cut straight out 
>> of
>> the algorithm in string_helpers.c and modified for a C environment
>> slightly (only in do_div and the typedefs) produces this
>> 
>> hello
>> STRING IS 512 B
>> 
>> With your input, so I don't think the problem is where you think it 
>> is.
>> 
>> James
>> 
>
> Vitaly, it might make sense to extend test-string_helpers.c to what you
> are trying to do right.

The issue is that string_get_size() enters an infinite loop on some
inputs so if we add a test for such inputs we'll hang our kernel...

-- 
  Vitaly

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

* Re: [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size()
  2015-09-14 12:43       ` Vitaly Kuznetsov
@ 2015-09-14 14:33         ` Andy Shevchenko
  0 siblings, 0 replies; 9+ messages in thread
From: Andy Shevchenko @ 2015-09-14 14:33 UTC (permalink / raw)
  To: Vitaly Kuznetsov
  Cc: James Bottomley, akpm@linux-foundation.org,
	linux@rasmusvillemoes.dk, linux-kernel@vger.kernel.org,
	kys@microsoft.com

On Mon, 2015-09-14 at 14:43 +0200, Vitaly Kuznetsov wrote:
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
> 
> > On Fri, 2015-09-11 at 18:31 +0000, James Bottomley wrote:
> > > On Thu, 2015-09-10 at 16:08 -0700, Andrew Morton wrote:
> > > > On Fri,  4 Sep 2015 14:56:33 +0200 Vitaly Kuznetsov <
> > > > vkuznets@redhat.com> wrote:
> > > > 
> > > > > string_get_size(1, 512, 0, ..., ...) call results in an 
> > > > > infinite 
> > > > > loop. The
> > > > > problem is that if size == 0 when we start calculating sf_cap 
> > > > > 
> > > > > this loop
> > > > > will never end.
> > > > > 
> > > > > The caller causing the issue is sd_read_capacity(), the 
> > > > > problem 
> > > > > was noticed
> > > > > on Hyper-V.
> > > > 
> > > > When fixing bugs, please provide enough info for others to be 
> > > > able 
> > > > to
> > > > understand which kernel version(s) need the fix.  In this case: 
> > > > 
> > > > what
> > > > end-user action triggers this bug?  (iow, how does sdkp
> > > > ->capacity
> > > > become zero?)
> > > 
> > > Any more details.  The attached programme, which is cut straight 
> > > out 
> > > of
> > > the algorithm in string_helpers.c and modified for a C 
> > > environment
> > > slightly (only in do_div and the typedefs) produces this
> > > 
> > > hello
> > > STRING IS 512 B
> > > 
> > > With your input, so I don't think the problem is where you think 
> > > it 
> > > is.
> > > 
> > > James
> > > 
> > 
> > Vitaly, it might make sense to extend test-string_helpers.c to what 
> > you
> > are trying to do right.
> 
> The issue is that string_get_size() enters an infinite loop on some
> inputs so if we add a test for such inputs we'll hang our kernel...
> 

I didn't see a problem to add this test case. Since test module is
dedicated for that (tests).

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

end of thread, other threads:[~2015-09-14 14:35 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-04 12:56 [PATCH] lib/string_helpers.c: fix infinite loop in string_get_size() Vitaly Kuznetsov
2015-09-10 23:08 ` Andrew Morton
2015-09-11 18:31   ` James Bottomley
2015-09-14  9:06     ` Andy Shevchenko
2015-09-14 12:43       ` Vitaly Kuznetsov
2015-09-14 14:33         ` Andy Shevchenko
2015-09-14  9:16     ` Vitaly Kuznetsov
2015-09-11  1:22 ` James Bottomley
2015-09-14  9:19   ` Vitaly Kuznetsov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox