summaryrefslogtreecommitdiffstats
path: root/chromium/media/gpu/buffer_validation.cc
blob: 3b7921b1b8a83dc25e1a0ca88b1b41d751aacd75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/gpu/buffer_validation.h"

#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
#include "media/base/video_frame.h"
#include "media/gpu/macros.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_memory_buffer.h"

#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include <sys/types.h>
#include <unistd.h>
#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)

namespace media {

bool GetFileSize(const int fd, size_t* size) {
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
  if (fd < 0) {
    VLOGF(1) << "Invalid file descriptor";
    return false;
  }

  off_t fd_size = lseek(fd, 0, SEEK_END);
  lseek(fd, 0, SEEK_SET);
  if (fd_size < 0u) {
    VPLOGF(1) << "Fail to find the size of fd";
    return false;
  }

  if (!base::IsValueInRangeForNumericType<size_t>(fd_size)) {
    VLOGF(1) << "fd_size is out of range of size_t"
             << ", size=" << size
             << ", size_t max=" << std::numeric_limits<size_t>::max()
             << ", size_t min=" << std::numeric_limits<size_t>::min();
    return false;
  }

  *size = static_cast<size_t>(fd_size);
  return true;
#else
  NOTIMPLEMENTED();
  return false;
#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
}

bool VerifyGpuMemoryBufferHandle(media::VideoPixelFormat pixel_format,
                                 const gfx::Size& coded_size,
                                 const gfx::GpuMemoryBufferHandle& gmb_handle) {
  if (gmb_handle.type != gfx::NATIVE_PIXMAP) {
    VLOGF(1) << "Unexpected GpuMemoryBufferType: " << gmb_handle.type;
    return false;
  }
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
  const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format);
  if (num_planes != gmb_handle.native_pixmap_handle.planes.size() ||
      num_planes == 0) {
    VLOGF(1) << "Invalid number of dmabuf planes passed: "
             << gmb_handle.native_pixmap_handle.planes.size()
             << ", expected: " << num_planes;
    return false;
  }

  // Strides monotonically decrease.
  for (size_t i = 1; i < num_planes; i++) {
    if (gmb_handle.native_pixmap_handle.planes[i - 1].stride <
        gmb_handle.native_pixmap_handle.planes[i].stride) {
      return false;
    }
  }

  for (size_t i = 0; i < num_planes; i++) {
    const auto& plane = gmb_handle.native_pixmap_handle.planes[i];
    DVLOGF(4) << "Plane " << i << ", offset: " << plane.offset
              << ", stride: " << plane.stride;

    size_t file_size_in_bytes;
    if (!plane.fd.is_valid() ||
        !GetFileSize(plane.fd.get(), &file_size_in_bytes))
      return false;

    size_t plane_height =
        media::VideoFrame::Rows(i, pixel_format, coded_size.height());
    base::CheckedNumeric<size_t> min_plane_size =
        base::CheckMul(plane.stride, plane_height);
    if (!min_plane_size.IsValid() || min_plane_size.ValueOrDie() > plane.size) {
      VLOGF(1) << "Invalid strides/sizes";
      return false;
    }

    // Check |offset| + (the size of a plane) on each plane is not larger than
    // |file_size_in_bytes|. This ensures we don't access out of a buffer
    // referred by |fd|.
    base::CheckedNumeric<size_t> min_buffer_size =
        base::CheckAdd(plane.offset, plane.size);
    if (!min_buffer_size.IsValid() ||
        min_buffer_size.ValueOrDie() > file_size_in_bytes) {
      VLOGF(1) << "Invalid strides/offsets";
      return false;
    }
  }
  return true;
#else
  NOTIMPLEMENTED();
  return false;
#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
}

}  // namespace media