mirror of
https://github.com/systemd/systemd.git
synced 2025-01-09 01:18:19 +03:00
analyze: capability: add support for decoding capability masks
This adds support in `systemd-analyze capability` for decoding capability masks (sets), e.g.: ```console $ systemd-analyze capability --mask 0000000000003c00 NAME NUMBER cap_net_bind_service 10 cap_net_broadcast 11 cap_net_admin 12 cap_net_raw 13 ``` This is intended as a convenience tool for pretty-printing capability values as found in e.g. `/proc/$PID/status`.
This commit is contained in:
parent
daa453acbe
commit
3e7a029c28
@ -80,7 +80,16 @@
|
|||||||
<command>systemd-analyze</command>
|
<command>systemd-analyze</command>
|
||||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||||
<arg choice="plain">capability</arg>
|
<arg choice="plain">capability</arg>
|
||||||
<arg choice="opt" rep="repeat"><replaceable>CAPABILITY</replaceable></arg>
|
<group choice="opt">
|
||||||
|
<arg choice="plain" rep="repeat"><replaceable>CAPABILITY</replaceable></arg>
|
||||||
|
<arg choice="plain">
|
||||||
|
<group choice="req">
|
||||||
|
<arg choice="plain">-m</arg>
|
||||||
|
<arg choice="plain">--mask</arg>
|
||||||
|
</group>
|
||||||
|
<replaceable>MASK</replaceable>
|
||||||
|
</arg>
|
||||||
|
</group>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>systemd-analyze</command>
|
<command>systemd-analyze</command>
|
||||||
@ -441,7 +450,20 @@ DATAERR 65 BSD
|
|||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title><command>systemd-analyze capability <optional><replaceable>CAPABILITY</replaceable>...</optional></command></title>
|
<title>
|
||||||
|
<command>systemd-analyze capability
|
||||||
|
<group choice="opt">
|
||||||
|
<arg choice="plain" rep="repeat"><replaceable>CAPABILITY</replaceable></arg>
|
||||||
|
<arg choice="plain">
|
||||||
|
<group choice="req">
|
||||||
|
<arg choice="plain">-m</arg>
|
||||||
|
<arg choice="plain">--mask</arg>
|
||||||
|
</group>
|
||||||
|
<replaceable>MASK</replaceable>
|
||||||
|
</arg>
|
||||||
|
</group>
|
||||||
|
</command>
|
||||||
|
</title>
|
||||||
|
|
||||||
<para>This command prints a list of Linux capabilities along with their numeric IDs. See <citerefentry
|
<para>This command prints a list of Linux capabilities along with their numeric IDs. See <citerefentry
|
||||||
project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||||
@ -451,6 +473,11 @@ DATAERR 65 BSD
|
|||||||
cabilities by name or numeric ID, in which case only the indicated capabilities are shown in the
|
cabilities by name or numeric ID, in which case only the indicated capabilities are shown in the
|
||||||
table.</para>
|
table.</para>
|
||||||
|
|
||||||
|
<para>Alternatively, if <option>--mask</option> is passed, a single numeric argument must be specified,
|
||||||
|
which is interpreted as a hexadecimal capability mask. In this case, only the capabilities present in
|
||||||
|
the mask are shown in the table. This mode is intended to aid in decoding capability sets available
|
||||||
|
via various debugging interfaces (e.g. <literal>/proc/PID/status</literal>).</para>
|
||||||
|
|
||||||
<example>
|
<example>
|
||||||
<title><command>Show some example capability names</command></title>
|
<title><command>Show some example capability names</command></title>
|
||||||
|
|
||||||
@ -462,6 +489,18 @@ cap_audit_control 30
|
|||||||
cap_setfcap 31
|
cap_setfcap 31
|
||||||
cap_mac_override 32</programlisting>
|
cap_mac_override 32</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title><command>Decode a capability mask extracted from /proc</command></title>
|
||||||
|
|
||||||
|
<programlisting>$ systemd-analyze capability -m 0000000000003c00
|
||||||
|
NAME NUMBER
|
||||||
|
cap_net_bind_service 10
|
||||||
|
cap_net_broadcast 11
|
||||||
|
cap_net_admin 12
|
||||||
|
cap_net_raw 13
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
|
@ -5,6 +5,18 @@
|
|||||||
#include "cap-list.h"
|
#include "cap-list.h"
|
||||||
#include "capability-util.h"
|
#include "capability-util.h"
|
||||||
#include "format-table.h"
|
#include "format-table.h"
|
||||||
|
#include "parse-util.h"
|
||||||
|
|
||||||
|
static int table_add_capability(Table *table, int c) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = table_add_many(table,
|
||||||
|
TABLE_STRING, capability_to_name(c) ?: "cap_???",
|
||||||
|
TABLE_UINT, c);
|
||||||
|
if (r < 0)
|
||||||
|
return table_log_add_error(r);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int verb_capabilities(int argc, char *argv[], void *userdata) {
|
int verb_capabilities(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_(table_unrefp) Table *table = NULL;
|
_cleanup_(table_unrefp) Table *table = NULL;
|
||||||
@ -20,15 +32,38 @@ int verb_capabilities(int argc, char *argv[], void *userdata) {
|
|||||||
/* Determine the maximum of the last cap known by the kernel and by us */
|
/* Determine the maximum of the last cap known by the kernel and by us */
|
||||||
last_cap = MAX((unsigned) CAP_LAST_CAP, cap_last_cap());
|
last_cap = MAX((unsigned) CAP_LAST_CAP, cap_last_cap());
|
||||||
|
|
||||||
if (strv_isempty(strv_skip(argv, 1)))
|
if (arg_capability == CAPABILITY_MASK) {
|
||||||
for (unsigned c = 0; c <= last_cap; c++) {
|
uint64_t cap_mask;
|
||||||
r = table_add_many(table,
|
|
||||||
TABLE_STRING, capability_to_name(c) ?: "cap_???",
|
if (argc != 2)
|
||||||
TABLE_UINT, c);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Exactly 1 positional argument expected.");
|
||||||
if (r < 0)
|
|
||||||
return table_log_add_error(r);
|
r = safe_atoux64(argv[1], &cap_mask);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Capability mask \"%s\" is not valid.", argv[1]);
|
||||||
|
|
||||||
|
for (unsigned c = 0; cap_mask != 0; ) {
|
||||||
|
if (cap_mask & 0b1) {
|
||||||
|
if (c > last_cap)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Capability %u is not known.", c);
|
||||||
|
|
||||||
|
r = table_add_capability(table, c);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
++c;
|
||||||
|
cap_mask >>= 1;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
(void) table_set_sort(table, (size_t) 1);
|
||||||
|
|
||||||
|
} else if (argc == 1) {
|
||||||
|
for (unsigned c = 0; c <= last_cap; c++) {
|
||||||
|
r = table_add_capability(table, c);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
@ -36,11 +71,9 @@ int verb_capabilities(int argc, char *argv[], void *userdata) {
|
|||||||
if (c < 0 || (unsigned) c > last_cap)
|
if (c < 0 || (unsigned) c > last_cap)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Capability \"%s\" is not known.", argv[i]);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Capability \"%s\" is not known.", argv[i]);
|
||||||
|
|
||||||
r = table_add_many(table,
|
r = table_add_capability(table, c);
|
||||||
TABLE_STRING, capability_to_name(c) ?: "cap_???",
|
|
||||||
TABLE_UINT, (unsigned) c);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return table_log_add_error(r);
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) table_set_sort(table, (size_t) 1);
|
(void) table_set_sort(table, (size_t) 1);
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
#include "verbs.h"
|
#include "verbs.h"
|
||||||
|
|
||||||
DotMode arg_dot = DEP_ALL;
|
DotMode arg_dot = DEP_ALL;
|
||||||
|
CapabilityMode arg_capability = CAPABILITY_LITERAL;
|
||||||
char **arg_dot_from_patterns = NULL, **arg_dot_to_patterns = NULL;
|
char **arg_dot_from_patterns = NULL, **arg_dot_to_patterns = NULL;
|
||||||
usec_t arg_fuzz = 0;
|
usec_t arg_fuzz = 0;
|
||||||
PagerFlags arg_pager_flags = 0;
|
PagerFlags arg_pager_flags = 0;
|
||||||
@ -358,6 +359,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "table", optional_argument, NULL, ARG_TABLE },
|
{ "table", optional_argument, NULL, ARG_TABLE },
|
||||||
{ "no-legend", optional_argument, NULL, ARG_NO_LEGEND },
|
{ "no-legend", optional_argument, NULL, ARG_NO_LEGEND },
|
||||||
{ "tldr", no_argument, NULL, ARG_TLDR },
|
{ "tldr", no_argument, NULL, ARG_TLDR },
|
||||||
|
{ "mask", no_argument, NULL, 'm' },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -366,7 +368,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "hH:M:U:q", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "hqH:M:U:m", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
@ -551,6 +553,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
arg_cat_flags = CAT_TLDR;
|
arg_cat_flags = CAT_TLDR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
arg_capability = CAPABILITY_MASK;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -614,6 +620,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (arg_table && !FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF))
|
if (arg_table && !FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--table and --json= are mutually exclusive.");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--table and --json= are mutually exclusive.");
|
||||||
|
|
||||||
|
if (arg_capability != CAPABILITY_LITERAL && !streq_ptr(argv[optind], "capability"))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --mask is only supported for capability.");
|
||||||
|
|
||||||
return 1; /* work to do */
|
return 1; /* work to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,13 @@ typedef enum DotMode {
|
|||||||
DEP_REQUIRE,
|
DEP_REQUIRE,
|
||||||
} DotMode;
|
} DotMode;
|
||||||
|
|
||||||
|
typedef enum CapabilityMode {
|
||||||
|
CAPABILITY_LITERAL,
|
||||||
|
CAPABILITY_MASK,
|
||||||
|
} CapabilityMode;
|
||||||
|
|
||||||
extern DotMode arg_dot;
|
extern DotMode arg_dot;
|
||||||
|
extern CapabilityMode arg_capability;
|
||||||
extern char **arg_dot_from_patterns, **arg_dot_to_patterns;
|
extern char **arg_dot_from_patterns, **arg_dot_to_patterns;
|
||||||
extern usec_t arg_fuzz;
|
extern usec_t arg_fuzz;
|
||||||
extern PagerFlags arg_pager_flags;
|
extern PagerFlags arg_pager_flags;
|
||||||
|
@ -105,6 +105,15 @@ systemd-analyze capability cap_chown CAP_KILL
|
|||||||
systemd-analyze capability 0 1 {30..32}
|
systemd-analyze capability 0 1 {30..32}
|
||||||
(! systemd-analyze capability cap_chown CAP_KILL "hello*")
|
(! systemd-analyze capability cap_chown CAP_KILL "hello*")
|
||||||
(! systemd-analyze capability --global)
|
(! systemd-analyze capability --global)
|
||||||
|
systemd-analyze capability -m 0000000000003c00
|
||||||
|
(! systemd-analyze capability -m 8000000000000000)
|
||||||
|
cap="$(systemd-analyze capability -m 0000000000003c00)"
|
||||||
|
[[ $cap != *cap_linux_immutable* ]]
|
||||||
|
[[ $cap == *cap_net_bind_service* ]]
|
||||||
|
[[ $cap == *cap_net_broadcast* ]]
|
||||||
|
[[ $cap == *cap_net_admin* ]]
|
||||||
|
[[ $cap == *cap_net_raw* ]]
|
||||||
|
[[ $cap != *cap_ipc_lock* ]]
|
||||||
# condition
|
# condition
|
||||||
mkdir -p /run/systemd/system
|
mkdir -p /run/systemd/system
|
||||||
UNIT_NAME="analyze-condition-$RANDOM.service"
|
UNIT_NAME="analyze-condition-$RANDOM.service"
|
||||||
|
Loading…
Reference in New Issue
Block a user