]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/attach.c
cgroup: improve support for multiple lxcpaths (v3)
[mirror_lxc.git] / src / lxc / attach.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
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.
13 *
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.
18 *
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
22 */
23
24 #define _GNU_SOURCE
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/param.h>
32 #include <sys/prctl.h>
33 #include <sys/mount.h>
34 #include <sys/syscall.h>
35 #include <linux/unistd.h>
36
37 #if !HAVE_DECL_PR_CAPBSET_DROP
38 #define PR_CAPBSET_DROP 24
39 #endif
40
41 #include "namespace.h"
42 #include "log.h"
43 #include "attach.h"
44 #include "caps.h"
45 #include "config.h"
46 #include "apparmor.h"
47
48 lxc_log_define(lxc_attach, lxc);
49
50 /* Define setns() if missing from the C library */
51 #ifndef HAVE_SETNS
52 static int setns(int fd, int nstype)
53 {
54 #ifdef __NR_setns
55 return syscall(__NR_setns, fd, nstype);
56 #else
57 errno = ENOSYS;
58 return -1;
59 #endif
60 }
61 #endif
62
63 /* Define unshare() if missing from the C library */
64 #ifndef HAVE_UNSHARE
65 static int unshare(int flags)
66 {
67 #ifdef __NR_unshare
68 return syscall(__NR_unshare, flags);
69 #else
70 errno = ENOSYS;
71 return -1;
72 #endif
73 }
74 #endif
75
76 /* Define getline() if missing from the C library */
77 #ifndef HAVE_GETLINE
78 #ifdef HAVE_FGETLN
79 #include <../include/getline.h>
80 #endif
81 #endif
82
83 struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
84 {
85 struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
86 FILE *proc_file;
87 char proc_fn[MAXPATHLEN];
88 char *line = NULL;
89 size_t line_bufsz = 0;
90 int ret, found;
91
92 if (!info) {
93 SYSERROR("Could not allocate memory.");
94 return NULL;
95 }
96
97 /* read capabilities */
98 snprintf(proc_fn, MAXPATHLEN, "/proc/%d/status", pid);
99
100 proc_file = fopen(proc_fn, "r");
101 if (!proc_file) {
102 SYSERROR("Could not open %s", proc_fn);
103 goto out_error;
104 }
105
106 found = 0;
107 while (getline(&line, &line_bufsz, proc_file) != -1) {
108 ret = sscanf(line, "CapBnd: %llx", &info->capability_mask);
109 if (ret != EOF && ret > 0) {
110 found = 1;
111 break;
112 }
113 }
114
115 fclose(proc_file);
116
117 if (!found) {
118 SYSERROR("Could not read capability bounding set from %s", proc_fn);
119 errno = ENOENT;
120 goto out_error;
121 }
122
123 /* read personality */
124 snprintf(proc_fn, MAXPATHLEN, "/proc/%d/personality", pid);
125
126 proc_file = fopen(proc_fn, "r");
127 if (!proc_file) {
128 SYSERROR("Could not open %s", proc_fn);
129 goto out_error;
130 }
131
132 ret = fscanf(proc_file, "%lx", &info->personality);
133 fclose(proc_file);
134
135 if (ret == EOF || ret == 0) {
136 SYSERROR("Could not read personality from %s", proc_fn);
137 errno = ENOENT;
138 goto out_error;
139 }
140 info->aa_profile = aa_get_profile(pid);
141
142 return info;
143
144 out_error:
145 free(info);
146 free(line);
147 return NULL;
148 }
149
150 int lxc_attach_to_ns(pid_t pid, int which)
151 {
152 char path[MAXPATHLEN];
153 /* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
154 * the file for user namepsaces in /proc/$pid/ns will be called
155 * 'user' once the kernel supports it
156 */
157 static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" };
158 static int flags[] = {
159 CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
160 CLONE_NEWUSER, CLONE_NEWNET
161 };
162 static const int size = sizeof(ns) / sizeof(char *);
163 int fd[size];
164 int i, j, saved_errno;
165
166
167 snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
168 if (access(path, X_OK)) {
169 ERROR("Does this kernel version support 'attach' ?");
170 return -1;
171 }
172
173 for (i = 0; i < size; i++) {
174 /* ignore if we are not supposed to attach to that
175 * namespace
176 */
177 if (which != -1 && !(which & flags[i])) {
178 fd[i] = -1;
179 continue;
180 }
181
182 snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
183 fd[i] = open(path, O_RDONLY);
184 if (fd[i] < 0) {
185 saved_errno = errno;
186
187 /* close all already opened file descriptors before
188 * we return an error, so we don't leak them
189 */
190 for (j = 0; j < i; j++)
191 close(fd[j]);
192
193 errno = saved_errno;
194 SYSERROR("failed to open '%s'", path);
195 return -1;
196 }
197 }
198
199 for (i = 0; i < size; i++) {
200 if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
201 saved_errno = errno;
202
203 for (j = i; j < size; j++)
204 close(fd[j]);
205
206 errno = saved_errno;
207 SYSERROR("failed to set namespace '%s'", ns[i]);
208 return -1;
209 }
210
211 close(fd[i]);
212 }
213
214 return 0;
215 }
216
217 int lxc_attach_remount_sys_proc()
218 {
219 int ret;
220
221 ret = unshare(CLONE_NEWNS);
222 if (ret < 0) {
223 SYSERROR("failed to unshare mount namespace");
224 return -1;
225 }
226
227 /* assume /proc is always mounted, so remount it */
228 ret = umount2("/proc", MNT_DETACH);
229 if (ret < 0) {
230 SYSERROR("failed to unmount /proc");
231 return -1;
232 }
233
234 ret = mount("none", "/proc", "proc", 0, NULL);
235 if (ret < 0) {
236 SYSERROR("failed to remount /proc");
237 return -1;
238 }
239
240 /* try to umount /sys - if it's not a mount point,
241 * we'll get EINVAL, then we ignore it because it
242 * may not have been mounted in the first place
243 */
244 ret = umount2("/sys", MNT_DETACH);
245 if (ret < 0 && errno != EINVAL) {
246 SYSERROR("failed to unmount /sys");
247 return -1;
248 } else if (ret == 0) {
249 /* remount it */
250 ret = mount("none", "/sys", "sysfs", 0, NULL);
251 if (ret < 0) {
252 SYSERROR("failed to remount /sys");
253 return -1;
254 }
255 }
256
257 return 0;
258 }
259
260 int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
261 {
262 int last_cap = lxc_caps_last_cap();
263 int cap;
264
265 for (cap = 0; cap <= last_cap; cap++) {
266 if (ctx->capability_mask & (1LL << cap))
267 continue;
268
269 if (prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)) {
270 SYSERROR("failed to remove capability id %d", cap);
271 return -1;
272 }
273 }
274
275 return 0;
276 }