| /** |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <stdlib.h> |
| |
| #ifdef TEST_ARM32 |
| #include <unistd.h> |
| #include "../includes/common.h" |
| |
| #include <string.h> |
| #include <algorithm> |
| #include <vector> |
| #include "vpx/vp8dx.h" |
| #include "vpx/vpx_decoder.h" |
| #include "vpx_ports/mem_ops.h" |
| |
| #define IVF_FILE_HDR_SZ 32 |
| #define IVF_FRAME_HDR_SZ (4 + 8) /* 4 byte size + 8 byte timestamp */ |
| |
| FILE *fp = nullptr; |
| |
| void exitHandler(void) { |
| if (fp) { |
| fclose(fp); |
| } |
| } |
| |
| bool testInProgress = false; |
| struct sigaction new_action, old_action; |
| void sigabrt_handler(int32_t signum, siginfo_t *info, void* context) { |
| if (testInProgress && info->si_signo == SIGABRT) { |
| (*old_action.sa_sigaction)(signum, info, context); |
| return; |
| } |
| _exit(EXIT_FAILURE); |
| } |
| #endif |
| |
| int32_t main(int32_t argc, char **argv) { |
| (void)argc; |
| (void)argv; |
| |
| #ifdef TEST_ARM32 |
| atexit(exitHandler); |
| |
| sigemptyset(&new_action.sa_mask); |
| new_action.sa_flags = SA_SIGINFO; |
| new_action.sa_sigaction = sigabrt_handler; |
| sigaction(SIGABRT, &new_action, &old_action); |
| |
| FAIL_CHECK(argc >= 2); |
| fp = fopen(argv[1], "rb"); |
| FAIL_CHECK(fp); |
| |
| fseek(fp, 0, SEEK_END); |
| size_t size = ftell(fp); |
| fseek(fp, 0, SEEK_SET); |
| FAIL_CHECK(size > IVF_FILE_HDR_SZ); |
| |
| std::vector<uint8_t> buffer(size); |
| FAIL_CHECK(fread((void *)buffer.data(), sizeof(uint8_t), size, fp) == size); |
| |
| vpx_codec_ctx_t codec; |
| vpx_codec_dec_cfg_t cfg; |
| memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t)); |
| cfg.threads = 1; |
| FAIL_CHECK(vpx_codec_dec_init(&codec, &vpx_codec_vp8_dx_algo, &cfg, 0) == VPX_CODEC_OK); |
| |
| uint8_t *data = buffer.data(); |
| data += IVF_FILE_HDR_SZ; |
| size -= IVF_FILE_HDR_SZ; |
| |
| while (size > IVF_FRAME_HDR_SZ) { |
| size_t frame_size = mem_get_le32(data); |
| size -= IVF_FRAME_HDR_SZ; |
| data += IVF_FRAME_HDR_SZ; |
| frame_size = std::min(size, frame_size); |
| |
| testInProgress = true; |
| vpx_codec_decode(&codec, data, frame_size, nullptr, 0); |
| testInProgress = false; |
| |
| vpx_codec_iter_t iter = nullptr; |
| vpx_image_t *img = nullptr; |
| while ((img = vpx_codec_get_frame(&codec, &iter)) != nullptr) { |
| if (img->d_w > img->w || img->d_h > img->h) { |
| return EXIT_VULNERABLE; |
| } |
| } |
| data += frame_size; |
| size -= frame_size; |
| } |
| vpx_codec_destroy(&codec); |
| #endif |
| |
| return EXIT_SUCCESS; |
| } |