security/integrity/evm/evm_crypto.c

Source file repositories/reference/linux-study-clean/security/integrity/evm/evm_crypto.c

File Facts

System
Linux kernel
Corpus path
security/integrity/evm/evm_crypto.c
Extension
.c
Size
11924 bytes
Lines
460
Domain
Core OS
Bucket
Security And Isolation
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct h_misc {
		/*
		 * Although inode->i_ino is now u64, this field remains
		 * unsigned long to allow existing HMAC and signatures from
		 * 32-bit hosts to continue working when i_ino hasn't changed
		 * and fits in a u32.
		 */
		unsigned long ino;
		__u32 generation;
		uid_t uid;
		gid_t gid;
		umode_t mode;
	} hmac_misc;

	memset(&hmac_misc, 0, sizeof(hmac_misc));
	/* Don't include the inode or generation number in portable
	 * signatures
	 */
	if (type != EVM_XATTR_PORTABLE_DIGSIG) {
		hmac_misc.ino = inode->i_ino;
		hmac_misc.generation = inode->i_generation;
	}
	/* The hmac uid and gid must be encoded in the initial user
	 * namespace (not the filesystems user namespace) as encoding
	 * them in the filesystems user namespace allows an attack
	 * where first they are written in an unprivileged fuse mount
	 * of a filesystem and then the system is tricked to mount the
	 * filesystem for real on next boot and trust it because
	 * everything is signed.
	 */
	hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid);
	hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
	hmac_misc.mode = inode->i_mode;
	crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
	if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
	    type != EVM_XATTR_PORTABLE_DIGSIG)
		crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
	crypto_shash_final(desc, digest);

	pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
		 (int)sizeof(struct h_misc), &hmac_misc);
}

/*
 * Dump large security xattr values as a continuous ascii hexadecimal string.
 * (pr_debug is limited to 64 bytes.)
 */
static void dump_security_xattr_l(const char *prefix, const void *src,
				  size_t count)
{
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
	char *asciihex, *p;

	p = asciihex = kmalloc(count * 2 + 1, GFP_KERNEL);
	if (!asciihex)
		return;

	p = bin2hex(p, src, count);
	*p = 0;
	pr_debug("%s: (%zu) %.*s\n", prefix, count, (int)count * 2, asciihex);
	kfree(asciihex);
#endif
}

static void dump_security_xattr(const char *name, const char *value,
				size_t value_len)
{
	if (value_len < 64)
		pr_debug("%s: (%zu) [%*phN]\n", name, value_len,
			 (int)value_len, value);
	else
		dump_security_xattr_l(name, value, value_len);
}

/*
 * Calculate the HMAC value across the set of protected security xattrs.
 *
 * Instead of retrieving the requested xattr, for performance, calculate
 * the hmac using the requested xattr value. Don't alloc/free memory for
 * each xattr, but attempt to re-use the previously allocated memory.
 */
static int evm_calc_hmac_or_hash(struct dentry *dentry,
				 const char *req_xattr_name,
				 const char *req_xattr_value,
				 size_t req_xattr_value_len,
				 uint8_t type, struct evm_digest *data,
				 struct evm_iint_cache *iint)
{
	struct inode *inode = d_inode(d_real(dentry, D_REAL_METADATA));
	struct xattr_list *xattr;

Annotation

Implementation Notes