Commit ad16ad00 authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds
Browse files

IMA: use inode->i_lock to protect read and write counters



Currently IMA used the iint->mutex to protect the i_readcount and
i_writecount.  This patch uses the inode->i_lock since we are going to
start using in inode objects and that is the most appropriate lock.

Signed-off-by: default avatarEric Paris <eparis@redhat.com>
Acked-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 15aac676
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ struct ima_iint_cache {
	unsigned char flags;
	u8 digest[IMA_DIGEST_SIZE];
	struct mutex mutex;	/* protects: version, flags, digest */
	/* protected by inode->i_lock */
	unsigned int readcount;	/* measured files readcount */
	unsigned int writecount;/* measured files writecount */
	struct kref refcount;	/* ima_iint_cache reference count */
+23 −34
Original line number Diff line number Diff line
@@ -85,42 +85,12 @@ out:
	return found;
}

/* ima_read_write_check - reflect possible reading/writing errors in the PCR.
 *
 * When opening a file for read, if the file is already open for write,
 * the file could change, resulting in a file measurement error.
 *
 * Opening a file for write, if the file is already open for read, results
 * in a time of measure, time of use (ToMToU) error.
 *
 * In either case invalidate the PCR.
 */
enum iint_pcr_error { TOMTOU, OPEN_WRITERS };
static void ima_read_write_check(enum iint_pcr_error error,
				 struct ima_iint_cache *iint,
				 struct inode *inode,
				 const unsigned char *filename)
{
	switch (error) {
	case TOMTOU:
		if (iint->readcount > 0)
			ima_add_violation(inode, filename, "invalid_pcr",
					  "ToMToU");
		break;
	case OPEN_WRITERS:
		if (iint->writecount > 0)
			ima_add_violation(inode, filename, "invalid_pcr",
					  "open_writers");
		break;
	}
}

/*
 * Update the counts given an fmode_t
 */
static void ima_inc_counts(struct ima_iint_cache *iint, fmode_t mode)
{
	BUG_ON(!mutex_is_locked(&iint->mutex));
	assert_spin_locked(&iint->inode->i_lock);

	if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
		iint->readcount++;
@@ -146,6 +116,7 @@ void ima_counts_get(struct file *file)
	fmode_t mode = file->f_mode;
	struct ima_iint_cache *iint;
	int rc;
	bool send_tomtou = false, send_writers = false;

	if (!iint_initialized || !S_ISREG(inode->i_mode))
		return;
@@ -153,22 +124,35 @@ void ima_counts_get(struct file *file)
	if (!iint)
		return;
	mutex_lock(&iint->mutex);
	spin_lock(&inode->i_lock);

	if (!ima_initialized)
		goto out;

	rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK);
	if (rc < 0)
		goto out;

	if (mode & FMODE_WRITE) {
		ima_read_write_check(TOMTOU, iint, inode, dentry->d_name.name);
		if (iint->readcount)
			send_tomtou = true;
		goto out;
	}
	ima_read_write_check(OPEN_WRITERS, iint, inode, dentry->d_name.name);

	if (atomic_read(&inode->i_writecount) > 0)
		send_writers = true;
out:
	ima_inc_counts(iint, file->f_mode);
	spin_unlock(&inode->i_lock);
	mutex_unlock(&iint->mutex);

	kref_put(&iint->refcount, iint_free);

	if (send_tomtou)
		ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
				  "ToMToU");
	if (send_writers)
		ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
				  "open_writers");
}

/*
@@ -181,6 +165,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode,
	bool dump = false;

	BUG_ON(!mutex_is_locked(&iint->mutex));
	assert_spin_locked(&inode->i_lock);

	if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
		if (unlikely(iint->readcount == 0))
@@ -223,7 +208,11 @@ void ima_file_free(struct file *file)
		return;

	mutex_lock(&iint->mutex);
	spin_lock(&inode->i_lock);

	ima_dec_counts(iint, inode, file);

	spin_unlock(&inode->i_lock);
	mutex_unlock(&iint->mutex);
	kref_put(&iint->refcount, iint_free);
}