diff mbox

[FFmpeg-devel] Fix signed integer overflows

Message ID 20170818061447.27158-1-vitalybuka@google.com
State Superseded
Headers show

Commit Message

Vitaly Buka Aug. 18, 2017, 6:14 a.m. UTC
Signed integer overflow is undefined behavior.
Detected with clang and -fsanitize=signed-integer-overflow

Signed-off-by: Vitaly Buka <vitalybuka@google.com>
---
 libavcodec/utils.c    | 2 +-
 libavformat/aviobuf.c | 4 +++-
 libavformat/mov.c     | 2 +-
 3 files changed, 5 insertions(+), 3 deletions(-)

Comments

Tomas Härdin Aug. 18, 2017, 8:11 a.m. UTC | #1
On 2017-08-18 08:14, Vitaly Buka wrote:
> Signed integer overflow is undefined behavior.
> Detected with clang and -fsanitize=signed-integer-overflow
>
> Signed-off-by: Vitaly Buka <vitalybuka@google.com>
> ---
>   libavcodec/utils.c    | 2 +-
>   libavformat/aviobuf.c | 4 +++-
>   libavformat/mov.c     | 2 +-
>   3 files changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
> index 1336e921c9..024dc1f3e2 100644
> --- a/libavcodec/utils.c
> +++ b/libavcodec/utils.c
> @@ -971,7 +971,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>           }
>   
>           if (!avctx->rc_initial_buffer_occupancy)
> -            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3 / 4;
> +            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3ll / 4;

Didn't know you could use lower case for long long constants. Neat

>           if (avctx->ticks_per_frame && avctx->time_base.num &&
>               avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) {
> diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
> index 7f4e740a33..319a402faf 100644
> --- a/libavformat/aviobuf.c
> +++ b/libavformat/aviobuf.c
> @@ -259,7 +259,9 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
>           offset1 = pos + (s->buf_ptr - s->buffer);
>           if (offset == 0)
>               return offset1;
> -        offset += offset1;
> +        // Use unsigned type to avoid undefined behavior of singed overflow.
> +        // Code below will report error on overflow anyway.
> +        offset += (uint64_t)offset1;

I presume offset1 is some value which is never >= 1<<63?

>       }
>       if (offset < 0)
>           return AVERROR(EINVAL);
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index 522ce60c2d..a14c9f182b 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -5572,7 +5572,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>   
>       if (atom.size < 0)
>           atom.size = INT64_MAX;
> -    while (total_size + 8 <= atom.size && !avio_feof(pb)) {
> +    while (total_size <= atom.size - 8 && !avio_feof(pb)) {

atom.size can never be < 8?

/Tomas
Carl Eugen Hoyos Aug. 18, 2017, 8:13 a.m. UTC | #2
2017-08-18 8:14 GMT+02:00 Vitaly Buka <vitalybuka-at-google.com@ffmpeg.org>:
> Signed integer overflow is undefined behavior.
> Detected with clang and -fsanitize=signed-integer-overflow

> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -5572,7 +5572,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
>
>      if (atom.size < 0)
>          atom.size = INT64_MAX;
> -    while (total_size + 8 <= atom.size && !avio_feof(pb)) {
> +    while (total_size <= atom.size - 8 && !avio_feof(pb)) {

Can you provide the sample that produces this overflow?

Carl Eugen
Vitaly Buka Aug. 18, 2017, 8:48 p.m. UTC | #3
On Fri, Aug 18, 2017 at 1:11 AM, Tomas Härdin <tjoppen@acc.umu.se> wrote:

> On 2017-08-18 08:14, Vitaly Buka wrote:
>
>> Signed integer overflow is undefined behavior.
>> Detected with clang and -fsanitize=signed-integer-overflow
>>
>> Signed-off-by: Vitaly Buka <vitalybuka@google.com>
>> ---
>>   libavcodec/utils.c    | 2 +-
>>   libavformat/aviobuf.c | 4 +++-
>>   libavformat/mov.c     | 2 +-
>>   3 files changed, 5 insertions(+), 3 deletions(-)
>>
>> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
>> index 1336e921c9..024dc1f3e2 100644
>> --- a/libavcodec/utils.c
>> +++ b/libavcodec/utils.c
>> @@ -971,7 +971,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>>           }
>>             if (!avctx->rc_initial_buffer_occupancy)
>> -            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size
>> * 3 / 4;
>> +            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size
>> * 3ll / 4;
>>
>
> Didn't know you could use lower case for long long constants. Neat
>
>           if (avctx->ticks_per_frame && avctx->time_base.num &&
>>               avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) {
>> diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
>> index 7f4e740a33..319a402faf 100644
>> --- a/libavformat/aviobuf.c
>> +++ b/libavformat/aviobuf.c
>> @@ -259,7 +259,9 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int
>> whence)
>>           offset1 = pos + (s->buf_ptr - s->buffer);
>>           if (offset == 0)
>>               return offset1;
>> -        offset += offset1;
>> +        // Use unsigned type to avoid undefined behavior of singed
>> overflow.
>> +        // Code below will report error on overflow anyway.
>> +        offset += (uint64_t)offset1;
>>
>
> I presume offset1 is some value which is never >= 1<<63?

Yes. it's it int64 so max value is (1ll<<63 - 1)

>


>
>
>       }
>>       if (offset < 0)
>>           return AVERROR(EINVAL);
>> diff --git a/libavformat/mov.c b/libavformat/mov.c
>> index 522ce60c2d..a14c9f182b 100644
>> --- a/libavformat/mov.c
>> +++ b/libavformat/mov.c
>> @@ -5572,7 +5572,7 @@ static int mov_read_default(MOVContext *c,
>> AVIOContext *pb, MOVAtom atom)
>>         if (atom.size < 0)
>>           atom.size = INT64_MAX;
>> -    while (total_size + 8 <= atom.size && !avio_feof(pb)) {
>> +    while (total_size <= atom.size - 8 && !avio_feof(pb)) {
>>
>
> atom.size can never be < 8?
>
It does not matter. We just need atom.size never < (INT64_MIN + 8)



>
> /Tomas
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Vitaly Buka Aug. 18, 2017, 9:02 p.m. UTC | #4
Not sure or it's going to be very hard for me.
third_party/ffmpeg/LGPL_pristine/libavformat/aviobuf.c:225:16

Error was:
mov.c:3961:23: runtime error: signed integer overflow: 9223372036854775807
+ 8 cannot be represented in type 'long'

On Fri, Aug 18, 2017 at 1:13 AM, Carl Eugen Hoyos <ceffmpeg@gmail.com>
wrote:

> 2017-08-18 8:14 GMT+02:00 Vitaly Buka <vitalybuka-at-google.com@ffmpeg.org
> >:
> > Signed integer overflow is undefined behavior.
> > Detected with clang and -fsanitize=signed-integer-overflow
>
> > --- a/libavformat/mov.c
> > +++ b/libavformat/mov.c
> > @@ -5572,7 +5572,7 @@ static int mov_read_default(MOVContext *c,
> AVIOContext *pb, MOVAtom atom)
> >
> >      if (atom.size < 0)
> >          atom.size = INT64_MAX;
> > -    while (total_size + 8 <= atom.size && !avio_feof(pb)) {
> > +    while (total_size <= atom.size - 8 && !avio_feof(pb)) {
>
> Can you provide the sample that produces this overflow?
>
> Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Michael Niedermayer Aug. 19, 2017, 11:50 p.m. UTC | #5
On Thu, Aug 17, 2017 at 11:14:47PM -0700, Vitaly Buka wrote:
> Signed integer overflow is undefined behavior.
> Detected with clang and -fsanitize=signed-integer-overflow
> 
> Signed-off-by: Vitaly Buka <vitalybuka@google.com>
> ---
>  libavcodec/utils.c    | 2 +-
>  libavformat/aviobuf.c | 4 +++-
>  libavformat/mov.c     | 2 +-
>  3 files changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
> index 1336e921c9..024dc1f3e2 100644
> --- a/libavcodec/utils.c
> +++ b/libavcodec/utils.c
> @@ -971,7 +971,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>          }
>  
>          if (!avctx->rc_initial_buffer_occupancy)
> -            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3 / 4;
> +            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3ll / 4;
>  
>          if (avctx->ticks_per_frame && avctx->time_base.num &&
>              avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) {
> diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
> index 7f4e740a33..319a402faf 100644
> --- a/libavformat/aviobuf.c
> +++ b/libavformat/aviobuf.c
> @@ -259,7 +259,9 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
>          offset1 = pos + (s->buf_ptr - s->buffer);
>          if (offset == 0)
>              return offset1;
> -        offset += offset1;
> +        // Use unsigned type to avoid undefined behavior of singed overflow.
> +        // Code below will report error on overflow anyway.
> +        offset += (uint64_t)offset1;

instead of 2 lines of comments why not add a if() that checks for
the specififc case and error out instead of the cast?

The code from the patch depends on the input being limited range
and being followed by a check. If either changes then the cast to
uin64_t would silently give something wrong


[...]
diff mbox

Patch

diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 1336e921c9..024dc1f3e2 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -971,7 +971,7 @@  FF_ENABLE_DEPRECATION_WARNINGS
         }
 
         if (!avctx->rc_initial_buffer_occupancy)
-            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3 / 4;
+            avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3ll / 4;
 
         if (avctx->ticks_per_frame && avctx->time_base.num &&
             avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) {
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 7f4e740a33..319a402faf 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -259,7 +259,9 @@  int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
         offset1 = pos + (s->buf_ptr - s->buffer);
         if (offset == 0)
             return offset1;
-        offset += offset1;
+        // Use unsigned type to avoid undefined behavior of singed overflow.
+        // Code below will report error on overflow anyway.
+        offset += (uint64_t)offset1;
     }
     if (offset < 0)
         return AVERROR(EINVAL);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 522ce60c2d..a14c9f182b 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -5572,7 +5572,7 @@  static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 
     if (atom.size < 0)
         atom.size = INT64_MAX;
-    while (total_size + 8 <= atom.size && !avio_feof(pb)) {
+    while (total_size <= atom.size - 8 && !avio_feof(pb)) {
         int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL;
         a.size = atom.size;
         a.type=0;