AppArmor: Add selfattr hooks
authorCasey Schaufler <casey@schaufler-ca.com>
Tue, 12 Sep 2023 20:56:54 +0000 (13:56 -0700)
committerPaul Moore <paul@paul-moore.com>
Mon, 13 Nov 2023 03:54:42 +0000 (22:54 -0500)
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>
Acked-by: John Johansen <john.johansen@canonical.com>
[PM: forward ported beyond v6.6 due merge window changes]
Signed-off-by: Paul Moore <paul@paul-moore.com>
security/apparmor/include/procattr.h
security/apparmor/lsm.c
security/apparmor/procattr.c

index 31689437e0e1ec895fa062ba8a93e504abeab737..03dbfdb2f2c09b947524bbc28affc3f66f32a40d 100644 (file)
@@ -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 */
index 093da0a9dbd857fc3566af5b9b2731ee8e728721..8165f80c10ffcc4f9939ac1df6d8ad897b23f70c 100644 (file)
@@ -776,6 +776,55 @@ static int apparmor_sb_pivotroot(const struct path *old_path,
        return error;
 }
 
+static int apparmor_getselfattr(unsigned int attr, struct lsm_ctx __user *lx,
+                               size_t *size, u32 flags)
+{
+       int error = -ENOENT;
+       struct aa_task_ctx *ctx = task_ctx(current);
+       struct aa_label *label = NULL;
+       size_t total_len = 0;
+       char *value;
+
+       switch (attr) {
+       case LSM_ATTR_CURRENT:
+               label = aa_get_newest_label(cred_label(current_cred()));
+               break;
+       case LSM_ATTR_PREV:
+               if (ctx->previous)
+                       label = aa_get_newest_label(ctx->previous);
+               break;
+       case LSM_ATTR_EXEC:
+               if (ctx->onexec)
+                       label = aa_get_newest_label(ctx->onexec);
+               break;
+       default:
+               error = -EOPNOTSUPP;
+               break;
+       }
+
+       if (label) {
+               error = aa_getprocattr(label, &value, false);
+               if (error > 0) {
+                       total_len = ALIGN(struct_size(lx, ctx, error), 8);
+                       if (total_len > *size)
+                               error = -E2BIG;
+                       else if (lx)
+                               error = lsm_fill_user_ctx(lx, value, error,
+                                                         LSM_ID_APPARMOR, 0);
+                       else
+                               error = 1;
+               }
+               kfree(value);
+       }
+
+       aa_put_label(label);
+
+       *size = total_len;
+       if (error < 0)
+               return error;
+       return 1;
+}
+
 static int apparmor_getprocattr(struct task_struct *task, const char *name,
                                char **value)
 {
@@ -795,7 +844,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);
@@ -803,8 +852,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;
@@ -835,7 +883,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);
@@ -850,7 +898,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)
@@ -870,13 +918,42 @@ out:
 
 fail:
        ad.subj_label = begin_current_label_crit_section();
-       ad.info = name;
+       if (attr == LSM_ATTR_CURRENT)
+               ad.info = "current";
+       else if (attr == LSM_ATTR_EXEC)
+               ad.info = "exec";
+       else
+               ad.info = "invalid";
        ad.error = error = -EINVAL;
        aa_audit_msg(AUDIT_APPARMOR_DENIED, &ad, NULL);
        end_current_label_crit_section(ad.subj_label);
        goto out;
 }
 
+static int apparmor_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
+                               size_t size, u32 flags)
+{
+       int rc;
+
+       if (attr != LSM_ATTR_CURRENT && attr != LSM_ATTR_EXEC)
+               return -EOPNOTSUPP;
+
+       rc = do_setattr(attr, ctx->ctx, ctx->ctx_len);
+       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)
@@ -1424,6 +1501,8 @@ static struct security_hook_list apparmor_hooks[] __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),
 
index 197d41f9c32b7b91280f91ffbb8ebaac8382da39..e3857e3d7c6c26783c5e3952358795d9858b7b58 100644 (file)
@@ -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,11 +58,12 @@ 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);
-       return len + 1;
+       return len;
 }
 
 /**