Commit d3634d0f authored by Dmitry Kasatkin's avatar Dmitry Kasatkin Committed by Mimi Zohar

ima: read and use signature hash algorithm

All files on the filesystem, currently, are hashed using the same hash
algorithm.  In preparation for files from different packages being
signed using different hash algorithms, this patch adds support for
reading the signature hash algorithm from the 'security.ima' extended
attribute and calculates the appropriate file data hash based on it.

Changelog:
- fix scripts Lindent and checkpatch msgs - Mimi
- fix md5 support for older version, which occupied 20 bytes in the
  xattr, not the expected 16 bytes.  Fix the comparison to compare
  only the first 16 bytes.
Signed-off-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
parent c7c8bb23
...@@ -19,17 +19,6 @@ ...@@ -19,17 +19,6 @@
#include "integrity.h" #include "integrity.h"
/*
* signature format v2 - for using with asymmetric keys
*/
struct signature_v2_hdr {
uint8_t version; /* signature format version */
uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/
uint16_t sig_size; /* signature size */
uint8_t sig[0]; /* signature payload */
} __packed;
/* /*
* Request an asymmetric key. * Request an asymmetric key.
*/ */
......
...@@ -99,7 +99,9 @@ static inline unsigned long ima_hash_key(u8 *digest) ...@@ -99,7 +99,9 @@ static inline unsigned long ima_hash_key(u8 *digest)
int ima_get_action(struct inode *inode, int mask, int function); int ima_get_action(struct inode *inode, int mask, int function);
int ima_must_measure(struct inode *inode, int mask, int function); int ima_must_measure(struct inode *inode, int mask, int function);
int ima_collect_measurement(struct integrity_iint_cache *iint, int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file); struct file *file,
struct evm_ima_xattr_data **xattr_value,
int *xattr_len);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename); const unsigned char *filename);
void ima_audit_measurement(struct integrity_iint_cache *iint, void ima_audit_measurement(struct integrity_iint_cache *iint,
...@@ -132,17 +134,25 @@ void ima_delete_rules(void); ...@@ -132,17 +134,25 @@ void ima_delete_rules(void);
#ifdef CONFIG_IMA_APPRAISE #ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename); struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); 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); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
int func); int func);
void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
struct ima_digest_data *hash);
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);
#else #else
static inline int ima_appraise_measurement(int func, static inline int ima_appraise_measurement(int func,
struct integrity_iint_cache *iint, struct integrity_iint_cache *iint,
struct file *file, struct file *file,
const unsigned char *filename) const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{ {
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
} }
...@@ -163,6 +173,19 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c ...@@ -163,6 +173,19 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c
{ {
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
} }
static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
int xattr_len,
struct ima_digest_data *hash)
{
}
static inline int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
return 0;
}
#endif #endif
/* LSM based policy rules require audit */ /* LSM based policy rules require audit */
......
...@@ -139,17 +139,27 @@ int ima_must_measure(struct inode *inode, int mask, int function) ...@@ -139,17 +139,27 @@ int ima_must_measure(struct inode *inode, int mask, int function)
* Return 0 on success, error code otherwise * Return 0 on success, error code otherwise
*/ */
int ima_collect_measurement(struct integrity_iint_cache *iint, int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file) struct file *file,
struct evm_ima_xattr_data **xattr_value,
int *xattr_len)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
const char *filename = file->f_dentry->d_name.name; const char *filename = file->f_dentry->d_name.name;
int result = 0; int result = 0;
if (xattr_value)
*xattr_len = ima_read_xattr(file->f_dentry, xattr_value);
if (!(iint->flags & IMA_COLLECTED)) { if (!(iint->flags & IMA_COLLECTED)) {
u64 i_version = file_inode(file)->i_version; u64 i_version = file_inode(file)->i_version;
/* use default hash algorithm */ /* use default hash algorithm */
iint->ima_hash.algo = ima_hash_algo; iint->ima_hash.algo = ima_hash_algo;
if (xattr_value)
ima_get_hash_algo(*xattr_value, *xattr_len,
&iint->ima_hash);
result = ima_calc_file_hash(file, &iint->ima_hash); result = ima_calc_file_hash(file, &iint->ima_hash);
if (!result) { if (!result) {
iint->version = i_version; iint->version = i_version;
......
...@@ -107,6 +107,34 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) ...@@ -107,6 +107,34 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
} }
} }
void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
struct ima_digest_data *hash)
{
struct signature_v2_hdr *sig;
if (!xattr_value || xattr_len < 0 || xattr_len <= 1 + sizeof(*sig))
return;
sig = (typeof(sig)) xattr_value->digest;
if (xattr_value->type != EVM_IMA_XATTR_DIGSIG || sig->version != 2)
return;
hash->algo = sig->hash_algo;
}
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
struct inode *inode = dentry->d_inode;
if (!inode->i_op->getxattr)
return 0;
return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
0, GFP_NOFS);
}
/* /*
* ima_appraise_measurement - appraise file measurement * ima_appraise_measurement - appraise file measurement
* *
...@@ -116,23 +144,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) ...@@ -116,23 +144,22 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
* Return 0 on success, error code otherwise * Return 0 on success, error code otherwise
*/ */
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename) struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{ {
struct dentry *dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct evm_ima_xattr_data *xattr_value = NULL;
enum integrity_status status = INTEGRITY_UNKNOWN; enum integrity_status status = INTEGRITY_UNKNOWN;
const char *op = "appraise_data"; const char *op = "appraise_data";
char *cause = "unknown"; char *cause = "unknown";
int rc; int rc = xattr_len;
if (!ima_appraise) if (!ima_appraise)
return 0; return 0;
if (!inode->i_op->getxattr) if (!inode->i_op->getxattr)
return INTEGRITY_UNKNOWN; return INTEGRITY_UNKNOWN;
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value,
0, GFP_NOFS);
if (rc <= 0) { if (rc <= 0) {
if (rc && rc != -ENODATA) if (rc && rc != -ENODATA)
goto out; goto out;
...@@ -159,7 +186,10 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -159,7 +186,10 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
status = INTEGRITY_FAIL; status = INTEGRITY_FAIL;
break; break;
} }
if (rc - 1 == iint->ima_hash.length) if (xattr_len - 1 >= iint->ima_hash.length)
/* xattr length may be longer. md5 hash in previous
version occupied 20 bytes in xattr, instead of 16
*/
rc = memcmp(xattr_value->digest, rc = memcmp(xattr_value->digest,
iint->ima_hash.digest, iint->ima_hash.digest,
iint->ima_hash.length); iint->ima_hash.length);
...@@ -207,7 +237,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -207,7 +237,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
ima_cache_flags(iint, func); ima_cache_flags(iint, func);
} }
ima_set_cache_status(iint, func, status); ima_set_cache_status(iint, func, status);
kfree(xattr_value);
return status; return status;
} }
...@@ -223,7 +252,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) ...@@ -223,7 +252,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
if (iint->flags & IMA_DIGSIG) if (iint->flags & IMA_DIGSIG)
return; return;
rc = ima_collect_measurement(iint, file); rc = ima_collect_measurement(iint, file, NULL, NULL);
if (rc < 0) if (rc < 0)
return; return;
......
...@@ -149,6 +149,8 @@ static int process_measurement(struct file *file, const char *filename, ...@@ -149,6 +149,8 @@ static int process_measurement(struct file *file, const char *filename,
char *pathbuf = NULL; char *pathbuf = NULL;
const char *pathname = NULL; const char *pathname = NULL;
int rc = -ENOMEM, action, must_appraise, _func; int rc = -ENOMEM, action, must_appraise, _func;
struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
int xattr_len = 0;
if (!ima_initialized || !S_ISREG(inode->i_mode)) if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0; return 0;
...@@ -187,7 +189,10 @@ static int process_measurement(struct file *file, const char *filename, ...@@ -187,7 +189,10 @@ static int process_measurement(struct file *file, const char *filename,
goto out_digsig; goto out_digsig;
} }
rc = ima_collect_measurement(iint, file); if (action & IMA_APPRAISE_SUBMASK)
xattr_ptr = &xattr_value;
rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
if (rc != 0) if (rc != 0)
goto out_digsig; goto out_digsig;
...@@ -198,7 +203,8 @@ static int process_measurement(struct file *file, const char *filename, ...@@ -198,7 +203,8 @@ static int process_measurement(struct file *file, const char *filename,
if (action & IMA_MEASURE) if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname); ima_store_measurement(iint, file, pathname);
if (action & IMA_APPRAISE_SUBMASK) if (action & IMA_APPRAISE_SUBMASK)
rc = ima_appraise_measurement(_func, iint, file, pathname); rc = ima_appraise_measurement(_func, iint, file, pathname,
xattr_value, xattr_len);
if (action & IMA_AUDIT) if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname); ima_audit_measurement(iint, pathname);
kfree(pathbuf); kfree(pathbuf);
...@@ -207,6 +213,7 @@ static int process_measurement(struct file *file, const char *filename, ...@@ -207,6 +213,7 @@ static int process_measurement(struct file *file, const char *filename,
rc = -EACCES; rc = -EACCES;
out: out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
kfree(xattr_value);
if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES; return -EACCES;
return 0; return 0;
......
...@@ -70,6 +70,17 @@ struct ima_digest_data { ...@@ -70,6 +70,17 @@ struct ima_digest_data {
u8 digest[IMA_MAX_DIGEST_SIZE]; u8 digest[IMA_MAX_DIGEST_SIZE];
} __packed; } __packed;
/*
* signature format v2 - for using with asymmetric keys
*/
struct signature_v2_hdr {
uint8_t version; /* signature format version */
uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
uint32_t keyid; /* IMA key identifier - not X509/PGP specific */
uint16_t sig_size; /* signature size */
uint8_t sig[0]; /* signature payload */
} __packed;
/* integrity data associated with an inode */ /* integrity data associated with an inode */
struct integrity_iint_cache { struct integrity_iint_cache {
struct rb_node rb_node; /* rooted in integrity_iint_tree */ struct rb_node rb_node; /* rooted in integrity_iint_tree */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment