summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2021-11-26 15:46:40 +0000
committerLuca Boccassi <luca.boccassi@microsoft.com>2021-11-26 18:17:26 +0000
commit0446921131218c3f23f8937f85294b3c244a923b (patch)
treea7906870474dbec7e2febaf518e948cee975b493 /src
parent83de7427dc7897669cfd83b3af7d6bbb914a307c (diff)
downloadsystemd-0446921131218c3f23f8937f85294b3c244a923b.tar.gz
analyze: add --profile switch to security verb
Allows to pass a portable profile when doing offline analysis of units. Especially useful for analyzing portable images, since a lot of the security-relevant settings in those cases come from the profiles, but they are not shipped in the portable images.
Diffstat (limited to 'src')
-rw-r--r--src/analyze/analyze-security.c40
-rw-r--r--src/analyze/analyze-security.h1
-rw-r--r--src/analyze/analyze.c25
3 files changed, 65 insertions, 1 deletions
diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c
index d3e011e903..d52518677c 100644
--- a/src/analyze/analyze-security.c
+++ b/src/analyze/analyze-security.c
@@ -9,6 +9,7 @@
#include "bus-map-properties.h"
#include "bus-unit-util.h"
#include "bus-util.h"
+#include "copy.h"
#include "env-util.h"
#include "format-table.h"
#include "in-addr-prefix-util.h"
@@ -17,6 +18,7 @@
#include "manager.h"
#include "missing_capability.h"
#include "missing_sched.h"
+#include "mkdir.h"
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
@@ -2646,6 +2648,7 @@ static int offline_security_checks(char **filenames,
bool run_generators,
unsigned threshold,
const char *root,
+ const char *profile,
PagerFlags pager_flags,
JsonFormatFlags json_format_flags) {
@@ -2682,6 +2685,13 @@ static int offline_security_checks(char **filenames,
if (r < 0)
return r;
+ if (profile) {
+ /* Ensure the temporary directory is in the search path, so that we can add drop-ins. */
+ r = strv_extend(&m->lookup_paths.search_path, m->lookup_paths.temporary_dir);
+ if (r < 0)
+ return log_oom();
+ }
+
log_debug("Loading remaining units from the command line...");
STRV_FOREACH(filename, filenames) {
@@ -2697,6 +2707,33 @@ static int offline_security_checks(char **filenames,
continue;
}
+ /* When a portable image is analyzed, the profile is what provides a good chunk of
+ * the security-related settings, but they are obviously not shipped with the image.
+ * This allows to take them in consideration. */
+ if (profile) {
+ _cleanup_free_ char *unit_name = NULL, *dropin = NULL, *profile_path = NULL;
+
+ r = path_extract_filename(prepared, &unit_name);
+ if (r < 0)
+ return log_oom();
+
+ dropin = strjoin(m->lookup_paths.temporary_dir, "/", unit_name, ".d/profile.conf");
+ if (!dropin)
+ return log_oom();
+ (void) mkdir_parents(dropin, 0755);
+
+ if (!is_path(profile)) {
+ r = find_portable_profile(profile, unit_name, &profile_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find portable profile %s: %m", profile);
+ profile = profile_path;
+ }
+
+ r = copy_file(profile, dropin, 0, 0644, 0, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy: %m");
+ }
+
k = manager_load_startable_unit_or_warn(m, NULL, prepared, &units[count]);
if (k < 0) {
if (r == 0)
@@ -2725,6 +2762,7 @@ int analyze_security(sd_bus *bus,
bool offline,
unsigned threshold,
const char *root,
+ const char *profile,
JsonFormatFlags json_format_flags,
PagerFlags pager_flags,
AnalyzeSecurityFlags flags) {
@@ -2735,7 +2773,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, profile, pager_flags, json_format_flags);
if (strv_length(units) != 1) {
overview_table = table_new("unit", "exposure", "predicate", "happy");
diff --git a/src/analyze/analyze-security.h b/src/analyze/analyze-security.h
index 492881c385..07483248ee 100644
--- a/src/analyze/analyze-security.h
+++ b/src/analyze/analyze-security.h
@@ -24,6 +24,7 @@ int analyze_security(sd_bus *bus,
bool offline,
unsigned threshold,
const char *root,
+ const char *profile,
JsonFormatFlags json_format_flags,
PagerFlags pager_flags,
AnalyzeSecurityFlags flags);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 740faa507b..a641be4179 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -105,6 +105,7 @@ static usec_t arg_base_time = USEC_INFINITY;
static char *arg_unit = NULL;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static bool arg_quiet = false;
+static char *arg_profile = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
@@ -112,6 +113,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep);
STATIC_DESTRUCTOR_REGISTER(arg_unit, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_profile, freep);
typedef struct BootTimes {
usec_t firmware_time;
@@ -2423,6 +2425,7 @@ static int do_security(int argc, char *argv[], void *userdata) {
arg_offline,
arg_threshold,
arg_root,
+ arg_profile,
arg_json_format_flags,
arg_pager_flags,
/*flags=*/ 0);
@@ -2497,6 +2500,8 @@ static int help(int argc, char *argv[], void *userdata) {
" --iterations=N Show the specified number of iterations\n"
" --base-time=TIMESTAMP Calculate calendar times relative to\n"
" specified time\n"
+ " --profile=name|PATH Include the specified profile in the\n"
+ " security review of the unit(s)\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -q --quiet Do not emit hints\n"
@@ -2536,6 +2541,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_THRESHOLD,
ARG_SECURITY_POLICY,
ARG_JSON,
+ ARG_PROFILE,
};
static const struct option options[] = {
@@ -2565,6 +2571,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "base-time", required_argument, NULL, ARG_BASE_TIME },
{ "unit", required_argument, NULL, 'U' },
{ "json", required_argument, NULL, ARG_JSON },
+ { "profile", required_argument, NULL, ARG_PROFILE },
{}
};
@@ -2713,6 +2720,24 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_PROFILE:
+ if (isempty(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Profile file name is empty");
+
+ if (is_path(optarg)) {
+ r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_profile);
+ if (r < 0)
+ return r;
+ if (!endswith(arg_profile, ".conf"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Profile file name must end with .conf: %s", arg_profile);
+ } else {
+ r = free_and_strdup(&arg_profile, optarg);
+ if (r < 0)
+ return log_oom();
+ }
+
+ break;
+
case 'U': {
_cleanup_free_ char *mangled = NULL;