1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <sched.h>
39#ifndef CLONE_NEWUTS
40# define CLONE_NEWUTS 0x04000000
41#endif
42#ifndef CLONE_NEWIPC
43# define CLONE_NEWIPC 0x08000000
44#endif
45#ifndef CLONE_NEWUSER
46# define CLONE_NEWUSER 0x10000000
47#endif
48#ifndef CLONE_NEWPID
49# define CLONE_NEWPID 0x20000000
50#endif
51#ifndef CLONE_NEWNET
52# define CLONE_NEWNET 0x40000000
53#endif
54
55#include "libbb.h"
56
57struct namespace_descr {
58 int flag;
59 char ns_nsfile8[8];
60};
61
62struct namespace_ctx {
63 char *path;
64 int fd;
65};
66
67enum {
68 OPT_user = 1 << 0,
69 OPT_ipc = 1 << 1,
70 OPT_uts = 1 << 2,
71 OPT_network = 1 << 3,
72 OPT_pid = 1 << 4,
73 OPT_mount = 1 << 5,
74 OPT_target = 1 << 6,
75 OPT_setuid = 1 << 7,
76 OPT_setgid = 1 << 8,
77 OPT_root = 1 << 9,
78 OPT_wd = 1 << 10,
79 OPT_nofork = 1 << 11,
80 OPT_prescred = (1 << 12) * ENABLE_LONG_OPTS,
81};
82enum {
83 NS_USR_POS = 0,
84 NS_IPC_POS,
85 NS_UTS_POS,
86 NS_NET_POS,
87 NS_PID_POS,
88 NS_MNT_POS,
89 NS_COUNT,
90};
91
92
93
94
95
96static const struct namespace_descr ns_list[] = {
97 { CLONE_NEWUSER, "ns/user", },
98 { CLONE_NEWIPC, "ns/ipc", },
99 { CLONE_NEWUTS, "ns/uts", },
100 { CLONE_NEWNET, "ns/net", },
101 { CLONE_NEWPID, "ns/pid", },
102 { CLONE_NEWNS, "ns/mnt", },
103};
104
105
106
107
108static const char opt_str[] ALIGN1 = "+""U::i::u::n::p::m::""t:+S:+G:+r::w::F";
109
110#if ENABLE_LONG_OPTS
111static const char nsenter_longopts[] ALIGN1 =
112 "user\0" Optional_argument "U"
113 "ipc\0" Optional_argument "i"
114 "uts\0" Optional_argument "u"
115 "net\0" Optional_argument "n"
116 "pid\0" Optional_argument "p"
117 "mount\0" Optional_argument "m"
118 "target\0" Required_argument "t"
119 "setuid\0" Required_argument "S"
120 "setgid\0" Required_argument "G"
121 "root\0" Optional_argument "r"
122 "wd\0" Optional_argument "w"
123 "no-fork\0" No_argument "F"
124 "preserve-credentials\0" No_argument "\xff"
125 ;
126#endif
127
128
129
130
131
132
133
134static int open_by_path_or_target(const char *path,
135 pid_t target_pid, const char *target_file)
136{
137 char proc_path_buf[sizeof("/proc/%u/1234567890") + sizeof(int)*3];
138
139 if (!path) {
140 if (target_pid == 0) {
141
142
143
144 bb_show_usage();
145 }
146 snprintf(proc_path_buf, sizeof(proc_path_buf),
147 "/proc/%u/%s", (unsigned)target_pid, target_file);
148 path = proc_path_buf;
149 }
150
151 return xopen(path, O_RDONLY);
152}
153
154int nsenter_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
155int nsenter_main(int argc UNUSED_PARAM, char **argv)
156{
157 int i;
158 unsigned int opts;
159 const char *root_dir_str = NULL;
160 const char *wd_str = NULL;
161 struct namespace_ctx ns_ctx_list[NS_COUNT];
162 int setgroups_failed;
163 int root_fd, wd_fd;
164 int target_pid = 0;
165 int uid = 0;
166 int gid = 0;
167
168 memset(ns_ctx_list, 0, sizeof(ns_ctx_list));
169
170 opts = getopt32long(argv, opt_str, nsenter_longopts,
171 &ns_ctx_list[NS_USR_POS].path,
172 &ns_ctx_list[NS_IPC_POS].path,
173 &ns_ctx_list[NS_UTS_POS].path,
174 &ns_ctx_list[NS_NET_POS].path,
175 &ns_ctx_list[NS_PID_POS].path,
176 &ns_ctx_list[NS_MNT_POS].path,
177 &target_pid, &uid, &gid,
178 &root_dir_str, &wd_str
179 );
180 argv += optind;
181
182 root_fd = wd_fd = -1;
183 if (opts & OPT_root)
184 root_fd = open_by_path_or_target(root_dir_str,
185 target_pid, "root");
186 if (opts & OPT_wd)
187 wd_fd = open_by_path_or_target(wd_str, target_pid, "cwd");
188
189 for (i = 0; i < NS_COUNT; i++) {
190 const struct namespace_descr *ns = &ns_list[i];
191 struct namespace_ctx *ns_ctx = &ns_ctx_list[i];
192
193 ns_ctx->fd = -1;
194 if (opts & (1 << i))
195 ns_ctx->fd = open_by_path_or_target(ns_ctx->path,
196 target_pid, ns->ns_nsfile8);
197 }
198
199
200
201
202
203 setgroups_failed = 0;
204 if ((opts & OPT_user) && !(opts & OPT_prescred)) {
205 opts |= (OPT_setuid | OPT_setgid);
206
207
208
209
210 setgroups_failed = (setgroups(0, NULL) < 0);
211 }
212
213 for (i = 0; i < NS_COUNT; i++) {
214 const struct namespace_descr *ns = &ns_list[i];
215 struct namespace_ctx *ns_ctx = &ns_ctx_list[i];
216
217 if (ns_ctx->fd < 0)
218 continue;
219 if (setns(ns_ctx->fd, ns->flag)) {
220 bb_perror_msg_and_die(
221 "setns(): can't reassociate to namespace '%s'",
222 ns->ns_nsfile8 + 3
223 );
224 }
225 close(ns_ctx->fd);
226
227 }
228
229 if (root_fd >= 0) {
230 if (wd_fd < 0) {
231
232
233
234
235 wd_fd = xopen(".", O_RDONLY);
236 }
237 xfchdir(root_fd);
238 xchroot(".");
239 close(root_fd);
240
241 }
242
243 if (wd_fd >= 0) {
244 xfchdir(wd_fd);
245 close(wd_fd);
246
247 }
248
249
250
251
252
253 if (!(opts & OPT_nofork) && (opts & OPT_pid)) {
254 xvfork_parent_waits_and_exits();
255
256 }
257
258 if (opts & OPT_setgid) {
259 if (setgroups(0, NULL) < 0 && setgroups_failed)
260 bb_simple_perror_msg_and_die("setgroups");
261 xsetgid(gid);
262 }
263 if (opts & OPT_setuid)
264 xsetuid(uid);
265
266 exec_prog_or_SHELL(argv);
267}
268