3 * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2018 Canonical Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
30 #include <linux/sched.h>
31 #include <sys/prctl.h>
33 #include <sys/types.h>
36 #if HAVE_SYS_PERSONALITY_H
37 #include <sys/personality.h>
40 #include <lxc/lxccontainer.h>
42 #include "tool_utils.h"
44 int lxc_fill_elevated_privileges(char *flaglist
, int *flags
)
46 char *token
, *saveptr
= NULL
;
52 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP
},
53 { "CAP", LXC_ATTACH_DROP_CAPABILITIES
},
54 { "LSM", LXC_ATTACH_LSM_EXEC
},
59 /* For the sake of backward compatibility, drop all privileges
60 * if none is specified.
62 for (i
= 0; all_privs
[i
].token
; i
++)
63 *flags
|= all_privs
[i
].flag
;
68 token
= strtok_r(flaglist
, "|", &saveptr
);
71 for (i
= 0; all_privs
[i
].token
; i
++)
72 if (!strcmp(all_privs
[i
].token
, token
))
73 aflag
= all_privs
[i
].flag
;
79 token
= strtok_r(NULL
, "|", &saveptr
);
85 signed long lxc_config_parse_arch(const char *arch
)
87 #if HAVE_SYS_PERSONALITY_H
93 { "x86", PER_LINUX32
},
94 { "linux32", PER_LINUX32
},
95 { "i386", PER_LINUX32
},
96 { "i486", PER_LINUX32
},
97 { "i586", PER_LINUX32
},
98 { "i686", PER_LINUX32
},
99 { "athlon", PER_LINUX32
},
100 { "mips", PER_LINUX32
},
101 { "mipsel", PER_LINUX32
},
102 { "ppc", PER_LINUX32
},
103 { "arm", PER_LINUX32
},
104 { "armv7l", PER_LINUX32
},
105 { "armhf", PER_LINUX32
},
106 { "armel", PER_LINUX32
},
107 { "powerpc", PER_LINUX32
},
108 { "linux64", PER_LINUX
},
109 { "x86_64", PER_LINUX
},
110 { "amd64", PER_LINUX
},
111 { "mips64", PER_LINUX
},
112 { "mips64el", PER_LINUX
},
113 { "ppc64", PER_LINUX
},
114 { "ppc64le", PER_LINUX
},
115 { "ppc64el", PER_LINUX
},
116 { "powerpc64", PER_LINUX
},
117 { "s390x", PER_LINUX
},
118 { "aarch64", PER_LINUX
},
119 { "arm64", PER_LINUX
},
121 size_t len
= sizeof(pername
) / sizeof(pername
[0]);
123 for (i
= 0; i
< len
; i
++) {
124 if (!strcmp(pername
[i
].name
, arch
))
125 return pername
[i
].per
;
143 const static struct ns_info
{
144 const char *proc_name
;
146 } ns_info
[LXC_NS_MAX
] = {
147 [LXC_NS_USER
] = { "user", CLONE_NEWUSER
},
148 [LXC_NS_MNT
] = { "mnt", CLONE_NEWNS
},
149 [LXC_NS_PID
] = { "pid", CLONE_NEWPID
},
150 [LXC_NS_UTS
] = { "uts", CLONE_NEWUTS
},
151 [LXC_NS_IPC
] = { "ipc", CLONE_NEWIPC
},
152 [LXC_NS_NET
] = { "net", CLONE_NEWNET
},
153 [LXC_NS_CGROUP
] = { "cgroup", CLONE_NEWCGROUP
}
156 int lxc_namespace_2_cloneflag(const char *namespace)
159 for (i
= 0; i
< LXC_NS_MAX
; i
++)
160 if (!strcasecmp(ns_info
[i
].proc_name
, namespace))
161 return ns_info
[i
].clone_flag
;
163 fprintf(stderr
, "Invalid namespace name \"%s\"", namespace);
167 int lxc_fill_namespace_flags(char *flaglist
, int *flags
)
169 char *token
, *saveptr
= NULL
;
173 fprintf(stderr
, "At least one namespace is needed\n");
177 token
= strtok_r(flaglist
, "|", &saveptr
);
180 aflag
= lxc_namespace_2_cloneflag(token
);
186 token
= strtok_r(NULL
, "|", &saveptr
);
194 #ifndef PR_CAPBSET_READ
195 #define PR_CAPBSET_READ 23
198 int lxc_caps_init(void)
200 uid_t uid
= getuid();
201 gid_t gid
= getgid();
202 uid_t euid
= geteuid();
208 if (prctl(PR_SET_KEEPCAPS
, 1)) {
209 fprintf(stderr
, "%s - Failed to set PR_SET_KEEPCAPS\n", strerror(errno
));
213 if (setresgid(gid
, gid
, gid
)) {
214 fprintf(stderr
, "%s - Failed to change gid to %d\n", strerror(errno
), gid
);
218 if (setresuid(uid
, uid
, uid
)) {
219 fprintf(stderr
, "%s - Failed to change uid to %d\n", strerror(errno
), uid
);
224 fprintf(stderr
, "%s - Failed to restore capabilities\n", strerror(errno
));
232 int lxc_caps_up(void)
238 /* when we are run as root, we don't want to play
239 * with the capabilities */
243 caps
= cap_get_proc();
245 fprintf(stderr
, "%s - Failed to cap_get_proc\n", strerror(errno
));
249 for (cap
= 0; cap
<= CAP_LAST_CAP
; cap
++) {
250 cap_flag_value_t flag
;
252 ret
= cap_get_flag(caps
, cap
, CAP_PERMITTED
, &flag
);
254 if (errno
== EINVAL
) {
257 fprintf(stderr
, "%s- Failed to call cap_get_flag\n", strerror(errno
));
262 ret
= cap_set_flag(caps
, CAP_EFFECTIVE
, 1, &cap
, flag
);
264 fprintf(stderr
, "%s - Failed to call cap_set_flag", strerror(errno
));
269 ret
= cap_set_proc(caps
);
271 fprintf(stderr
, "%s - Failed to cap_set_proc", strerror(errno
));
282 int wait_for_pid(pid_t pid
)
287 ret
= waitpid(pid
, &status
, 0);
295 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
300 int lxc_wait_for_pid_status(pid_t pid
)
305 ret
= waitpid(pid
, &status
, 0);
316 int lxc_safe_uint(const char *numstr
, unsigned int *converted
)
319 unsigned long int uli
;
321 while (isspace(*numstr
))
328 uli
= strtoul(numstr
, &err
, 0);
329 if (errno
== ERANGE
&& uli
== ULONG_MAX
)
332 if (err
== numstr
|| *err
!= '\0')
338 *converted
= (unsigned int)uli
;
342 int lxc_safe_int(const char *numstr
, int *converted
)
348 sli
= strtol(numstr
, &err
, 0);
349 if (errno
== ERANGE
&& (sli
== LONG_MAX
|| sli
== LONG_MIN
))
352 if (errno
!= 0 && sli
== 0)
355 if (err
== numstr
|| *err
!= '\0')
358 if (sli
> INT_MAX
|| sli
< INT_MIN
)
361 *converted
= (int)sli
;
365 int lxc_safe_long(const char *numstr
, long int *converted
)
371 sli
= strtol(numstr
, &err
, 0);
372 if (errno
== ERANGE
&& (sli
== LONG_MAX
|| sli
== LONG_MIN
))
375 if (errno
!= 0 && sli
== 0)
378 if (err
== numstr
|| *err
!= '\0')
385 void lxc_free_array(void **array
, lxc_free_fn element_free_fn
)
388 for (p
= array
; p
&& *p
; p
++)
393 int lxc_grow_array(void ***array
, size_t* capacity
, size_t new_size
, size_t capacity_increment
)
398 /* first time around, catch some trivial mistakes of the user
399 * only initializing one of these */
400 if (!*array
|| !*capacity
) {
405 new_capacity
= *capacity
;
406 while (new_size
+ 1 > new_capacity
)
407 new_capacity
+= capacity_increment
;
408 if (new_capacity
!= *capacity
) {
409 /* we have to reallocate */
410 new_array
= realloc(*array
, new_capacity
* sizeof(void *));
413 memset(&new_array
[*capacity
], 0, (new_capacity
- (*capacity
)) * sizeof(void *));
415 *capacity
= new_capacity
;
418 /* array has sufficient elements */
422 char **lxc_string_split(const char *string
, char _sep
)
424 char *token
, *str
, *saveptr
= NULL
;
425 char sep
[2] = {_sep
, '\0'};
426 char **tmp
= NULL
, **result
= NULL
;
427 size_t result_capacity
= 0;
428 size_t result_count
= 0;
432 return calloc(1, sizeof(char *));
434 str
= alloca(strlen(string
) + 1);
436 for (; (token
= strtok_r(str
, sep
, &saveptr
)); str
= NULL
) {
437 r
= lxc_grow_array((void ***)&result
, &result_capacity
, result_count
+ 1, 16);
440 result
[result_count
] = strdup(token
);
441 if (!result
[result_count
])
446 /* if we allocated too much, reduce it */
447 tmp
= realloc(result
, (result_count
+ 1) * sizeof(char *));
451 /* Make sure we don't return uninitialized memory. */
452 if (result_count
== 0)
457 lxc_free_array((void **)result
, free
);
462 char **lxc_normalize_path(const char *path
)
466 size_t components_len
= 0;
469 components
= lxc_string_split(path
, '/');
472 for (p
= components
; *p
; p
++)
475 /* resolve '.' and '..' */
476 for (pos
= 0; pos
< components_len
; ) {
477 if (!strcmp(components
[pos
], ".") || (!strcmp(components
[pos
], "..") && pos
== 0)) {
478 /* eat this element */
479 free(components
[pos
]);
480 memmove(&components
[pos
], &components
[pos
+1], sizeof(char *) * (components_len
- pos
));
482 } else if (!strcmp(components
[pos
], "..")) {
483 /* eat this and the previous element */
484 free(components
[pos
- 1]);
485 free(components
[pos
]);
486 memmove(&components
[pos
-1], &components
[pos
+1], sizeof(char *) * (components_len
- pos
));
497 char *lxc_string_join(const char *sep
, const char **parts
, bool use_as_prefix
)
501 size_t sep_len
= strlen(sep
);
502 size_t result_len
= use_as_prefix
* sep_len
;
504 /* calculate new string length */
505 for (p
= (char **)parts
; *p
; p
++)
506 result_len
+= (p
> (char **)parts
) * sep_len
+ strlen(*p
);
508 result
= calloc(result_len
+ 1, 1);
514 for (p
= (char **)parts
; *p
; p
++) {
515 if (p
> (char **)parts
)
523 int is_dir(const char *path
)
526 int ret
= stat(path
, &statbuf
);
527 if (ret
== 0 && S_ISDIR(statbuf
.st_mode
))
532 size_t lxc_array_len(void **array
)
537 for (p
= array
; p
&& *p
; p
++)