smack: Implement the watch_key and post_notification hooks

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>
This commit is contained in:
David Howells 2020-01-14 17:07:13 +00:00
parent 3e412ccc22
commit a8478a6029
2 changed files with 83 additions and 1 deletions

View File

@ -75,6 +75,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_IBPKEY 13 #define LSM_AUDIT_DATA_IBPKEY 13
#define LSM_AUDIT_DATA_IBENDPORT 14 #define LSM_AUDIT_DATA_IBENDPORT 14
#define LSM_AUDIT_DATA_LOCKDOWN 15 #define LSM_AUDIT_DATA_LOCKDOWN 15
#define LSM_AUDIT_DATA_NOTIFICATION 16
union { union {
struct path path; struct path path;
struct dentry *dentry; struct dentry *dentry;

View File

@ -41,6 +41,7 @@
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/fs_context.h> #include <linux/fs_context.h>
#include <linux/fs_parser.h> #include <linux/fs_parser.h>
#include <linux/watch_queue.h>
#include "smack.h" #include "smack.h"
#define TRANS_TRUE "TRUE" #define TRANS_TRUE "TRUE"
@ -4284,7 +4285,7 @@ static int smack_key_permission(key_ref_t key_ref,
if (tkp == NULL) if (tkp == NULL)
return -EACCES; return -EACCES;
if (smack_privileged_cred(CAP_MAC_OVERRIDE, cred)) if (smack_privileged(CAP_MAC_OVERRIDE))
return 0; return 0;
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
@ -4326,8 +4327,81 @@ static int smack_key_getsecurity(struct key *key, char **_buffer)
return length; 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 */ #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 * 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_free, smack_key_free),
LSM_HOOK_INIT(key_permission, smack_key_permission), LSM_HOOK_INIT(key_permission, smack_key_permission),
LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity), LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity),
#ifdef CONFIG_KEY_NOTIFICATIONS
LSM_HOOK_INIT(watch_key, smack_watch_key),
#endif
#endif /* CONFIG_KEYS */ #endif /* CONFIG_KEYS */
#ifdef CONFIG_WATCH_QUEUE
LSM_HOOK_INIT(post_notification, smack_post_notification),
#endif
/* Audit hooks */ /* Audit hooks */
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init), LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init),