bug-tar
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-tar] [PATCH] Check for CAP_CHOWN on Linux before defaulting to --sa


From: Jürg Billeter
Subject: [Bug-tar] [PATCH] Check for CAP_CHOWN on Linux before defaulting to --same-owner -p
Date: Thu, 15 Feb 2018 13:24:17 +0100

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]