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