forked from Minki/linux
ima: Define ima-modsig template
Define new "d-modsig" template field which holds the digest that is expected to match the one contained in the modsig, and also new "modsig" template field which holds the appended file signature. Add a new "ima-modsig" defined template descriptor with the new fields as well as the ones from the "ima-sig" descriptor. Change ima_store_measurement() to accept a struct modsig * argument so that it can be passed along to the templates via struct ima_event_data. Suggested-by: Mimi Zohar <zohar@linux.ibm.com> Signed-off-by: Thiago Jung Bauermann <bauerman@linux.ibm.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
This commit is contained in:
parent
15588227e0
commit
3878d505aa
@ -68,8 +68,10 @@ descriptors by adding their identifier to the format string
|
||||
- 'd-ng': the digest of the event, calculated with an arbitrary hash
|
||||
algorithm (field format: [<hash algo>:]digest, where the digest
|
||||
prefix is shown only if the hash algorithm is not SHA1 or MD5);
|
||||
- 'd-modsig': the digest of the event without the appended modsig;
|
||||
- 'n-ng': the name of the event, without size limitations;
|
||||
- 'sig': the file signature;
|
||||
- 'modsig' the appended file signature;
|
||||
- 'buf': the buffer data that was used to generate the hash without size limitations;
|
||||
|
||||
|
||||
@ -79,6 +81,7 @@ Below, there is the list of defined template descriptors:
|
||||
- "ima-ng" (default): its format is ``d-ng|n-ng``;
|
||||
- "ima-sig": its format is ``d-ng|n-ng|sig``;
|
||||
- "ima-buf": its format is ``d-ng|n-ng|buf``;
|
||||
- "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
|
||||
|
||||
|
||||
Use
|
||||
|
@ -60,6 +60,7 @@ struct ima_event_data {
|
||||
const unsigned char *filename;
|
||||
struct evm_ima_xattr_data *xattr_value;
|
||||
int xattr_len;
|
||||
const struct modsig *modsig;
|
||||
const char *violation;
|
||||
const void *buf;
|
||||
int buf_len;
|
||||
@ -211,7 +212,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, int pcr,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
struct ima_template_desc *template_desc);
|
||||
void ima_audit_measurement(struct integrity_iint_cache *iint,
|
||||
const unsigned char *filename);
|
||||
@ -312,6 +313,10 @@ 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_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
|
||||
int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
|
||||
const u8 **digest, u32 *digest_size);
|
||||
int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
|
||||
u32 *data_len);
|
||||
void ima_free_modsig(struct modsig *modsig);
|
||||
#else
|
||||
static inline bool ima_hook_supports_modsig(enum ima_hooks func)
|
||||
@ -330,6 +335,19 @@ static inline void ima_collect_modsig(struct modsig *modsig, const void *buf,
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ima_get_modsig_digest(const struct modsig *modsig,
|
||||
enum hash_algo *algo, const u8 **digest,
|
||||
u32 *digest_size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int ima_get_raw_modsig(const struct modsig *modsig,
|
||||
const void **data, u32 *data_len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void ima_free_modsig(struct modsig *modsig)
|
||||
{
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ out:
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, int pcr,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
struct ima_template_desc *template_desc)
|
||||
{
|
||||
static const char op[] = "add_template_measure";
|
||||
@ -300,7 +300,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
.file = file,
|
||||
.filename = filename,
|
||||
.xattr_value = xattr_value,
|
||||
.xattr_len = xattr_len };
|
||||
.xattr_len = xattr_len,
|
||||
.modsig = modsig };
|
||||
int violation = 0;
|
||||
|
||||
if (iint->measured_pcrs & (0x1 << pcr))
|
||||
|
@ -323,7 +323,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
||||
|
||||
if (action & IMA_MEASURE)
|
||||
ima_store_measurement(iint, file, pathname,
|
||||
xattr_value, xattr_len, pcr,
|
||||
xattr_value, xattr_len, modsig, pcr,
|
||||
template_desc);
|
||||
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
|
||||
inode_lock(inode);
|
||||
|
@ -138,6 +138,25 @@ int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
|
||||
VERIFYING_MODULE_SIGNATURE, NULL, NULL);
|
||||
}
|
||||
|
||||
int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
|
||||
const u8 **digest, u32 *digest_size)
|
||||
{
|
||||
*algo = modsig->hash_algo;
|
||||
*digest = modsig->digest;
|
||||
*digest_size = modsig->digest_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
|
||||
u32 *data_len)
|
||||
{
|
||||
*data = &modsig->raw_pkcs7;
|
||||
*data_len = modsig->raw_pkcs7_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ima_free_modsig(struct modsig *modsig)
|
||||
{
|
||||
if (!modsig)
|
||||
|
@ -6,6 +6,9 @@
|
||||
* ima_policy.c
|
||||
* - initialize default measure policy rules
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
@ -845,6 +848,38 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
|
||||
ima_log_string_op(ab, key, value, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validating the appended signature included in the measurement list requires
|
||||
* the file hash calculated without the appended signature (i.e., the 'd-modsig'
|
||||
* field). Therefore, notify the user if they have the 'modsig' field but not
|
||||
* the 'd-modsig' field in the template.
|
||||
*/
|
||||
static void check_template_modsig(const struct ima_template_desc *template)
|
||||
{
|
||||
#define MSG "template with 'modsig' field also needs 'd-modsig' field\n"
|
||||
bool has_modsig, has_dmodsig;
|
||||
static bool checked;
|
||||
int i;
|
||||
|
||||
/* We only need to notify the user once. */
|
||||
if (checked)
|
||||
return;
|
||||
|
||||
has_modsig = has_dmodsig = false;
|
||||
for (i = 0; i < template->num_fields; i++) {
|
||||
if (!strcmp(template->fields[i]->field_id, "modsig"))
|
||||
has_modsig = true;
|
||||
else if (!strcmp(template->fields[i]->field_id, "d-modsig"))
|
||||
has_dmodsig = true;
|
||||
}
|
||||
|
||||
if (has_modsig && !has_dmodsig)
|
||||
pr_notice(MSG);
|
||||
|
||||
checked = true;
|
||||
#undef MSG
|
||||
}
|
||||
|
||||
static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
@ -1187,6 +1222,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||
else if (entry->action == APPRAISE)
|
||||
temp_ima_appraise |= ima_appraise_flag(entry->func);
|
||||
|
||||
if (!result && entry->flags & IMA_MODSIG_ALLOWED) {
|
||||
template_desc = entry->template ? entry->template :
|
||||
ima_template_desc_current();
|
||||
check_template_modsig(template_desc);
|
||||
}
|
||||
|
||||
audit_log_format(ab, "res=%d", !result);
|
||||
audit_log_end(ab);
|
||||
return result;
|
||||
|
@ -23,6 +23,7 @@ static struct ima_template_desc builtin_templates[] = {
|
||||
{.name = "ima-ng", .fmt = "d-ng|n-ng"},
|
||||
{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
|
||||
{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
|
||||
{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
|
||||
{.name = "", .fmt = ""}, /* placeholder for a custom format */
|
||||
};
|
||||
|
||||
@ -42,6 +43,10 @@ static const struct ima_template_field supported_fields[] = {
|
||||
.field_show = ima_show_template_sig},
|
||||
{.field_id = "buf", .field_init = ima_eventbuf_init,
|
||||
.field_show = ima_show_template_buf},
|
||||
{.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,
|
||||
.field_show = ima_show_template_digest_ng},
|
||||
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
|
||||
.field_show = ima_show_template_sig},
|
||||
};
|
||||
|
||||
/*
|
||||
@ -49,7 +54,7 @@ static const struct ima_template_field supported_fields[] = {
|
||||
* need to be accounted for since they shouldn't be defined in the same template
|
||||
* description as 'd-ng' and 'n-ng' respectively.
|
||||
*/
|
||||
#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf")
|
||||
#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
|
||||
|
||||
static struct ima_template_desc *ima_template;
|
||||
|
||||
|
@ -225,7 +225,8 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
||||
static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
|
||||
u8 hash_algo,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
/*
|
||||
@ -328,6 +329,41 @@ out:
|
||||
hash_algo, field_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function writes the digest of the file which is expected to match the
|
||||
* digest contained in the file's appended signature.
|
||||
*/
|
||||
int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
enum hash_algo hash_algo;
|
||||
const u8 *cur_digest;
|
||||
u32 cur_digestsize;
|
||||
|
||||
if (!event_data->modsig)
|
||||
return 0;
|
||||
|
||||
if (event_data->violation) {
|
||||
/* Recording a violation. */
|
||||
hash_algo = HASH_ALGO_SHA1;
|
||||
cur_digest = NULL;
|
||||
cur_digestsize = 0;
|
||||
} else {
|
||||
int rc;
|
||||
|
||||
rc = ima_get_modsig_digest(event_data->modsig, &hash_algo,
|
||||
&cur_digest, &cur_digestsize);
|
||||
if (rc)
|
||||
return rc;
|
||||
else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0)
|
||||
/* There was some error collecting the digest. */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||
hash_algo, field_data);
|
||||
}
|
||||
|
||||
static int ima_eventname_init_common(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data,
|
||||
bool size_limit)
|
||||
@ -406,3 +442,29 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
|
||||
event_data->buf_len, DATA_FMT_HEX,
|
||||
field_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_eventmodsig_init - include the appended file signature as part of the
|
||||
* template data
|
||||
*/
|
||||
int ima_eventmodsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
const void *data;
|
||||
u32 data_len;
|
||||
int rc;
|
||||
|
||||
if (!event_data->modsig)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* modsig is a runtime structure containing pointers. Get its raw data
|
||||
* instead.
|
||||
*/
|
||||
rc = ima_get_raw_modsig(event_data->modsig, &data, &data_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
|
||||
field_data);
|
||||
}
|
||||
|
@ -36,10 +36,14 @@ int ima_eventname_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventdigest_ng_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventname_ng_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventbuf_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventmodsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
|
||||
|
Loading…
Reference in New Issue
Block a user