tar defaults to --same-owner --same-permissions if the effective UID is ROOT_UID. On Linux, tar may be running as root with limited privileges, e.g., in a sandbox where arbitrary chown(2) is not allowed and thus --same-owner will fail. This adds a check for CAP_CHOWN. If tar is running as root without that capability, it will behave the same as when running as non-root user. --- configure.ac | 3 +++ src/common.h | 1 + src/extract.c | 3 +-- src/system.c | 21 +++++++++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index 0bddbeb..b46c722 100644 --- a/configure.ac +++ b/configure.ac @@ -49,6 +49,9 @@ AC_CHECK_HEADERS([sys/buf.h], [], [], #include <sys/param.h> #endif]) +AC_CHECK_HEADERS([linux/capability.h], [], [], +[#include <sys/capability.h>]) + AC_HEADER_MAJOR AC_MSG_CHECKING([for st_fstype string in struct stat]) diff --git a/src/common.h b/src/common.h index bbe167e..125e4e9 100644 --- a/src/common.h +++ b/src/common.h @@ -868,6 +868,7 @@ int sys_exec_info_script (const char **archive_name, int volume_number); void sys_exec_checkpoint_script (const char *script_name, const char *archive_name, int checkpoint_number); +bool sys_chown_capable_root (void); /* Module compare.c */ void report_difference (struct tar_stat_info *st, const char *message, ...) diff --git a/src/extract.c b/src/extract.c index 395db55..f808007 100644 --- a/src/extract.c +++ b/src/extract.c @@ -24,7 +24,6 @@ #include <quotearg.h> #include <errno.h> #include <priv-set.h> -#include <root-uid.h> #include <utimens.h> #include "common.h" @@ -175,7 +174,7 @@ struct string_list void extr_init (void) { - we_are_root = geteuid () == ROOT_UID; + we_are_root = sys_chown_capable_root (); same_permissions_option += we_are_root; same_owner_option += we_are_root; diff --git a/src/system.c b/src/system.c index b4f6985..4f0510a 100644 --- a/src/system.c +++ b/src/system.c @@ -21,9 +21,14 @@ #include "common.h" #include <priv-set.h> #include <rmt.h> +#include <root-uid.h> #include <signal.h> #include <wordsplit.h> +#ifdef HAVE_LINUX_CAPABILITY_H +#include <sys/capability.h> +#endif + static _Noreturn void xexec (const char *cmd) { @@ -898,3 +903,19 @@ sys_exec_checkpoint_script (const char *script_name, } #endif /* not MSDOS */ + +bool sys_chown_capable_root (void) +{ +#ifdef HAVE_LINUX_CAPABILITY_H + struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 }; + struct __user_cap_data_struct data[2] = { { 0 } }; + + if (capget (&hdr, data) == 0) + { + if ((data[0].effective & (1 << CAP_CHOWN)) == 0) + return false; + } +#endif + + return geteuid () == ROOT_UID; +} -- 2.16.1