]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_attach.c
2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2010
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/param.h>
30 #include <sys/types.h>
35 #include "arguments.h"
43 #include "namespace.h"
45 #if HAVE_SYS_PERSONALITY_H
46 #include <sys/personality.h>
49 lxc_log_define(lxc_attach_ui
, lxc
);
51 static const struct option my_longopts
[] = {
52 {"elevated-privileges", no_argument
, 0, 'e'},
53 {"arch", required_argument
, 0, 'a'},
54 {"namespaces", required_argument
, 0, 's'},
55 {"remount-sys-proc", no_argument
, 0, 'R'},
59 static int elevated_privileges
= 0;
60 static signed long new_personality
= -1;
61 static int namespace_flags
= -1;
62 static int remount_sys_proc
= 0;
64 static int my_parser(struct lxc_arguments
* args
, int c
, char* arg
)
69 case 'e': elevated_privileges
= 1; break;
70 case 'R': remount_sys_proc
= 1; break;
72 new_personality
= lxc_config_parse_arch(arg
);
73 if (new_personality
< 0) {
74 lxc_error(args
, "invalid architecture specified: %s", arg
);
80 ret
= lxc_fill_namespace_flags(arg
, &namespace_flags
);
84 elevated_privileges
= 1;
91 static struct lxc_arguments my_args
= {
92 .progname
= "lxc-attach",
96 Execute the specified command - enter the container NAME\n\
99 -n, --name=NAME NAME for name of the container\n\
100 -e, --elevated-privileges\n\
101 Use elevated privileges (capabilities, cgroup\n\
102 restrictions) instead of those of the container.\n\
103 WARNING: This may leak privleges into the container.\n\
105 -a, --arch=ARCH Use ARCH for program instead of container's own\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",
118 .options
= my_longopts
,
123 int main(int argc
, char *argv
[])
127 struct passwd
*passwd
;
128 struct lxc_proc_context_info
*init_ctx
;
129 struct lxc_handler
*handler
;
130 void *cgroup_data
= NULL
;
133 /* TODO: add cmdline arg to set lxcpath */
134 const char *lxcpath
= NULL
;
136 ret
= lxc_caps_init();
140 ret
= lxc_arguments_parse(&my_args
, argc
, argv
);
144 ret
= lxc_log_init(my_args
.name
, my_args
.log_file
, my_args
.log_priority
,
145 my_args
.progname
, my_args
.quiet
);
149 init_pid
= get_init_pid(my_args
.name
, lxcpath
);
151 ERROR("failed to get the init pid");
155 init_ctx
= lxc_proc_get_context_info(init_pid
);
157 ERROR("failed to get context of the init process, pid = %d", init_pid
);
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
166 ret
= lxc_cgroup_prepare_attach(my_args
.name
, &cgroup_data
);
168 ERROR("failed to prepare attaching to cgroup");
173 curdir
= getcwd(NULL
, 0);
175 /* determine which namespaces the container was created with
176 * by asking lxc-start
178 if (namespace_flags
== -1) {
179 namespace_flags
= lxc_get_clone_flags(my_args
.name
, lxcpath
);
181 if (namespace_flags
== -1) {
182 ERROR("failed to automatically determine the "
183 "namespaces which the container unshared");
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
192 ret
= lxc_attach_to_ns(init_pid
, namespace_flags
);
194 ERROR("failed to enter the namespace");
198 if (curdir
&& chdir(curdir
))
199 WARN("could not change directory to '%s'", curdir
);
203 /* hack: we need sync.h infrastructure - and that needs a handler */
204 handler
= calloc(1, sizeof(*handler
));
206 if (lxc_sync_init(handler
)) {
207 ERROR("failed to initialize synchronization socket");
214 SYSERROR("failed to fork");
221 lxc_sync_fini_child(handler
);
223 /* wait until the child has done configuring itself before
224 * we put it in a cgroup that potentially limits these
226 if (lxc_sync_wait_child(handler
, LXC_SYNC_CONFIGURE
))
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
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
239 ret
= lxc_cgroup_finish_attach(cgroup_data
, pid
);
241 ERROR("failed to attach process to cgroup");
246 /* tell the child we are done initializing */
247 if (lxc_sync_wake_child(handler
, LXC_SYNC_POST_CONFIGURE
))
250 lxc_sync_fini(handler
);
253 if (waitpid(pid
, &status
, 0) < 0) {
256 SYSERROR("failed to wait '%d'", pid
);
260 if (WIFEXITED(status
))
261 return WEXITSTATUS(status
);
267 lxc_sync_fini_parent(handler
);
268 lxc_cgroup_dispose_attach(cgroup_data
);
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.
275 if (!(namespace_flags
& CLONE_NEWNS
) && remount_sys_proc
) {
276 ret
= lxc_attach_remount_sys_proc();
282 #if HAVE_SYS_PERSONALITY_H
283 if (new_personality
< 0)
284 new_personality
= init_ctx
->personality
;
286 if (personality(new_personality
) == -1) {
287 ERROR("could not ensure correct architecture: %s",
293 if (!elevated_privileges
&& lxc_attach_drop_privs(init_ctx
)) {
294 ERROR("could not drop privileges");
298 /* tell parent we are done setting up the container and wait
299 * until we have been put in the container's cgroup, if
301 if (lxc_sync_barrier_parent(handler
, LXC_SYNC_CONFIGURE
))
304 lxc_sync_fini(handler
);
307 execvp(my_args
.argv
[0], my_args
.argv
);
308 SYSERROR("failed to exec '%s'", my_args
.argv
[0]);
314 passwd
= getpwuid(uid
);
316 SYSERROR("failed to get passwd " \
317 "entry for uid '%d'", uid
);
322 char *const args
[] = {
327 execvp(args
[0], args
);
328 SYSERROR("failed to exec '%s'", args
[0]);