1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #include "sandboxed_api/sandbox2/buffer.h"
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include <sys/mman.h>
18*ec63e07aSXin Li #include <sys/stat.h>
19*ec63e07aSXin Li #include <unistd.h>
20*ec63e07aSXin Li
21*ec63e07aSXin Li #include <cerrno>
22*ec63e07aSXin Li #include <cstddef>
23*ec63e07aSXin Li #include <cstdint>
24*ec63e07aSXin Li #include <memory>
25*ec63e07aSXin Li #include <utility>
26*ec63e07aSXin Li
27*ec63e07aSXin Li #include "absl/memory/memory.h"
28*ec63e07aSXin Li #include "absl/status/status.h"
29*ec63e07aSXin Li #include "absl/status/statusor.h"
30*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util.h"
31*ec63e07aSXin Li
32*ec63e07aSXin Li namespace sandbox2 {
33*ec63e07aSXin Li
34*ec63e07aSXin Li // Creates a new Buffer that is backed by the specified file descriptor.
CreateFromFd(int fd)35*ec63e07aSXin Li absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateFromFd(int fd) {
36*ec63e07aSXin Li // Using `new` to access a non-public constructor.
37*ec63e07aSXin Li auto buffer = absl::WrapUnique(new Buffer());
38*ec63e07aSXin Li
39*ec63e07aSXin Li struct stat stat_buf;
40*ec63e07aSXin Li if (fstat(fd, &stat_buf) != 0) {
41*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "Could not stat buffer fd");
42*ec63e07aSXin Li }
43*ec63e07aSXin Li size_t size = stat_buf.st_size;
44*ec63e07aSXin Li int prot = PROT_READ | PROT_WRITE;
45*ec63e07aSXin Li int flags = MAP_SHARED;
46*ec63e07aSXin Li off_t offset = 0;
47*ec63e07aSXin Li buffer->buf_ =
48*ec63e07aSXin Li reinterpret_cast<uint8_t*>(mmap(nullptr, size, prot, flags, fd, offset));
49*ec63e07aSXin Li if (buffer->buf_ == MAP_FAILED) {
50*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "Could not map buffer fd");
51*ec63e07aSXin Li }
52*ec63e07aSXin Li buffer->fd_ = fd;
53*ec63e07aSXin Li buffer->size_ = size;
54*ec63e07aSXin Li return std::move(buffer); // GCC 7 needs the move (C++ DR #1579)
55*ec63e07aSXin Li }
56*ec63e07aSXin Li
57*ec63e07aSXin Li // Creates a new Buffer of the specified size, backed by a temporary file that
58*ec63e07aSXin Li // will be immediately deleted.
CreateWithSize(size_t size)59*ec63e07aSXin Li absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(size_t size) {
60*ec63e07aSXin Li int fd;
61*ec63e07aSXin Li if (!util::CreateMemFd(&fd)) {
62*ec63e07aSXin Li return absl::InternalError("Could not create buffer temp file");
63*ec63e07aSXin Li }
64*ec63e07aSXin Li if (ftruncate(fd, size) != 0) {
65*ec63e07aSXin Li return absl::ErrnoToStatus(errno, "Could not extend buffer fd");
66*ec63e07aSXin Li }
67*ec63e07aSXin Li return CreateFromFd(fd);
68*ec63e07aSXin Li }
69*ec63e07aSXin Li
~Buffer()70*ec63e07aSXin Li Buffer::~Buffer() {
71*ec63e07aSXin Li if (buf_ != nullptr) {
72*ec63e07aSXin Li munmap(buf_, size_);
73*ec63e07aSXin Li }
74*ec63e07aSXin Li if (fd_ != -1) {
75*ec63e07aSXin Li close(fd_);
76*ec63e07aSXin Li }
77*ec63e07aSXin Li }
78*ec63e07aSXin Li
79*ec63e07aSXin Li } // namespace sandbox2
80