[PATCH v1] mmc: fix signed vs unsigned compare in read check in _spl_load()

Franco VENTURI fventuri at comcast.net
Wed Jul 31 14:27:24 CEST 2024


Peng,
no, with just the condition 'read < sizeof(*header)', the variable 'read' (which is a signed integer) will be converted ('balanced') to unsigned to match the type of 'sizeof()' as per the C standard specification (see https://stackoverflow.com/a/17294164).

This means that a value read = -2 will be converted to unsigned  0xFFFFFFFE, the comparison 'read < sizeof(*header)' will be false, and the _spl_load() function will not return -EIO

In order to fix this bug one has to check first if the value of 'read' is negative *and* then check 'read' against 'sizeof(*header)'.


To better explain this bug, this morning I wrote the following small C program:


int main()
{
    int read = -2;
    typedef struct {
        int a;
        int b;
        int c;
    } header_t;
    header_t hdr;
    header_t *header = &hdr;

    printf("case 1 - read < sizeof(*header)\n");
    if (read < sizeof(*header)) {
        printf("would return -EIO\n");
    } else {
        printf("would continue\n");
    }
    printf("\n");

    printf("case 2 - read < 0 || read < sizeof(*header)\n");
    if (read < 0 || read < sizeof(*header)) {
        printf("would return -EIO\n");
    } else {
        printf("would continue\n");
    }
    printf("\n");

    printf("case 3 - read < (ssize_t)sizeof(*header)\n");
    if (read < (ssize_t)sizeof(*header)) {
        printf("would return -EIO\n");
    } else {
        printf("would continue\n");
    }
    printf("\n");

    return 0;
}

When I run this program, this is the output:

case 1 - read < sizeof(*header)
would continue

case 2 - read < 0 || read < sizeof(*header)
would return -EIO

case 3 - read < (ssize_t)sizeof(*header)
would return -EIO



Hope this makes sense,
Franco

> On 07/30/2024 9:45 AM EDT Peng Fan <peng.fan at nxp.com> wrote:
> 
>  
> > Subject: [PATCH v1] mmc: fix signed vs unsigned compare in read
> > check in _spl_load()
> > 
> > Fix signed vs unsigned compare in read check in _spl_load()
> > 
> > Issue: when info->read() returns a negative value because of an error,
> >        the comparison of 'read' (signed) with 'sizeof(*header)'
> >        (unsigned silently converts the negative value into a very
> >        large unsigned value and the check on the error condition
> >        always return false, i.e. the error is not detected
> > Symptoms: if spl_load_image_fat() is unable to find the file 'uImage',
> >           the SPL phase of the boot process just hangs after displaying
> >           the following line:
> >           Trying to boot from MMC1
> > Fix: first check if 'read' is negative then check its value against
> >      'sizeof(*header)'
> > Reference:
> > 
> > Signed-off-by: Franco Venturi <fventuri at comcast.net>
> > ---
> > 
> >  include/spl_load.h | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/include/spl_load.h b/include/spl_load.h index
> > 1c2b296c0a..1e05599d29 100644
> > --- a/include/spl_load.h
> > +++ b/include/spl_load.h
> > @@ -22,7 +22,7 @@ static inline int _spl_load(struct spl_image_info
> > *spl_image,
> > 
> >  	read = info->read(info, offset, ALIGN(sizeof(*header),
> >  					      spl_get_bl_len(info)),
> > header);
> > -	if (read < sizeof(*header))
> > +	if (read < 0 || read < sizeof(*header))
> 
> "read < 0" will imply that "read < sizeof(*header)", so there
> should no need to include this change.
> 
> Regards,
> Peng.
> 
> >  		return -EIO;
> > 
> >  	if (image_get_magic(header) == FDT_MAGIC) {
> > --
> > 2.45.2


More information about the U-Boot mailing list