|
68 | 68 | #include "manager-serialize.h"
|
69 | 69 | #include "mkdir-label.h"
|
70 | 70 | #include "mount-setup.h"
|
| 71 | +#include "mount-util.h" |
71 | 72 | #include "os-util.h"
|
72 | 73 | #include "pager.h"
|
73 | 74 | #include "parse-argument.h"
|
@@ -140,6 +141,7 @@ static char **arg_default_environment;
|
140 | 141 | static char **arg_manager_environment;
|
141 | 142 | static uint64_t arg_capability_bounding_set;
|
142 | 143 | static bool arg_no_new_privs;
|
| 144 | +static int arg_protect_system; |
143 | 145 | static nsec_t arg_timer_slack_nsec;
|
144 | 146 | static Set* arg_syscall_archs;
|
145 | 147 | static FILE* arg_serialization;
|
@@ -610,6 +612,43 @@ static int config_parse_oom_score_adjust(
|
610 | 612 | return 0;
|
611 | 613 | }
|
612 | 614 |
|
| 615 | +static int config_parse_protect_system_pid1( |
| 616 | + const char *unit, |
| 617 | + const char *filename, |
| 618 | + unsigned line, |
| 619 | + const char *section, |
| 620 | + unsigned section_line, |
| 621 | + const char *lvalue, |
| 622 | + int ltype, |
| 623 | + const char *rvalue, |
| 624 | + void *data, |
| 625 | + void *userdata) { |
| 626 | + |
| 627 | + int *v = ASSERT_PTR(data), r; |
| 628 | + |
| 629 | + /* This is modelled after the per-service ProtectSystem= setting, but a bit more restricted on one |
| 630 | + * hand, and more automatic in another. i.e. we currently only support yes/no (not "strict" or |
| 631 | + * "full"). And we will enable this automatically for the initrd unless configured otherwise. |
| 632 | + * |
| 633 | + * We might extend this later to match more closely what the per-service ProtectSystem= can do, but |
| 634 | + * this is not trivial, due to ordering constraints: besides /usr/ we don't really have much mounted |
| 635 | + * at the moment we enable this logic. */ |
| 636 | + |
| 637 | + if (isempty(rvalue) || streq(rvalue, "auto")) { |
| 638 | + *v = -1; |
| 639 | + return 0; |
| 640 | + } |
| 641 | + |
| 642 | + r = parse_boolean(rvalue); |
| 643 | + if (r < 0) { |
| 644 | + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse ProtectSystem= argument '%s', ignoring: %m", rvalue); |
| 645 | + return 0; |
| 646 | + } |
| 647 | + |
| 648 | + *v = r; |
| 649 | + return 0; |
| 650 | +} |
| 651 | + |
613 | 652 | static int parse_config_file(void) {
|
614 | 653 | const ConfigTableItem items[] = {
|
615 | 654 | { "Manager", "LogLevel", config_parse_level2, 0, NULL },
|
@@ -637,6 +676,7 @@ static int parse_config_file(void) {
|
637 | 676 | { "Manager", "RuntimeWatchdogPreGovernor", config_parse_string, CONFIG_PARSE_STRING_SAFE, &arg_watchdog_pretimeout_governor },
|
638 | 677 | { "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set },
|
639 | 678 | { "Manager", "NoNewPrivileges", config_parse_bool, 0, &arg_no_new_privs },
|
| 679 | + { "Manager", "ProtectSystem", config_parse_protect_system_pid1, 0, &arg_protect_system }, |
640 | 680 | #if HAVE_SECCOMP
|
641 | 681 | { "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
|
642 | 682 | #else
|
@@ -1684,6 +1724,35 @@ static void initialize_core_pattern(bool skip_setup) {
|
1684 | 1724 | arg_early_core_pattern);
|
1685 | 1725 | }
|
1686 | 1726 |
|
| 1727 | +static void apply_protect_system(bool skip_setup) { |
| 1728 | + int r; |
| 1729 | + |
| 1730 | + if (skip_setup || getpid_cached() != 1 || arg_protect_system == 0) |
| 1731 | + return; |
| 1732 | + |
| 1733 | + if (arg_protect_system < 0 && !in_initrd()) { |
| 1734 | + log_debug("ProtectSystem=auto selected, but not running in an initrd, skipping."); |
| 1735 | + return; |
| 1736 | + } |
| 1737 | + |
| 1738 | + r = make_mount_point("/usr"); |
| 1739 | + if (r < 0) { |
| 1740 | + log_warning_errno(r, "Failed to make /usr/ a mount point, ignoring: %m"); |
| 1741 | + return; |
| 1742 | + } |
| 1743 | + |
| 1744 | + if (mount_nofollow_verbose( |
| 1745 | + LOG_WARNING, |
| 1746 | + /* what= */ NULL, |
| 1747 | + "/usr", |
| 1748 | + /* fstype= */ NULL, |
| 1749 | + MS_BIND|MS_REMOUNT|MS_RDONLY, |
| 1750 | + /* options= */ NULL) < 0) |
| 1751 | + return; |
| 1752 | + |
| 1753 | + log_info("Successfully made /usr/ read-only."); |
| 1754 | +} |
| 1755 | + |
1687 | 1756 | static void update_cpu_affinity(bool skip_setup) {
|
1688 | 1757 | _cleanup_free_ char *mask = NULL;
|
1689 | 1758 |
|
@@ -2531,6 +2600,7 @@ static void reset_arguments(void) {
|
2531 | 2600 |
|
2532 | 2601 | arg_capability_bounding_set = CAP_MASK_UNSET;
|
2533 | 2602 | arg_no_new_privs = false;
|
| 2603 | + arg_protect_system = -1; |
2534 | 2604 | arg_timer_slack_nsec = NSEC_INFINITY;
|
2535 | 2605 |
|
2536 | 2606 | arg_syscall_archs = set_free(arg_syscall_archs);
|
@@ -3040,9 +3110,12 @@ int main(int argc, char *argv[]) {
|
3040 | 3110 | cmdline_take_random_seed();
|
3041 | 3111 | }
|
3042 | 3112 |
|
3043 |
| - /* A core pattern might have been specified via the cmdline. */ |
| 3113 | + /* A core pattern might have been specified via the cmdline. */ |
3044 | 3114 | initialize_core_pattern(skip_setup);
|
3045 | 3115 |
|
| 3116 | + /* Make /usr/ read-only */ |
| 3117 | + apply_protect_system(skip_setup); |
| 3118 | + |
3046 | 3119 | /* Close logging fds, in order not to confuse collecting passed fds and terminal logic below */
|
3047 | 3120 | log_close();
|
3048 | 3121 |
|
|
0 commit comments