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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
/* nsenter.c - Enter existing namespaces
*
* Copyright 2014 andy Lutomirski <luto@amacapital.net>
*
* No standard
*
* unshare.c - run command in new context
*
* Copyright 2011 Rob Landley <rob@landley.net>
*
* No Standard
*
// Note: flags go in same order (right to left) for shared subset
USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
USE_UNSHARE(NEWTOY(unshare, "<1^rimnpuU", TOYFLAG_USR|TOYFLAG_BIN))
config UNSHARE
bool "unshare"
default y
depends on TOYBOX_CONTAINER
help
usage: unshare [-imnpuUr] COMMAND...
Create new container namespace(s) for this process and its children, so
some attribute is not shared with the parent process.
-i SysV IPC (message queues, semaphores, shared memory)
-m Mount/unmount tree
-n Network address, sockets, routing, iptables
-p Process IDs and init
-r Become root (map current euid/egid to 0/0, implies -U)
-u Host and domain names
-U UIDs, GIDs, capabilities
A namespace allows a set of processes to have a different view of the
system than other sets of processes.
config NSENTER
bool "nsenter"
default n
help
usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...
Run COMMAND in an existing (set of) namespace(s).
-t PID to take namespaces from (--target)
-F don't fork, even if -p is used (--no-fork)
The namespaces to switch are:
-i SysV IPC: message queues, semaphores, shared memory (--ipc)
-m Mount/unmount tree (--mnt)
-n Network address, sockets, routing, iptables (--net)
-p Process IDs and init, will fork unless -F is used (--pid)
-u Host and domain names (--uts)
-U UIDs, GIDs, capabilities (--user)
If -t isn't specified, each namespace argument must provide a path
to a namespace file, ala "-i=/proc/$PID/ns/ipc"
*/
#define FOR_nsenter
#include "toys.h"
#include <linux/sched.h>
int unshare(int flags);
int setns(int fd, int nstype);
GLOBALS(
char *nsnames[6];
long targetpid;
)
// Code that must run in unshare's flag context
#define CLEANUP_nsenter
#define FOR_unshare
#include <generated/flags.h>
static void write_ugid_map(char *map, unsigned eugid)
{
int bytes = sprintf(toybuf, "0 %u 1", eugid), fd = xopen(map, O_WRONLY);
xwrite(fd, toybuf, bytes);
xclose(fd);
}
static int handle_r(int test)
{
int fd;
if (!CFG_UNSHARE || !(toys.optflags & FLAG_r) || *toys.which->name!='u')
return 0;
if (!test) return 1;
if (toys.optflags & FLAG_r) {
if ((fd = open("/proc/self/setgroups", O_WRONLY)) >= 0) {
xwrite(fd, "deny", 4);
close(fd);
}
write_ugid_map("/proc/self/uid_map", geteuid());
write_ugid_map("/proc/self/gid_map", getegid());
}
return 0;
}
// Shift back to the context GLOBALS lives in (I.E. matching the filename).
#define CLEANUP_unshare
#define FOR_nsenter
#include <generated/flags.h>
void unshare_main(void)
{
unsigned flags[]={CLONE_NEWUSER, CLONE_NEWUTS, CLONE_NEWPID, CLONE_NEWNET,
CLONE_NEWNS, CLONE_NEWIPC}, f = 0;
int i, fd;
// unshare -U does not imply -r, so we cannot use [+rU]
if (handle_r(0)) toys.optflags |= FLAG_U;
// Create new namespace(s)?
if (CFG_UNSHARE && *toys.which->name=='u') {
for (i = 0; i<ARRAY_LEN(flags); i++)
if (toys.optflags & (1<<i)) f |= flags[i];
if (unshare(f)) perror_exit(0);
handle_r(1);
// Bind to existing namespace(s)?
} else if (CFG_NSENTER) {
char *nsnames = "user\0uts\0pid\0net\0mnt\0ipc";
for (i = 0; i<ARRAY_LEN(flags); i++) {
char *filename = TT.nsnames[i];
if (toys.optflags & (1<<i)) {
if (!filename || !*filename) {
if (!(toys.optflags & FLAG_t)) error_exit("need -t or =filename");
sprintf(toybuf, "/proc/%ld/ns/%s", TT.targetpid, nsnames);
filename = toybuf;
}
if (setns(fd = xopen(filename, O_RDONLY), flags[i]))
perror_exit("setns");
close(fd);
}
nsnames += strlen(nsnames)+1;
}
if ((toys.optflags & FLAG_p) && !(toys.optflags & FLAG_F)) {
pid_t pid = xfork();
if (pid) {
while (waitpid(pid, 0, 0) == -1 && errno == EINTR);
return;
}
}
}
xexec(toys.optargs);
}
void nsenter_main(void)
{
unshare_main();
}
|