util: introduce our own gperf based capability list
authorLennart Poettering <lennart@poettering.net>
Wed, 10 Dec 2014 02:16:14 +0000 (03:16 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 10 Dec 2014 02:21:07 +0000 (03:21 +0100)
This way, we can ensure we have a more complete, up-to-date list of
capabilities around, always.

12 files changed:
.gitignore
Makefile.am
src/core/execute.c
src/core/load-fragment.c
src/libsystemd/sd-bus/bus-dump.c
src/nspawn/nspawn.c
src/shared/.gitignore
src/shared/cap-list.c [new file with mode: 0644]
src/shared/cap-list.h [new file with mode: 0644]
src/shared/condition.c
src/shared/missing.h
src/test/test-cap-list.c [new file with mode: 0644]

index 06d411a..b0fc12f 100644 (file)
 /test-bus-zero-copy
 /test-calendarspec
 /test-capability
+/test-cap-list
 /test-catalog
 /test-cgroup
 /test-cgroup-mask
index 2af4a32..23210ff 100644 (file)
@@ -863,6 +863,8 @@ libsystemd_shared_la_SOURCES = \
        src/shared/af-list.h \
        src/shared/arphrd-list.c \
        src/shared/arphrd-list.h \
+       src/shared/cap-list.c \
+       src/shared/cap-list.h \
        src/shared/audit.c \
        src/shared/audit.h \
        src/shared/xml.c \
@@ -903,7 +905,9 @@ nodist_libsystemd_shared_la_SOURCES = \
        src/shared/af-from-name.h \
        src/shared/af-to-name.h \
        src/shared/arphrd-from-name.h \
-       src/shared/arphrd-to-name.h
+       src/shared/arphrd-to-name.h \
+       src/shared/cap-from-name.h \
+       src/shared/cap-to-name.h
 
 libsystemd_shared_la_CFLAGS = \
        $(AM_CFLAGS) \
@@ -1191,6 +1195,8 @@ CLEANFILES += \
        src/shared/af-from-name.gperf \
        src/shared/arphrd-list.txt \
        src/shared/arphrd-from-name.gperf \
+       src/shared/cap-list.txt \
+       src/shared/cap-from-name.gperf \
        src/resolve/dns_type-list.txt \
        src/resolve/dns_type-from-name.gperf
 
@@ -1201,6 +1207,8 @@ BUILT_SOURCES += \
        src/shared/af-to-name.h \
        src/shared/arphrd-from-name.h \
        src/shared/arphrd-to-name.h \
+       src/shared/cap-from-name.h \
+       src/shared/cap-to-name.h \
        src/resolve/dns_type-from-name.h \
        src/resolve/dns_type-to-name.h
 
@@ -1226,6 +1234,7 @@ src/shared/af-list.txt:
 src/shared/af-to-name.h: src/shared/af-list.txt
        $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const af_names[] = { "} !/AF_FILE/ && !/AF_ROUTE/ && !/AF_LOCAL/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
 
+
 src/shared/arphrd-list.txt:
        $(AM_V_at)$(MKDIR_P) $(dir $@)
        $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include net/if_arp.h - </dev/null | $(AWK) '/^#define[ \t]+ARPHRD_[^ \t]+[ \t]+[^ \t]/ { print $$2; }' | sed -e 's/ARPHRD_//' >$@
@@ -1237,6 +1246,20 @@ src/shared/arphrd-from-name.gperf: src/shared/arphrd-list.txt
        $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct arphrd_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, ARPHRD_%s\n", $$1, $$1 }' <$< >$@
 
 
+src/shared/cap-list.txt:
+       $(AM_V_at)$(MKDIR_P) $(dir $@)
+       $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/capability.h -include missing.h - </dev/null | $(AWK) '/^#define[ \t]+CAP_[A-Z_]+[ \t]+/ { print $$2; }' | grep -v CAP_LAST_CAP >$@
+
+src/shared/cap-to-name.h: src/shared/cap-list.txt
+       $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const capability_names[] = { "} { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
+
+src/shared/cap-from-name.gperf: src/shared/cap-list.txt
+       $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct capability_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' <$< >$@
+
+src/shared/cap-from-name.h: src/shared/cap-from-name.gperf
+       $(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_capability -H hash_capability_name -p -C <$< >$@
+
+
 src/resolve/dns_type-list.txt: src/resolve/dns-type.h
        $(AM_V_at)$(MKDIR_P) $(dir $@)
        $(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
@@ -1353,7 +1376,8 @@ tests += \
        test-bus-policy \
        test-locale-util \
        test-execute \
-       test-copy
+       test-copy \
+       test-cap-list
 
 EXTRA_DIST += \
        test/a.service \
@@ -1579,6 +1603,12 @@ test_uid_range_SOURCES = \
 test_uid_range_LDADD = \
        libsystemd-shared.la
 
+test_cap_list_SOURCES = \
+       src/test/test-cap-list.c
+
+test_cap_list_LDADD = \
+       libsystemd-shared.la
+
 test_socket_util_SOURCES = \
        src/test/test-socket-util.c
 
index b7ac4c7..955090c 100644 (file)
@@ -86,6 +86,7 @@
 #include "smack-util.h"
 #include "bus-kernel.h"
 #include "label.h"
+#include "cap-list.h"
 
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
@@ -2296,13 +2297,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 fprintf(f, "%sCapabilityBoundingSet:", prefix);
 
                 for (l = 0; l <= cap_last_cap(); l++)
-                        if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
-                                _cleanup_cap_free_charp_ char *t;
-
-                                t = cap_to_name(l);
-                                if (t)
-                                        fprintf(f, " %s", t);
-                        }
+                        if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l)))
+                                fprintf(f, " %s", strna(capability_to_name(l)));
 
                 fputs("\n", f);
         }
index 7f109b8..259323b 100644 (file)
@@ -59,6 +59,7 @@
 #include "bus-error.h"
 #include "errno-list.h"
 #include "af-list.h"
+#include "cap-list.h"
 
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
@@ -1040,17 +1041,15 @@ int config_parse_bounding_set(const char *unit,
 
         FOREACH_WORD_QUOTED(word, l, rvalue, state) {
                 _cleanup_free_ char *t = NULL;
-                int r;
-                cap_value_t cap;
+                int cap;
 
                 t = strndup(word, l);
                 if (!t)
                         return log_oom();
 
-                r = cap_from_name(t, &cap);
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, errno,
-                                   "Failed to parse capability in bounding set, ignoring: %s", t);
+                cap = capability_from_name(t);
+                if (cap < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
                         continue;
                 }
 
index 9d2aaa8..33d0ed2 100644 (file)
@@ -24,6 +24,7 @@
 #include "strv.h"
 #include "audit.h"
 #include "macro.h"
+#include "cap-list.h"
 
 #include "bus-message.h"
 #include "bus-internal.h"
@@ -290,15 +291,13 @@ static void dump_capabilities(
 
         for (;;) {
                 if (r > 0) {
-                        _cleanup_cap_free_charp_ char *t;
 
                         if (n > 0)
                                 fputc(' ', f);
                         if (n % 4 == 3)
                                 fprintf(f, terse ? "\n          " : "\n        ");
 
-                        t = cap_to_name(i);
-                        fprintf(f, "%s", t);
+                        fprintf(f, "%s", strna(capability_to_name(i)));
                         n++;
                 }
 
index 932696a..0466ddb 100644 (file)
@@ -90,6 +90,7 @@
 #include "base-filesystem.h"
 #include "barrier.h"
 #include "event-util.h"
+#include "cap-list.h"
 
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
@@ -401,7 +402,6 @@ static int parse_argv(int argc, char *argv[]) {
 
                         FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) {
                                 _cleanup_free_ char *t;
-                                cap_value_t cap;
 
                                 t = strndup(word, length);
                                 if (!t)
@@ -413,7 +413,10 @@ static int parse_argv(int argc, char *argv[]) {
                                         else
                                                 minus = (uint64_t) -1;
                                 } else {
-                                        if (cap_from_name(t, &cap) < 0) {
+                                        int cap;
+
+                                        cap = capability_from_name(t);
+                                        if (cap < 0) {
                                                 log_error("Failed to parse capability %s.", t);
                                                 return -EINVAL;
                                         }
index 61709e8..e22411e 100644 (file)
@@ -1,3 +1,7 @@
+/cap-from-name.gperf
+/cap-from-name.h
+/cap-list.txt
+/cap-to-name.h
 /errno-from-name.gperf
 /errno-from-name.h
 /errno-list.txt
diff --git a/src/shared/cap-list.c b/src/shared/cap-list.c
new file mode 100644 (file)
index 0000000..56d1488
--- /dev/null
@@ -0,0 +1,62 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <linux/capability.h>
+#include <string.h>
+
+#include "util.h"
+#include "cap-list.h"
+#include "missing.h"
+
+static const struct capability_name* lookup_capability(register const char *str, register unsigned int len);
+
+#include "cap-to-name.h"
+#include "cap-from-name.h"
+
+const char *capability_to_name(int id) {
+
+        if (id < 0)
+                return NULL;
+
+        if (id >= (int) ELEMENTSOF(capability_names))
+                return NULL;
+
+        return capability_names[id];
+}
+
+int capability_from_name(const char *name) {
+        const struct capability_name *sc;
+        int r, i;
+
+        assert(name);
+
+        /* Try to parse numeric capability */
+        r = safe_atoi(name, &i);
+        if (r >= 0 && i >= 0)
+                return i;
+
+        /* Try to parse string capability */
+        sc = lookup_capability(name, strlen(name));
+        if (!sc)
+                return -EINVAL;
+
+        return sc->id;
+}
diff --git a/src/shared/cap-list.h b/src/shared/cap-list.h
new file mode 100644 (file)
index 0000000..c699e46
--- /dev/null
@@ -0,0 +1,25 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+const char *capability_to_name(int id);
+int capability_from_name(const char *name);
index 59f2622..dcbf9a7 100644 (file)
@@ -39,6 +39,7 @@
 #include "selinux-util.h"
 #include "audit.h"
 #include "condition.h"
+#include "cap-list.h"
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
         Condition *c;
@@ -235,7 +236,7 @@ static int condition_test_security(Condition *c) {
 
 static int condition_test_capability(Condition *c) {
         _cleanup_fclose_ FILE *f = NULL;
-        cap_value_t value;
+        int value;
         char line[LINE_MAX];
         unsigned long long capabilities = -1;
 
@@ -244,8 +245,8 @@ static int condition_test_capability(Condition *c) {
         assert(c->type == CONDITION_CAPABILITY);
 
         /* If it's an invalid capability, we don't have it */
-
-        if (cap_from_name(c->parameter, &value) < 0)
+        value = capability_from_name(c->parameter);
+        if (value < 0)
                 return -EINVAL;
 
         /* If it's a valid capability we default to assume
index cf73877..478988c 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/if_link.h>
 #include <linux/loop.h>
 #include <linux/audit.h>
+#include <linux/capability.h>
 
 #ifdef HAVE_AUDIT
 #include <libaudit.h>
@@ -606,3 +607,27 @@ static inline int setns(int fd, int nstype) {
 #ifndef AUDIT_NLGRP_MAX
 #define AUDIT_NLGRP_READLOG 1
 #endif
+
+#ifndef CAP_MAC_OVERRIDE
+#define CAP_MAC_OVERRIDE 32
+#endif
+
+#ifndef CAP_MAC_ADMIN
+#define CAP_MAC_ADMIN 33
+#endif
+
+#ifndef CAP_SYSLOG
+#define CAP_SYSLOG 34
+#endif
+
+#ifndef CAP_WAKE_ALARM
+#define CAP_WAKE_ALARM 35
+#endif
+
+#ifndef CAP_BLOCK_SUSPEND
+#define CAP_BLOCK_SUSPEND 36
+#endif
+
+#ifndef CAP_AUDIT_READ
+#define CAP_AUDIT_READ 37
+#endif
diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c
new file mode 100644 (file)
index 0000000..dfa9a06
--- /dev/null
@@ -0,0 +1,47 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "log.h"
+#include "cap-list.h"
+#include "capability.h"
+
+int main(int argc, char *argv[]) {
+        int i;
+
+        assert_se(!capability_to_name(-1));
+        assert_se(!capability_to_name(cap_last_cap()+1));
+
+        for (i = 0; i <= (int) cap_last_cap(); i++) {
+                const char *n;
+
+                assert_se(n = capability_to_name(i));
+                assert_se(capability_from_name(n) == i);
+                printf("%s = %i\n", n, i);
+        }
+
+        assert_se(capability_from_name("asdfbsd") == -EINVAL);
+        assert_se(capability_from_name("CAP_AUDIT_READ") == CAP_AUDIT_READ);
+        assert_se(capability_from_name("0") == 0);
+        assert_se(capability_from_name("15") == 15);
+        assert_se(capability_from_name("-1") == -EINVAL);
+
+        return 0;
+}