diff options
author | Adrian Reber <areber@redhat.com> | 2020-07-24 19:08:07 +0300 |
---|---|---|
committer | Andrei Vagin <avagin@gmail.com> | 2022-10-25 17:26:42 +0300 |
commit | de70d2c9c10daac00d8e7c0f20da33eb31c48993 (patch) | |
tree | c9984ff1da743aecd8814fb56d80cceed1388a37 | |
parent | 294aedcc417f77850df12a7a99198335b851fe29 (diff) |
non-root: add functions to work with capabilities
This adds the function check_caps() which checks if CRIU is running
with at least CAP_CHECKPOINT_RESTORE. That is the minimum capability
CRIU needs to do a minimal checkpoint and restore from it.
In addition helper functions are added to easily query for other
capability for enhanced checkpoint/restore support.
Co-authored-by: Younes Manton <ymanton@ca.ibm.com>
Signed-off-by: Adrian Reber <areber@redhat.com>
Signed-off-by: Younes Manton <ymanton@ca.ibm.com>
-rw-r--r-- | criu/cr-check.c | 46 | ||||
-rw-r--r-- | criu/include/crtools.h | 1 | ||||
-rw-r--r-- | criu/include/util-caps.h | 58 |
3 files changed, 104 insertions, 1 deletions
diff --git a/criu/cr-check.c b/criu/cr-check.c index 6c95ffb25..b90e6a9bf 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -29,7 +29,7 @@ #include "sockets.h" #include "crtools.h" #include "log.h" -#include "util-pie.h" +#include "util-caps.h" #include "prctl.h" #include "files.h" #include "sk-inet.h" @@ -1655,3 +1655,47 @@ static char *feature_name(int (*func)(void)) } return NULL; } + +static int pr_set_dumpable(int value) +{ + int ret = prctl(PR_SET_DUMPABLE, value, 0, 0, 0); + if (ret < 0) + pr_perror("Unable to set PR_SET_DUMPABLE"); + return ret; +} + +int check_caps(void) +{ + struct proc_status_creds creds; + int exit_code = -1; + + if (parse_pid_status(PROC_SELF, &creds.s, NULL)) + goto out; + + memcpy(&opts.cap_eff, &creds.cap_eff, sizeof(u32) * PROC_CAP_SIZE); + + if (!has_cap_checkpoint_restore(opts.cap_eff)) + goto out; + + /* For some things we need to know if we are running as root. */ + opts.uid = geteuid(); + + if (opts.uid) { + /* + * At his point we know we are running as non-root with the necessary + * capabilities available. Now we have to make the process dumpable + * so that /proc/self is not owned by root. + */ + if (pr_set_dumpable(1)) + return -1; + } + + exit_code = 0; +out: + if (exit_code) { + pr_msg("CRIU needs to have the CAP_SYS_ADMIN or the CAP_CHECKPOINT_RESTORE capability: \n"); + pr_msg("setcap cap_checkpoint_restore+eip %s\n", opts.argv_0); + } + + return exit_code; +} diff --git a/criu/include/crtools.h b/criu/include/crtools.h index b9309654f..b54b9d929 100644 --- a/criu/include/crtools.h +++ b/criu/include/crtools.h @@ -26,6 +26,7 @@ extern int cr_pre_dump_tasks(pid_t pid); extern int cr_restore_tasks(void); extern int convert_to_elf(char *elf_path, int fd_core); extern int cr_check(void); +extern int check_caps(void); extern int cr_dedup(void); extern int cr_lazy_pages(bool daemon); diff --git a/criu/include/util-caps.h b/criu/include/util-caps.h new file mode 100644 index 000000000..7ccd162f5 --- /dev/null +++ b/criu/include/util-caps.h @@ -0,0 +1,58 @@ +#ifndef __CR_UTIL_CAPS_H__ +#define __CR_UTIL_CAPS_H__ + +#include <sys/capability.h> + +#ifndef CAP_CHECKPOINT_RESTORE +#define CAP_CHECKPOINT_RESTORE 40 +#endif + +static inline bool has_capability(int cap, u32 *cap_eff) +{ + int mask = CAP_TO_MASK(cap); + int index = CAP_TO_INDEX(cap); + u32 effective; + + effective = cap_eff[index]; + + if (!(mask & effective)) { + pr_debug("Effective capability %d missing\n", cap); + return false; + } + + return true; +} + +static inline bool has_cap_checkpoint_restore(u32 *cap_eff) +{ + /* + * Everything guarded by CAP_CHECKPOINT_RESTORE is also + * guarded by CAP_SYS_ADMIN. Check for both capabilities. + */ + if (has_capability(CAP_CHECKPOINT_RESTORE, cap_eff) || has_capability(CAP_SYS_ADMIN, cap_eff)) + return true; + + return false; +} + +static inline bool has_cap_net_admin(u32 *cap_eff) +{ + return has_capability(CAP_NET_ADMIN, cap_eff); +} + +static inline bool has_cap_sys_chroot(u32 *cap_eff) +{ + return has_capability(CAP_SYS_CHROOT, cap_eff); +} + +static inline bool has_cap_setuid(u32 *cap_eff) +{ + return has_capability(CAP_SETUID, cap_eff); +} + +static inline bool has_cap_sys_resource(u32 *cap_eff) +{ + return has_capability(CAP_SYS_RESOURCE, cap_eff); +} + +#endif /* __CR_UTIL_CAPS_H__ */ |