~mmach/netext73/busybox

« back to all changes in this revision

Viewing changes to .pc/platform-linux.diff/util-linux/nsenter.c

  • Committer: mmach
  • Date: 2023-07-06 04:40:25 UTC
  • Revision ID: netbit73@gmail.com-20230706044025-2ia9985i8wzdn2a7
1.36.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vi: set sw=4 ts=4: */
 
2
/*
 
3
 * Mini nsenter implementation for busybox.
 
4
 *
 
5
 * Copyright (C) 2016 by Bartosz Golaszewski <bartekgola@gmail.com>
 
6
 *
 
7
 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 
8
 */
 
9
//config:config NSENTER
 
10
//config:       bool "nsenter (6.5 kb)"
 
11
//config:       default y
 
12
//config:       help
 
13
//config:       Run program with namespaces of other processes.
 
14
 
 
15
//applet:IF_NSENTER(APPLET(nsenter, BB_DIR_USR_BIN, BB_SUID_DROP))
 
16
 
 
17
//kbuild:lib-$(CONFIG_NSENTER) += nsenter.o
 
18
 
 
19
//usage:#define nsenter_trivial_usage
 
20
//usage:       "[OPTIONS] [PROG ARGS]"
 
21
//usage:#define nsenter_full_usage "\n"
 
22
//usage:     "\n        -t PID          Target process to get namespaces from"
 
23
//usage:     "\n        -m[FILE]        Enter mount namespace"
 
24
//usage:     "\n        -u[FILE]        Enter UTS namespace (hostname etc)"
 
25
//usage:     "\n        -i[FILE]        Enter System V IPC namespace"
 
26
//usage:     "\n        -n[FILE]        Enter network namespace"
 
27
//usage:     "\n        -p[FILE]        Enter pid namespace"
 
28
//usage:     "\n        -U[FILE]        Enter user namespace"
 
29
//usage:     "\n        -S UID          Set uid in entered namespace"
 
30
//usage:     "\n        -G GID          Set gid in entered namespace"
 
31
//usage:        IF_LONG_OPTS(
 
32
//usage:     "\n        --preserve-credentials  Don't touch uids or gids"
 
33
//usage:        )
 
34
//usage:     "\n        -r[DIR]         Set root directory"
 
35
//usage:     "\n        -w[DIR]         Set working directory"
 
36
//usage:     "\n        -F              Don't fork before exec'ing PROG"
 
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
 
 
57
struct namespace_descr {
 
58
        int flag;               /* value passed to setns() */
 
59
        char ns_nsfile8[8];     /* "ns/" + namespace file in process' procfs entry */
 
60
};
 
61
 
 
62
struct namespace_ctx {
 
63
        char *path;             /* optional path to a custom ns file */
 
64
        int fd;                 /* opened namespace file descriptor */
 
65
};
 
66
 
 
67
enum {
 
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
};
 
82
enum {
 
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
 * The order is significant in nsenter.
 
93
 * The user namespace comes first, so that it is entered first.
 
94
 * This gives an unprivileged user the potential to enter other namespaces.
 
95
 */
 
96
static const struct namespace_descr ns_list[] ALIGN_INT = {
 
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
 * Upstream nsenter doesn't support the short option for --preserve-credentials
 
106
 * "+": stop on first non-option
 
107
 */
 
108
static const char opt_str[] ALIGN1 = "+""U::i::u::n::p::m::""t:+S:+G:+r::w::F";
 
109
 
 
110
#if ENABLE_LONG_OPTS
 
111
static 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
 * Open a file and return the new descriptor. If a full path is provided in
 
130
 * fs_path, then the file to which it points is opened. Otherwise (fd_path is
 
131
 * NULL) the routine builds a path to a procfs file using the following
 
132
 * template: '/proc/<target_pid>/<target_file>'.
 
133
 */
 
134
static 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
                        /* Example:
 
142
                         * "nsenter -p PROG" - neither -pFILE nor -tPID given.
 
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
 
 
154
int nsenter_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 
155
int 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
         * Entering the user namespace without --preserve-credentials implies
 
201
         * --setuid & --setgid and clearing root's groups.
 
202
         */
 
203
        setgroups_failed = 0;
 
204
        if ((opts & OPT_user) && !(opts & OPT_prescred)) {
 
205
                opts |= (OPT_setuid | OPT_setgid);
 
206
                /*
 
207
                 * We call setgroups() before and after setns() and only
 
208
                 * bail-out if it fails twice.
 
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 /* skip over "ns/" */
 
223
                        );
 
224
                }
 
225
                close(ns_ctx->fd); /* should close fds, to not confuse exec'ed PROG */
 
226
                /*ns_ctx->fd = -1;*/
 
227
        }
 
228
 
 
229
        if (root_fd >= 0) {
 
230
                if (wd_fd < 0) {
 
231
                        /*
 
232
                         * Save the current working directory if we're not
 
233
                         * changing it.
 
234
                         */
 
235
                        wd_fd = xopen(".", O_RDONLY);
 
236
                }
 
237
                xfchdir(root_fd);
 
238
                xchroot(".");
 
239
                close(root_fd);
 
240
                /*root_fd = -1;*/
 
241
        }
 
242
 
 
243
        if (wd_fd >= 0) {
 
244
                xfchdir(wd_fd);
 
245
                close(wd_fd);
 
246
                /*wd_fd = -1;*/
 
247
        }
 
248
 
 
249
        /*
 
250
         * Entering the pid namespace implies forking unless it's been
 
251
         * explicitly requested by the user not to.
 
252
         */
 
253
        if (!(opts & OPT_nofork) && (opts & OPT_pid)) {
 
254
                xvfork_parent_waits_and_exits();
 
255
                /* Child continues */
 
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
}