/* * ima_rdwr_violation_check * * Only invalidate the PCR for measured files: * - Opening a file for write when already open for read, * results in a time of measure, time of use (ToMToU) error. * - Opening a file for read when already open for write, * could result in a file measurement error. *
*/ staticvoid ima_rdwr_violation_check(struct file *file, struct ima_iint_cache *iint, int must_measure, char **pathbuf, constchar **pathname, char *filename)
{ struct inode *inode = file_inode(file);
fmode_t mode = file->f_mode; bool send_tomtou = false, send_writers = false;
if (mode & FMODE_WRITE) { if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { if (!iint)
iint = ima_iint_find(inode);
/* IMA_MEASURE is set from reader side */ if (iint && test_and_clear_bit(IMA_MAY_EMIT_TOMTOU,
&iint->atomic_flags))
send_tomtou = true;
}
} else { if (must_measure)
set_bit(IMA_MAY_EMIT_TOMTOU, &iint->atomic_flags);
/* Limit number of open_writers violations */ if (inode_is_open_for_write(inode) && must_measure) { if (!test_and_set_bit(IMA_EMITTED_OPENWRITERS,
&iint->atomic_flags))
send_writers = true;
}
}
/** * ima_file_free - called on __fput() * @file: pointer to file structure being freed * * Flag files that changed, based on i_version
*/ staticvoid ima_file_free(struct file *file)
{ struct inode *inode = file_inode(file); struct ima_iint_cache *iint;
if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return;
if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) /* * Reset appraisal flags (action and non-action rule-specific) * if ima_inode_post_setattr was called.
*/
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
IMA_NONACTION_RULE_FLAGS);
/* * Re-evaulate the file if either the xattr has changed or the * kernel has no way of detecting file change on the filesystem. * (Limited to privileged mounted filesystems.)
*/ if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) ||
((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
!(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) &&
!(action & IMA_FAIL_UNVERIFIABLE_SIGS))) {
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
}
/* * On stacked filesystems, detect and re-evaluate file data and * metadata changes.
*/
real_inode = d_real_inode(file_dentry(file)); if (real_inode != inode &&
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) { if (!IS_I_VERSION(real_inode) ||
integrity_inode_attrs_changed(&iint->real_inode,
real_inode)) {
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
}
/* * Reset the EVM status when metadata changed.
*/
metadata_inode = d_inode(d_real(file_dentry(file),
D_REAL_METADATA)); if (evm_metadata_changed(inode, metadata_inode))
iint->flags &= ~(IMA_APPRAISED |
IMA_APPRAISED_SUBMASK);
}
/* * Read the appended modsig if allowed by the policy, and allow * an additional measurement list entry, if needed, based on the * template format and whether the file was already measured.
*/ if (iint->flags & IMA_MODSIG_ALLOWED) {
rc = ima_read_modsig(func, buf, size, &modsig);
/** * ima_file_mmap - based on policy, collect/store measurement. * @file: pointer to the file to be measured (May be NULL) * @reqprot: protection requested by the application * @prot: protection that will be applied by the kernel * @flags: operational flags * * Measure files being mmapped executable based on the ima_must_measure() * policy decision. * * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/ staticint ima_file_mmap(struct file *file, unsignedlong reqprot, unsignedlong prot, unsignedlong flags)
{ struct lsm_prop prop; int ret;
if (!file) return 0;
security_current_getlsmprop_subj(&prop);
if (reqprot & PROT_EXEC) {
ret = process_measurement(file, current_cred(), &prop, NULL,
0, MAY_EXEC, MMAP_CHECK_REQPROT); if (ret) return ret;
}
/** * ima_file_mprotect - based on policy, limit mprotect change * @vma: vm_area_struct protection is set to * @reqprot: protection requested by the application * @prot: protection that will be applied by the kernel * * Files can be mmap'ed read/write and later changed to execute to circumvent * IMA's mmap appraisal policy rules. Due to locking issues (mmap semaphore * would be taken before i_mutex), files can not be measured or appraised at * this point. Eliminate this integrity gap by denying the mprotect * PROT_EXECUTE change, if an mmap appraise policy rule exists. * * On mprotect change success, return 0. On failure, return -EACESS.
*/ staticint ima_file_mprotect(struct vm_area_struct *vma, unsignedlong reqprot, unsignedlong prot)
{ struct ima_template_desc *template = NULL; struct file *file; char filename[NAME_MAX]; char *pathbuf = NULL; constchar *pathname = NULL; struct inode *inode; struct lsm_prop prop; int result = 0; int action; int pcr;
/* Is mprotect making an mmap'ed file executable? */ if (!(ima_policy_flag & IMA_APPRAISE) || !vma->vm_file ||
!(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) return 0;
/** * ima_bprm_check - based on policy, collect/store measurement. * @bprm: contains the linux_binprm structure * * The OS protects against an executable file, already open for write, * from being executed in deny_write_access() and an executable file, * already open for execute, from being modified in get_write_access(). * So we can be certain that what we verify and measure here is actually * what is being executed. * * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/ staticint ima_bprm_check(struct linux_binprm *bprm)
{ int ret; struct lsm_prop prop;
security_current_getlsmprop_subj(&prop);
ret = process_measurement(bprm->file, current_cred(),
&prop, NULL, 0, MAY_EXEC, BPRM_CHECK); if (ret) return ret;
/** * ima_bprm_creds_for_exec - collect/store/appraise measurement. * @bprm: contains the linux_binprm structure * * Based on the IMA policy and the execveat(2) AT_EXECVE_CHECK flag, measure * and appraise the integrity of a file to be executed by script interpreters. * Unlike any of the other LSM hooks where the kernel enforces file integrity, * enforcing file integrity is left up to the discretion of the script * interpreter (userspace). * * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/ staticint ima_bprm_creds_for_exec(struct linux_binprm *bprm)
{ /* * As security_bprm_check() is called multiple times, both * the script and the shebang interpreter are measured, appraised, * and audited. Limit usage of this LSM hook to just measuring, * appraising, and auditing the indirect script execution * (e.g. ./sh example.sh).
*/ if (!bprm->is_check) return 0;
return ima_bprm_check(bprm);
}
/** * ima_file_check - based on policy, collect/store measurement. * @file: pointer to the file to be measured * @mask: contains MAY_READ, MAY_WRITE, MAY_EXEC or MAY_APPEND * * Measure files based on the ima_must_measure() policy decision. * * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/ staticint ima_file_check(struct file *file, int mask)
{ struct lsm_prop prop;
rc = ima_collect_measurement(&tmp_iint, file, NULL, 0,
ima_hash_algo, NULL); if (rc < 0) { /* ima_hash could be allocated in case of failure. */ if (rc != -ENOMEM)
kfree(tmp_iint.ima_hash);
return -EOPNOTSUPP;
}
iint = &tmp_iint;
mutex_lock(&iint->mutex);
}
if (!iint) return -EOPNOTSUPP;
/* * ima_file_hash can be called when ima_collect_measurement has still * not been called, we might not always have a hash.
*/ if (!iint->ima_hash || !(iint->flags & IMA_COLLECTED)) {
mutex_unlock(&iint->mutex); return -EOPNOTSUPP;
}
/** * ima_file_hash - return a measurement of the file * @file: pointer to the file * @buf: buffer in which to store the hash * @buf_size: length of the buffer * * On success, return the hash algorithm (as defined in the enum hash_algo). * If buf is not NULL, this function also outputs the hash into buf. * If the hash is larger than buf_size, then only buf_size bytes will be copied. * It generally just makes sense to pass a buffer capable of holding the largest * possible hash: IMA_MAX_DIGEST_SIZE. * The file hash returned is based on the entire file, including the appended * signature. * * If the measurement cannot be performed, return -EOPNOTSUPP. * If the parameters are incorrect, return -EINVAL.
*/ int ima_file_hash(struct file *file, char *buf, size_t buf_size)
{ if (!file) return -EINVAL;
/** * ima_inode_hash - return the stored measurement if the inode has been hashed * and is in the iint cache. * @inode: pointer to the inode * @buf: buffer in which to store the hash * @buf_size: length of the buffer * * On success, return the hash algorithm (as defined in the enum hash_algo). * If buf is not NULL, this function also outputs the hash into buf. * If the hash is larger than buf_size, then only buf_size bytes will be copied. * It generally just makes sense to pass a buffer capable of holding the largest * possible hash: IMA_MAX_DIGEST_SIZE. * The hash returned is based on the entire contents, including the appended * signature. * * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP. * If the parameters are incorrect, return -EINVAL.
*/ int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
{ if (!inode) return -EINVAL;
/** * ima_post_create_tmpfile - mark newly created tmpfile as new * @idmap: idmap of the mount the inode was found from * @inode: inode of the newly created tmpfile * * No measuring, appraising or auditing of newly created tmpfiles is needed. * Skip calling process_measurement(), but indicate which newly, created * tmpfiles are in policy.
*/ staticvoid ima_post_create_tmpfile(struct mnt_idmap *idmap, struct inode *inode)
{ struct ima_iint_cache *iint; int must_appraise;
if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return;
must_appraise = ima_must_appraise(idmap, inode, MAY_ACCESS,
FILE_CHECK); if (!must_appraise) return;
/* Nothing to do if we can't allocate memory */
iint = ima_inode_get(inode); if (!iint) return;
/* needed for writing the security xattrs */
set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
iint->ima_file_status = INTEGRITY_PASS;
}
/** * ima_post_path_mknod - mark as a new inode * @idmap: idmap of the mount the inode was found from * @dentry: newly created dentry * * Mark files created via the mknodat syscall as new, so that the * file data can be written later.
*/ staticvoid ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
{ struct ima_iint_cache *iint; struct inode *inode = dentry->d_inode; int must_appraise;
if (!ima_policy_flag || !S_ISREG(inode->i_mode)) return;
must_appraise = ima_must_appraise(idmap, inode, MAY_ACCESS,
FILE_CHECK); if (!must_appraise) return;
/* Nothing to do if we can't allocate memory */
iint = ima_inode_get(inode); if (!iint) return;
/** * ima_read_file - pre-measure/appraise hook decision based on policy * @file: pointer to the file to be measured/appraised/audit * @read_id: caller identifier * @contents: whether a subsequent call will be made to ima_post_read_file() * * Permit reading a file based on policy. The policy rules are written * in terms of the policy identifier. Appraising the integrity of * a file requires a file descriptor. * * For permission return 0, otherwise return -EACCES.
*/ staticint ima_read_file(struct file *file, enum kernel_read_file_id read_id, bool contents)
{ enum ima_hooks func; struct lsm_prop prop;
/* * Do devices using pre-allocated memory run the risk of the * firmware being accessible to the device prior to the completion * of IMA's signature verification any more than when using two * buffers? It may be desirable to include the buffer address * in this API and walk all the dma_map_single() mappings to check.
*/
/* * There will be a call made to ima_post_read_file() with * a filled buffer, so we don't need to perform an extra * read early here.
*/ if (contents) return 0;
/** * ima_post_read_file - in memory collect/appraise/audit measurement * @file: pointer to the file to be measured/appraised/audit * @buf: pointer to in memory file contents * @size: size of in memory file contents * @read_id: caller identifier * * Measure/appraise/audit in memory file based on policy. Policy rules * are written in terms of a policy identifier. * * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/ staticint ima_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id read_id)
{ enum ima_hooks func; struct lsm_prop prop;
/* permit signed certs */ if (!file && read_id == READING_X509_CERTIFICATE) return 0;
if (!file || !buf || size == 0) { /* should never happen */ if (ima_appraise & IMA_APPRAISE_ENFORCE) return -EACCES; return 0;
}
/** * ima_load_data - appraise decision based on policy * @id: kernel load data caller identifier * @contents: whether the full contents will be available in a later * call to ima_post_load_data(). * * Callers of this LSM hook can not measure, appraise, or audit the * data provided by userspace. Enforce policy rules requiring a file * signature (eg. kexec'ed kernel image). * * For permission return 0, otherwise return -EACCES.
*/ staticint ima_load_data(enum kernel_load_data_id id, bool contents)
{ bool ima_enforce, sig_enforce;
switch (id) { case LOADING_KEXEC_IMAGE: if (IS_ENABLED(CONFIG_KEXEC_SIG)
&& arch_ima_get_secureboot()) {
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); return -EACCES;
}
if (ima_enforce && (ima_appraise & IMA_APPRAISE_KEXEC)) {
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */
} break; case LOADING_FIRMWARE: if (ima_enforce && (ima_appraise & IMA_APPRAISE_FIRMWARE) && !contents) {
pr_err("Prevent firmware sysfs fallback loading.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */
} break; case LOADING_MODULE:
sig_enforce = is_module_sig_enforced();
if (ima_enforce && (!sig_enforce
&& (ima_appraise & IMA_APPRAISE_MODULES))) {
pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n"); return -EACCES; /* INTEGRITY_UNKNOWN */
} break; default: break;
} return 0;
}
/** * ima_post_load_data - appraise decision based on policy * @buf: pointer to in memory file contents * @size: size of in memory file contents * @load_id: kernel load data caller identifier * @description: @load_id-specific description of contents * * Measure/appraise/audit in memory buffer based on policy. Policy rules * are written in terms of a policy identifier. * * On success return 0. On integrity appraisal error, assuming the file * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/ staticint ima_post_load_data(char *buf, loff_t size, enum kernel_load_data_id load_id, char *description)
{ if (load_id == LOADING_FIRMWARE) { if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
(ima_appraise & IMA_APPRAISE_ENFORCE)) {
pr_err("Prevent firmware loading_store.\n"); return -EACCES; /* INTEGRITY_UNKNOWN */
} return 0;
}
/* * Measure the init_module syscall buffer containing the ELF image.
*/ if (load_id == LOADING_MODULE)
ima_measure_critical_data("modules", "init_module",
buf, size, true, NULL, 0);
return 0;
}
/** * process_buffer_measurement - Measure the buffer or the buffer data hash * @idmap: idmap of the mount the inode was found from * @inode: inode associated with the object being measured (NULL for KEY_CHECK) * @buf: pointer to the buffer that needs to be added to the log. * @size: size of buffer(in bytes). * @eventname: event name to be used for the buffer entry. * @func: IMA hook * @pcr: pcr to extend the measurement * @func_data: func specific data, may be NULL * @buf_hash: measure buffer data hash * @digest: buffer digest will be written to * @digest_len: buffer length * * Based on policy, either the buffer data or buffer data hash is measured * * Return: 0 if the buffer has been successfully measured, 1 if the digest * has been written to the passed location but not added to a measurement entry, * a negative value otherwise.
*/ int process_buffer_measurement(struct mnt_idmap *idmap, struct inode *inode, constvoid *buf, int size, constchar *eventname, enum ima_hooks func, int pcr, constchar *func_data, bool buf_hash, u8 *digest, size_t digest_len)
{ int ret = 0; constchar *audit_cause = "ENOMEM"; struct ima_template_entry *entry = NULL; struct ima_iint_cache iint = {}; struct ima_event_data event_data = {.iint = &iint,
.filename = eventname,
.buf = buf,
.buf_len = size}; struct ima_template_desc *template; struct ima_max_digest_data hash; struct ima_digest_data *hash_hdr = container_of(&hash.hdr, struct ima_digest_data, hdr); char digest_hash[IMA_MAX_DIGEST_SIZE]; int digest_hash_len = hash_digest_size[ima_hash_algo]; int violation = 0; int action = 0; struct lsm_prop prop;
if (digest && digest_len < digest_hash_len) return -EINVAL;
if (!ima_policy_flag && !digest) return -ENOENT;
template = ima_template_desc_buf(); if (!template) {
ret = -EINVAL;
audit_cause = "ima_template_desc_buf"; goto out;
}
/* * Both LSM hooks and auxiliary based buffer measurements are * based on policy. To avoid code duplication, differentiate * between the LSM hooks and auxiliary buffer measurements, * retrieving the policy rule information only for the LSM hook * buffer measurements.
*/ if (func) {
security_current_getlsmprop_subj(&prop);
action = ima_get_action(idmap, inode, current_cred(),
&prop, 0, func, &pcr, &template,
func_data, NULL); if (!(action & IMA_MEASURE) && !digest) return -ENOENT;
}
/** * ima_kexec_cmdline - measure kexec cmdline boot args * @kernel_fd: file descriptor of the kexec kernel being loaded * @buf: pointer to buffer * @size: size of buffer * * Buffers can only be measured, not appraised.
*/ void ima_kexec_cmdline(int kernel_fd, constvoid *buf, int size)
{ if (!buf || !size) return;
/** * ima_measure_critical_data - measure kernel integrity critical data * @event_label: unique event label for grouping and limiting critical data * @event_name: event name for the record in the IMA measurement list * @buf: pointer to buffer data * @buf_len: length of buffer data (in bytes) * @hash: measure buffer data hash * @digest: buffer digest will be written to * @digest_len: buffer length * * Measure data critical to the integrity of the kernel into the IMA log * and extend the pcr. Examples of critical data could be various data * structures, policies, and states stored in kernel memory that can * impact the integrity of the system. * * Return: 0 if the buffer has been successfully measured, 1 if the digest * has been written to the passed location but not added to a measurement entry, * a negative value otherwise.
*/ int ima_measure_critical_data(constchar *event_label, constchar *event_name, constvoid *buf, size_t buf_len, bool hash, u8 *digest, size_t digest_len)
{ if (!event_name || !event_label || !buf || !buf_len) return -ENOPARAM;
/** * ima_kernel_module_request - Prevent crypto-pkcs1(rsa,*) requests * @kmod_name: kernel module name * * Avoid a verification loop where verifying the signature of the modprobe * binary requires executing modprobe itself. Since the modprobe iint->mutex * is already held when the signature verification is performed, a deadlock * occurs as soon as modprobe is executed within the critical region, since * the same lock cannot be taken again. * * This happens when public_key_verify_signature(), in case of RSA algorithm, * use alg_name to store internal information in order to construct an * algorithm on the fly, but crypto_larval_lookup() will try to use alg_name * in order to load a kernel module with same name. * * Since we don't have any real "crypto-pkcs1(rsa,*)" kernel modules, * we are safe to fail such module request from crypto_larval_lookup(), and * avoid the verification loop. * * Return: Zero if it is safe to load the kernel module, -EINVAL otherwise.
*/ staticint ima_kernel_module_request(char *kmod_name)
{ if (strncmp(kmod_name, "crypto-pkcs1(rsa,", 17) == 0) return -EINVAL;
return 0;
}
#endif/* CONFIG_INTEGRITY_ASYMMETRIC_KEYS */
staticint __init init_ima(void)
{ int error;
/*Note that turning IMA off is intentionally limited to kdump kernel.*/ if (ima_disabled && is_kdump_kernel()) {
pr_info("IMA functionality is disabled"); return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.