88 lines
2.2 KiB
Diff
88 lines
2.2 KiB
Diff
diff -ru a/configure.ac b/configure.ac
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -59,6 +59,9 @@
|
|
AC_CHECK_HEADERS(pthread.h,
|
|
[AC_SEARCH_LIBS(pthread_atfork, pthread)],
|
|
[AC_MSG_WARN(pthread.h not found, disabling pthread_atfork.)])
|
|
+AC_CHECK_HEADERS(sys/vfs.h, [
|
|
+ AC_CHECK_HEADERS(linux/magic.h, [] [AC_MSG_WARN(linux/magic.h is required in order to verify procfs.)])
|
|
+ ], [AC_MSG_WARN(sys/vfs.h is required in order to verify procfs.)])
|
|
|
|
AC_C_CONST
|
|
AC_C_INLINE
|
|
diff -ru a/src/cap-ng.c b/src/cap-ng.c
|
|
--- a/src/cap-ng.c
|
|
+++ b/src/cap-ng.c
|
|
@@ -44,6 +44,10 @@
|
|
#ifdef HAVE_LINUX_SECUREBITS_H
|
|
#include <linux/securebits.h>
|
|
#endif
|
|
+#ifdef HAVE_LINUX_MAGIC_H
|
|
+#include <sys/vfs.h>
|
|
+#include <linux/magic.h>
|
|
+#endif
|
|
|
|
# define hidden __attribute__ ((visibility ("hidden")))
|
|
unsigned int last_cap hidden = 0;
|
|
@@ -168,6 +172,15 @@
|
|
m.state = CAPNG_NEW;
|
|
}
|
|
|
|
+static inline int test_cap(unsigned int cap)
|
|
+{
|
|
+ // prctl returns 0 or 1 for valid caps, -1 otherwise
|
|
+ return prctl(PR_CAPBSET_READ, cap) >= 0;
|
|
+}
|
|
+
|
|
+// The maximum cap value is determined by VFS_CAP_U32
|
|
+#define MAX_CAP_VALUE (VFS_CAP_U32 * sizeof(__le32) * 8)
|
|
+
|
|
static void init_lib(void) __attribute__ ((constructor));
|
|
static void init_lib(void)
|
|
{
|
|
@@ -178,8 +191,15 @@
|
|
if (last_cap == 0) {
|
|
int fd;
|
|
|
|
+ // Try to read last cap from procfs
|
|
fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
|
|
if (fd >= 0) {
|
|
+#ifdef HAVE_LINUX_MAGIC_H
|
|
+ struct statfs st;
|
|
+ // Bail out if procfs is invalid or fstatfs fails
|
|
+ if (fstatfs(fd, &st) || st.f_type != PROC_SUPER_MAGIC)
|
|
+ goto fail;
|
|
+#endif
|
|
char buf[8];
|
|
int num = read(fd, buf, sizeof(buf) - 1);
|
|
if (num > 0) {
|
|
@@ -189,10 +209,25 @@
|
|
if (errno == 0)
|
|
last_cap = val;
|
|
}
|
|
+fail:
|
|
close(fd);
|
|
}
|
|
- if (last_cap == 0)
|
|
- last_cap = CAP_LAST_CAP;
|
|
+ // Run a binary search over capabilities
|
|
+ if (last_cap == 0) {
|
|
+ // starting with last_cap=MAX_CAP_VALUE means we always know
|
|
+ // that cap1 is invalid after the first iteration
|
|
+ last_cap = MAX_CAP_VALUE;
|
|
+ unsigned int cap0 = 0, cap1 = MAX_CAP_VALUE;
|
|
+
|
|
+ while (cap0 < last_cap) {
|
|
+ if (test_cap(last_cap))
|
|
+ cap0 = last_cap;
|
|
+ else
|
|
+ cap1 = last_cap;
|
|
+
|
|
+ last_cap = (cap0 + cap1) / 2U;
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
|