Opened 4 years ago

Closed 4 years ago

#8716 closed defect (fixed)

Heap buffer overflow in ff_dnn_load_model_native

Reported by: Assaf Sion Owned by: Guo Yejun
Priority: important Component: avfilter
Version: git-master Keywords: dnn
Cc: assafsion@gmaiil.com, yejun.guo@intel.com Blocked By:
Blocking: Reproduced by developer: yes
Analyzed by developer: no

Description

In dnn_backend_native.c the call to ff_dnn_load_model_native could cause a heap buffer overflow caused by a missing check of the variable operand_index while accessing network->operands and setting the name. this could cause a read buffer overflow and may use as a primitive to leak addresses or sensitive memory.

I compiled ffmpeg on Ubuntu 18.04 with the following configuration:
configuration: --cc=clang --extra-cflags='-O0 -g3 -fsanitize=address -Wno-error -fPIC' --extra-ldflags='-O0 -g3 -fsanitize=address -Wno-error -fPIC' --enable-debug --disable-asm --disable-optimizations --disable-shared --enable-libopenjpeg --enable-gpl --enable-libass --enable-libfdk-aac --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-nonfree

the bug could be reproduced while running the following command line:
ffmpeg -v debug -i 10.jpg -vf format=rgb24,sr=dnn_backend=native:model=crash_dnn_backend_native_1 derain.jpg

the output after running the command:

ffmpeg version N-97806-gf603d10b1e Copyright (c) 2000-2020 the FFmpeg developers

built with clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
configuration: --cc=clang --extra-cflags='-O0 -g3 -fsanitize=address -Wno-error -fPIC' --extra-ldflags='-O0 -g3 -fsanitize=address -Wno-error -fPIC' --enable-debug --disable-asm --disable-optimizations --disable-shared --enable-libopenjpeg --enable-gpl --enable-libass --enable-libfdk-aac --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-nonfree
libavutil 56. 45.100 / 56. 45.100
libavcodec 58. 84.100 / 58. 84.100
libavformat 58. 43.100 / 58. 43.100
libavdevice 58. 9.103 / 58. 9.103
libavfilter 7. 81.100 / 7. 81.100
libswscale 5. 6.101 / 5. 6.101
libswresample 3. 6.100 / 3. 6.100
libpostproc 55. 6.100 / 55. 6.100

Splitting the commandline.
Reading option '-v' ... matched as option 'v' (set logging level) with argument 'debug'.
Reading option '-i' ... matched as input url with argument '10.jpg'.
Reading option '-vf' ... matched as option 'vf' (set video filters) with argument 'format=rgb24,sr=dnn_backend=native:model=crash_dnn_backend_native_1'.
Reading option 'derain.jpg' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option v (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input url 10.jpg.
Successfully parsed a group of options.
Opening an input file: 10.jpg.
[NULL @ 0x61b000000080] Opening '10.jpg' for reading
[file @ 0x60c000000040] Setting default whitelist 'file,crypto,data'
[image2 @ 0x61b000000080] Format image2 probed with size=2048 and score=50
[image2 @ 0x61b000000080] Before avformat_find_stream_info() pos: 0 bytes read:18522 seeks:0 nb_streams:1
[mjpeg @ 0x619000000580] marker=d8 avail_size_in_buf=18520
[mjpeg @ 0x619000000580] marker parser used 0 bytes (0 bits)
[mjpeg @ 0x619000000580] marker=e0 avail_size_in_buf=18518
[mjpeg @ 0x619000000580] marker parser used 16 bytes (128 bits)
[mjpeg @ 0x619000000580] marker=e1 avail_size_in_buf=18500
[mjpeg @ 0x619000000580] marker parser used 12833 bytes (102664 bits)
[mjpeg @ 0x619000000580] marker=db avail_size_in_buf=5664
[mjpeg @ 0x619000000580] index=0
[mjpeg @ 0x619000000580] qscale[0]: 2
[mjpeg @ 0x619000000580] marker parser used 67 bytes (536 bits)
[mjpeg @ 0x619000000580] marker=db avail_size_in_buf=5595
[mjpeg @ 0x619000000580] index=1
[mjpeg @ 0x619000000580] qscale[1]: 8
[mjpeg @ 0x619000000580] marker parser used 67 bytes (536 bits)
[mjpeg @ 0x619000000580] marker=c0 avail_size_in_buf=5526
[mjpeg @ 0x619000000580] Changing bps from 0 to 8
[mjpeg @ 0x619000000580] sof0: picture: 432x173
[mjpeg @ 0x619000000580] component 0 1:1 id: 0 quant:0
[mjpeg @ 0x619000000580] component 1 1:1 id: 1 quant:1
[mjpeg @ 0x619000000580] component 2 1:1 id: 2 quant:1
[mjpeg @ 0x619000000580] pix fmt id 11111100
[mjpeg @ 0x619000000580] Format yuvj444p chosen by get_format().
[mjpeg @ 0x619000000580] marker parser used 17 bytes (136 bits)
[mjpeg @ 0x619000000580] marker=c4 avail_size_in_buf=5507
[mjpeg @ 0x619000000580] marker parser used 0 bytes (0 bits)
[mjpeg @ 0x619000000580] marker=c4 avail_size_in_buf=5478
[mjpeg @ 0x619000000580] marker parser used 0 bytes (0 bits)
[mjpeg @ 0x619000000580] marker=c4 avail_size_in_buf=5420
[mjpeg @ 0x619000000580] marker parser used 0 bytes (0 bits)
[mjpeg @ 0x619000000580] marker=c4 avail_size_in_buf=5393
[mjpeg @ 0x619000000580] marker parser used 0 bytes (0 bits)
[mjpeg @ 0x619000000580] escaping removed 16 bytes
[mjpeg @ 0x619000000580] marker=da avail_size_in_buf=5360
[mjpeg @ 0x619000000580] marker parser used 5344 bytes (42752 bits)
[mjpeg @ 0x619000000580] marker=d9 avail_size_in_buf=0
[mjpeg @ 0x619000000580] decode frame unused 0 bytes
[image2 @ 0x61b000000080] After avformat_find_stream_info() pos: 18522 bytes read:18522 seeks:0 frames:1
Input #0, image2, from '10.jpg':

Duration: 00:00:00.04, start: 0.000000, bitrate: 3704 kb/s

Stream #0:0, 1, 1/25: Video: mjpeg (Baseline), 1 reference frame, yuvj444p(pc, bt470bg/unknown/unknown, center), 432x173 [SAR 96:96 DAR 432:173], 0/1, 25 tbr, 25 tbn, 25 tbc

Successfully opened the file.
Parsing a group of options: output url derain.jpg.
Applying option vf (set video filters) with argument format=rgb24,sr=dnn_backend=native:model=crash_dnn_backend_native_1.
Successfully parsed a group of options.
Opening an output file: derain.jpg.
Successfully opened the file.
Stream mapping:

Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))

Press [q] to stop, ? for help
cur_dts is invalid st:0 (0) [init:0 i_done:0 finish:0] (this is harmless if it occurs once at the start per stream)
[mjpeg @ 0x619000000a80] marker=d8 avail_size_in_buf=18520
[mjpeg @ 0x619000000a80] marker parser used 0 bytes (0 bits)
[mjpeg @ 0x619000000a80] marker=e0 avail_size_in_buf=18518
[mjpeg @ 0x619000000a80] marker parser used 16 bytes (128 bits)
[mjpeg @ 0x619000000a80] marker=e1 avail_size_in_buf=18500
[mjpeg @ 0x619000000a80] marker parser used 12833 bytes (102664 bits)
[mjpeg @ 0x619000000a80] marker=db avail_size_in_buf=5664
[mjpeg @ 0x619000000a80] index=0
[mjpeg @ 0x619000000a80] qscale[0]: 2
[mjpeg @ 0x619000000a80] marker parser used 67 bytes (536 bits)
[mjpeg @ 0x619000000a80] marker=db avail_size_in_buf=5595
[mjpeg @ 0x619000000a80] index=1
[mjpeg @ 0x619000000a80] qscale[1]: 8
[mjpeg @ 0x619000000a80] marker parser used 67 bytes (536 bits)
[mjpeg @ 0x619000000a80] marker=c0 avail_size_in_buf=5526
[mjpeg @ 0x619000000a80] sof0: picture: 432x173
[mjpeg @ 0x619000000a80] component 0 1:1 id: 0 quant:0
[mjpeg @ 0x619000000a80] component 1 1:1 id: 1 quant:1
[mjpeg @ 0x619000000a80] component 2 1:1 id: 2 quant:1
[mjpeg @ 0x619000000a80] pix fmt id 11111100
[mjpeg @ 0x619000000a80] Format yuvj444p chosen by get_format().
[mjpeg @ 0x619000000a80] marker parser used 17 bytes (136 bits)
[mjpeg @ 0x619000000a80] marker=c4 avail_size_in_buf=5507
[mjpeg @ 0x619000000a80] class=0 index=0 nb_codes=8
[mjpeg @ 0x619000000a80] marker parser used 27 bytes (216 bits)
[mjpeg @ 0x619000000a80] marker=c4 avail_size_in_buf=5478
[mjpeg @ 0x619000000a80] class=1 index=0 nb_codes=226
[mjpeg @ 0x619000000a80] marker parser used 56 bytes (448 bits)
[mjpeg @ 0x619000000a80] marker=c4 avail_size_in_buf=5420
[mjpeg @ 0x619000000a80] class=0 index=1 nb_codes=6
[mjpeg @ 0x619000000a80] marker parser used 25 bytes (200 bits)
[mjpeg @ 0x619000000a80] marker=c4 avail_size_in_buf=5393
[mjpeg @ 0x619000000a80] class=1 index=1 nb_codes=82
[mjpeg @ 0x619000000a80] marker parser used 31 bytes (248 bits)
[mjpeg @ 0x619000000a80] escaping removed 16 bytes
[mjpeg @ 0x619000000a80] marker=da avail_size_in_buf=5360
[mjpeg @ 0x619000000a80] component: 0
[mjpeg @ 0x619000000a80] component: 1
[mjpeg @ 0x619000000a80] component: 2
[mjpeg @ 0x619000000a80] marker parser used 5343 bytes (42742 bits)
[mjpeg @ 0x619000000a80] marker=d9 avail_size_in_buf=0
[mjpeg @ 0x619000000a80] decode frame unused 0 bytes
detected 32 logical cores
[Parsed_format_0 @ 0x610000000040] Setting 'pix_fmts' to value 'rgb24'
[Parsed_sr_1 @ 0x610000000140] Setting 'dnn_backend' to value 'native'
[Parsed_sr_1 @ 0x610000000140] Setting 'model' to value 'crash_dnn_backend_native_1'
[file @ 0x60d000000040] Setting default whitelist 'file,crypto,data'
=================================================================
==95291==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x610000000a99 at pc 0x0000013b0b46 bp 0x7fffffff81e0 sp 0x7fffffff81d8
WRITE of size 1 at 0x610000000a99 thread T0

#0 0x13b0b45 in avio_get_str /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavformat/aviobuf.c:866:22
#1 0x130d50e in ff_dnn_load_model_native /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/dnn/dnn_backend_native.c:233:9
#2 0xe5802e in init /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/vf_sr.c:84:25
#3 0x6c56ca in avfilter_init_dict /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/avfilter.c:912:15
#4 0x6c6747 in avfilter_init_str /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/avfilter.c:1013:11
#5 0x74b4fe in create_filter /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/graphparser.c:149:11
#6 0x747826 in parse_filter /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/graphparser.c:192:11
#7 0x74685f in avfilter_graph_parse2 /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavfilter/graphparser.c:427:20
#8 0x5687d7 in configure_filtergraph /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg_filter.c:1061:16
#9 0x5d66a3 in ifilter_send_frame /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:2166:15
#10 0x5d5669 in send_frame_to_filters /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:2247:15
#11 0x5d0f2b in decode_video /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:2446:11
#12 0x59ba41 in process_input_packet /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:2600:19
#13 0x5be936 in process_input /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:4491:5
#14 0x597af6 in transcode_step /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:4611:11
#15 0x590da5 in transcode /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:4665:15
#16 0x58efda in main /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/fftools/ffmpeg.c:4866:9
#17 0x7ffff2cb9b96 in libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
#18 0x423839 in _start (/home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/ffmpeg_g+0x423839)

Address 0x610000000a99 is a wild pointer.
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/cyber/VulnResearch/ffmpeg/clean/13_5_ffmpeg/FFmpeg/libavformat/aviobuf.c:866:22 in avio_get_str
Shadow bytes around the buggy address:

0x0c207fff8100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

=>0x0c207fff8150: fa fa fa[fa]fa fa fa fa fa fa fa fa fa fa fa fa

0x0c207fff8160: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff8190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c207fff81a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

Shadow byte legend (one shadow byte represents 8 application bytes):

Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb

==95291==ABORTING
[1] + Done "/usr/bin/gdb" --interpreter=mi --tty=${DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-tnrcrzm8.01d" 1>"/tmp/Microsoft-MIEngine-Out-7wia81vb.b6z"

Attachments (2)

10.jpg (18.1 KB ) - added by Assaf Sion 4 years ago.
crash_dnn_backend_native_1 (111 bytes ) - added by Assaf Sion 4 years ago.

Download all attachments as: .zip

Change History (10)

by Assaf Sion, 4 years ago

Attachment: 10.jpg added

by Assaf Sion, 4 years ago

Attachment: crash_dnn_backend_native_1 added

comment:1 by Guo Yejun, 4 years ago

Cc: yejun.guo@intel.com added
Owner: set to Guo Yejun
Status: newopen
  1. could you please re-generate the native model with script tools/python/convert.py and try it again?

I checked file crash_dnn_backend_native_1 and there might be a version mismatch. (There is version checking now in ffmpeg c/python code.)

  1. if the issue still exists with step 1, could you share the .pb file?

thanks.

comment:2 by Assaf Sion, 4 years ago

The bug won`t trigger without the native model that I crafted my self.
The whole reason for this is bug is when using a crafted model file, you could trigger the bug.

comment:3 by Guo Yejun, 4 years ago

sorry, i don't quite understand you meaning.

could you share how you generate file crash_dnn_backend_native_1, thanks.

comment:4 by Assaf Sion, 4 years ago

I manually crafted it.
I am a security researcher and I noticed that this part of the code could be exploited,
Therefor, I crafted crash_dnn_backend_native_1 myself.

comment:5 by Carl Eugen Hoyos, 4 years ago

Keywords: dnn added
Priority: criticalimportant
Reproduced by developer: set

Also reproducible with valgrind.

comment:6 by Guo Yejun, 4 years ago

thanks, the patch for the fix is sent out, see https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=1463

comment:7 by Assaf Sion, 4 years ago

This bug was assigned with CVE-2020-14212.

comment:8 by Carl Eugen Hoyos, 4 years ago

Resolution: fixed
Status: openclosed
Note: See TracTickets for help on using tickets.