smack: Implement the watch_key and post_notification hooks
authorDavid Howells <dhowells@redhat.com>
Tue, 14 Jan 2020 17:07:13 +0000 (17:07 +0000)
committerDavid Howells <dhowells@redhat.com>
Tue, 19 May 2020 14:47:38 +0000 (15:47 +0100)
Implement the watch_key security hook in Smack to make sure that a key
grants the caller Read permission in order to set a watch on a key.

Also implement the post_notification security hook to make sure that the
notification source is granted Write permission by the watch queue.

For the moment, the watch_devices security hook is left unimplemented as
it's not obvious what the object should be since the queue is global and
didn't previously exist.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
include/linux/lsm_audit.h
security/smack/smack_lsm.c

index 99d629f..28f23b3 100644 (file)
@@ -75,6 +75,7 @@ struct common_audit_data {
 #define LSM_AUDIT_DATA_IBPKEY  13
 #define LSM_AUDIT_DATA_IBENDPORT 14
 #define LSM_AUDIT_DATA_LOCKDOWN 15
+#define LSM_AUDIT_DATA_NOTIFICATION 16
        union   {
                struct path path;
                struct dentry *dentry;
index 0d6bb53..3c4d483 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/parser.h>
 #include <linux/fs_context.h>
 #include <linux/fs_parser.h>
+#include <linux/watch_queue.h>
 #include "smack.h"
 
 #define TRANS_TRUE     "TRUE"
@@ -4284,7 +4285,7 @@ static int smack_key_permission(key_ref_t key_ref,
        if (tkp == NULL)
                return -EACCES;
 
-       if (smack_privileged_cred(CAP_MAC_OVERRIDE, cred))
+       if (smack_privileged(CAP_MAC_OVERRIDE))
                return 0;
 
 #ifdef CONFIG_AUDIT
@@ -4326,8 +4327,81 @@ static int smack_key_getsecurity(struct key *key, char **_buffer)
        return length;
 }
 
+
+#ifdef CONFIG_KEY_NOTIFICATIONS
+/**
+ * smack_watch_key - Smack access to watch a key for notifications.
+ * @key: The key to be watched
+ *
+ * Return 0 if the @watch->cred has permission to read from the key object and
+ * an error otherwise.
+ */
+static int smack_watch_key(struct key *key)
+{
+       struct smk_audit_info ad;
+       struct smack_known *tkp = smk_of_current();
+       int rc;
+
+       if (key == NULL)
+               return -EINVAL;
+       /*
+        * If the key hasn't been initialized give it access so that
+        * it may do so.
+        */
+       if (key->security == NULL)
+               return 0;
+       /*
+        * This should not occur
+        */
+       if (tkp == NULL)
+               return -EACCES;
+
+       if (smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred()))
+               return 0;
+
+#ifdef CONFIG_AUDIT
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);
+       ad.a.u.key_struct.key = key->serial;
+       ad.a.u.key_struct.key_desc = key->description;
+#endif
+       rc = smk_access(tkp, key->security, MAY_READ, &ad);
+       rc = smk_bu_note("key watch", tkp, key->security, MAY_READ, rc);
+       return rc;
+}
+#endif /* CONFIG_KEY_NOTIFICATIONS */
 #endif /* CONFIG_KEYS */
 
+#ifdef CONFIG_WATCH_QUEUE
+/**
+ * smack_post_notification - Smack access to post a notification to a queue
+ * @w_cred: The credentials of the watcher.
+ * @cred: The credentials of the event source (may be NULL).
+ * @n: The notification message to be posted.
+ */
+static int smack_post_notification(const struct cred *w_cred,
+                                  const struct cred *cred,
+                                  struct watch_notification *n)
+{
+       struct smk_audit_info ad;
+       struct smack_known *subj, *obj;
+       int rc;
+
+       /* Always let maintenance notifications through. */
+       if (n->type == WATCH_TYPE_META)
+               return 0;
+
+       if (!cred)
+               return 0;
+       subj = smk_of_task(smack_cred(cred));
+       obj = smk_of_task(smack_cred(w_cred));
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NOTIFICATION);
+       rc = smk_access(subj, obj, MAY_WRITE, &ad);
+       rc = smk_bu_note("notification", subj, obj, MAY_WRITE, rc);
+       return rc;
+}
+#endif /* CONFIG_WATCH_QUEUE */
+
 /*
  * Smack Audit hooks
  *
@@ -4716,8 +4790,15 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(key_free, smack_key_free),
        LSM_HOOK_INIT(key_permission, smack_key_permission),
        LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity),
+#ifdef CONFIG_KEY_NOTIFICATIONS
+       LSM_HOOK_INIT(watch_key, smack_watch_key),
+#endif
 #endif /* CONFIG_KEYS */
 
+#ifdef CONFIG_WATCH_QUEUE
+       LSM_HOOK_INIT(post_notification, smack_post_notification),
+#endif
+
  /* Audit hooks */
 #ifdef CONFIG_AUDIT
        LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init),