diff mbox series

ossaudio: fix out of bounds write

Message ID 20200707180836.5435-1-vr_qemu@t-online.de
State New
Headers show
Series ossaudio: fix out of bounds write | expand

Commit Message

Volker Rümelin July 7, 2020, 6:08 p.m. UTC
In function oss_read() a read error currently does not exit the
read loop. With no data to read the variable pos will quickly
underflow and a subsequent successful read overwrites memory
outside the buffer. This patch adds the missing break statement
to the error path of the function.

To reproduce start qemu with -audiodev oss,id=audio0 and in the
guest start audio recording. After some time this will trigger
an exception.

Fixes: 3ba4066d08 "ossaudio: port to the new audio backend api"

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
 audio/ossaudio.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Philippe Mathieu-Daudé July 8, 2020, 8:30 a.m. UTC | #1
On 7/7/20 8:08 PM, Volker Rümelin wrote:
> In function oss_read() a read error currently does not exit the
> read loop. With no data to read the variable pos will quickly
> underflow and a subsequent successful read overwrites memory
> outside the buffer. This patch adds the missing break statement
> to the error path of the function.

Correct, but ...

> 
> To reproduce start qemu with -audiodev oss,id=audio0 and in the
> guest start audio recording. After some time this will trigger
> an exception.
> 
> Fixes: 3ba4066d08 "ossaudio: port to the new audio backend api"
> 
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
> ---
>  audio/ossaudio.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/audio/ossaudio.c b/audio/ossaudio.c
> index f88d076ec2..a7dcaa31ad 100644
> --- a/audio/ossaudio.c
> +++ b/audio/ossaudio.c
> @@ -691,6 +691,7 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
>                             len, dst);
>                  break;
>              }
> +            break;
>          }
>  
>          pos += nread;

... now pos += -1, then the size returned misses the last byte.
Volker Rümelin July 8, 2020, 8:09 p.m. UTC | #2
> On 7/7/20 8:08 PM, Volker Rümelin wrote:
>> In function oss_read() a read error currently does not exit the
>> read loop. With no data to read the variable pos will quickly
>> underflow and a subsequent successful read overwrites memory
>> outside the buffer. This patch adds the missing break statement
>> to the error path of the function.
> Correct, but ...
>
>> To reproduce start qemu with -audiodev oss,id=audio0 and in the
>> guest start audio recording. After some time this will trigger
>> an exception.
>>
>> Fixes: 3ba4066d08 "ossaudio: port to the new audio backend api"
>>
>> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>> ---
>>  audio/ossaudio.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/audio/ossaudio.c b/audio/ossaudio.c
>> index f88d076ec2..a7dcaa31ad 100644
>> --- a/audio/ossaudio.c
>> +++ b/audio/ossaudio.c
>> @@ -691,6 +691,7 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
>>                             len, dst);
>>                  break;
>>              }
>> +            break;
>>          }
>>  
>>          pos += nread;
> ... now pos += -1, then the size returned misses the last byte.
>
Hi Philippe,

no, the added break breaks the while loop. The next executed instruction after this break is the return pos statement not pos += nread.

With best regards,
Volker
BALATON Zoltan July 9, 2020, 1:08 a.m. UTC | #3
On Wed, 8 Jul 2020, Philippe Mathieu-Daudé wrote:
> On 7/7/20 8:08 PM, Volker Rümelin wrote:
>> In function oss_read() a read error currently does not exit the
>> read loop. With no data to read the variable pos will quickly
>> underflow and a subsequent successful read overwrites memory
>> outside the buffer. This patch adds the missing break statement
>> to the error path of the function.
>
> Correct, but ...
>
>>
>> To reproduce start qemu with -audiodev oss,id=audio0 and in the
>> guest start audio recording. After some time this will trigger
>> an exception.
>>
>> Fixes: 3ba4066d08 "ossaudio: port to the new audio backend api"
>>
>> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
>> ---
>>  audio/ossaudio.c | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/audio/ossaudio.c b/audio/ossaudio.c
>> index f88d076ec2..a7dcaa31ad 100644
>> --- a/audio/ossaudio.c
>> +++ b/audio/ossaudio.c
>> @@ -691,6 +691,7 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
>>                             len, dst);
>>                  break;
>>              }
>> +            break;

Maybe it would be less confusing if you converted the switch(errno) to an 
if then you wouldn't have two senses of break; in close proximity. I was 
thinking something like

if (nread == -1) {
     if (errno != EINTR && errno != EAGAIN) {
         logerr();
     }
     break; /* from while, which is now clear */
}

>>          }
>>
>>          pos += nread;
>
> ... now pos += -1, then the size returned misses the last byte.

Don't you break from loop in if () above this so -1 is never added to pos 
after this patch? What happens for EINTR and EAGAIN? Now we break from the 
loop for those too, should it be continue; instead?

Regards,
BALATON Zoltan
Gerd Hoffmann July 9, 2020, 12:55 p.m. UTC | #4
> > diff --git a/audio/ossaudio.c b/audio/ossaudio.c
> > index f88d076ec2..a7dcaa31ad 100644
> > --- a/audio/ossaudio.c
> > +++ b/audio/ossaudio.c
> > @@ -691,6 +691,7 @@ static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
> >                             len, dst);
> >                  break;
> >              }
> > +            break;
> >          }
> >  
> >          pos += nread;
> 
> ... now pos += -1, then the size returned misses the last byte.

No, it doesn't.  break leaves the while loop, not the if condition.
From patch context it isn't obvious though, you need to look at the
source code ...

Patch queued.

thanks,
  Gerd
diff mbox series

Patch

diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index f88d076ec2..a7dcaa31ad 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -691,6 +691,7 @@  static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
                            len, dst);
                 break;
             }
+            break;
         }
 
         pos += nread;