1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "createns"
18 #include <log/log.h>
19
20 #include <cutils/properties.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <sched.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/mount.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31
32 #include <limits>
33 #include <string>
34 #include <vector>
35
36 static const char kNamespacePath[] = "/data/vendor/var/run/netns/";
37 static const char kProcNsNet[] = "/proc/self/ns/net";
38
39 class Fd {
40 public:
Fd(int fd)41 explicit Fd(int fd) : mFd(fd) { }
42 Fd(const Fd&) = delete;
~Fd()43 ~Fd() {
44 if (mFd != -1) {
45 ::close(mFd);
46 mFd = -1;
47 }
48 }
49
get() const50 int get() const { return mFd; }
51 Fd& operator=(const Fd&) = delete;
52 private:
53 int mFd;
54 };
55
usage(const char * program)56 static void usage(const char* program) {
57 ALOGE("%s <namespace>", program);
58 }
59
removeFile(const char * file)60 static bool removeFile(const char* file) {
61 if (::unlink(file) == -1) {
62 ALOGE("Failed to unlink file '%s': %s", file, strerror(errno));
63 return false;
64 }
65 return true;
66 }
67
getNamespacePath(const char * name)68 static std::string getNamespacePath(const char* name) {
69 size_t len = strlen(name);
70 if (len == 0) {
71 ALOGE("Must provide a namespace argument that is not empty");
72 return std::string();
73 }
74
75 if (std::numeric_limits<size_t>::max() - sizeof(kNamespacePath) < len) {
76 // The argument is so big the resulting string can't fit in size_t
77 ALOGE("Namespace argument too long");
78 return std::string();
79 }
80
81 std::vector<char> nsPath(sizeof(kNamespacePath) + len);
82 size_t totalSize = strlcpy(nsPath.data(), kNamespacePath, nsPath.size());
83 if (totalSize >= nsPath.size()) {
84 // The resulting string had to be concatenated to fit, this is a logic
85 // error in the code above that determines the size of the data.
86 ALOGE("Could not create namespace path");
87 return std::string();
88 }
89 totalSize = strlcat(nsPath.data(), name, nsPath.size());
90 if (totalSize >= nsPath.size()) {
91 // The resulting string had to be concatenated to fit, this is a logic
92 // error in the code above that determines the size of the data.
93 ALOGE("Could not append to namespace path");
94 return std::string();
95 }
96 return nsPath.data();
97 }
98
writeNamespacePid(const char * name,pid_t pid)99 static bool writeNamespacePid(const char* name, pid_t pid) {
100 std::string path = getNamespacePath(name);
101 if (path.empty()) {
102 return false;
103 }
104 path += ".pid";
105
106 Fd fd(::open(path.c_str(),
107 O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
108 S_IRUSR | S_IWUSR | S_IRGRP));
109 if (fd.get() == -1) {
110 ALOGE("Unable to create file '%s': %s", path.c_str(), strerror(errno));
111 return false;
112 }
113
114 // In order to safely print a pid_t we use int64_t with a known format
115 // specifier. Ensure that a pid_t will fit in a pid_t. According to POSIX
116 // pid_t is signed.
117 static_assert(sizeof(pid_t) <= sizeof(int64_t),
118 "pid_t is larger than int64_t");
119 char pidString[32];
120 int printed = snprintf(pidString,
121 sizeof(pidString),
122 "%" PRId64,
123 static_cast<int64_t>(pid));
124 if (printed <= 0) {
125 ALOGE("Unabled to created PID string for writing");
126 removeFile(path.c_str());
127 return false;
128 }
129
130 const char* toPrint = pidString;
131 int remaining = printed;
132 for (;;) {
133 int result = ::write(fd.get(), toPrint, remaining);
134 if (result < 0) {
135 if (errno == EINTR) {
136 continue;
137 }
138 ALOGE("Unable to write pid to file %s: %s",
139 path.c_str(), strerror(errno));
140 removeFile(path.c_str());
141 return false;
142 } else if (result < printed) {
143 remaining -= result;
144 toPrint += result;
145 } else {
146 break;
147 }
148 }
149 return true;
150 }
151
main(int argc,char * argv[])152 int main(int argc, char* argv[]) {
153 if (argc != 2) {
154 usage(argv[0]);
155 return 1;
156 }
157 if (::unshare(CLONE_NEWNET) != 0) {
158 ALOGE("Failed to create network namespace '%s': %s",
159 argv[1],
160 strerror(errno));
161 return 1;
162 }
163
164 std::string path = getNamespacePath(argv[1]);
165 if (path.empty()) {
166 return 1;
167 }
168 {
169 // Open and then immediately close the fd
170 Fd fd(::open(path.c_str(), O_CREAT|O_RDONLY, S_IRUSR | S_IRGRP));
171 if (fd.get() == -1) {
172 ALOGE("Failed to open file %s: %s", path.c_str(), strerror(errno));
173 return 1;
174 }
175 }
176 if (::mount(kProcNsNet, path.c_str(), nullptr, MS_BIND, nullptr) != 0) {
177 ALOGE("Failed to bind %s to %s: %s",
178 kProcNsNet,
179 path.c_str(),
180 strerror(errno));
181 // Clean up on failure
182 removeFile(path.c_str());
183 return 1;
184 }
185
186 if (!writeNamespacePid(argv[1], ::getpid())) {
187 return 1;
188 }
189 property_set("vendor.qemu.networknamespace", "ready");
190
191 for (;;) {
192 pause();
193 }
194
195 return 0;
196 }
197
198