Check for setcap executables, as we already do for setuid and
setgid ones, and refuse to run them in the same way. BZ#335143.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13990 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index 6d525ee..2bba339 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -359,6 +359,18 @@
    return (res == -1) ? (-1LL) : buf.size;
 }
 
+SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len )
+{
+   SysRes res;
+#if defined(VGO_linux)
+   res = VG_(do_syscall4)(__NR_getxattr, (UWord)file_name, (UWord)attr_name,
+                          attr_value, attr_value_len);
+#else
+   res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
+#endif
+   return res;
+}
+
 Bool VG_(is_dir) ( const HChar* f )
 {
    struct vg_stat buf;
@@ -600,6 +612,13 @@
       return VKI_EACCES;
    }
 
+   res = VG_(getxattr)(f, "security.capability", (Addr)0, 0);
+   if (!sr_isError(res) && !allow_setuid) {
+      if (is_setuid)
+         *is_setuid = True;
+      return VKI_EACCES;
+   }
+
    if (VG_(geteuid)() == st.uid) {
       if (!(st.mode & VKI_S_IXUSR))
          return VKI_EACCES;
diff --git a/coregrind/m_ume/main.c b/coregrind/m_ume/main.c
index 7be6df1..dc17d27 100644
--- a/coregrind/m_ume/main.c
+++ b/coregrind/m_ume/main.c
@@ -87,7 +87,7 @@
       if (is_setuid && !VG_(clo_xml)) {
          VG_(message)(Vg_UserMsg, "\n");
          VG_(message)(Vg_UserMsg,
-                      "Warning: Can't execute setuid/setgid executable: %s\n",
+                      "Warning: Can't execute setuid/setgid/setcap executable: %s\n",
                       exe_name);
          VG_(message)(Vg_UserMsg, "Possible workaround: remove "
                       "--trace-children=yes, if in effect\n");
diff --git a/coregrind/pub_core_libcfile.h b/coregrind/pub_core_libcfile.h
index 7a8e25c..f27725b 100644
--- a/coregrind/pub_core_libcfile.h
+++ b/coregrind/pub_core_libcfile.h
@@ -49,6 +49,9 @@
 /* Return the size of a file, or -1 in case of error */
 extern Long VG_(fsize) ( Int fd );
 
+/* Lookup an extended attribute for a file */
+extern SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len );
+
 /* Is the file a directory? */
 extern Bool VG_(is_dir) ( const HChar* f );