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 // Checks various things related to namespaces, depending on the first argument:
16 // ./binary 0 <file1> <file2> ... <fileN>:
17 // Make sure all provided files exist and are RO, return 0 on OK.
18 // Returns the index of the first non-existing file on failure.
19 // ./binary 1 <file1> <file2> ... <fileN>:
20 // Make sure all provided files exist and are RW, return 0 on OK.
21 // Returns the index of the first non-existing file on failure.
22 // ./binary 2
23 // Make sure that we run in a PID namespace (this implies getpid() == 1)
24 // Returns 0 on OK.
25 // ./binary 3 <uid> <gid>
26 // Make sure getuid()/getgid() returns the provided uid/gid (User namespace).
27 // Returns 0 on OK.
28 // ./binary 4 <file1> <file2> ... <fileN>:
29 // Create provided files, return 0 on OK.
30 // Returns the index of the first non-creatable file on failure.
31 #include <fcntl.h>
32 #include <ifaddrs.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35
36 #include <cstdlib>
37 #include <string>
38 #include <vector>
39
40 #include "absl/container/flat_hash_set.h"
41 #include "absl/log/check.h"
42 #include "absl/strings/str_cat.h"
43 #include "sandboxed_api/sandbox2/comms.h"
44 #include "sandboxed_api/util/fileops.h"
45 #include "sandboxed_api/util/path.h"
46
47 namespace {
48
49 using sapi::file::JoinPath;
50 using sapi::file_util::fileops::ListDirectoryEntries;
51
IsDirectory(const std::string & path)52 bool IsDirectory(const std::string& path) {
53 struct stat statbuf;
54 PCHECK(lstat(path.c_str(), &statbuf) == 0) << "Failed to stat " << path;
55 return statbuf.st_mode & S_IFDIR;
56 }
57
ListDirectoriesRecursively(const std::string & path,std::vector<std::string> & files)58 void ListDirectoriesRecursively(const std::string& path,
59 std::vector<std::string>& files) {
60 std::string error;
61 std::vector<std::string> entries;
62 CHECK(ListDirectoryEntries(path, &entries, &error)) << error;
63 for (const std::string& entry : entries) {
64 std::string new_path = JoinPath(path, entry);
65 // Don't descent into /sys or /proc, just mark their existence
66 if (new_path == "/sys" || new_path == "/proc") {
67 files.push_back(new_path);
68 continue;
69 }
70 if (IsDirectory(new_path)) {
71 ListDirectoriesRecursively(new_path, files);
72 } else {
73 files.push_back(new_path);
74 }
75 }
76 }
77
78 } // namespace
79
main(int argc,char * argv[])80 int main(int argc, char* argv[]) {
81 if (argc < 2) {
82 return 0;
83 }
84
85 int mode = atoi(argv[1]); // NOLINT(runtime/deprecated_fn)
86 std::vector<std::string> result;
87
88 sandbox2::Comms comms(sandbox2::Comms::kDefaultConnection);
89
90 switch (mode) {
91 case 0:
92 // Make sure file exist
93 for (int i = 2; i < argc; i++) {
94 if (access(argv[i], R_OK) == 0) {
95 result.push_back(argv[i]);
96 }
97 }
98 break;
99
100 case 1:
101 for (int i = 2; i < argc; i++) {
102 if (access(argv[i], W_OK) == 0) {
103 result.push_back(argv[i]);
104 }
105 }
106 break;
107
108 case 2:
109 result.push_back(absl::StrCat(getpid()));
110 break;
111
112 case 3:
113 result.push_back(absl::StrCat(getuid()));
114 result.push_back(absl::StrCat(getgid()));
115 break;
116
117 case 4:
118 for (int i = 2; i < argc; ++i) {
119 if (open(argv[i], O_CREAT | O_WRONLY, 0644) != -1) {
120 result.push_back(argv[i]);
121 }
122 }
123 break;
124
125 case 5: {
126 absl::flat_hash_set<std::string> ifnames;
127 struct ifaddrs* addrs;
128 if (getifaddrs(&addrs)) {
129 return -1;
130 }
131 for (struct ifaddrs* cur = addrs; cur; cur = cur->ifa_next) {
132 ifnames.insert(cur->ifa_name);
133 }
134 result.insert(result.end(), ifnames.begin(), ifnames.end());
135 freeifaddrs(addrs);
136 break;
137 }
138
139 case 6:
140 ListDirectoriesRecursively(argv[2], result);
141 break;
142 case 7: {
143 char hostname[1000];
144 if (gethostname(hostname, sizeof(hostname)) == -1) {
145 return -1;
146 }
147 result.push_back(hostname);
148 break;
149 }
150
151 default:
152 return 1;
153 }
154
155 CHECK(comms.SendUint64(result.size()));
156 for (const std::string& entry : result) {
157 CHECK(comms.SendString(entry));
158 }
159 return 0;
160 }
161