2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-01 23:05:11 +00:00

parser: add support for attach_disconnected.ipc flag

The attach_disconnected.ipc flag allows the use of disconnected paths
on posix mqueues. This flag is a subset of attach_disconnected, and it
does not allow disconnected paths for all files.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
This commit is contained in:
Georgia Garcia
2025-02-25 19:18:58 -03:00
parent 2afdf1b214
commit d9b3603f48
8 changed files with 68 additions and 15 deletions

View File

@@ -115,6 +115,7 @@ B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
| 'attach_disconnected.ipc' | 'attach_disconnected.ipc='I<ABS PATH>
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL> | 'error='I<ERROR CODE>
B<ERROR CODE> = (case insensitive error code name starting with 'E'; see errno(3))
@@ -560,6 +561,14 @@ allowed. Its intent is a debug and policy development tool.
attach disconnected objects to the supplied path instead of the root of
the namespace.
=item B<attach_disconnected.ipc> A subset of attach_disconnected, but specific
for IPC namespaces. It allows attaching disconnected IPC paths without having
to allow attaching all types of files.
=item B<attach_disconnected.ipc>=I<ABS PATH> Like attach_disconnected.ipc, but
attach disconnected posix mqueue to the supplied path instead of the root of
the namespace.
=item B<chroot_relative> This forces file names to be relative to a
chroot and behave as if the chroot is a mount namespace.

View File

@@ -189,7 +189,7 @@ extern int preprocess_only;
#define PATH_DELEGATE_DELETED 0x20
#define PATH_ATTACH 0x40
#define PATH_NO_ATTACH 0x80
#define PATH_IPC_ATTACH 0x100
#ifdef DEBUG
@@ -334,6 +334,7 @@ extern int features_supports_io_uring;
extern int features_supports_flag_interruptible;
extern int features_supports_flag_signal;
extern int features_supports_flag_error;
extern int features_supports_flag_disconnected_ipc;
extern int kernel_supports_oob;
extern int kernel_supports_promptdev;
extern int kernel_supports_permstable32;

View File

@@ -86,6 +86,7 @@ int features_supports_io_uring = 0; /* kernel supports io_uring rules */
int features_supports_flag_interruptible = 0;
int features_supports_flag_signal = 0;
int features_supports_flag_error = 0;
int features_supports_flag_disconnected_ipc = 0; /* kernel supports disconnected paths for ipc ns */
int kernel_supports_oob = 0; /* out of band transitions */
int kernel_supports_promptdev = 0; /* prompt via audit perms */
int kernel_supports_permstable32 = 0; /* extended permissions */

View File

@@ -474,6 +474,11 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
"disconnected");
}
if (profile->flags.disconnected_ipc && features_supports_flag_disconnected_ipc) {
sd_write_string(buf, profile->flags.disconnected_ipc,
"disconnected_ipc");
}
if (profile->flags.signal && features_supports_flag_signal) {
sd_write_name(buf, "kill");
sd_write_uint32(buf, profile->flags.signal);
@@ -500,6 +505,8 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
flags |= 0x4;
if (profile->flags.path & PATH_CHROOT_NSATTACH)
flags |= 0x10;
if (profile->flags.path & PATH_IPC_ATTACH)
flags |= 0x20;
sd_write_name(buf, "path_flags");
sd_write_uint32(buf, flags);

View File

@@ -991,6 +991,9 @@ void set_supported_features()
features_supports_flag_error = features_intersect(kernel_features,
policy_features,
"policy/profile/error");
features_supports_flag_disconnected_ipc = features_intersect(kernel_features,
policy_features,
"domain/disconnected.ipc");
}
static bool do_print_cache_dir(aa_features *features, int dirfd, const char *path)

View File

@@ -272,6 +272,23 @@ static int process_variables_in_rules(Profile &prof)
return 0;
}
static int process_variable_in_attach_disconnected(char **disconnected)
{
int error = expand_entry_variables(disconnected);
if (error)
return error;
filter_slashes(*disconnected);
// TODO: semantic check should go somewhere else
if ((*disconnected)[0] != '/')
yyerror(_("attach_disconnected path must begin with a /"));
int n = strlen(*disconnected);
// removing trailing / */
while (n && (*disconnected)[n-1] == '/')
(*disconnected)[--n] = 0;
return error;
}
static int process_variables_in_name(Profile &prof)
{
/* this needs to be done before alias expansion, ie. altnames are
@@ -280,20 +297,10 @@ static int process_variables_in_name(Profile &prof)
int error = expand_entry_variables(&prof.name);
if (!error && prof.attachment)
error = expand_entry_variables(&prof.attachment);
if (!error && prof.flags.disconnected_path) {
error = expand_entry_variables(&prof.flags.disconnected_path);
if (error)
return error;
filter_slashes(prof.flags.disconnected_path);
// TODO: semantic check should go somewhere else
if (prof.flags.disconnected_path[0] != '/')
yyerror(_("attach_disconnected_path value must begin with a /"));
int n = strlen(prof.flags.disconnected_path);
// removing trailing / */
while (n && prof.flags.disconnected_path[n-1] == '/')
prof.flags.disconnected_path[--n] = 0;
}
if (!error && prof.flags.disconnected_path)
error = process_variable_in_attach_disconnected(&prof.flags.disconnected_path);
if (!error && prof.flags.disconnected_ipc)
error = process_variable_in_attach_disconnected(&prof.flags.disconnected_ipc);
return error;
}

View File

@@ -97,6 +97,8 @@ Profile::~Profile()
free(attachment);
if (flags.disconnected_path)
free(flags.disconnected_path);
if (flags.disconnected_ipc)
free(flags.disconnected_ipc);
if (ns)
free(ns);
for (int i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++)

View File

@@ -159,6 +159,7 @@ public:
int audit;
int path;
char *disconnected_path;
char *disconnected_ipc;
int signal;
int error;
@@ -170,6 +171,7 @@ public:
audit = 0;
path = 0;
disconnected_path = NULL;
disconnected_ipc = NULL;
signal = 0;
error = 0;
}
@@ -216,6 +218,12 @@ public:
yyerror("unknown error code specified for error=\'%s\'\n", str + 6);
} else if (strcmp(str, "interruptible") == 0) {
flags |= FLAG_INTERRUPTIBLE;
} else if (strcmp(str, "attach_disconnected.ipc") == 0) {
path |= PATH_IPC_ATTACH;
} else if (strncmp(str, "attach_disconnected.ipc=", 24) == 0) {
/* TODO: make this a proper parse */
path |= PATH_IPC_ATTACH;
disconnected_ipc = strdup(str + 24);
} else {
yyerror(_("Invalid profile flag: %s."), str);
}
@@ -237,6 +245,8 @@ public:
os << ", kill.signal=" << signal;
if (error)
os << ", error=" << find_error_name_mapping(error);
if (disconnected_ipc)
os << ", attach_disconnected.ipc=" << disconnected_ipc;
if (flags & FLAG_PROMPT_COMPAT)
os << ", prompt_dev";
@@ -277,6 +287,9 @@ public:
if ((path & (PATH_ATTACH | PATH_NO_ATTACH)) ==
(PATH_ATTACH | PATH_NO_ATTACH))
yyerror(_("Profile flag attach_disconnected conflicts with no_attach_disconnected"));
if ((path & (PATH_IPC_ATTACH | PATH_NO_ATTACH)) ==
(PATH_IPC_ATTACH | PATH_NO_ATTACH))
yyerror(_("Profile flag attach_disconnected.ipc conflicts with no_attach_disconnected"));
if ((path & (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH)) ==
(PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH))
yyerror(_("Profile flag chroot_attach conflicts with chroot_no_attach"));
@@ -291,6 +304,16 @@ public:
disconnected_path = rhs.disconnected_path;
}
}
if (rhs.disconnected_ipc) {
if (disconnected_ipc) {
if (strcmp(disconnected_ipc, rhs.disconnected_ipc) != 0) {
yyerror(_("Profile flag attach_disconnected set to conflicting values: '%s' and '%s'"), disconnected_ipc, rhs.disconnected_ipc);
}
// same so do nothing
} else {
disconnected_ipc = rhs.disconnected_ipc;
}
}
if (rhs.signal) {
if (signal) {
if (signal != rhs.signal) {