Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39b07096 authored by Thiago Jung Bauermann's avatar Thiago Jung Bauermann Committed by Mimi Zohar
Browse files

ima: Implement support for module-style appended signatures



Implement the appraise_type=imasig|modsig option, allowing IMA to read and
verify modsig signatures.

In case a file has both an xattr signature and an appended modsig, IMA will
only use the appended signature if the key used by the xattr signature
isn't present in the IMA or platform keyring.

Because modsig verification needs to convert from an integrity keyring id
to the keyring itself, add an integrity_keyring_from_id() function in
digsig.c so that integrity_modsig_verify() can use it.

Signed-off-by: default avatarThiago Jung Bauermann <bauerman@linux.ibm.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent a5fbeb61
Loading
Loading
Loading
Loading
+34 −9
Original line number Diff line number Diff line
@@ -39,11 +39,10 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
#define restrict_link_to_ima restrict_link_by_builtin_trusted
#endif

int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
			    const char *digest, int digestlen)
static struct key *integrity_keyring_from_id(const unsigned int id)
{
	if (id >= INTEGRITY_KEYRING_MAX || siglen < 2)
		return -EINVAL;
	if (id >= INTEGRITY_KEYRING_MAX)
		return ERR_PTR(-EINVAL);

	if (!keyring[id]) {
		keyring[id] =
@@ -52,23 +51,49 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
			int err = PTR_ERR(keyring[id]);
			pr_err("no %s keyring: %d\n", keyring_name[id], err);
			keyring[id] = NULL;
			return err;
			return ERR_PTR(err);
		}
	}

	return keyring[id];
}

int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
			    const char *digest, int digestlen)
{
	struct key *keyring;

	if (siglen < 2)
		return -EINVAL;

	keyring = integrity_keyring_from_id(id);
	if (IS_ERR(keyring))
		return PTR_ERR(keyring);

	switch (sig[1]) {
	case 1:
		/* v1 API expect signature without xattr type */
		return digsig_verify(keyring[id], sig + 1, siglen - 1,
				     digest, digestlen);
		return digsig_verify(keyring, sig + 1, siglen - 1, digest,
				     digestlen);
	case 2:
		return asymmetric_verify(keyring[id], sig, siglen,
					 digest, digestlen);
		return asymmetric_verify(keyring, sig, siglen, digest,
					 digestlen);
	}

	return -EOPNOTSUPP;
}

int integrity_modsig_verify(const unsigned int id, const struct modsig *modsig)
{
	struct key *keyring;

	keyring = integrity_keyring_from_id(id);
	if (IS_ERR(keyring))
		return PTR_ERR(keyring);

	return ima_modsig_verify(keyring, modsig);
}

static int __init __integrity_init_keyring(const unsigned int id,
					   key_perm_t perm,
					   struct key_restriction *restriction)
+3 −0
Original line number Diff line number Diff line
@@ -236,6 +236,9 @@ config IMA_APPRAISE_BOOTPARAM
config IMA_APPRAISE_MODSIG
	bool "Support module-style signatures for appraisal"
	depends on IMA_APPRAISE
	depends on INTEGRITY_ASYMMETRIC_KEYS
	select PKCS7_MESSAGE_PARSER
	select MODULE_SIG_FORMAT
	default n
	help
	   Adds support for signatures appended to files. The format of the
+20 −2
Original line number Diff line number Diff line
@@ -196,6 +196,10 @@ enum ima_hooks {
	__ima_hooks(__ima_hook_enumify)
};

extern const char *const func_tokens[];

struct modsig;

/* LIM API function definitions */
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
		   int mask, enum ima_hooks func, int *pcr,
@@ -249,7 +253,7 @@ int ima_appraise_measurement(enum ima_hooks func,
			     struct integrity_iint_cache *iint,
			     struct file *file, const unsigned char *filename,
			     struct evm_ima_xattr_data *xattr_value,
			     int xattr_len);
			     int xattr_len, const struct modsig *modsig);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -265,7 +269,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
					   struct file *file,
					   const unsigned char *filename,
					   struct evm_ima_xattr_data *xattr_value,
					   int xattr_len)
					   int xattr_len,
					   const struct modsig *modsig)
{
	return INTEGRITY_UNKNOWN;
}
@@ -304,11 +309,24 @@ static inline int ima_read_xattr(struct dentry *dentry,

#ifdef CONFIG_IMA_APPRAISE_MODSIG
bool ima_hook_supports_modsig(enum ima_hooks func);
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
		    struct modsig **modsig);
void ima_free_modsig(struct modsig *modsig);
#else
static inline bool ima_hook_supports_modsig(enum ima_hooks func)
{
	return false;
}

static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
				  loff_t buf_len, struct modsig **modsig)
{
	return -EOPNOTSUPP;
}

static inline void ima_free_modsig(struct modsig *modsig)
{
}
#endif /* CONFIG_IMA_APPRAISE_MODSIG */

/* LSM based policy rules require audit */
+47 −4
Original line number Diff line number Diff line
@@ -276,6 +276,33 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
	return rc;
}

/*
 * modsig_verify - verify modsig signature
 *
 * Verify whether the signature matches the file contents.
 *
 * Return 0 on success, error code otherwise.
 */
static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
			 enum integrity_status *status, const char **cause)
{
	int rc;

	rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
	if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
	    func == KEXEC_KERNEL_CHECK)
		rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM,
					     modsig);
	if (rc) {
		*cause = "invalid-signature";
		*status = INTEGRITY_FAIL;
	} else {
		*status = INTEGRITY_PASS;
	}

	return rc;
}

/*
 * ima_appraise_measurement - appraise file measurement
 *
@@ -288,7 +315,7 @@ int ima_appraise_measurement(enum ima_hooks func,
			     struct integrity_iint_cache *iint,
			     struct file *file, const unsigned char *filename,
			     struct evm_ima_xattr_data *xattr_value,
			     int xattr_len)
			     int xattr_len, const struct modsig *modsig)
{
	static const char op[] = "appraise_data";
	const char *cause = "unknown";
@@ -296,11 +323,14 @@ int ima_appraise_measurement(enum ima_hooks func,
	struct inode *inode = d_backing_inode(dentry);
	enum integrity_status status = INTEGRITY_UNKNOWN;
	int rc = xattr_len;
	bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;

	if (!(inode->i_opflags & IOP_XATTR))
	/* If not appraising a modsig, we need an xattr. */
	if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
		return INTEGRITY_UNKNOWN;

	if (rc <= 0) {
	/* If reading the xattr failed and there's no modsig, error out. */
	if (rc <= 0 && !try_modsig) {
		if (rc && rc != -ENODATA)
			goto out;

@@ -323,6 +353,10 @@ int ima_appraise_measurement(enum ima_hooks func,
	case INTEGRITY_UNKNOWN:
		break;
	case INTEGRITY_NOXATTRS:	/* No EVM protected xattrs. */
		/* It's fine not to have xattrs when using a modsig. */
		if (try_modsig)
			break;
		/* fall through */
	case INTEGRITY_NOLABEL:		/* No security.evm xattr. */
		cause = "missing-HMAC";
		goto out;
@@ -337,6 +371,15 @@ int ima_appraise_measurement(enum ima_hooks func,
		rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
				  &cause);

	/*
	 * If we have a modsig and either no imasig or the imasig's key isn't
	 * known, then try verifying the modsig.
	 */
	if (try_modsig &&
	    (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG ||
	     rc == -ENOKEY))
		rc = modsig_verify(func, modsig, &status, &cause);

out:
	/*
	 * File signatures on some filesystems can not be properly verified.
@@ -353,7 +396,7 @@ int ima_appraise_measurement(enum ima_hooks func,
				    op, cause, rc, 0);
	} else if (status != INTEGRITY_PASS) {
		/* Fix mode, but don't replace file signatures. */
		if ((ima_appraise & IMA_APPRAISE_FIX) &&
		if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
		    (!xattr_value ||
		     xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
			if (!ima_fix_xattr(dentry, iint))
+9 −2
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
	int rc = 0, action, must_appraise = 0;
	int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
	struct evm_ima_xattr_data *xattr_value = NULL;
	struct modsig *modsig = NULL;
	int xattr_len = 0;
	bool violation_check;
	enum hash_algo hash_algo;
@@ -302,10 +303,15 @@ static int process_measurement(struct file *file, const struct cred *cred,
	}

	if ((action & IMA_APPRAISE_SUBMASK) ||
		    strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
	    strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) {
		/* read 'security.ima' */
		xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);

		/* Read the appended modsig if allowed by the policy. */
		if (iint->flags & IMA_MODSIG_ALLOWED)
			ima_read_modsig(func, buf, size, &modsig);
	}

	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);

	rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
@@ -322,7 +328,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
	if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
		inode_lock(inode);
		rc = ima_appraise_measurement(func, iint, file, pathname,
					      xattr_value, xattr_len);
					      xattr_value, xattr_len, modsig);
		inode_unlock(inode);
		if (!rc)
			rc = mmap_violation_check(func, file, &pathbuf,
@@ -339,6 +345,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
		rc = -EACCES;
	mutex_unlock(&iint->mutex);
	kfree(xattr_value);
	ima_free_modsig(modsig);
out:
	if (pathbuf)
		__putname(pathbuf);
Loading