summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-12-10 03:16:14 +0100
committerLennart Poettering <lennart@poettering.net>2014-12-10 03:21:07 +0100
commit2822da4fb7f891e5320f02f1d00f64b72221ced4 (patch)
tree53d99b2f6cfd0d0e81b47671a03f1c3e1e5880fc
parent45823da23ccfea5159fafa844ede0a873a460df8 (diff)
util: introduce our own gperf based capability list
This way, we can ensure we have a more complete, up-to-date list of capabilities around, always.
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am34
-rw-r--r--src/core/execute.c10
-rw-r--r--src/core/load-fragment.c11
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c5
-rw-r--r--src/nspawn/nspawn.c7
-rw-r--r--src/shared/.gitignore4
-rw-r--r--src/shared/cap-list.c62
-rw-r--r--src/shared/cap-list.h25
-rw-r--r--src/shared/condition.c7
-rw-r--r--src/shared/missing.h25
-rw-r--r--src/test/test-cap-list.c47
12 files changed, 215 insertions, 23 deletions
diff --git a/.gitignore b/.gitignore
index 06d411a93..b0fc12fac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -152,6 +152,7 @@
/test-bus-zero-copy
/test-calendarspec
/test-capability
+/test-cap-list
/test-catalog
/test-cgroup
/test-cgroup-mask
diff --git a/Makefile.am b/Makefile.am
index 2af4a32aa..23210ff33 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
diff --git a/src/core/execute.c b/src/core/execute.c
index b7ac4c7b2..955090c44 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -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);
}
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 7f109b893..259323bd5 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -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;
}
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 9d2aaa829..33d0ed2df 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -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++;
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 932696aa9..0466ddbff 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -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;
}
diff --git a/src/shared/.gitignore b/src/shared/.gitignore
index 61709e8da..e22411e48 100644
--- a/src/shared/.gitignore
+++ b/src/shared/.gitignore
@@ -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
index 000000000..56d1488f4
--- /dev/null
+++ b/src/shared/cap-list.c
@@ -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
index 000000000..c699e466a
--- /dev/null
+++ b/src/shared/cap-list.h
@@ -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);
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 59f262244..dcbf9a7e8 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -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
diff --git a/src/shared/missing.h b/src/shared/missing.h
index cf7387751..478988c8a 100644
--- a/src/shared/missing.h
+++ b/src/shared/missing.h
@@ -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
index 000000000..dfa9a063c
--- /dev/null
+++ b/src/test/test-cap-list.c
@@ -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;
+}