2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-03 15:55:46 +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' B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative' | '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> | 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL> | 'error='I<ERROR CODE>
B<ERROR CODE> = (case insensitive error code name starting with 'E'; see errno(3)) 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 attach disconnected objects to the supplied path instead of the root of
the namespace. 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 =item B<chroot_relative> This forces file names to be relative to a
chroot and behave as if the chroot is a mount namespace. 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_DELEGATE_DELETED 0x20
#define PATH_ATTACH 0x40 #define PATH_ATTACH 0x40
#define PATH_NO_ATTACH 0x80 #define PATH_NO_ATTACH 0x80
#define PATH_IPC_ATTACH 0x100
#ifdef DEBUG #ifdef DEBUG
@@ -334,6 +334,7 @@ extern int features_supports_io_uring;
extern int features_supports_flag_interruptible; extern int features_supports_flag_interruptible;
extern int features_supports_flag_signal; extern int features_supports_flag_signal;
extern int features_supports_flag_error; extern int features_supports_flag_error;
extern int features_supports_flag_disconnected_ipc;
extern int kernel_supports_oob; extern int kernel_supports_oob;
extern int kernel_supports_promptdev; extern int kernel_supports_promptdev;
extern int kernel_supports_permstable32; 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_interruptible = 0;
int features_supports_flag_signal = 0; int features_supports_flag_signal = 0;
int features_supports_flag_error = 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_oob = 0; /* out of band transitions */
int kernel_supports_promptdev = 0; /* prompt via audit perms */ int kernel_supports_promptdev = 0; /* prompt via audit perms */
int kernel_supports_permstable32 = 0; /* extended permissions */ int kernel_supports_permstable32 = 0; /* extended permissions */

View File

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

View File

@@ -991,6 +991,9 @@ void set_supported_features()
features_supports_flag_error = features_intersect(kernel_features, features_supports_flag_error = features_intersect(kernel_features,
policy_features, policy_features,
"policy/profile/error"); "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) 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; 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) static int process_variables_in_name(Profile &prof)
{ {
/* this needs to be done before alias expansion, ie. altnames are /* 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); int error = expand_entry_variables(&prof.name);
if (!error && prof.attachment) if (!error && prof.attachment)
error = expand_entry_variables(&prof.attachment); error = expand_entry_variables(&prof.attachment);
if (!error && prof.flags.disconnected_path) { if (!error && prof.flags.disconnected_path)
error = expand_entry_variables(&prof.flags.disconnected_path); error = process_variable_in_attach_disconnected(&prof.flags.disconnected_path);
if (error) if (!error && prof.flags.disconnected_ipc)
return error; error = process_variable_in_attach_disconnected(&prof.flags.disconnected_ipc);
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;
}
return error; return error;
} }

View File

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

View File

@@ -159,6 +159,7 @@ public:
int audit; int audit;
int path; int path;
char *disconnected_path; char *disconnected_path;
char *disconnected_ipc;
int signal; int signal;
int error; int error;
@@ -170,6 +171,7 @@ public:
audit = 0; audit = 0;
path = 0; path = 0;
disconnected_path = NULL; disconnected_path = NULL;
disconnected_ipc = NULL;
signal = 0; signal = 0;
error = 0; error = 0;
} }
@@ -216,6 +218,12 @@ public:
yyerror("unknown error code specified for error=\'%s\'\n", str + 6); yyerror("unknown error code specified for error=\'%s\'\n", str + 6);
} else if (strcmp(str, "interruptible") == 0) { } else if (strcmp(str, "interruptible") == 0) {
flags |= FLAG_INTERRUPTIBLE; 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 { } else {
yyerror(_("Invalid profile flag: %s."), str); yyerror(_("Invalid profile flag: %s."), str);
} }
@@ -237,6 +245,8 @@ public:
os << ", kill.signal=" << signal; os << ", kill.signal=" << signal;
if (error) if (error)
os << ", error=" << find_error_name_mapping(error); os << ", error=" << find_error_name_mapping(error);
if (disconnected_ipc)
os << ", attach_disconnected.ipc=" << disconnected_ipc;
if (flags & FLAG_PROMPT_COMPAT) if (flags & FLAG_PROMPT_COMPAT)
os << ", prompt_dev"; os << ", prompt_dev";
@@ -277,6 +287,9 @@ public:
if ((path & (PATH_ATTACH | PATH_NO_ATTACH)) == if ((path & (PATH_ATTACH | PATH_NO_ATTACH)) ==
(PATH_ATTACH | PATH_NO_ATTACH)) (PATH_ATTACH | PATH_NO_ATTACH))
yyerror(_("Profile flag attach_disconnected conflicts with no_attach_disconnected")); 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)) == if ((path & (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH)) ==
(PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH)) (PATH_CHROOT_NSATTACH | PATH_CHROOT_NO_ATTACH))
yyerror(_("Profile flag chroot_attach conflicts with chroot_no_attach")); yyerror(_("Profile flag chroot_attach conflicts with chroot_no_attach"));
@@ -291,6 +304,16 @@ public:
disconnected_path = rhs.disconnected_path; 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 (rhs.signal) {
if (signal) { if (signal) {
if (signal != rhs.signal) { if (signal != rhs.signal) {