mirror of
https://github.com/systemd/systemd
synced 2026-03-27 01:04:53 +01:00
Compare commits
11 Commits
77afbef692
...
7d50cd65bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d50cd65bb | ||
|
|
f0a8ec4372 | ||
|
|
4b4a8ef741 | ||
|
|
c1e6f21556 | ||
|
|
f77e015a88 | ||
|
|
9ff61565be | ||
|
|
239ac0c7f7 | ||
|
|
7bf5ec4538 | ||
|
|
9ccb531a5f | ||
|
|
9e2dbfef47 | ||
|
|
94cb45d57f |
@ -930,6 +930,15 @@ evdev:input:b0003v04B3p301B*
|
||||
evdev:name:SIPODEV Lenovo HID Device:dmi:*:svnLENOVO:*:pvrLenovoideapadD330-10IGM:*
|
||||
KEYBOARD_KEY_70073=f21 # Fn+Supr (Touchpad toggle)
|
||||
|
||||
###########################################################
|
||||
# LG
|
||||
###########################################################
|
||||
|
||||
# LG Gram
|
||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLGElectronics:pn1*.AAS*:*
|
||||
KEYBOARD_KEY_a0=!mute
|
||||
KEYBOARD_KEY_ae=!volumedown
|
||||
KEYBOARD_KEY_b0=!volumeup
|
||||
|
||||
###########################################################
|
||||
# Logitech
|
||||
|
||||
33
hwdb.d/70-analyzers.hwdb
Normal file
33
hwdb.d/70-analyzers.hwdb
Normal file
@ -0,0 +1,33 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# Database for signal analyzers (protocol analyzers, logic analyzers,
|
||||
# oscilloscopes, multimeters, bench power supplies, etc.) that should
|
||||
# be accessible to the seat owner.
|
||||
#
|
||||
# Permitted keys:
|
||||
# Specify if a device is a signal analyzer
|
||||
# ID_SIGNAL_ANALYZER=1|0
|
||||
|
||||
###########################################################
|
||||
# Total Phase
|
||||
###########################################################
|
||||
# Aarvark I2C/SPI Host Adapter
|
||||
usb:v0403pe0d0*
|
||||
ID_SIGNAL_ANALYZER=1
|
||||
|
||||
# Beagle Protocol Analyzers
|
||||
usb:v1679p2001*
|
||||
ID_SIGNAL_ANALYZER=1
|
||||
|
||||
# Cheetah SPI Host Adapter
|
||||
usb:v1679p2002*
|
||||
ID_SIGNAL_ANALYZER=1
|
||||
|
||||
# Komodo CAN Duo Interface
|
||||
usb:v1679p3001*
|
||||
ID_SIGNAL_ANALYZER=1
|
||||
|
||||
# Power Delivery Analyzers
|
||||
usb:v1679p6003*
|
||||
usb:v0483pdf11*
|
||||
ID_SIGNAL_ANALYZER=1
|
||||
@ -27,6 +27,7 @@ hwdb_files_test = files('''
|
||||
60-keyboard.hwdb
|
||||
60-seat.hwdb
|
||||
60-sensor.hwdb
|
||||
70-analyzers.hwdb
|
||||
70-joystick.hwdb
|
||||
70-mouse.hwdb
|
||||
70-pointingstick.hwdb
|
||||
|
||||
@ -147,6 +147,7 @@ def property_grammar():
|
||||
('ID_INPUT_TOUCHPAD', Or((Literal('0'), Literal('1')))),
|
||||
('ID_INPUT_TOUCHSCREEN', Or((Literal('0'), Literal('1')))),
|
||||
('ID_INPUT_TRACKBALL', Or((Literal('0'), Literal('1')))),
|
||||
('ID_SIGNAL_ANALYZER', Or((Literal('0'), Literal('1')))),
|
||||
('POINTINGSTICK_SENSITIVITY', INTEGER),
|
||||
('POINTINGSTICK_CONST_ACCEL', REAL),
|
||||
('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))),
|
||||
|
||||
@ -967,25 +967,25 @@ Service b@0.service not loaded, b.socket cannot be started.
|
||||
<entry>RestrictSUIDSGID</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWUSER</entry>
|
||||
<entry>RestrictNamespaces_user</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWNS</entry>
|
||||
<entry>RestrictNamespaces_mnt</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWIPC</entry>
|
||||
<entry>RestrictNamespaces_ipc</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWPID</entry>
|
||||
<entry>RestrictNamespaces_pid</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWCGROUP</entry>
|
||||
<entry>RestrictNamespaces_cgroup</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWUTS</entry>
|
||||
<entry>RestrictNamespaces_uts</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWNET</entry>
|
||||
<entry>RestrictNamespaces_net</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictAddressFamilies_AF_INET_INET6</entry>
|
||||
@ -1109,6 +1109,22 @@ Service b@0.service not loaded, b.socket cannot be started.
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--json=<replaceable>MODE</replaceable></option></term>
|
||||
|
||||
<listitem><para>With the <command>security</command> command, generate a JSON formatted
|
||||
output of the security analysis table. The format is a JSON array with objects
|
||||
containing the following fields: <varname>set</varname> which indicates if the setting has
|
||||
been enabled or not, <varname>name</varname> which is what is used to refer to the setting,
|
||||
<varname>json_field</varname> which is the JSON compatible identifier of the setting,
|
||||
<varname>description</varname> which is an outline of the setting state, and
|
||||
<varname>exposure</varname> which is a number in the range 0.0…10.0, where a higher value
|
||||
corresponds to a higher security threat. The JSON version of the table is printed to standard
|
||||
output. The <replaceable>MODE</replaceable> passed to the option can be one of three:
|
||||
<option>off</option> which is the default, <option>pretty</option> and <option>short</option>
|
||||
which respectively output a prettified or shorted JSON version of the security table.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--iterations=<replaceable>NUMBER</replaceable></option></term>
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"
|
||||
|
||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
|
||||
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
|
||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="hwdb 'usb:v$attr{idVendor}p$attr{idProduct}'"
|
||||
|
||||
ACTION!="add", GOTO="default_end"
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ _systemd_analyze() {
|
||||
|
||||
elif __contains_word "$verb" ${VERBS[SECURITY]}; then
|
||||
if [[ $cur = -* ]]; then
|
||||
comps='--help --version --no-pager --system --user -H --host -M --machine --offline --threshold --security-policy'
|
||||
comps='--help --version --no-pager --system --user -H --host -M --machine --offline --threshold --security-policy --json=off --json=pretty --json=short'
|
||||
else
|
||||
if __contains_word "--user" ${COMP_WORDS[*]}; then
|
||||
mode=--user
|
||||
|
||||
@ -93,6 +93,7 @@ _arguments \
|
||||
'--offline=[Perform a security review of the specified unit file(s)]:BOOL' \
|
||||
'--threshold=[Set a value to compare the overall security exposure level with]: NUMBER' \
|
||||
'--security-policy=[Allow user to use customized requirements to compare unit file(s) against]: PATH' \
|
||||
'--json=[Generate a JSON output of the security analysis table]:MODE:(pretty short off)' \
|
||||
'--no-pager[Do not pipe output into a pager]' \
|
||||
'--man=[Do (not) check for existence of man pages]:boolean:(1 0)' \
|
||||
'--order[When generating graph for dot, show only order]' \
|
||||
|
||||
@ -1340,8 +1340,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.offset = offsetof(SecurityInfo, restrict_suid_sgid),
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWUSER",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWUSER",
|
||||
.id = "RestrictNamespaces=~user",
|
||||
.json_field = "RestrictNamespaces_user",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create user namespaces",
|
||||
.description_bad = "Service may create user namespaces",
|
||||
@ -1351,8 +1351,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.parameter = CLONE_NEWUSER,
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWNS",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWNS",
|
||||
.id = "RestrictNamespaces=~mnt",
|
||||
.json_field = "RestrictNamespaces_mnt",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create file system namespaces",
|
||||
.description_bad = "Service may create file system namespaces",
|
||||
@ -1362,8 +1362,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.parameter = CLONE_NEWNS,
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWIPC",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWIPC",
|
||||
.id = "RestrictNamespaces=~ipc",
|
||||
.json_field = "RestrictNamespaces_ipc",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create IPC namespaces",
|
||||
.description_bad = "Service may create IPC namespaces",
|
||||
@ -1373,8 +1373,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.parameter = CLONE_NEWIPC,
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWPID",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWPID",
|
||||
.id = "RestrictNamespaces=~pid",
|
||||
.json_field = "RestrictNamespaces_pid",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create process namespaces",
|
||||
.description_bad = "Service may create process namespaces",
|
||||
@ -1384,8 +1384,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.parameter = CLONE_NEWPID,
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWCGROUP",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWCGROUP",
|
||||
.id = "RestrictNamespaces=~cgroup",
|
||||
.json_field = "RestrictNamespaces_cgroup",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create cgroup namespaces",
|
||||
.description_bad = "Service may create cgroup namespaces",
|
||||
@ -1395,8 +1395,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.parameter = CLONE_NEWCGROUP,
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWNET",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWNET",
|
||||
.id = "RestrictNamespaces=~net",
|
||||
.json_field = "RestrictNamespaces_net",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create network namespaces",
|
||||
.description_bad = "Service may create network namespaces",
|
||||
@ -1406,8 +1406,8 @@ static const struct security_assessor security_assessor_table[] = {
|
||||
.parameter = CLONE_NEWNET,
|
||||
},
|
||||
{
|
||||
.id = "RestrictNamespaces=~CLONE_NEWUTS",
|
||||
.json_field = "RestrictNamespaces_CLONE_NEWUTS",
|
||||
.id = "RestrictNamespaces=~uts",
|
||||
.json_field = "RestrictNamespaces_uts",
|
||||
.url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
|
||||
.description_good = "Service cannot create hostname namespaces",
|
||||
.description_bad = "Service may create hostname namespaces",
|
||||
@ -1709,7 +1709,9 @@ static int assess(const SecurityInfo *info,
|
||||
Table *overview_table,
|
||||
AnalyzeSecurityFlags flags,
|
||||
unsigned threshold,
|
||||
JsonVariant *policy) {
|
||||
JsonVariant *policy,
|
||||
PagerFlags pager_flags,
|
||||
JsonFormatFlags json_format_flags) {
|
||||
|
||||
static const struct {
|
||||
uint64_t exposure;
|
||||
@ -1732,15 +1734,19 @@ static int assess(const SecurityInfo *info,
|
||||
int r;
|
||||
|
||||
if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
|
||||
details_table = table_new(" ", "name", "description", "weight", "badness", "range", "exposure");
|
||||
details_table = table_new(" ", "name", "json_field", "description", "weight", "badness", "range", "exposure");
|
||||
if (!details_table)
|
||||
return log_oom();
|
||||
|
||||
r = table_set_json_field_name(details_table, 0, "set");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set JSON field name of column 0: %m");
|
||||
|
||||
(void) table_set_sort(details_table, (size_t) 3, (size_t) 1);
|
||||
(void) table_set_reverse(details_table, 3, true);
|
||||
|
||||
if (getenv_bool("SYSTEMD_ANALYZE_DEBUG") <= 0)
|
||||
(void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 6);
|
||||
(void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 7);
|
||||
}
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
|
||||
@ -1774,23 +1780,23 @@ static int assess(const SecurityInfo *info,
|
||||
}
|
||||
|
||||
if (details_table) {
|
||||
const char *checkmark, *description, *color = NULL;
|
||||
const char *id = a->id;
|
||||
const char *description, *color = NULL;
|
||||
int checkmark;
|
||||
|
||||
if (badness == UINT64_MAX) {
|
||||
checkmark = " ";
|
||||
checkmark = -1;
|
||||
description = access_description_na(a, policy);
|
||||
color = NULL;
|
||||
} else if (badness == a->range) {
|
||||
checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
|
||||
checkmark = 0;
|
||||
description = access_description_bad(a, policy);
|
||||
color = ansi_highlight_red();
|
||||
} else if (badness == 0) {
|
||||
checkmark = special_glyph(SPECIAL_GLYPH_CHECK_MARK);
|
||||
checkmark = 1;
|
||||
description = access_description_good(a, policy);
|
||||
color = ansi_highlight_green();
|
||||
} else {
|
||||
checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
|
||||
checkmark = 0;
|
||||
description = NULL;
|
||||
color = ansi_highlight_red();
|
||||
}
|
||||
@ -1798,16 +1804,24 @@ static int assess(const SecurityInfo *info,
|
||||
if (d)
|
||||
description = d;
|
||||
|
||||
if (json_variant_by_key(policy, a->json_field) != NULL)
|
||||
id = a->json_field;
|
||||
if (checkmark < 0) {
|
||||
r = table_add_many(details_table, TABLE_EMPTY);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
} else {
|
||||
r = table_add_many(details_table,
|
||||
TABLE_BOOLEAN_CHECKMARK, checkmark > 0,
|
||||
TABLE_SET_MINIMUM_WIDTH, 1,
|
||||
TABLE_SET_MAXIMUM_WIDTH, 1,
|
||||
TABLE_SET_ELLIPSIZE_PERCENT, 0,
|
||||
TABLE_SET_COLOR, color);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = table_add_many(details_table,
|
||||
TABLE_STRING, checkmark,
|
||||
TABLE_SET_MINIMUM_WIDTH, 1,
|
||||
TABLE_SET_MAXIMUM_WIDTH, 1,
|
||||
TABLE_SET_ELLIPSIZE_PERCENT, 0,
|
||||
TABLE_SET_COLOR, color,
|
||||
TABLE_STRING, id, TABLE_SET_URL, a->url,
|
||||
TABLE_STRING, a->id, TABLE_SET_URL, a->url,
|
||||
TABLE_STRING, a->json_field,
|
||||
TABLE_STRING, description,
|
||||
TABLE_UINT64, weight, TABLE_SET_ALIGN_PERCENT, 100,
|
||||
TABLE_UINT64, badness, TABLE_SET_ALIGN_PERCENT, 100,
|
||||
@ -1829,14 +1843,14 @@ static int assess(const SecurityInfo *info,
|
||||
TableCell *cell;
|
||||
uint64_t x;
|
||||
|
||||
assert_se(weight = table_get_at(details_table, row, 3));
|
||||
assert_se(badness = table_get_at(details_table, row, 4));
|
||||
assert_se(range = table_get_at(details_table, row, 5));
|
||||
assert_se(weight = table_get_at(details_table, row, 4));
|
||||
assert_se(badness = table_get_at(details_table, row, 5));
|
||||
assert_se(range = table_get_at(details_table, row, 6));
|
||||
|
||||
if (*badness == UINT64_MAX || *badness == 0)
|
||||
continue;
|
||||
|
||||
assert_se(cell = table_get_cell(details_table, row, 6));
|
||||
assert_se(cell = table_get_cell(details_table, row, 7));
|
||||
|
||||
x = DIV_ROUND_UP(DIV_ROUND_UP(*badness * *weight * 100U, *range), weight_sum);
|
||||
xsprintf(buf, "%" PRIu64 ".%" PRIu64, x / 10, x % 10);
|
||||
@ -1846,7 +1860,13 @@ static int assess(const SecurityInfo *info,
|
||||
return log_error_errno(r, "Failed to update cell in table: %m");
|
||||
}
|
||||
|
||||
r = table_print(details_table, stdout);
|
||||
if (json_format_flags & JSON_FORMAT_OFF) {
|
||||
r = table_hide_column_from_display(details_table, (size_t) 2);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set columns to display: %m");
|
||||
}
|
||||
|
||||
r = table_print_with_pager(details_table, json_format_flags, pager_flags, /* show_header= */true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to output table: %m");
|
||||
}
|
||||
@ -1859,7 +1879,7 @@ static int assess(const SecurityInfo *info,
|
||||
|
||||
assert(i < ELEMENTSOF(badness_table));
|
||||
|
||||
if (details_table) {
|
||||
if (details_table && (json_format_flags & JSON_FORMAT_OFF)) {
|
||||
_cleanup_free_ char *clickable = NULL;
|
||||
const char *name;
|
||||
|
||||
@ -2386,7 +2406,9 @@ static int analyze_security_one(sd_bus *bus,
|
||||
Table *overview_table,
|
||||
AnalyzeSecurityFlags flags,
|
||||
unsigned threshold,
|
||||
JsonVariant *policy) {
|
||||
JsonVariant *policy,
|
||||
PagerFlags pager_flags,
|
||||
JsonFormatFlags json_format_flags) {
|
||||
|
||||
_cleanup_(security_info_freep) SecurityInfo *info = security_info_new();
|
||||
if (!info)
|
||||
@ -2403,7 +2425,7 @@ static int analyze_security_one(sd_bus *bus,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = assess(info, overview_table, flags, threshold, policy);
|
||||
r = assess(info, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -2589,7 +2611,12 @@ static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, Security
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int offline_security_check(Unit *u, unsigned threshold, JsonVariant *policy) {
|
||||
static int offline_security_check(Unit *u,
|
||||
unsigned threshold,
|
||||
JsonVariant *policy,
|
||||
PagerFlags pager_flags,
|
||||
JsonFormatFlags json_format_flags) {
|
||||
|
||||
_cleanup_(table_unrefp) Table *overview_table = NULL;
|
||||
AnalyzeSecurityFlags flags = 0;
|
||||
_cleanup_(security_info_freep) SecurityInfo *info = NULL;
|
||||
@ -2604,7 +2631,7 @@ static int offline_security_check(Unit *u, unsigned threshold, JsonVariant *poli
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return assess(info, overview_table, flags, threshold, policy);
|
||||
return assess(info, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
|
||||
}
|
||||
|
||||
static int offline_security_checks(char **filenames,
|
||||
@ -2613,7 +2640,9 @@ static int offline_security_checks(char **filenames,
|
||||
bool check_man,
|
||||
bool run_generators,
|
||||
unsigned threshold,
|
||||
const char *root) {
|
||||
const char *root,
|
||||
PagerFlags pager_flags,
|
||||
JsonFormatFlags json_format_flags) {
|
||||
|
||||
const ManagerTestRunFlags flags =
|
||||
MANAGER_TEST_RUN_MINIMAL |
|
||||
@ -2673,7 +2702,7 @@ static int offline_security_checks(char **filenames,
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
k = offline_security_check(units[i], threshold, policy);
|
||||
k = offline_security_check(units[i], threshold, policy, pager_flags, json_format_flags);
|
||||
if (k < 0 && r == 0)
|
||||
r = k;
|
||||
}
|
||||
@ -2690,6 +2719,8 @@ int analyze_security(sd_bus *bus,
|
||||
bool offline,
|
||||
unsigned threshold,
|
||||
const char *root,
|
||||
JsonFormatFlags json_format_flags,
|
||||
PagerFlags pager_flags,
|
||||
AnalyzeSecurityFlags flags) {
|
||||
|
||||
_cleanup_(table_unrefp) Table *overview_table = NULL;
|
||||
@ -2698,7 +2729,7 @@ int analyze_security(sd_bus *bus,
|
||||
assert(bus);
|
||||
|
||||
if (offline)
|
||||
return offline_security_checks(units, policy, scope, check_man, run_generators, threshold, root);
|
||||
return offline_security_checks(units, policy, scope, check_man, run_generators, threshold, root, pager_flags, json_format_flags);
|
||||
|
||||
if (strv_length(units) != 1) {
|
||||
overview_table = table_new("unit", "exposure", "predicate", "happy");
|
||||
@ -2758,7 +2789,7 @@ int analyze_security(sd_bus *bus,
|
||||
flags |= ANALYZE_SECURITY_SHORT|ANALYZE_SECURITY_ONLY_LOADED|ANALYZE_SECURITY_ONLY_LONG_RUNNING;
|
||||
|
||||
STRV_FOREACH(i, list) {
|
||||
r = analyze_security_one(bus, *i, overview_table, flags, threshold, policy);
|
||||
r = analyze_security_one(bus, *i, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
|
||||
if (r < 0 && ret >= 0)
|
||||
ret = r;
|
||||
}
|
||||
@ -2793,7 +2824,7 @@ int analyze_security(sd_bus *bus,
|
||||
} else
|
||||
name = mangled;
|
||||
|
||||
r = analyze_security_one(bus, name, overview_table, flags, threshold, policy);
|
||||
r = analyze_security_one(bus, name, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
|
||||
if (r < 0 && ret >= 0)
|
||||
ret = r;
|
||||
}
|
||||
@ -2805,10 +2836,9 @@ int analyze_security(sd_bus *bus,
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
r = table_print(overview_table, stdout);
|
||||
r = table_print_with_pager(overview_table, json_format_flags, pager_flags, /* show_header= */true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to output table: %m");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "json.h"
|
||||
#include "pager.h"
|
||||
#include "unit-file.h"
|
||||
|
||||
typedef enum AnalyzeSecurityFlags {
|
||||
@ -23,4 +24,6 @@ int analyze_security(sd_bus *bus,
|
||||
bool offline,
|
||||
unsigned threshold,
|
||||
const char *root,
|
||||
JsonFormatFlags json_format_flags,
|
||||
PagerFlags pager_flags,
|
||||
AnalyzeSecurityFlags flags);
|
||||
|
||||
@ -97,6 +97,7 @@ static unsigned arg_threshold = 100;
|
||||
static unsigned arg_iterations = 1;
|
||||
static usec_t arg_base_time = USEC_INFINITY;
|
||||
static char *arg_unit = NULL;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
|
||||
@ -2196,6 +2197,8 @@ static int do_security(int argc, char *argv[], void *userdata) {
|
||||
arg_offline,
|
||||
arg_threshold,
|
||||
arg_root,
|
||||
arg_json_format_flags,
|
||||
arg_pager_flags,
|
||||
/*flags=*/ 0);
|
||||
}
|
||||
|
||||
@ -2250,6 +2253,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" --version Show package version\n"
|
||||
" --security-policy=PATH Use custom JSON security policy instead\n"
|
||||
" of built-in one\n"
|
||||
" --json=pretty|short|off Generate JSON output of the security\n"
|
||||
" analysis table\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --system Operate on system systemd instance\n"
|
||||
" --user Operate on user systemd instance\n"
|
||||
@ -2303,6 +2308,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_OFFLINE,
|
||||
ARG_THRESHOLD,
|
||||
ARG_SECURITY_POLICY,
|
||||
ARG_JSON,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -2330,6 +2336,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "iterations", required_argument, NULL, ARG_ITERATIONS },
|
||||
{ "base-time", required_argument, NULL, ARG_BASE_TIME },
|
||||
{ "unit", required_argument, NULL, 'U' },
|
||||
{ "json", required_argument, NULL, ARG_JSON },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -2454,6 +2461,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_JSON:
|
||||
r = parse_json_argument(optarg, &arg_json_format_flags);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_ITERATIONS:
|
||||
r = safe_atou(optarg, &arg_iterations);
|
||||
if (r < 0)
|
||||
@ -2489,6 +2502,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --offline= is only supported for security right now.");
|
||||
|
||||
if (arg_json_format_flags != JSON_FORMAT_OFF && !streq_ptr(argv[optind], "security"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --json= is only supported for security right now.");
|
||||
|
||||
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --threshold= is only supported for security right now.");
|
||||
|
||||
@ -80,4 +80,7 @@ ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess"
|
||||
# 3D printers, CNC machines, laser cutters, 3D scanners, etc.
|
||||
ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess"
|
||||
|
||||
# Protocol analyzers
|
||||
ENV{ID_SIGNAL_ANALYZER}=="?*", ENV{DEVTYPE}=="usb_device", TAG+="uaccess"
|
||||
|
||||
LABEL="uaccess_end"
|
||||
|
||||
@ -11,8 +11,10 @@
|
||||
#include "dirent-util.h"
|
||||
#include "discover-image.h"
|
||||
#include "dissect-image.h"
|
||||
#include "env-file.h"
|
||||
#include "errno-list.h"
|
||||
#include "escape.h"
|
||||
#include "extension-release.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
@ -230,6 +232,8 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(portable_metadata_hash_ops, char,
|
||||
static int extract_now(
|
||||
const char *where,
|
||||
char **matches,
|
||||
const char *image_name,
|
||||
bool path_is_extension,
|
||||
int socket_fd,
|
||||
PortableMetadata **ret_os_release,
|
||||
Hashmap **ret_unit_files) {
|
||||
@ -239,6 +243,7 @@ static int extract_now(
|
||||
_cleanup_(lookup_paths_free) LookupPaths paths = {};
|
||||
_cleanup_close_ int os_release_fd = -1;
|
||||
_cleanup_free_ char *os_release_path = NULL;
|
||||
const char *os_release_id;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
@ -253,19 +258,27 @@ static int extract_now(
|
||||
|
||||
assert(where);
|
||||
|
||||
/* First, find /etc/os-release and send it upstream (or just save it). */
|
||||
r = open_os_release(where, &os_release_path, &os_release_fd);
|
||||
/* First, find os-release/extension-release and send it upstream (or just save it). */
|
||||
if (path_is_extension) {
|
||||
os_release_id = strjoina("/usr/lib/extension-release.d/extension-release.", image_name);
|
||||
r = open_extension_release(where, image_name, &os_release_path, &os_release_fd);
|
||||
} else {
|
||||
os_release_id = "/etc/os-release";
|
||||
r = open_os_release(where, &os_release_path, &os_release_fd);
|
||||
}
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Couldn't acquire os-release file, ignoring: %m");
|
||||
log_debug_errno(r,
|
||||
"Couldn't acquire %s file, ignoring: %m",
|
||||
path_is_extension ? "extension-release " : "os-release");
|
||||
else {
|
||||
if (socket_fd >= 0) {
|
||||
r = send_item(socket_fd, "/etc/os-release", os_release_fd);
|
||||
r = send_item(socket_fd, os_release_id, os_release_fd);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to send os-release file: %m");
|
||||
}
|
||||
|
||||
if (ret_os_release) {
|
||||
os_release = portable_metadata_new("/etc/os-release", NULL, os_release_fd);
|
||||
os_release = portable_metadata_new(os_release_id, NULL, os_release_fd);
|
||||
if (!os_release)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -351,7 +364,7 @@ static int extract_now(
|
||||
|
||||
static int portable_extract_by_path(
|
||||
const char *path,
|
||||
bool extract_os_release,
|
||||
bool path_is_extension,
|
||||
char **matches,
|
||||
PortableMetadata **ret_os_release,
|
||||
Hashmap **ret_unit_files,
|
||||
@ -369,7 +382,7 @@ static int portable_extract_by_path(
|
||||
/* We can't turn this into a loop-back block device, and this returns EISDIR? Then this is a directory
|
||||
* tree and not a raw device. It's easy then. */
|
||||
|
||||
r = extract_now(path, matches, -1, &os_release, &unit_files);
|
||||
r = extract_now(path, matches, NULL, path_is_extension, -1, &os_release, &unit_files);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -423,15 +436,22 @@ static int portable_extract_by_path(
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
DissectImageFlags flags = DISSECT_IMAGE_READ_ONLY;
|
||||
|
||||
seq[0] = safe_close(seq[0]);
|
||||
|
||||
r = dissected_image_mount(m, tmpdir, UID_INVALID, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
|
||||
if (path_is_extension)
|
||||
flags |= DISSECT_IMAGE_VALIDATE_OS_EXT;
|
||||
else
|
||||
flags |= DISSECT_IMAGE_VALIDATE_OS;
|
||||
|
||||
r = dissected_image_mount(m, tmpdir, UID_INVALID, UID_INVALID, flags);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to mount dissected image: %m");
|
||||
goto child_finish;
|
||||
}
|
||||
|
||||
r = extract_now(tmpdir, matches, seq[1], NULL, NULL);
|
||||
r = extract_now(tmpdir, matches, m->image_name, path_is_extension, seq[1], NULL, NULL);
|
||||
|
||||
child_finish:
|
||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
@ -477,7 +497,7 @@ static int portable_extract_by_path(
|
||||
|
||||
add = NULL;
|
||||
|
||||
} else if (PORTABLE_METADATA_IS_OS_RELEASE(add)) {
|
||||
} else if (PORTABLE_METADATA_IS_OS_RELEASE(add) || PORTABLE_METADATA_IS_EXTENSION_RELEASE(add)) {
|
||||
|
||||
assert(!os_release);
|
||||
os_release = TAKE_PTR(add);
|
||||
@ -491,13 +511,12 @@ static int portable_extract_by_path(
|
||||
child = 0;
|
||||
}
|
||||
|
||||
/* When the portable image is layered, the image with units will not
|
||||
* have a full filesystem, so no os-release - it will be in the root layer */
|
||||
if (extract_os_release && !os_release)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image '%s' lacks os-release data, refusing.", path);
|
||||
|
||||
if (!extract_os_release && hashmap_isempty(unit_files))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't find any matching unit files in image '%s', refusing.", path);
|
||||
if (!os_release)
|
||||
return sd_bus_error_setf(error,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image '%s' lacks %s data, refusing.",
|
||||
path,
|
||||
path_is_extension ? "extension-release" : "os-release");
|
||||
|
||||
if (ret_unit_files)
|
||||
*ret_unit_files = TAKE_PTR(unit_files);
|
||||
@ -508,14 +527,18 @@ static int portable_extract_by_path(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int portable_extract(
|
||||
static int extract_image_and_extensions(
|
||||
const char *name_or_path,
|
||||
char **matches,
|
||||
char **extension_image_paths,
|
||||
bool validate_sysext,
|
||||
Image **ret_image,
|
||||
OrderedHashmap **ret_extension_images,
|
||||
PortableMetadata **ret_os_release,
|
||||
Hashmap **ret_unit_files,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
|
||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
||||
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
||||
@ -524,6 +547,9 @@ int portable_extract(
|
||||
int r;
|
||||
|
||||
assert(name_or_path);
|
||||
assert(matches);
|
||||
assert(ret_image);
|
||||
assert(ret_extension_images);
|
||||
|
||||
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
|
||||
if (r < 0)
|
||||
@ -550,19 +576,106 @@ int portable_extract(
|
||||
}
|
||||
}
|
||||
|
||||
r = portable_extract_by_path(image->path, true, matches, &os_release, &unit_files, error);
|
||||
r = portable_extract_by_path(image->path, /* path_is_extension= */ false, matches, &os_release, &unit_files, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
||||
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
|
||||
/* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
|
||||
* match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
|
||||
if (validate_sysext) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
r = portable_extract_by_path(ext->path, false, matches, NULL, &extra_unit_files, error);
|
||||
r = take_fdopen_unlocked(&os_release->fd, "r", &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_env_file(f, os_release->name,
|
||||
"ID", &id,
|
||||
"VERSION_ID", &version_id,
|
||||
"SYSEXT_LEVEL", &sysext_level);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
|
||||
_cleanup_strv_free_ char **extension_release = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, &extension_release_meta, &extra_unit_files, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_move(unit_files, extra_unit_files);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!validate_sysext)
|
||||
continue;
|
||||
|
||||
r = take_fdopen_unlocked(&extension_release_meta->fd, "r", &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = load_env_file_pairs(f, extension_release_meta->name, &extension_release);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = extension_release_validate(ext->path, id, version_id, sysext_level, extension_release);
|
||||
if (r == 0)
|
||||
return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
|
||||
}
|
||||
|
||||
*ret_image = TAKE_PTR(image);
|
||||
*ret_extension_images = TAKE_PTR(extension_images);
|
||||
if (ret_os_release)
|
||||
*ret_os_release = TAKE_PTR(os_release);
|
||||
if (ret_unit_files)
|
||||
*ret_unit_files = TAKE_PTR(unit_files);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int portable_extract(
|
||||
const char *name_or_path,
|
||||
char **matches,
|
||||
char **extension_image_paths,
|
||||
PortableMetadata **ret_os_release,
|
||||
Hashmap **ret_unit_files,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
||||
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
||||
_cleanup_(image_unrefp) Image *image = NULL;
|
||||
int r;
|
||||
|
||||
r = extract_image_and_extensions(name_or_path,
|
||||
matches,
|
||||
extension_image_paths,
|
||||
/* validate_sysext= */ false,
|
||||
&image,
|
||||
&extension_images,
|
||||
&os_release,
|
||||
&unit_files,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (hashmap_isempty(unit_files)) {
|
||||
_cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
|
||||
if (!extensions)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_bus_error_setf(error,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Couldn't find any matching unit files in image '%s%s%s', refusing.",
|
||||
image->path,
|
||||
isempty(extensions) ? "" : "' or any of its extensions '",
|
||||
isempty(extensions) ? "" : extensions);
|
||||
}
|
||||
|
||||
*ret_os_release = TAKE_PTR(os_release);
|
||||
@ -1138,47 +1251,31 @@ int portable_attach(
|
||||
_cleanup_(lookup_paths_free) LookupPaths paths = {};
|
||||
_cleanup_(image_unrefp) Image *image = NULL;
|
||||
PortableMetadata *item;
|
||||
Image *ext;
|
||||
char **p;
|
||||
int r;
|
||||
|
||||
assert(name_or_path);
|
||||
|
||||
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
|
||||
r = extract_image_and_extensions(name_or_path,
|
||||
matches,
|
||||
extension_image_paths,
|
||||
/* validate_sysext= */ true,
|
||||
&image,
|
||||
&extension_images,
|
||||
/* os_release= */ NULL,
|
||||
&unit_files,
|
||||
error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!strv_isempty(extension_image_paths)) {
|
||||
extension_images = ordered_hashmap_new(&image_hash_ops);
|
||||
if (!extension_images)
|
||||
|
||||
if (hashmap_isempty(unit_files)) {
|
||||
_cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
|
||||
if (!extensions)
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(p, extension_image_paths) {
|
||||
_cleanup_(image_unrefp) Image *new = NULL;
|
||||
|
||||
r = image_find_harder(IMAGE_PORTABLE, *p, NULL, &new);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_hashmap_put(extension_images, new->name, new);
|
||||
if (r < 0)
|
||||
return r;
|
||||
TAKE_PTR(new);
|
||||
}
|
||||
}
|
||||
|
||||
r = portable_extract_by_path(image->path, true, matches, NULL, &unit_files, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
||||
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
|
||||
|
||||
r = portable_extract_by_path(ext->path, false, matches, NULL, &extra_unit_files, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = hashmap_move(unit_files, extra_unit_files);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return sd_bus_error_setf(error,
|
||||
SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Couldn't find any matching unit files in image '%s%s%s', refusing.",
|
||||
image->path,
|
||||
isempty(extensions) ? "" : "' or any of its extensions '",
|
||||
isempty(extensions) ? "" : extensions);
|
||||
}
|
||||
|
||||
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);
|
||||
|
||||
@ -16,6 +16,7 @@ typedef struct PortableMetadata {
|
||||
} PortableMetadata;
|
||||
|
||||
#define PORTABLE_METADATA_IS_OS_RELEASE(m) (streq((m)->name, "/etc/os-release"))
|
||||
#define PORTABLE_METADATA_IS_EXTENSION_RELEASE(m) (startswith((m)->name, "/usr/lib/extension-release.d/extension-release."))
|
||||
#define PORTABLE_METADATA_IS_UNIT(m) (!IN_SET((m)->name[0], 0, '/'))
|
||||
|
||||
typedef enum PortableFlags {
|
||||
|
||||
@ -1742,17 +1742,28 @@ int dissected_image_mount(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (flags & DISSECT_IMAGE_VALIDATE_OS) {
|
||||
r = path_is_os_tree(where);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
if ((flags & (DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_VALIDATE_OS_EXT)) != 0) {
|
||||
/* If either one of the validation flags are set, ensure that the image qualifies
|
||||
* as one or the other (or both). */
|
||||
bool ok = false;
|
||||
|
||||
if (FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS)) {
|
||||
r = path_is_os_tree(where);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
ok = true;
|
||||
}
|
||||
if (!ok && FLAGS_SET(flags, DISSECT_IMAGE_VALIDATE_OS_EXT)) {
|
||||
r = path_is_extension_tree(where, m->image_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EMEDIUMTYPE;
|
||||
if (r > 0)
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2623,6 +2634,7 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
|
||||
DISSECT_IMAGE_READ_ONLY|
|
||||
DISSECT_IMAGE_MOUNT_ROOT_ONLY|
|
||||
DISSECT_IMAGE_VALIDATE_OS|
|
||||
DISSECT_IMAGE_VALIDATE_OS_EXT|
|
||||
DISSECT_IMAGE_USR_NO_ROOT);
|
||||
if (r < 0) {
|
||||
/* Let parent know the error */
|
||||
|
||||
@ -100,19 +100,20 @@ typedef enum DissectImageFlags {
|
||||
DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root and /usr partitions */
|
||||
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only the non-root and non-/usr partitions */
|
||||
DISSECT_IMAGE_VALIDATE_OS = 1 << 8, /* Refuse mounting images that aren't identifiable as OS images */
|
||||
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
|
||||
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
|
||||
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
|
||||
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
|
||||
DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */
|
||||
DISSECT_IMAGE_MKDIR = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */
|
||||
DISSECT_IMAGE_USR_NO_ROOT = 1 << 15, /* If no root fs is in the image, but /usr is, then allow this (so that we can mount the rootfs as tmpfs or so */
|
||||
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 16, /* Don't accept disks without root partition (or at least /usr partition if DISSECT_IMAGE_USR_NO_ROOT is set) */
|
||||
DISSECT_IMAGE_MOUNT_READ_ONLY = 1 << 17, /* Make mounts read-only */
|
||||
DISSECT_IMAGE_VALIDATE_OS_EXT = 1 << 9, /* Refuse mounting images that aren't identifiable as OS extension images */
|
||||
DISSECT_IMAGE_NO_UDEV = 1 << 10, /* Don't wait for udev initializing things */
|
||||
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 11, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
|
||||
DISSECT_IMAGE_FSCK = 1 << 12, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
|
||||
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 13, /* Only recognize single file system images */
|
||||
DISSECT_IMAGE_VERITY_SHARE = 1 << 14, /* When activating a verity device, reuse existing one if already open */
|
||||
DISSECT_IMAGE_MKDIR = 1 << 15, /* Make top-level directory to mount right before mounting, if missing */
|
||||
DISSECT_IMAGE_USR_NO_ROOT = 1 << 16, /* If no root fs is in the image, but /usr is, then allow this (so that we can mount the rootfs as tmpfs or so */
|
||||
DISSECT_IMAGE_REQUIRE_ROOT = 1 << 17, /* Don't accept disks without root partition (or at least /usr partition if DISSECT_IMAGE_USR_NO_ROOT is set) */
|
||||
DISSECT_IMAGE_MOUNT_READ_ONLY = 1 << 18, /* Make mounts read-only */
|
||||
DISSECT_IMAGE_READ_ONLY = DISSECT_IMAGE_DEVICE_READ_ONLY |
|
||||
DISSECT_IMAGE_MOUNT_READ_ONLY,
|
||||
DISSECT_IMAGE_GROWFS = 1 << 18, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
|
||||
DISSECT_IMAGE_MOUNT_IDMAPPED = 1 << 19, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
|
||||
DISSECT_IMAGE_GROWFS = 1 << 19, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
|
||||
DISSECT_IMAGE_MOUNT_IDMAPPED = 1 << 20, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
|
||||
} DissectImageFlags;
|
||||
|
||||
struct DissectedImage {
|
||||
|
||||
@ -267,6 +267,7 @@ static size_t table_data_size(TableDataType type, const void *data) {
|
||||
case TABLE_STRV_WRAPPED:
|
||||
return sizeof(char **);
|
||||
|
||||
case TABLE_BOOLEAN_CHECKMARK:
|
||||
case TABLE_BOOLEAN:
|
||||
return sizeof(bool);
|
||||
|
||||
@ -848,6 +849,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
|
||||
data = va_arg(ap, char * const *);
|
||||
break;
|
||||
|
||||
case TABLE_BOOLEAN_CHECKMARK:
|
||||
case TABLE_BOOLEAN:
|
||||
buffer.b = va_arg(ap, int);
|
||||
data = &buffer.b;
|
||||
@ -1443,6 +1445,9 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
|
||||
case TABLE_BOOLEAN:
|
||||
return yes_no(d->boolean);
|
||||
|
||||
case TABLE_BOOLEAN_CHECKMARK:
|
||||
return special_glyph(d->boolean ? SPECIAL_GLYPH_CHECK_MARK : SPECIAL_GLYPH_CROSS_MARK);
|
||||
|
||||
case TABLE_TIMESTAMP:
|
||||
case TABLE_TIMESTAMP_UTC:
|
||||
case TABLE_TIMESTAMP_RELATIVE: {
|
||||
@ -2488,6 +2493,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
|
||||
case TABLE_STRV_WRAPPED:
|
||||
return json_variant_new_array_strv(ret, d->strv);
|
||||
|
||||
case TABLE_BOOLEAN_CHECKMARK:
|
||||
case TABLE_BOOLEAN:
|
||||
return json_variant_new_boolean(ret, d->boolean);
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ typedef enum TableDataType {
|
||||
TABLE_STRV_WRAPPED,
|
||||
TABLE_PATH,
|
||||
TABLE_BOOLEAN,
|
||||
TABLE_BOOLEAN_CHECKMARK,
|
||||
TABLE_TIMESTAMP,
|
||||
TABLE_TIMESTAMP_UTC,
|
||||
TABLE_TIMESTAMP_RELATIVE,
|
||||
|
||||
@ -412,43 +412,43 @@ cat <<EOF >/tmp/testfile.json
|
||||
"weight": 1000,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWUSER":
|
||||
"RestrictNamespaces_user":
|
||||
{"description_good": "Servicecannotcreateusernamespaces",
|
||||
"description_bad": "Servicemaycreateusernamespaces",
|
||||
"weight": 1500,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWNS":
|
||||
"RestrictNamespaces_mnt":
|
||||
{"description_good": "Service cannot create file system namespaces",
|
||||
"description_bad": "Service may create file system namespaces",
|
||||
"weight": 500,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWIPC":
|
||||
"RestrictNamespaces_ipc":
|
||||
{"description_good": "Service cannot create IPC namespaces",
|
||||
"description_bad": "Service may create IPC namespaces",
|
||||
"weight": 500,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWPID":
|
||||
"RestrictNamespaces_pid":
|
||||
{"description_good": "Service cannot create process namespaces",
|
||||
"description_bad": "Service may create process namespaces",
|
||||
"weight": 500,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWCGROUP":
|
||||
"RestrictNamespaces_cgroup":
|
||||
{"description_good": "Service cannot create cgroup namespaces",
|
||||
"description_bad": "Service may create cgroup namespaces",
|
||||
"weight": 500,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWNET":
|
||||
"RestrictNamespaces_net":
|
||||
{"description_good": "Service cannot create network namespaces",
|
||||
"description_bad": "Service may create network namespaces",
|
||||
"weight": 500,
|
||||
"range": 1
|
||||
},
|
||||
"RestrictNamespaces_CLONE_NEWUTS":
|
||||
"RestrictNamespaces_uts":
|
||||
{"description_good": "Service cannot create hostname namespaces",
|
||||
"description_bad": "Service may create hostname namespaces",
|
||||
"weight": 100,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user