~xnox/ubuntu/saucy/lxc/dep8

« back to all changes in this revision

Viewing changes to src/lxc/lxc_attach.c

  • Committer: Stéphane Graber
  • Date: 2013-02-18 15:20:18 UTC
  • mto: This revision was merged to the branch mainline in revision 190.
  • Revision ID: stgraber@ubuntu.com-20130218152018-ls2gi9hkqs2kuhj8
Tags: upstream-0.9.0~alpha3
Import upstream version 0.9.0~alpha3

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <sys/param.h>
30
30
#include <sys/types.h>
31
31
#include <sys/wait.h>
32
 
#include <sys/personality.h>
33
32
 
34
33
#include "attach.h"
35
34
#include "commands.h"
36
35
#include "arguments.h"
37
36
#include "caps.h"
38
 
#include "attach.h"
 
37
#include "cgroup.h"
 
38
#include "config.h"
39
39
#include "confile.h"
40
40
#include "start.h"
41
41
#include "sync.h"
42
42
#include "log.h"
 
43
#include "namespace.h"
 
44
 
 
45
#if HAVE_SYS_PERSONALITY_H
 
46
#include <sys/personality.h>
 
47
#endif
43
48
 
44
49
lxc_log_define(lxc_attach_ui, lxc);
45
50
 
46
51
static const struct option my_longopts[] = {
47
52
        {"elevated-privileges", no_argument, 0, 'e'},
48
53
        {"arch", required_argument, 0, 'a'},
 
54
        {"namespaces", required_argument, 0, 's'},
 
55
        {"remount-sys-proc", no_argument, 0, 'R'},
49
56
        LXC_COMMON_OPTIONS
50
57
};
51
58
 
52
59
static int elevated_privileges = 0;
53
60
static signed long new_personality = -1;
 
61
static int namespace_flags = -1;
 
62
static int remount_sys_proc = 0;
54
63
 
55
64
static int my_parser(struct lxc_arguments* args, int c, char* arg)
56
65
{
 
66
        int ret;
 
67
 
57
68
        switch (c) {
58
69
        case 'e': elevated_privileges = 1; break;
 
70
        case 'R': remount_sys_proc = 1; break;
59
71
        case 'a':
60
72
                new_personality = lxc_config_parse_arch(arg);
61
73
                if (new_personality < 0) {
63
75
                        return -1;
64
76
                }
65
77
                break;
 
78
        case 's':
 
79
                namespace_flags = 0;
 
80
                ret = lxc_fill_namespace_flags(arg, &namespace_flags);
 
81
                if (ret)
 
82
                        return -1;
 
83
                /* -s implies -e */
 
84
                elevated_privileges = 1;
 
85
                break;
66
86
        }
67
87
 
68
88
        return 0;
83
103
                    WARNING: This may leak privleges into the container.\n\
84
104
                    Use with care.\n\
85
105
  -a, --arch=ARCH   Use ARCH for program instead of container's own\n\
86
 
                    architecture.\n",
 
106
                    architecture.\n\
 
107
  -s, --namespaces=FLAGS\n\
 
108
                    Don't attach to all the namespaces of the container\n\
 
109
                    but just to the following OR'd list of flags:\n\
 
110
                    MOUNT, PID, UTSNAME, IPC, USER or NETWORK\n\
 
111
                    WARNING: Using -s implies -e, it may therefore\n\
 
112
                    leak privileges into the container. Use with care.\n\
 
113
  -R, --remount-sys-proc\n\
 
114
                    Remount /sys and /proc if not attaching to the\n\
 
115
                    mount namespace when using -s in order to properly\n\
 
116
                    reflect the correct namespace context. See the\n\
 
117
                    lxc-attach(1) manual page for details.\n",
87
118
        .options  = my_longopts,
88
119
        .parser   = my_parser,
89
120
        .checker  = NULL,
90
121
};
91
122
 
92
 
int main(int argc, char *argv[], char *envp[])
 
123
int main(int argc, char *argv[])
93
124
{
94
125
        int ret;
95
126
        pid_t pid, init_pid;
96
127
        struct passwd *passwd;
97
128
        struct lxc_proc_context_info *init_ctx;
98
129
        struct lxc_handler *handler;
 
130
        void *cgroup_data = NULL;
99
131
        uid_t uid;
100
132
        char *curdir;
 
133
        /* TODO: add cmdline arg to set lxcpath */
 
134
        const char *lxcpath = NULL;
101
135
 
102
136
        ret = lxc_caps_init();
103
137
        if (ret)
107
141
        if (ret)
108
142
                return ret;
109
143
 
110
 
        ret = lxc_log_init(my_args.log_file, my_args.log_priority,
 
144
        ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
111
145
                           my_args.progname, my_args.quiet);
112
146
        if (ret)
113
147
                return ret;
114
148
 
115
 
        init_pid = get_init_pid(my_args.name);
 
149
        init_pid = get_init_pid(my_args.name, lxcpath);
116
150
        if (init_pid < 0) {
117
151
                ERROR("failed to get the init pid");
118
152
                return -1;
124
158
                return -1;
125
159
        }
126
160
 
 
161
        if (!elevated_privileges) {
 
162
                /* we have to do this now since /sys/fs/cgroup may not
 
163
                 * be available inside the container or we may not have
 
164
                 * the required permissions anymore
 
165
                 */
 
166
                ret = lxc_cgroup_prepare_attach(my_args.name, &cgroup_data);
 
167
                if (ret < 0) {
 
168
                        ERROR("failed to prepare attaching to cgroup");
 
169
                        return -1;
 
170
                }
 
171
        }
 
172
 
 
173
        curdir = getcwd(NULL, 0);
 
174
 
 
175
        /* determine which namespaces the container was created with
 
176
         * by asking lxc-start
 
177
         */
 
178
        if (namespace_flags == -1) {
 
179
                namespace_flags = lxc_get_clone_flags(my_args.name, lxcpath);
 
180
                /* call failed */
 
181
                if (namespace_flags == -1) {
 
182
                        ERROR("failed to automatically determine the "
 
183
                              "namespaces which the container unshared");
 
184
                        return -1;
 
185
                }
 
186
        }
 
187
 
 
188
        /* we need to attach before we fork since certain namespaces
 
189
         * (such as pid namespaces) only really affect children of the
 
190
         * current process and not the process itself
 
191
         */
 
192
        ret = lxc_attach_to_ns(init_pid, namespace_flags);
 
193
        if (ret < 0) {
 
194
                ERROR("failed to enter the namespace");
 
195
                return -1;
 
196
        }
 
197
 
 
198
        if (curdir && chdir(curdir))
 
199
                WARN("could not change directory to '%s'", curdir);
 
200
 
 
201
        free(curdir);
 
202
 
127
203
        /* hack: we need sync.h infrastructure - and that needs a handler */
128
204
        handler = calloc(1, sizeof(*handler));
129
205
 
150
226
                if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
151
227
                        return -1;
152
228
 
153
 
                if (!elevated_privileges && lxc_attach_proc_to_cgroups(pid, init_ctx))
154
 
                        return -1;
 
229
                /* now that we are done with all privileged operations,
 
230
                 * we can add ourselves to the cgroup. Since we smuggled in
 
231
                 * the fds earlier, we still have write permission
 
232
                 */
 
233
                if (!elevated_privileges) {
 
234
                        /* since setns() for pid namespaces only really
 
235
                         * affects child processes, the pid we have is
 
236
                         * still valid outside the container, so this is
 
237
                         * fine
 
238
                         */
 
239
                        ret = lxc_cgroup_finish_attach(cgroup_data, pid);
 
240
                        if (ret < 0) {
 
241
                                ERROR("failed to attach process to cgroup");
 
242
                                return -1;
 
243
                        }
 
244
                }
155
245
 
156
246
                /* tell the child we are done initializing */
157
247
                if (lxc_sync_wake_child(handler, LXC_SYNC_POST_CONFIGURE))
175
265
 
176
266
        if (!pid) {
177
267
                lxc_sync_fini_parent(handler);
178
 
 
179
 
                curdir = get_current_dir_name();
180
 
 
181
 
                ret = lxc_attach_to_ns(init_pid);
182
 
                if (ret < 0) {
183
 
                        ERROR("failed to enter the namespace");
184
 
                        return -1;
 
268
                lxc_cgroup_dispose_attach(cgroup_data);
 
269
 
 
270
                /* A description of the purpose of this functionality is
 
271
                 * provided in the lxc-attach(1) manual page. We have to
 
272
                 * remount here and not in the parent process, otherwise
 
273
                 * /proc may not properly reflect the new pid namespace.
 
274
                 */
 
275
                if (!(namespace_flags & CLONE_NEWNS) && remount_sys_proc) {
 
276
                        ret = lxc_attach_remount_sys_proc();
 
277
                        if (ret < 0) {
 
278
                                return -1;
 
279
                        }
185
280
                }
186
281
 
187
 
                if (curdir && chdir(curdir))
188
 
                        WARN("could not change directory to '%s'", curdir);
189
 
 
190
 
                free(curdir);
191
 
 
 
282
                #if HAVE_SYS_PERSONALITY_H
192
283
                if (new_personality < 0)
193
284
                        new_personality = init_ctx->personality;
194
285
 
197
288
                              strerror(errno));
198
289
                        return -1;
199
290
                }
 
291
                #endif
200
292
 
201
293
                if (!elevated_privileges && lxc_attach_drop_privs(init_ctx)) {
202
294
                        ERROR("could not drop privileges");
212
304
                lxc_sync_fini(handler);
213
305
 
214
306
                if (my_args.argc) {
215
 
                        execve(my_args.argv[0], my_args.argv, envp);
 
307
                        execvp(my_args.argv[0], my_args.argv);
216
308
                        SYSERROR("failed to exec '%s'", my_args.argv[0]);
217
309
                        return -1;
218
310
                }
232
324
                                NULL,
233
325
                        };
234
326
 
235
 
                        execve(args[0], args, envp);
 
327
                        execvp(args[0], args);
236
328
                        SYSERROR("failed to exec '%s'", args[0]);
237
329
                        return -1;
238
330
                }