[PATCH v6 09/11] AppArmor: Add selfattr hooks
From: Casey Schaufler <casey@schaufler-ca.com>
Date: 2023-02-22 20:14:00
Also in:
linux-api, lkml
Subsystem:
apparmor security module, security subsystem, the rest · Maintainers:
John Johansen, Paul Moore, James Morris, "Serge E. Hallyn", Linus Torvalds
Add hooks for setselfattr and getselfattr. These hooks are not very different from their setprocattr and getprocattr equivalents, and much of the code is shared. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> --- security/apparmor/include/procattr.h | 2 +- security/apparmor/lsm.c | 91 ++++++++++++++++++++++++++-- security/apparmor/procattr.c | 11 +++- 3 files changed, 94 insertions(+), 10 deletions(-)
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
index 31689437e0e1..03dbfdb2f2c0 100644
--- a/security/apparmor/include/procattr.h
+++ b/security/apparmor/include/procattr.h@@ -11,7 +11,7 @@ #ifndef __AA_PROCATTR_H #define __AA_PROCATTR_H -int aa_getprocattr(struct aa_label *label, char **string); +int aa_getprocattr(struct aa_label *label, char **string, bool newline); int aa_setprocattr_changehat(char *args, size_t size, int flags); #endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 0c2f4d47af42..165fffff095a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c@@ -632,6 +632,44 @@ static int apparmor_sb_pivotroot(const struct path *old_path, return error; } +static int apparmor_getselfattr(u64 __user attr, struct lsm_ctx __user *lx, + size_t *size) +{ + int error = -ENOENT; + struct aa_task_ctx *ctx = task_ctx(current); + struct aa_label *label = NULL; + size_t total_len; + char *value; + + if (attr == LSM_ATTR_CURRENT) + label = aa_get_newest_label(cred_label(current_cred())); + else if (attr == LSM_ATTR_PREV && ctx->previous) + label = aa_get_newest_label(ctx->previous); + else if (attr == LSM_ATTR_EXEC && ctx->onexec) + label = aa_get_newest_label(ctx->onexec); + else + error = -EOPNOTSUPP; + + if (label) { + error = aa_getprocattr(label, &value, false); + if (error > 0) { + total_len = error + sizeof(*ctx); + if (total_len > *size) + error = -E2BIG; + else + lsm_fill_user_ctx(lx, value, error, + LSM_ID_APPARMOR, 0); + } + } + + aa_put_label(label); + + *size = total_len; + if (error > 0) + return 0; + return error; +} + static int apparmor_getprocattr(struct task_struct *task, const char *name, char **value) {
@@ -651,7 +689,7 @@ static int apparmor_getprocattr(struct task_struct *task, const char *name, error = -EINVAL; if (label) - error = aa_getprocattr(label, value); + error = aa_getprocattr(label, value, true); aa_put_label(label); put_cred(cred);
@@ -659,8 +697,7 @@ static int apparmor_getprocattr(struct task_struct *task, const char *name, return error; } -static int apparmor_setprocattr(const char *name, void *value, - size_t size) +static int do_setattr(u64 attr, void *value, size_t size) { char *command, *largs = NULL, *args = value; size_t arg_size;
@@ -691,7 +728,7 @@ static int apparmor_setprocattr(const char *name, void *value, goto out; arg_size = size - (args - (largs ? largs : (char *) value)); - if (strcmp(name, "current") == 0) { + if (attr == LSM_ATTR_CURRENT) { if (strcmp(command, "changehat") == 0) { error = aa_setprocattr_changehat(args, arg_size, AA_CHANGE_NOFLAGS);
@@ -706,7 +743,7 @@ static int apparmor_setprocattr(const char *name, void *value, error = aa_change_profile(args, AA_CHANGE_STACK); } else goto fail; - } else if (strcmp(name, "exec") == 0) { + } else if (attr == LSM_ATTR_EXEC) { if (strcmp(command, "exec") == 0) error = aa_change_profile(args, AA_CHANGE_ONEXEC); else if (strcmp(command, "stack") == 0)
@@ -726,13 +763,53 @@ static int apparmor_setprocattr(const char *name, void *value, fail: aad(&sa)->label = begin_current_label_crit_section(); - aad(&sa)->info = name; + if (attr == LSM_ATTR_CURRENT) + aad(&sa)->info = "current"; + else if (attr == LSM_ATTR_EXEC) + aad(&sa)->info = "exec"; + else + aad(&sa)->info = "invalid"; aad(&sa)->error = error = -EINVAL; aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL); end_current_label_crit_section(aad(&sa)->label); goto out; } +static int apparmor_setselfattr(u64 __user attr, struct lsm_ctx __user *ctx, + size_t __user size) +{ + struct lsm_ctx *lctx; + void *context; + int rc; + + context = kmalloc(size, GFP_KERNEL); + if (context == NULL) + return -ENOMEM; + + lctx = (struct lsm_ctx *)context; + if (copy_from_user(context, ctx, size)) + rc = -EFAULT; + else if (lctx->ctx_len > size) + rc = -EINVAL; + else + rc = do_setattr(attr, lctx + 1, lctx->ctx_len); + + kfree(context); + if (rc > 0) + return 0; + return rc; +} + +static int apparmor_setprocattr(const char *name, void *value, + size_t size) +{ + int attr = lsm_name_to_attr(name); + + if (attr) + return do_setattr(attr, value, size); + return -EINVAL; +} + /** * apparmor_bprm_committing_creds - do task cleanup on committing new creds * @bprm: binprm for the exec (NOT NULL)
@@ -1256,6 +1333,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(file_lock, apparmor_file_lock), LSM_HOOK_INIT(file_truncate, apparmor_file_truncate), + LSM_HOOK_INIT(getselfattr, apparmor_getselfattr), + LSM_HOOK_INIT(setselfattr, apparmor_setselfattr), LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
index 197d41f9c32b..196f319aa3b2 100644
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c@@ -20,6 +20,7 @@ * aa_getprocattr - Return the label information for @label * @label: the label to print label info about (NOT NULL) * @string: Returns - string containing the label info (NOT NULL) + * @newline: indicates that a newline should be added * * Requires: label != NULL && string != NULL *
@@ -27,7 +28,7 @@ * * Returns: size of string placed in @string else error code on failure */ -int aa_getprocattr(struct aa_label *label, char **string) +int aa_getprocattr(struct aa_label *label, char **string, bool newline) { struct aa_ns *ns = labels_ns(label); struct aa_ns *current_ns = aa_get_current_ns();
@@ -57,10 +58,14 @@ int aa_getprocattr(struct aa_label *label, char **string) return len; } - (*string)[len] = '\n'; - (*string)[len + 1] = 0; + if (newline) + (*string)[len++] = '\n'; + (*string)[len] = 0; aa_put_ns(current_ns); + + if (newline) + return len; return len + 1; }
--
2.39.0