Commit a8478a60 authored by David Howells's avatar David Howells
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
parent 3e412ccc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+82 −1
Original line number Diff line number Diff line
@@ -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),