1
0
mirror of https://github.com/systemd/systemd synced 2026-03-27 09:14:51 +01:00

Compare commits

..

No commits in common. "7d50cd65bbaed9189f9d647591b980b3a2f3cce8" and "77afbef6925d829d9c3da6636a873358846c0290" have entirely different histories.

19 changed files with 136 additions and 369 deletions

View File

@ -930,15 +930,6 @@ 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

View File

@ -1,33 +0,0 @@
# 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

View File

@ -27,7 +27,6 @@ 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

View File

@ -147,7 +147,6 @@ 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'))),

View File

@ -967,25 +967,25 @@ Service b@0.service not loaded, b.socket cannot be started.
<entry>RestrictSUIDSGID</entry>
</row>
<row>
<entry>RestrictNamespaces_user</entry>
<entry>RestrictNamespaces_CLONE_NEWUSER</entry>
</row>
<row>
<entry>RestrictNamespaces_mnt</entry>
<entry>RestrictNamespaces_CLONE_NEWNS</entry>
</row>
<row>
<entry>RestrictNamespaces_ipc</entry>
<entry>RestrictNamespaces_CLONE_NEWIPC</entry>
</row>
<row>
<entry>RestrictNamespaces_pid</entry>
<entry>RestrictNamespaces_CLONE_NEWPID</entry>
</row>
<row>
<entry>RestrictNamespaces_cgroup</entry>
<entry>RestrictNamespaces_CLONE_NEWCGROUP</entry>
</row>
<row>
<entry>RestrictNamespaces_uts</entry>
<entry>RestrictNamespaces_CLONE_NEWUTS</entry>
</row>
<row>
<entry>RestrictNamespaces_net</entry>
<entry>RestrictNamespaces_CLONE_NEWNET</entry>
</row>
<row>
<entry>RestrictAddressFamilies_AF_INET_INET6</entry>
@ -1109,22 +1109,6 @@ 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>

View File

@ -12,7 +12,6 @@ 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"

View File

@ -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 --json=off --json=pretty --json=short'
comps='--help --version --no-pager --system --user -H --host -M --machine --offline --threshold --security-policy'
else
if __contains_word "--user" ${COMP_WORDS[*]}; then
mode=--user

View File

@ -93,7 +93,6 @@ _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]' \

View File

@ -1340,8 +1340,8 @@ static const struct security_assessor security_assessor_table[] = {
.offset = offsetof(SecurityInfo, restrict_suid_sgid),
},
{
.id = "RestrictNamespaces=~user",
.json_field = "RestrictNamespaces_user",
.id = "RestrictNamespaces=~CLONE_NEWUSER",
.json_field = "RestrictNamespaces_CLONE_NEWUSER",
.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=~mnt",
.json_field = "RestrictNamespaces_mnt",
.id = "RestrictNamespaces=~CLONE_NEWNS",
.json_field = "RestrictNamespaces_CLONE_NEWNS",
.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=~ipc",
.json_field = "RestrictNamespaces_ipc",
.id = "RestrictNamespaces=~CLONE_NEWIPC",
.json_field = "RestrictNamespaces_CLONE_NEWIPC",
.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=~pid",
.json_field = "RestrictNamespaces_pid",
.id = "RestrictNamespaces=~CLONE_NEWPID",
.json_field = "RestrictNamespaces_CLONE_NEWPID",
.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=~cgroup",
.json_field = "RestrictNamespaces_cgroup",
.id = "RestrictNamespaces=~CLONE_NEWCGROUP",
.json_field = "RestrictNamespaces_CLONE_NEWCGROUP",
.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=~net",
.json_field = "RestrictNamespaces_net",
.id = "RestrictNamespaces=~CLONE_NEWNET",
.json_field = "RestrictNamespaces_CLONE_NEWNET",
.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=~uts",
.json_field = "RestrictNamespaces_uts",
.id = "RestrictNamespaces=~CLONE_NEWUTS",
.json_field = "RestrictNamespaces_CLONE_NEWUTS",
.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,9 +1709,7 @@ static int assess(const SecurityInfo *info,
Table *overview_table,
AnalyzeSecurityFlags flags,
unsigned threshold,
JsonVariant *policy,
PagerFlags pager_flags,
JsonFormatFlags json_format_flags) {
JsonVariant *policy) {
static const struct {
uint64_t exposure;
@ -1734,19 +1732,15 @@ static int assess(const SecurityInfo *info,
int r;
if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
details_table = table_new(" ", "name", "json_field", "description", "weight", "badness", "range", "exposure");
details_table = table_new(" ", "name", "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) 3, (size_t) 7);
(void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 6);
}
for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
@ -1780,23 +1774,23 @@ static int assess(const SecurityInfo *info,
}
if (details_table) {
const char *description, *color = NULL;
int checkmark;
const char *checkmark, *description, *color = NULL;
const char *id = a->id;
if (badness == UINT64_MAX) {
checkmark = -1;
checkmark = " ";
description = access_description_na(a, policy);
color = NULL;
} else if (badness == a->range) {
checkmark = 0;
checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
description = access_description_bad(a, policy);
color = ansi_highlight_red();
} else if (badness == 0) {
checkmark = 1;
checkmark = special_glyph(SPECIAL_GLYPH_CHECK_MARK);
description = access_description_good(a, policy);
color = ansi_highlight_green();
} else {
checkmark = 0;
checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
description = NULL;
color = ansi_highlight_red();
}
@ -1804,24 +1798,16 @@ static int assess(const SecurityInfo *info,
if (d)
description = d;
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);
}
if (json_variant_by_key(policy, a->json_field) != NULL)
id = a->json_field;
r = table_add_many(details_table,
TABLE_STRING, a->id, TABLE_SET_URL, a->url,
TABLE_STRING, a->json_field,
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, description,
TABLE_UINT64, weight, TABLE_SET_ALIGN_PERCENT, 100,
TABLE_UINT64, badness, TABLE_SET_ALIGN_PERCENT, 100,
@ -1843,14 +1829,14 @@ static int assess(const SecurityInfo *info,
TableCell *cell;
uint64_t x;
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));
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));
if (*badness == UINT64_MAX || *badness == 0)
continue;
assert_se(cell = table_get_cell(details_table, row, 7));
assert_se(cell = table_get_cell(details_table, row, 6));
x = DIV_ROUND_UP(DIV_ROUND_UP(*badness * *weight * 100U, *range), weight_sum);
xsprintf(buf, "%" PRIu64 ".%" PRIu64, x / 10, x % 10);
@ -1860,13 +1846,7 @@ static int assess(const SecurityInfo *info,
return log_error_errno(r, "Failed to update cell in table: %m");
}
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);
r = table_print(details_table, stdout);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
}
@ -1879,7 +1859,7 @@ static int assess(const SecurityInfo *info,
assert(i < ELEMENTSOF(badness_table));
if (details_table && (json_format_flags & JSON_FORMAT_OFF)) {
if (details_table) {
_cleanup_free_ char *clickable = NULL;
const char *name;
@ -2406,9 +2386,7 @@ static int analyze_security_one(sd_bus *bus,
Table *overview_table,
AnalyzeSecurityFlags flags,
unsigned threshold,
JsonVariant *policy,
PagerFlags pager_flags,
JsonFormatFlags json_format_flags) {
JsonVariant *policy) {
_cleanup_(security_info_freep) SecurityInfo *info = security_info_new();
if (!info)
@ -2425,7 +2403,7 @@ static int analyze_security_one(sd_bus *bus,
if (r < 0)
return r;
r = assess(info, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
r = assess(info, overview_table, flags, threshold, policy);
if (r < 0)
return r;
@ -2611,12 +2589,7 @@ 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,
PagerFlags pager_flags,
JsonFormatFlags json_format_flags) {
static int offline_security_check(Unit *u, unsigned threshold, JsonVariant *policy) {
_cleanup_(table_unrefp) Table *overview_table = NULL;
AnalyzeSecurityFlags flags = 0;
_cleanup_(security_info_freep) SecurityInfo *info = NULL;
@ -2631,7 +2604,7 @@ static int offline_security_check(Unit *u,
if (r < 0)
return r;
return assess(info, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
return assess(info, overview_table, flags, threshold, policy);
}
static int offline_security_checks(char **filenames,
@ -2640,9 +2613,7 @@ static int offline_security_checks(char **filenames,
bool check_man,
bool run_generators,
unsigned threshold,
const char *root,
PagerFlags pager_flags,
JsonFormatFlags json_format_flags) {
const char *root) {
const ManagerTestRunFlags flags =
MANAGER_TEST_RUN_MINIMAL |
@ -2702,7 +2673,7 @@ static int offline_security_checks(char **filenames,
}
for (size_t i = 0; i < count; i++) {
k = offline_security_check(units[i], threshold, policy, pager_flags, json_format_flags);
k = offline_security_check(units[i], threshold, policy);
if (k < 0 && r == 0)
r = k;
}
@ -2719,8 +2690,6 @@ 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;
@ -2729,7 +2698,7 @@ int analyze_security(sd_bus *bus,
assert(bus);
if (offline)
return offline_security_checks(units, policy, scope, check_man, run_generators, threshold, root, pager_flags, json_format_flags);
return offline_security_checks(units, policy, scope, check_man, run_generators, threshold, root);
if (strv_length(units) != 1) {
overview_table = table_new("unit", "exposure", "predicate", "happy");
@ -2789,7 +2758,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, pager_flags, json_format_flags);
r = analyze_security_one(bus, *i, overview_table, flags, threshold, policy);
if (r < 0 && ret >= 0)
ret = r;
}
@ -2824,7 +2793,7 @@ int analyze_security(sd_bus *bus,
} else
name = mangled;
r = analyze_security_one(bus, name, overview_table, flags, threshold, policy, pager_flags, json_format_flags);
r = analyze_security_one(bus, name, overview_table, flags, threshold, policy);
if (r < 0 && ret >= 0)
ret = r;
}
@ -2836,9 +2805,10 @@ int analyze_security(sd_bus *bus,
fflush(stdout);
}
r = table_print_with_pager(overview_table, json_format_flags, pager_flags, /* show_header= */true);
r = table_print(overview_table, stdout);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
}
return ret;
}

View File

@ -6,7 +6,6 @@
#include "sd-bus.h"
#include "json.h"
#include "pager.h"
#include "unit-file.h"
typedef enum AnalyzeSecurityFlags {
@ -24,6 +23,4 @@ int analyze_security(sd_bus *bus,
bool offline,
unsigned threshold,
const char *root,
JsonFormatFlags json_format_flags,
PagerFlags pager_flags,
AnalyzeSecurityFlags flags);

View File

@ -97,7 +97,6 @@ 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);
@ -2197,8 +2196,6 @@ 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);
}
@ -2253,8 +2250,6 @@ 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"
@ -2308,7 +2303,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_OFFLINE,
ARG_THRESHOLD,
ARG_SECURITY_POLICY,
ARG_JSON,
};
static const struct option options[] = {
@ -2336,7 +2330,6 @@ 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 },
{}
};
@ -2461,12 +2454,6 @@ 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)
@ -2502,10 +2489,6 @@ 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.");

View File

@ -80,7 +80,4 @@ 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"

View File

@ -11,10 +11,8 @@
#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"
@ -232,8 +230,6 @@ 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) {
@ -243,7 +239,6 @@ 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;
@ -258,27 +253,19 @@ static int extract_now(
assert(where);
/* 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);
}
/* First, find /etc/os-release and send it upstream (or just save it). */
r = open_os_release(where, &os_release_path, &os_release_fd);
if (r < 0)
log_debug_errno(r,
"Couldn't acquire %s file, ignoring: %m",
path_is_extension ? "extension-release " : "os-release");
log_debug_errno(r, "Couldn't acquire os-release file, ignoring: %m");
else {
if (socket_fd >= 0) {
r = send_item(socket_fd, os_release_id, os_release_fd);
r = send_item(socket_fd, "/etc/os-release", 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(os_release_id, NULL, os_release_fd);
os_release = portable_metadata_new("/etc/os-release", NULL, os_release_fd);
if (!os_release)
return -ENOMEM;
@ -364,7 +351,7 @@ static int extract_now(
static int portable_extract_by_path(
const char *path,
bool path_is_extension,
bool extract_os_release,
char **matches,
PortableMetadata **ret_os_release,
Hashmap **ret_unit_files,
@ -382,7 +369,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, NULL, path_is_extension, -1, &os_release, &unit_files);
r = extract_now(path, matches, -1, &os_release, &unit_files);
if (r < 0)
return r;
@ -436,22 +423,15 @@ 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]);
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);
r = dissected_image_mount(m, tmpdir, UID_INVALID, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
if (r < 0) {
log_debug_errno(r, "Failed to mount dissected image: %m");
goto child_finish;
}
r = extract_now(tmpdir, matches, m->image_name, path_is_extension, seq[1], NULL, NULL);
r = extract_now(tmpdir, matches, seq[1], NULL, NULL);
child_finish:
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
@ -497,7 +477,7 @@ static int portable_extract_by_path(
add = NULL;
} else if (PORTABLE_METADATA_IS_OS_RELEASE(add) || PORTABLE_METADATA_IS_EXTENSION_RELEASE(add)) {
} else if (PORTABLE_METADATA_IS_OS_RELEASE(add)) {
assert(!os_release);
os_release = TAKE_PTR(add);
@ -511,12 +491,13 @@ static int portable_extract_by_path(
child = 0;
}
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");
/* 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 (ret_unit_files)
*ret_unit_files = TAKE_PTR(unit_files);
@ -527,18 +508,14 @@ static int portable_extract_by_path(
return 0;
}
static int extract_image_and_extensions(
int portable_extract(
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;
@ -547,9 +524,6 @@ static int extract_image_and_extensions(
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)
@ -576,106 +550,19 @@ static int extract_image_and_extensions(
}
}
r = portable_extract_by_path(image->path, /* path_is_extension= */ false, matches, &os_release, &unit_files, error);
r = portable_extract_by_path(image->path, true, matches, &os_release, &unit_files, error);
if (r < 0)
return r;
/* 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 = 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);
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;
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);
@ -1251,31 +1138,47 @@ int portable_attach(
_cleanup_(lookup_paths_free) LookupPaths paths = {};
_cleanup_(image_unrefp) Image *image = NULL;
PortableMetadata *item;
Image *ext;
char **p;
int r;
r = extract_image_and_extensions(name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ true,
&image,
&extension_images,
/* os_release= */ NULL,
&unit_files,
error);
assert(name_or_path);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
if (r < 0)
return r;
if (!strv_isempty(extension_image_paths)) {
extension_images = ordered_hashmap_new(&image_hash_ops);
if (!extension_images)
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;
if (hashmap_isempty(unit_files)) {
_cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
if (!extensions)
return -ENOMEM;
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
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 = 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;
}
r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL);

View File

@ -16,7 +16,6 @@ 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 {

View File

@ -1742,28 +1742,17 @@ int dissected_image_mount(
if (r < 0)
return r;
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)) {
if (flags & DISSECT_IMAGE_VALIDATE_OS) {
r = path_is_os_tree(where);
if (r < 0)
return r;
if (r == 0) {
r = path_is_extension_tree(where, m->image_name);
if (r < 0)
return r;
if (r > 0)
ok = true;
if (r == 0)
return -EMEDIUMTYPE;
}
if (!ok)
return -ENOMEDIUM;
}
}
@ -2634,7 +2623,6 @@ 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 */

View File

@ -100,20 +100,19 @@ 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_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_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_READ_ONLY = DISSECT_IMAGE_DEVICE_READ_ONLY |
DISSECT_IMAGE_MOUNT_READ_ONLY,
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= */
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= */
} DissectImageFlags;
struct DissectedImage {

View File

@ -267,7 +267,6 @@ 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);
@ -849,7 +848,6 @@ 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;
@ -1445,9 +1443,6 @@ 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: {
@ -2493,7 +2488,6 @@ 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);

View File

@ -16,7 +16,6 @@ typedef enum TableDataType {
TABLE_STRV_WRAPPED,
TABLE_PATH,
TABLE_BOOLEAN,
TABLE_BOOLEAN_CHECKMARK,
TABLE_TIMESTAMP,
TABLE_TIMESTAMP_UTC,
TABLE_TIMESTAMP_RELATIVE,

View File

@ -412,43 +412,43 @@ cat <<EOF >/tmp/testfile.json
"weight": 1000,
"range": 1
},
"RestrictNamespaces_user":
"RestrictNamespaces_CLONE_NEWUSER":
{"description_good": "Servicecannotcreateusernamespaces",
"description_bad": "Servicemaycreateusernamespaces",
"weight": 1500,
"range": 1
},
"RestrictNamespaces_mnt":
"RestrictNamespaces_CLONE_NEWNS":
{"description_good": "Service cannot create file system namespaces",
"description_bad": "Service may create file system namespaces",
"weight": 500,
"range": 1
},
"RestrictNamespaces_ipc":
"RestrictNamespaces_CLONE_NEWIPC":
{"description_good": "Service cannot create IPC namespaces",
"description_bad": "Service may create IPC namespaces",
"weight": 500,
"range": 1
},
"RestrictNamespaces_pid":
"RestrictNamespaces_CLONE_NEWPID":
{"description_good": "Service cannot create process namespaces",
"description_bad": "Service may create process namespaces",
"weight": 500,
"range": 1
},
"RestrictNamespaces_cgroup":
"RestrictNamespaces_CLONE_NEWCGROUP":
{"description_good": "Service cannot create cgroup namespaces",
"description_bad": "Service may create cgroup namespaces",
"weight": 500,
"range": 1
},
"RestrictNamespaces_net":
"RestrictNamespaces_CLONE_NEWNET":
{"description_good": "Service cannot create network namespaces",
"description_bad": "Service may create network namespaces",
"weight": 500,
"range": 1
},
"RestrictNamespaces_uts":
"RestrictNamespaces_CLONE_NEWUTS":
{"description_good": "Service cannot create hostname namespaces",
"description_bad": "Service may create hostname namespaces",
"weight": 100,