xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/embed_file.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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/embed_file.h"
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include <fcntl.h>
18*ec63e07aSXin Li #include <sys/stat.h>
19*ec63e07aSXin Li #include <unistd.h>
20*ec63e07aSXin Li 
21*ec63e07aSXin Li #include <string>
22*ec63e07aSXin Li 
23*ec63e07aSXin Li #include "sandboxed_api/file_toc.h"
24*ec63e07aSXin Li #include "absl/strings/str_cat.h"
25*ec63e07aSXin Li #include "absl/synchronization/mutex.h"
26*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util.h"
27*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h"
28*ec63e07aSXin Li #include "sandboxed_api/util/raw_logging.h"
29*ec63e07aSXin Li 
30*ec63e07aSXin Li namespace sapi {
31*ec63e07aSXin Li 
32*ec63e07aSXin Li namespace {
33*ec63e07aSXin Li 
34*ec63e07aSXin Li #ifndef F_ADD_SEALS
35*ec63e07aSXin Li #define F_ADD_SEALS 1033
36*ec63e07aSXin Li #define F_SEAL_SEAL 0x0001
37*ec63e07aSXin Li #define F_SEAL_SHRINK 0x0002
38*ec63e07aSXin Li #define F_SEAL_GROW 0x0004
39*ec63e07aSXin Li #define F_SEAL_WRITE 0x0008
40*ec63e07aSXin Li #endif
41*ec63e07aSXin Li 
SealFile(int fd)42*ec63e07aSXin Li bool SealFile(int fd) {
43*ec63e07aSXin Li   constexpr int kMaxRetries = 10;
44*ec63e07aSXin Li   for (int i = 0; i < kMaxRetries; ++i) {
45*ec63e07aSXin Li     if (fcntl(fd, F_ADD_SEALS,
46*ec63e07aSXin Li               F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE) == 0) {
47*ec63e07aSXin Li       return true;
48*ec63e07aSXin Li     }
49*ec63e07aSXin Li   }
50*ec63e07aSXin Li   return false;
51*ec63e07aSXin Li }
52*ec63e07aSXin Li 
53*ec63e07aSXin Li }  // namespace
54*ec63e07aSXin Li 
instance()55*ec63e07aSXin Li EmbedFile* EmbedFile::instance() {
56*ec63e07aSXin Li   static auto* embed_file_instance = new EmbedFile();
57*ec63e07aSXin Li   return embed_file_instance;
58*ec63e07aSXin Li }
59*ec63e07aSXin Li 
CreateFdForFileToc(const FileToc * toc)60*ec63e07aSXin Li int EmbedFile::CreateFdForFileToc(const FileToc* toc) {
61*ec63e07aSXin Li   // Create a memfd/temp file and write contents of the SAPI library to it.
62*ec63e07aSXin Li   int fd = -1;
63*ec63e07aSXin Li   if (!sandbox2::util::CreateMemFd(&fd, toc->name)) {
64*ec63e07aSXin Li     SAPI_RAW_LOG(ERROR, "Couldn't create a temporary file for TOC name '%s'",
65*ec63e07aSXin Li                  toc->name);
66*ec63e07aSXin Li     return -1;
67*ec63e07aSXin Li   }
68*ec63e07aSXin Li   file_util::fileops::FDCloser embed_fd(fd);
69*ec63e07aSXin Li 
70*ec63e07aSXin Li   if (!file_util::fileops::WriteToFD(embed_fd.get(), toc->data, toc->size)) {
71*ec63e07aSXin Li     SAPI_RAW_PLOG(ERROR, "Couldn't write SAPI embed file '%s' to memfd file",
72*ec63e07aSXin Li                   toc->name);
73*ec63e07aSXin Li     return -1;
74*ec63e07aSXin Li   }
75*ec63e07aSXin Li 
76*ec63e07aSXin Li   // Make the underlying file non-writeable.
77*ec63e07aSXin Li   if (fchmod(embed_fd.get(),
78*ec63e07aSXin Li              S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
79*ec63e07aSXin Li     SAPI_RAW_PLOG(ERROR, "Could't make FD=%d RX-only", embed_fd.get());
80*ec63e07aSXin Li     return -1;
81*ec63e07aSXin Li   }
82*ec63e07aSXin Li 
83*ec63e07aSXin Li   // Seal the file
84*ec63e07aSXin Li   if (!SealFile(embed_fd.get())) {
85*ec63e07aSXin Li     SAPI_RAW_PLOG(ERROR, "Couldn't apply file seals to FD=%d", embed_fd.get());
86*ec63e07aSXin Li     return -1;
87*ec63e07aSXin Li   }
88*ec63e07aSXin Li 
89*ec63e07aSXin Li   // Instead of working around problems with CRIU we reopen the file as
90*ec63e07aSXin Li   // read-only.
91*ec63e07aSXin Li   fd = open(absl::StrCat("/proc/", getpid(), "/fd/", embed_fd.get()).c_str(),
92*ec63e07aSXin Li             O_RDONLY | O_CLOEXEC);
93*ec63e07aSXin Li   if (fd == -1) {
94*ec63e07aSXin Li     SAPI_RAW_PLOG(ERROR, "Couldn't reopen '%d' read-only through /proc",
95*ec63e07aSXin Li                   embed_fd.get());
96*ec63e07aSXin Li     return -1;
97*ec63e07aSXin Li   }
98*ec63e07aSXin Li   return fd;
99*ec63e07aSXin Li }
100*ec63e07aSXin Li 
GetFdForFileToc(const FileToc * toc)101*ec63e07aSXin Li int EmbedFile::GetFdForFileToc(const FileToc* toc) {
102*ec63e07aSXin Li   // Access to file_tocs_ must be guarded.
103*ec63e07aSXin Li   absl::MutexLock lock{&file_tocs_mutex_};
104*ec63e07aSXin Li 
105*ec63e07aSXin Li   // If a file-descriptor for this toc already exists, just return it.
106*ec63e07aSXin Li   auto entry = file_tocs_.find(toc);
107*ec63e07aSXin Li   if (entry != file_tocs_.end()) {
108*ec63e07aSXin Li     SAPI_RAW_VLOG(3,
109*ec63e07aSXin Li                   "Returning pre-existing embed file entry for '%s', fd: %d "
110*ec63e07aSXin Li                   "(orig name: '%s')",
111*ec63e07aSXin Li                   toc->name, entry->second, entry->first->name);
112*ec63e07aSXin Li     return entry->second;
113*ec63e07aSXin Li   }
114*ec63e07aSXin Li 
115*ec63e07aSXin Li   int embed_fd = CreateFdForFileToc(toc);
116*ec63e07aSXin Li   if (embed_fd == -1) {
117*ec63e07aSXin Li     SAPI_RAW_LOG(ERROR, "Cannot create a file for FileTOC: '%s'", toc->name);
118*ec63e07aSXin Li     return -1;
119*ec63e07aSXin Li   }
120*ec63e07aSXin Li 
121*ec63e07aSXin Li   SAPI_RAW_VLOG(1, "Created new embed file entry for '%s' with fd: %d",
122*ec63e07aSXin Li                 toc->name, embed_fd);
123*ec63e07aSXin Li 
124*ec63e07aSXin Li   file_tocs_[toc] = embed_fd;
125*ec63e07aSXin Li   return embed_fd;
126*ec63e07aSXin Li }
127*ec63e07aSXin Li 
GetDupFdForFileToc(const FileToc * toc)128*ec63e07aSXin Li int EmbedFile::GetDupFdForFileToc(const FileToc* toc) {
129*ec63e07aSXin Li   int fd = GetFdForFileToc(toc);
130*ec63e07aSXin Li   if (fd == -1) {
131*ec63e07aSXin Li     return -1;
132*ec63e07aSXin Li   }
133*ec63e07aSXin Li   fd = dup(fd);
134*ec63e07aSXin Li   if (fd == -1) {
135*ec63e07aSXin Li     SAPI_RAW_PLOG(ERROR, "dup failed");
136*ec63e07aSXin Li   }
137*ec63e07aSXin Li   return fd;
138*ec63e07aSXin Li }
139*ec63e07aSXin Li 
140*ec63e07aSXin Li }  // namespace sapi
141