summaryrefslogtreecommitdiff
path: root/security/apparmor
diff options
context:
space:
mode:
authorGeorgia Garcia <georgia.garcia@canonical.com>2023-03-20 14:43:41 -0300
committerJohn Johansen <john.johansen@canonical.com>2023-10-18 15:58:49 -0700
commitc4371d90633b73cf6e86aff43ff2b5d95ad2b9eb (patch)
tree79ba65647ca619a148ed995aeca5e4a3ebc3716e /security/apparmor
parentfa9b63adabcfa9b724120ef3352cf6fb82b4b9a5 (diff)
apparmor: add io_uring mediation
For now, the io_uring mediation is limited to sqpoll and override_creds. Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor')
-rw-r--r--security/apparmor/apparmorfs.c7
-rw-r--r--security/apparmor/audit.c2
-rw-r--r--security/apparmor/include/apparmor.h2
-rw-r--r--security/apparmor/include/audit.h6
-rw-r--r--security/apparmor/include/perms.h3
-rw-r--r--security/apparmor/lsm.c113
6 files changed, 131 insertions, 2 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 7170349c8af0..a608a6bd76c5 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2390,6 +2390,12 @@ static struct aa_sfs_entry aa_sfs_entry_query[] = {
AA_SFS_DIR("label", aa_sfs_entry_query_label),
{ }
};
+
+static struct aa_sfs_entry aa_sfs_entry_io_uring[] = {
+ AA_SFS_FILE_STRING("mask", "sqpoll override_creds"),
+ { }
+};
+
static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("policy", aa_sfs_entry_policy),
AA_SFS_DIR("domain", aa_sfs_entry_domain),
@@ -2403,6 +2409,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
AA_SFS_DIR("signal", aa_sfs_entry_signal),
AA_SFS_DIR("query", aa_sfs_entry_query),
+ AA_SFS_DIR("io_uring", aa_sfs_entry_io_uring),
{ }
};
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 3b24f4a8c727..45beb1c5f747 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -59,7 +59,7 @@ static const char *const aa_class_names[] = {
"module",
"lsm",
"namespace",
- "unknown",
+ "io_uring",
"unknown",
"unknown",
"unknown",
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index e2b759f24064..f83934913b0f 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -30,10 +30,10 @@
#define AA_CLASS_NET 14
#define AA_CLASS_LABEL 16
#define AA_CLASS_POSIX_MQUEUE 17
-#define AA_CLASS_IO_URING 18
#define AA_CLASS_MODULE 19
#define AA_CLASS_DISPLAY_LSM 20
#define AA_CLASS_NS 21
+#define AA_CLASS_IO_URING 22
#define AA_CLASS_X 31
#define AA_CLASS_DBUS 32
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 095707e05b70..acbb03b9bd25 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -105,6 +105,9 @@ enum audit_type {
#define OP_USERNS_CREATE "userns_create"
+#define OP_URING_OVERRIDE "uring_override"
+#define OP_URING_SQPOLL "uring_sqpoll"
+
struct apparmor_audit_data {
int error;
int type;
@@ -153,6 +156,9 @@ struct apparmor_audit_data {
const char *data;
unsigned long flags;
} mnt;
+ struct {
+ struct aa_label *target;
+ } uring;
};
struct common_audit_data common;
diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h
index 83534df8939f..0f7e913c3fc2 100644
--- a/security/apparmor/include/perms.h
+++ b/security/apparmor/include/perms.h
@@ -48,6 +48,9 @@
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
+#define AA_MAY_CREATE_SQPOLL AA_MAY_CREATE
+#define AA_MAY_OVERRIDE_CRED AA_MAY_APPEND
+#define AA_URING_PERM_MASK (AA_MAY_OVERRIDE_CRED | AA_MAY_CREATE_SQPOLL)
#define PERMS_CHRS_MASK (MAY_READ | MAY_WRITE | AA_MAY_CREATE | \
AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index c61835bd7db9..c80c1bd3024a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -582,6 +582,114 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
false);
}
+#ifdef CONFIG_IO_URING
+static const char *audit_uring_mask(u32 mask)
+{
+ if (mask & AA_MAY_CREATE_SQPOLL)
+ return "sqpoll";
+ if (mask & AA_MAY_OVERRIDE_CRED)
+ return "override_creds";
+ return "";
+}
+
+static void audit_uring_cb(struct audit_buffer *ab, void *va)
+{
+ struct apparmor_audit_data *ad = aad_of_va(va);
+
+ if (ad->request & AA_URING_PERM_MASK) {
+ audit_log_format(ab, " requested=\"%s\"",
+ audit_uring_mask(ad->request));
+ if (ad->denied & AA_URING_PERM_MASK) {
+ audit_log_format(ab, " denied=\"%s\"",
+ audit_uring_mask(ad->denied));
+ }
+ }
+ if (ad->uring.target) {
+ audit_log_format(ab, " tcontext=");
+ aa_label_xaudit(ab, labels_ns(ad->subj_label),
+ ad->uring.target,
+ FLAGS_NONE, GFP_ATOMIC);
+ }
+}
+
+static int profile_uring(struct aa_profile *profile, u32 request,
+ struct aa_label *new, int cap,
+ struct apparmor_audit_data *ad)
+{
+ unsigned int state;
+ struct aa_ruleset *rules;
+ int error = 0;
+
+ AA_BUG(!profile);
+
+ rules = list_first_entry(&profile->rules, typeof(*rules), list);
+ state = RULE_MEDIATES(rules, AA_CLASS_IO_URING);
+ if (state) {
+ struct aa_perms perms = { };
+
+ if (new) {
+ aa_label_match(profile, rules, new, state,
+ false, request, &perms);
+ } else {
+ perms = *aa_lookup_perms(rules->policy, state);
+ }
+ aa_apply_modes_to_perms(profile, &perms);
+ error = aa_check_perms(profile, &perms, request, ad,
+ audit_uring_cb);
+ }
+
+ return error;
+}
+
+/**
+ * apparmor_uring_override_creds - check the requested cred override
+ * @new: the target creds
+ *
+ * Check to see if the current task is allowed to override it's credentials
+ * to service an io_uring operation.
+ */
+int apparmor_uring_override_creds(const struct cred *new)
+{
+ struct aa_profile *profile;
+ struct aa_label *label;
+ int error;
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING,
+ OP_URING_OVERRIDE);
+
+ ad.uring.target = cred_label(new);
+ label = __begin_current_label_crit_section();
+ error = fn_for_each(label, profile,
+ profile_uring(profile, AA_MAY_OVERRIDE_CRED,
+ cred_label(new), CAP_SYS_ADMIN, &ad));
+ __end_current_label_crit_section(label);
+
+ return error;
+}
+
+/**
+ * apparmor_uring_sqpoll - check if a io_uring polling thread can be created
+ *
+ * Check to see if the current task is allowed to create a new io_uring
+ * kernel polling thread.
+ */
+int apparmor_uring_sqpoll(void)
+{
+ struct aa_profile *profile;
+ struct aa_label *label;
+ int error;
+ DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING,
+ OP_URING_SQPOLL);
+
+ label = __begin_current_label_crit_section();
+ error = fn_for_each(label, profile,
+ profile_uring(profile, AA_MAY_CREATE_SQPOLL,
+ NULL, CAP_SYS_ADMIN, &ad));
+ __end_current_label_crit_section(label);
+
+ return error;
+}
+#endif /* CONFIG_IO_URING */
+
static int apparmor_sb_mount(const char *dev_name, const struct path *path,
const char *type, unsigned long flags, void *data)
{
@@ -1346,6 +1454,11 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
+
+#ifdef CONFIG_IO_URING
+ LSM_HOOK_INIT(uring_override_creds, apparmor_uring_override_creds),
+ LSM_HOOK_INIT(uring_sqpoll, apparmor_uring_sqpoll),
+#endif
};
/*