mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
core: Add AppArmor profile switching
This permit to switch to a specific apparmor profile when starting a daemon. This will result in a non operation if apparmor is disabled. It also add a new build requirement on libapparmor for using this feature.
This commit is contained in:
parent
37f78db2f4
commit
eef65bf3ee
@ -1020,6 +1020,7 @@ libsystemd_core_la_CFLAGS = \
|
||||
$(AUDIT_CFLAGS) \
|
||||
$(CAP_CFLAGS) \
|
||||
$(KMOD_CFLAGS) \
|
||||
$(APPARMOR_CFLAGS) \
|
||||
$(SECCOMP_CFLAGS) \
|
||||
-pthread
|
||||
|
||||
@ -1035,6 +1036,7 @@ libsystemd_core_la_LIBADD = \
|
||||
$(AUDIT_LIBS) \
|
||||
$(CAP_LIBS) \
|
||||
$(KMOD_LIBS) \
|
||||
$(APPARMOR_LIBS) \
|
||||
$(SECCOMP_LIBS)
|
||||
|
||||
if HAVE_SECCOMP
|
||||
|
16
configure.ac
16
configure.ac
@ -385,6 +385,21 @@ if test "x$enable_selinux" != "xno"; then
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_SELINUX, [test "$have_selinux" = "yes"])
|
||||
|
||||
have_apparmor=no
|
||||
AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--disable-apparmor], [Disable optional AppArmor support]))
|
||||
if test "x$enable_apparmor" != "xno"; then
|
||||
PKG_CHECK_MODULES([APPARMOR], [libapparmor],
|
||||
[AC_DEFINE(HAVE_APPARMOR, 1, [Define if AppArmor is available])
|
||||
have_apparmor=yes
|
||||
M4_DEFINES="$M4_DEFINES -DHAVE_APPARMOR"],
|
||||
[have_apparmor=no])
|
||||
if test "x$have_apparmor" = xno -a "x$enable_apparmor" = xyes; then
|
||||
AC_MSG_ERROR([*** AppArmor support requested but libraries not found])
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_APPARMOR, [test "$have_apparmor" = "yes"])
|
||||
|
||||
|
||||
AC_ARG_WITH(debug-shell,
|
||||
AS_HELP_STRING([--with-debug-shell=PATH],
|
||||
[Path to debug shell binary]),
|
||||
@ -1110,6 +1125,7 @@ AC_MSG_RESULT([
|
||||
PAM: ${have_pam}
|
||||
AUDIT: ${have_audit}
|
||||
IMA: ${have_ima}
|
||||
AppArmor: ${have_apparmor}
|
||||
SELinux: ${have_selinux}
|
||||
SECCOMP: ${have_seccomp}
|
||||
SMACK: ${have_smack}
|
||||
|
@ -967,6 +967,19 @@
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>AppArmorProfile=</varname></term>
|
||||
|
||||
<listitem><para>Take a profile name as argument.
|
||||
The process executed by the unit will switch to
|
||||
this profile when started. Profiles must already
|
||||
be loaded in the kernel, or the unit will fail.
|
||||
This result in a non operation if AppArmor is not
|
||||
enabled. If prefixed by <literal>-</literal>, all errors
|
||||
will be ignored.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>IgnoreSIGPIPE=</varname></term>
|
||||
|
||||
|
@ -45,6 +45,12 @@
|
||||
#define _SELINUX_FEATURE_ "-SELINUX"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_APPARMOR
|
||||
#define _APPARMOR_FEATURE_ "+APPARMOR"
|
||||
#else
|
||||
#define _APPARMOR_FEATURE_ "-APPARMOR"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMA
|
||||
#define _IMA_FEATURE_ "+IMA"
|
||||
#else
|
||||
@ -87,4 +93,4 @@
|
||||
#define _SECCOMP_FEATURE_ "-SECCOMP"
|
||||
#endif
|
||||
|
||||
#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ " " _SECCOMP_FEATURE_
|
||||
#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ " " _SECCOMP_FEATURE_ " " _APPARMOR_FEATURE_
|
||||
|
@ -482,6 +482,24 @@ static int property_get_selinux_context(
|
||||
return sd_bus_message_append(reply, "(bs)", c->selinux_context_ignore, c->selinux_context);
|
||||
}
|
||||
|
||||
static int property_get_apparmor_profile(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
ExecContext *c = userdata;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(c);
|
||||
|
||||
return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
|
||||
}
|
||||
|
||||
static int property_get_personality(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
@ -560,6 +578,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
|
@ -55,6 +55,10 @@
|
||||
#include <seccomp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_APPARMOR
|
||||
#include <sys/apparmor.h>
|
||||
#endif
|
||||
|
||||
#include "execute.h"
|
||||
#include "strv.h"
|
||||
#include "macro.h"
|
||||
@ -77,6 +81,7 @@
|
||||
#include "async.h"
|
||||
#include "selinux-util.h"
|
||||
#include "errno-list.h"
|
||||
#include "apparmor-util.h"
|
||||
|
||||
#ifdef HAVE_SECCOMP
|
||||
#include "seccomp-util.h"
|
||||
@ -1597,6 +1602,16 @@ int exec_spawn(ExecCommand *command,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_APPARMOR
|
||||
if (context->apparmor_profile && use_apparmor()) {
|
||||
err = aa_change_onexec(context->apparmor_profile);
|
||||
if (err < 0 && !context->apparmor_profile_ignore) {
|
||||
r = EXIT_APPARMOR_PROFILE;
|
||||
goto fail_child;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env);
|
||||
@ -1759,6 +1774,9 @@ void exec_context_done(ExecContext *c) {
|
||||
free(c->selinux_context);
|
||||
c->selinux_context = NULL;
|
||||
|
||||
free(c->apparmor_profile);
|
||||
c->apparmor_profile = NULL;
|
||||
|
||||
#ifdef HAVE_SECCOMP
|
||||
set_free(c->syscall_filter);
|
||||
c->syscall_filter = NULL;
|
||||
@ -2188,6 +2206,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
|
||||
fprintf(f,
|
||||
"%sSystemCallErrorNumber: %s\n",
|
||||
prefix, strna(errno_to_name(c->syscall_errno)));
|
||||
|
||||
if (c->apparmor_profile)
|
||||
fprintf(f,
|
||||
"%sAppArmorProfile: %s%s\n",
|
||||
prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
|
||||
}
|
||||
|
||||
void exec_status_start(ExecStatus *s, pid_t pid) {
|
||||
|
@ -141,6 +141,9 @@ struct ExecContext {
|
||||
bool selinux_context_ignore;
|
||||
char *selinux_context;
|
||||
|
||||
bool apparmor_profile_ignore;
|
||||
char *apparmor_profile;
|
||||
|
||||
char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
|
||||
unsigned long mount_flags;
|
||||
|
||||
|
@ -90,7 +90,10 @@ $1.IgnoreSIGPIPE, config_parse_bool, 0,
|
||||
$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id)
|
||||
m4_ifdef(`HAVE_SELINUX',
|
||||
`$1.SELinuxContext, config_parse_exec_selinux_context, 0, offsetof($1, exec_context)',
|
||||
`$1.SELinuxContext, config_parse_warn_compat, 0, 0')'
|
||||
`$1.SELinuxContext, config_parse_warn_compat, 0, 0')
|
||||
m4_ifdef(`HAVE_APPARMOR',
|
||||
`$1.AppArmorProfile, config_parse_exec_apparmor_profile,0, offsetof($1, exec_context)',
|
||||
`$1.AppArmorProfile, config_parse_warn_compat, 0, 0')'
|
||||
)m4_dnl
|
||||
m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
|
||||
`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
|
||||
|
@ -61,7 +61,7 @@
|
||||
#include "seccomp-util.h"
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK)
|
||||
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
|
||||
int config_parse_warn_compat(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
@ -1192,6 +1192,55 @@ int config_parse_exec_selinux_context(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_exec_apparmor_profile(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
ExecContext *c = data;
|
||||
Unit *u = userdata;
|
||||
bool ignore;
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
free(c->apparmor_profile);
|
||||
c->apparmor_profile = NULL;
|
||||
c->apparmor_profile_ignore = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rvalue[0] == '-') {
|
||||
ignore = true;
|
||||
rvalue++;
|
||||
} else
|
||||
ignore = false;
|
||||
|
||||
r = unit_name_printf(u, rvalue, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", strerror(-r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(c->apparmor_profile);
|
||||
c->apparmor_profile = k;
|
||||
c->apparmor_profile_ignore = ignore;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_timer(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@ -2910,7 +2959,7 @@ void unit_dump_config_items(FILE *f) {
|
||||
const ConfigParserCallback callback;
|
||||
const char *rvalue;
|
||||
} table[] = {
|
||||
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK)
|
||||
#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_LIBWRAP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
|
||||
{ config_parse_warn_compat, "NOTSUPPORTED" },
|
||||
#endif
|
||||
{ config_parse_int, "INTEGER" },
|
||||
|
@ -89,6 +89,7 @@ int config_parse_job_mode(const char *unit, const char *filename, unsigned line,
|
||||
int config_parse_job_mode_isolate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_exec_selinux_context(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_exec_apparmor_profile(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
/* gperf prototypes */
|
||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
|
||||
|
@ -136,6 +136,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
|
||||
|
||||
case EXIT_PERSONALITY:
|
||||
return "PERSONALITY";
|
||||
|
||||
case EXIT_APPARMOR_PROFILE:
|
||||
return "APPARMOR";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@ typedef enum ExitStatus {
|
||||
EXIT_NO_NEW_PRIVILEGES,
|
||||
EXIT_SECCOMP,
|
||||
EXIT_SELINUX_CONTEXT,
|
||||
EXIT_PERSONALITY /* 230 */
|
||||
EXIT_PERSONALITY, /* 230 */
|
||||
EXIT_APPARMOR_PROFILE
|
||||
} ExitStatus;
|
||||
|
||||
typedef enum ExitStatusLevel {
|
||||
|
Loading…
Reference in New Issue
Block a user