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 #include "namespace.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <linux/limits.h>
22 #include <sched.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #include "log.h"
29
30 static const char kNetNsDir[] = "/data/vendor/var/run/netns";
31
32 // Set the current namespace to that of the /proc/<pid>/ns/net provided in
33 // |path|. This may be a link or mount point for that same file, anything that
34 // when opened will be an fd usable by setns is fine.
setNamespaceFromPath(const char * path)35 static bool setNamespaceFromPath(const char* path) {
36 int nsFd = open(path, O_RDONLY | O_CLOEXEC);
37 if (nsFd == -1) {
38 loge("Cannot open network namespace at '%s': %s\n",
39 path, strerror(errno));
40 return false;
41 }
42
43 if (setns(nsFd, CLONE_NEWNET) == -1) {
44 loge("Cannot set network namespace at '%s': %s\n",
45 path, strerror(errno));
46 close(nsFd);
47 return false;
48 }
49 close(nsFd);
50 return true;
51 }
52
setNetworkNamespace(const char * ns)53 bool setNetworkNamespace(const char* ns) {
54 // There is a file in the net namespace dir (usually /var/run/netns) with
55 // the same name as the namespace. This file is bound to /proc/<pid>/ns/net
56 // by the 'ip' command when the namespace is created. This allows us to
57 // access the file of a process running in that network namespace without
58 // knowing its pid, knowing the namespace name is enough.
59 //
60 // We are going to call setns which requires a file descriptor to that proc
61 // file in /proc/<pid>/net. The process has to already be running in that
62 // namespace. Since the file in the net namespace dir has been bound to
63 // such a file already we just have to open /var/run/netns/<namespace> and
64 // we have the required file descriptor.
65 char nsPath[PATH_MAX];
66 snprintf(nsPath, sizeof(nsPath), "%s/%s", kNetNsDir, ns);
67 return setNamespaceFromPath(nsPath);
68 }
69
setNetworkNamespace(pid_t pid)70 bool setNetworkNamespace(pid_t pid) {
71 // If we know the pid we can create the path to the /proc file right away
72 // and use that when we call setns.
73 char nsPath[PATH_MAX];
74 static_assert(sizeof(pid_t) <= sizeof(unsigned long long),
75 "Cast requires sizeof(pid_t) <= sizeof(unsigned long long)");
76 snprintf(nsPath, sizeof(nsPath), "/proc/%llu/ns/net/",
77 static_cast<unsigned long long>(pid));
78 return setNamespaceFromPath(nsPath);
79 }
80
81