mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-22 17:57:49 +03:00
systemd-analyze: add new 'security' option to allow user to choose custom requirements
A new option --security-policy= is added to work with the 'security' verb in order to enable users to create and pass in a JSON file consisting of user defined requirements against which to compare the specified unit file(s). These requirements then serve as the measure of security threats for the file instead of the initial hard coded set of requirements that the 'security' verb of systemd-analyze relied on. Example Run: A snapshot of the user defined testfile.json file is shown below instead of the complete file for readability purposes. { "PrivateDevices": {"description_good": "Service has no access to hardware devices", "description_bad": "Service potentially has access to hardware devices", "weight": 1000, "range": 1 }, "PrivateMounts": {"description_good": "Service cannot install system mounts", "description_bad": "Service may install system mounts", "weight": 1000, "range": 1 }, "PrivateNetwork": {"description_good": "Service has no access to the host's network", "description_bad": "Service has access to the host's network", "weight": 2500, "range": 1 }, "PrivateTmp": {"description_good": "Service has no access to other software's temporary files", "description_bad": "Service has access to other software's temporary files", "weight": 1000, "range": 1 }, "PrivateUsers": {"description_good": "Service does not have access to other users", "description_bad": "Service has access to other users", "weight": 1000, "range": 1 } } 1. I created the jsontest.service file in order to test the --security-policy= option as follows: maanya-goenka@debian:~/systemd (custom-security)$ cat<<EOF>jsontest.service > [Service] > ExecStart = echo hello > PrivateNetwork = yes > PrivateDevices = yes > PrivateMounts = yes > EOF The security analysis table outputted below has been truncated to include only the first few lines for readability. maanya-goenka@debian:~/systemd (custom-security)$ sudo build/systemd-analyze security --root= --offline=true --security-policy=src/analyze/testfile.json jsontest.service /usr/lib/systemd/system/plymouth-start.service:15: Unit configured to use KillMode=none. This is unsafe, as it disables systemd's process lifecycle management for the service. Please update your service to use a safer KillMode=, such as 'mixed' or 'control-group'. Support for KillMode=none is deprecated and will eventually be removed. /usr/lib/systemd/system/gdm.service:30: Standard output type syslog is obsolete, automatically updating to journal. Please update your unit file, and consider removing the setting altogether. /usr/lib/systemd/system/dbus.socket:5: ListenStream= references a path below legacy directory /var/run/, updating /var/run/dbus/system_bus_socket → /run/dbus/system_bus_socket; please update the unit file accordingly. NAME DESCRIPTION ✓ PrivateNetwork Service has no access to the host's network ✗ UserOrDynamicUser Service runs as root user ✗ CapabilityBoundingSet_CAP_SET_UID_GID_PCAP Service may change UID/GID identities/capabilities ✓ PrivateMounts Service cannot install system mounts ✓ PrivateDevices Service has no access to hardware devices → Overall exposure level for jsontest.service: 8.3 EXPOSED 🙁 maanya-goenka@debian:~/systemd (custom-security)$ echo $? 0 2. In order to ensure that the JSON data was actually being correctly parsed, I made some changes to the JSON file, specifically to the id "PrivateNetwork" as follows: Before: -------- "PrivateNetwork": {"description_good": "Service has no access to the host's network", "description_bad": "Service has access to the host's network", "weight": 2500, "range": 1 } After: -------- "PrivateNetwork": {"description_good": "Service runs without access to host network", "description_bad": "Service has access to the host's network", "weight": 6000, "range": 1 } As expected, the new description for the description_good field of the Private Network id was updated in the analysis table outputted below and the overall exposure level of the unit file decreased because the weight assigned to 'Private Network' (which is set to yes) increased from 2500 to 6000. maanya-goenka@debian:~/systemd (custom-security)$ sudo build/systemd-analyze security --root= --offline=true --security-policy=src/analyze/testfile.json jsontest.service /usr/lib/systemd/system/plymouth-start.service:15: Unit configured to use KillMode=none. This is unsafe, as it disables systemd's process lifecycle management for the service. Please update your service to use a safer KillMode=, such as 'mixed' or 'control-group'. Support for KillMode=none is deprecated and will eventually be removed. /usr/lib/systemd/system/gdm.service:30: Standard output type syslog is obsolete, automatically updating to journal. Please update your unit file, and consider removing the setting altogether. /usr/lib/systemd/system/dbus.socket:5: ListenStream= references a path below legacy directory /var/run/, updating /var/run/dbus/system_bus_socket → /run/dbus/system_bus_socket; please update the unit file accordingly. NAME DESCRIPTION ✓ PrivateNetwork Service runs without access to the host's network ✗ UserOrDynamicUser Service runs as root user ✗ CapabilityBoundingSet_CAP_SET_UID_GID_PCAP Service may change UID/GID identities/capabilities ✓ PrivateMounts Service cannot install system mounts ✓ PrivateDevices Service has no access to hardware devices → Overall exposure level for jsontest.service: 7.8 EXPOSED 🙁 maanya-goenka@debian:~/systemd (custom-security)$ echo $? 0 3. When paired with security's --threshold= option, systemd-analyze exits with a non-zero error status indicating that the overall exposure level for the unit file (=78) is greater than the set threshold (=70). The same jsontest.service file is used for the demo run below: maanya-goenka@debian:~/systemd (custom-security)$ sudo build/systemd-analyze security --root= --offline=true --security-policy=src/analyze/testfile.json --threshold=70 jsontest.service /usr/lib/systemd/system/plymouth-start.service:15: Unit configured to use KillMode=none. This is unsafe, as it disables systemd's process lifecycle management for the service. Please update your service to use a safer KillMode=, such as 'mixed' or 'control-group'. Support for KillMode=none is deprecated and will eventually be removed. /usr/lib/systemd/system/gdm.service:30: Standard output type syslog is obsolete, automatically updating to journal. Please update your unit file, and consider removing the setting altogether. /usr/lib/systemd/system/dbus.socket:5: ListenStream= references a path below legacy directory /var/run/, updating /var/run/dbus/system_bus_socket → /run/dbus/system_bus_socket; please update the unit file accordingly. NAME DESCRIPTION ✓ PrivateNetwork Service runs without access to host network ✗ UserOrDynamicUser Service runs as root user ✗ CapabilityBoundingSet_CAP_SET_UID_GID_PCAP Service may change UID/GID identities/capabilities ✓ PrivateMounts Service cannot install system mounts ✓ PrivateDevices Service has no access to hardware devices → Overall exposure level for jsontest.service: 7.8 EXPOSED 🙁 maanya-goenka@debian:~/systemd (custom-security)$ echo $? 1 new option
This commit is contained in:
parent
37b3e1394a
commit
ecfd082b71
@ -792,6 +792,323 @@ Service b@0.service not loaded, b.socket cannot be started.
|
||||
as well and its default value is 100.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--security-policy=<replaceable>PATH</replaceable></option></term>
|
||||
|
||||
<listitem><para>With <command>security</command>, allow the user to define a custom set of
|
||||
requirements formatted as a JSON file against which to compare the specified unit file(s)
|
||||
and determine their overall exposure level to security threats.</para>
|
||||
|
||||
<table>
|
||||
<title>Accepted Assessment Test Identifiers</title>
|
||||
|
||||
<tgroup cols='1'>
|
||||
<colspec colname='directive' />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Assessment Test Identifier</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>UserOrDynamicUser</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SupplementaryGroups</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>PrivateMounts</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>PrivateDevices</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>PrivateTmp</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>PrivateNetwork</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>PrivateUsers</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectControlGroups</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectKernelModules</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectKernelTunables</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectKernelLogs</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectClock</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectHome</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectHostname</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectSystem</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RootDirectoryOrRootImage</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>LockPersonality</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>MemoryDenyWriteExecute</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>NoNewPrivileges</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_ADMIN</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SET_UID_GID_PCAP</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_PTRACE</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_TIME</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_NET_ADMIN</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_RAWIO</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_MODULE</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_AUDIT</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYSLOG</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_NICE_RESOURCE</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_MKNOD</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_CHOWN_FSETID_SETFCAP</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_DAC_FOWNER_IPC_OWNER</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_KILL</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_NET_BIND_SERVICE_BROADCAST_RAW</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_BOOT</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_MAC</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_LINUX_IMMUTABLE</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_IPC_LOCK</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_CHROOT</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_BLOCK_SUSPEND</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_WAKE_ALARM</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_LEASE</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>CapabilityBoundingSet_CAP_SYS_TTY_CONFIG</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>UMask</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>KeyringMode</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProtectProc</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>ProcSubset</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>NotifyAccess</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RemoveIPC</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Delegate</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictRealtime</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictSUIDSGID</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWUSER</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWNS</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWIPC</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWPID</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWCGROUP</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWUTS</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictNamespaces_CLONE_NEWNET</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictAddressFamilies_AF_INET_INET6</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictAddressFamilies_AF_UNIX</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictAddressFamilies_AF_NETLINK</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictAddressFamilies_AF_PACKET</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>RestrictAddressFamilies_OTHER</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallArchitectures</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_swap</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_obsolete</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_clock</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_cpu_emulation</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_debug</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_mount</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_module</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_raw_io</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_reboot</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_privileged</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>SystemCallFilter_resources</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>IPAddressDeny</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>DeviceAllow</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>AmbientCapabilities</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<example>
|
||||
<title>JSON Policy</title>
|
||||
<para>The JSON file passed as a path parameter to <option>--security-policy=</option>
|
||||
has a top-level JSON object, with keys being the assessment test identifiers mentioned
|
||||
above. The values in the file should be JSON objects with one or more of the
|
||||
following fields: description_na (string), description_good (string), description_bad
|
||||
(string), weight (unsigned integer), and range (unsigned integer). If any of these fields
|
||||
corresponding to a specific id of the unit file is missing from the JSON object, the
|
||||
default built-in field value corresponding to that same id is used for security analysis
|
||||
as default. The weight and range fields are used in determining the overall exposure level
|
||||
of the unit files so by allowing users to manipulate these fields, 'security' gives them
|
||||
the option to decide for themself which ids are more important and hence, should have a greater
|
||||
effect on the exposure level. </para>
|
||||
|
||||
<programlisting>
|
||||
{
|
||||
"PrivateDevices":
|
||||
{
|
||||
"description_good": "Service has no access to hardware devices",
|
||||
"description_bad": "Service potentially has access to hardware devices",
|
||||
"weight": 1000,
|
||||
"range": 1
|
||||
},
|
||||
"PrivateMounts":
|
||||
{
|
||||
"description_good": "Service cannot install system mounts",
|
||||
"description_bad": "Service may install system mounts",
|
||||
"weight": 1000,
|
||||
"range": 1
|
||||
},
|
||||
"PrivateNetwork":
|
||||
{
|
||||
"description_good": "Service has no access to the host's network",
|
||||
"description_bad": "Service has access to the host's network",
|
||||
"weight": 2500,
|
||||
"range": 1
|
||||
},
|
||||
"PrivateTmp":
|
||||
{
|
||||
"description_good": "Service has no access to other software's temporary files",
|
||||
"description_bad": "Service has access to other software's temporary files",
|
||||
"weight": 1000,
|
||||
"range": 1
|
||||
},
|
||||
"PrivateUsers":
|
||||
{
|
||||
"description_good": "Service does not have access to other users",
|
||||
"description_bad": "Service has access to other users",
|
||||
"weight": 1000,
|
||||
"range": 1
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--iterations=<replaceable>NUMBER</replaceable></option></term>
|
||||
|
||||
|
@ -144,7 +144,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'
|
||||
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
|
||||
|
@ -92,6 +92,7 @@ _arguments \
|
||||
'--recursive-errors=[When verifying a unit, control dependency verification]:MODE' \
|
||||
'--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' \
|
||||
'--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]' \
|
||||
|
@ -2481,8 +2481,16 @@ static int offline_security_checks(char **filenames, UnitFileScope scope, bool c
|
||||
return r;
|
||||
}
|
||||
|
||||
int analyze_security(sd_bus *bus, char **units, UnitFileScope scope, bool check_man, bool run_generators,
|
||||
bool offline, unsigned threshold, const char *root, AnalyzeSecurityFlags flags) {
|
||||
int analyze_security(sd_bus *bus,
|
||||
char **units,
|
||||
JsonVariant *policy,
|
||||
UnitFileScope scope,
|
||||
bool check_man,
|
||||
bool run_generators,
|
||||
bool offline,
|
||||
unsigned threshold,
|
||||
const char *root,
|
||||
AnalyzeSecurityFlags flags) {
|
||||
|
||||
_cleanup_(table_unrefp) Table *overview_table = NULL;
|
||||
int ret = 0, r;
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "json.h"
|
||||
#include "unit-file.h"
|
||||
|
||||
typedef enum AnalyzeSecurityFlags {
|
||||
@ -13,5 +14,13 @@ typedef enum AnalyzeSecurityFlags {
|
||||
ANALYZE_SECURITY_ONLY_LONG_RUNNING = 1 << 2,
|
||||
} AnalyzeSecurityFlags;
|
||||
|
||||
int analyze_security(sd_bus *bus, char **units, UnitFileScope scope, bool check_man, bool run_generators,
|
||||
bool offline, unsigned threshold, const char *root, AnalyzeSecurityFlags flags);
|
||||
int analyze_security(sd_bus *bus,
|
||||
char **units,
|
||||
JsonVariant *policy,
|
||||
UnitFileScope scope,
|
||||
bool check_man,
|
||||
bool run_generators,
|
||||
bool offline,
|
||||
unsigned threshold,
|
||||
const char *root,
|
||||
AnalyzeSecurityFlags flags);
|
||||
|
@ -91,6 +91,7 @@ static bool arg_man = true;
|
||||
static bool arg_generators = false;
|
||||
static char *arg_root = NULL;
|
||||
static char *arg_image = NULL;
|
||||
static char *arg_security_policy = NULL;
|
||||
static bool arg_offline = false;
|
||||
static unsigned arg_threshold = 100;
|
||||
static unsigned arg_iterations = 1;
|
||||
@ -100,6 +101,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep);
|
||||
|
||||
typedef struct BootTimes {
|
||||
usec_t firmware_time;
|
||||
@ -2154,7 +2156,9 @@ static int do_verify(int argc, char *argv[], void *userdata) {
|
||||
|
||||
static int do_security(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *policy = NULL;
|
||||
int r;
|
||||
unsigned line, column;
|
||||
|
||||
r = acquire_bus(&bus, NULL);
|
||||
if (r < 0)
|
||||
@ -2162,7 +2166,35 @@ static int do_security(int argc, char *argv[], void *userdata) {
|
||||
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
return analyze_security(bus, strv_skip(argv, 1), arg_scope, arg_man, arg_generators, arg_offline, arg_threshold, arg_root, 0);
|
||||
if (arg_security_policy) {
|
||||
r = json_parse_file(/*f=*/ NULL, arg_security_policy, /*flags=*/ 0, &policy, &line, &column);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse '%s' at %u:%u: %m", arg_security_policy, line, column);
|
||||
} else {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *pp = NULL;
|
||||
|
||||
r = search_and_fopen_nulstr("systemd-analyze-security.policy", "re", /*root=*/ NULL, CONF_PATHS_NULSTR("systemd"), &f, &pp);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
if (f != NULL) {
|
||||
r = json_parse_file(f, pp, /*flags=*/ 0, &policy, &line, &column);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "[%s:%u:%u] Failed to parse JSON policy: %m", pp, line, column);
|
||||
}
|
||||
}
|
||||
|
||||
return analyze_security(bus,
|
||||
strv_skip(argv, 1),
|
||||
policy,
|
||||
arg_scope,
|
||||
arg_man,
|
||||
arg_generators,
|
||||
arg_offline,
|
||||
arg_threshold,
|
||||
arg_root,
|
||||
/*flags=*/ 0);
|
||||
}
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
@ -2214,6 +2246,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" --threshold=N Exit with a non-zero status when overall\n"
|
||||
" exposure level is over threshold value\n"
|
||||
" --version Show package version\n"
|
||||
" --security-policy=PATH Use custom JSON security policy instead\n"
|
||||
" of built-in one\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"
|
||||
@ -2266,6 +2300,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_RECURSIVE_ERRORS,
|
||||
ARG_OFFLINE,
|
||||
ARG_THRESHOLD,
|
||||
ARG_SECURITY_POLICY,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -2278,6 +2313,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "recursive-errors", required_argument, NULL, ARG_RECURSIVE_ERRORS },
|
||||
{ "offline", required_argument, NULL, ARG_OFFLINE },
|
||||
{ "threshold", required_argument, NULL, ARG_THRESHOLD },
|
||||
{ "security-policy", required_argument, NULL, ARG_SECURITY_POLICY },
|
||||
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||
{ "user", no_argument, NULL, ARG_USER },
|
||||
{ "global", no_argument, NULL, ARG_GLOBAL },
|
||||
@ -2409,6 +2445,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_SECURITY_POLICY:
|
||||
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_security_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_ITERATIONS:
|
||||
r = safe_atou(optarg, &arg_iterations);
|
||||
if (r < 0)
|
||||
@ -2447,6 +2489,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --user is not supported for cat-config right now.");
|
||||
|
||||
if (arg_security_policy && !streq_ptr(argv[optind], "security"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --security-policy= is only supported for security.");
|
||||
|
||||
if ((arg_root || arg_image) && (!STRPTR_IN_SET(argv[optind], "cat-config", "verify")) &&
|
||||
(!(streq_ptr(argv[optind], "security") && arg_offline)))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
|
Loading…
x
Reference in New Issue
Block a user