ima_appraise.c Interaktion und Portierbarkeitunbekannt
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( C ) 2011 IBM Corporation
*
* Author :
* Mimi Zohar < zohar @ us . ibm . com >
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/binfmts.h>
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/magic.h>
#include <linux/ima.h>
#include <linux/evm.h>
#include <linux/fsverity.h>
#include <keys/system_keyring.h>
#include <uapi/linux/fsverity.h>
#include "ima.h"
#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
static char *ima_appraise_cmdline_default __initdata;
core_param(ima_appraise, ima_appraise_cmdline_default, charp, 0 );
void __init ima_appraise_parse_cmdline(void )
{
const char *str = ima_appraise_cmdline_default;
bool sb_state = arch_ima_get_secureboot();
int appraisal_state = ima_appraise;
if (!str)
return ;
if (strncmp(str, "off" , 3 ) == 0 )
appraisal_state = 0 ;
else if (strncmp(str, "log" , 3 ) == 0 )
appraisal_state = IMA_APPRAISE_LOG;
else if (strncmp(str, "fix" , 3 ) == 0 )
appraisal_state = IMA_APPRAISE_FIX;
else if (strncmp(str, "enforce" , 7 ) == 0 )
appraisal_state = IMA_APPRAISE_ENFORCE;
else
pr_err("invalid \" %s\" appraise option" , str);
/* If appraisal state was changed, but secure boot is enabled,
* keep its default */
if (sb_state) {
if (!(appraisal_state & IMA_APPRAISE_ENFORCE))
pr_info("Secure boot enabled: ignoring ima_appraise=%s option" ,
str);
} else {
ima_appraise = appraisal_state;
}
}
#endif
/*
* is_ima_appraise_enabled - return appraise status
*
* Only return enabled , if not in ima_appraise = " fix " or " log " modes .
*/
bool is_ima_appraise_enabled(void )
{
return ima_appraise & IMA_APPRAISE_ENFORCE;
}
/*
* ima_must_appraise - set appraise flag
*
* Return 1 to appraise or hash
*/
int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
int mask, enum ima_hooks func)
{
struct lsm_prop prop;
if (!ima_appraise)
return 0 ;
security_current_getlsmprop_subj(&prop);
return ima_match_policy(idmap, inode, current_cred(), &prop,
func, mask, IMA_APPRAISE | IMA_HASH, NULL,
NULL, NULL, NULL);
}
static int ima_fix_xattr(struct dentry *dentry, struct ima_iint_cache *iint)
{
int rc, offset;
u8 algo = iint->ima_hash->algo;
if (algo <= HASH_ALGO_SHA1) {
offset = 1 ;
iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST;
} else {
offset = 0 ;
iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
iint->ima_hash->xattr.ng.algo = algo;
}
rc = __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_IMA,
&iint->ima_hash->xattr.data[offset],
(sizeof (iint->ima_hash->xattr) - offset) +
iint->ima_hash->length, 0 );
return rc;
}
/* Return specific func appraised cached result */
enum integrity_status ima_get_cache_status(struct ima_iint_cache *iint,
enum ima_hooks func)
{
switch (func) {
case MMAP_CHECK:
case MMAP_CHECK_REQPROT:
return iint->ima_mmap_status;
case BPRM_CHECK:
return iint->ima_bprm_status;
case CREDS_CHECK:
return iint->ima_creds_status;
case FILE_CHECK:
case POST_SETATTR:
return iint->ima_file_status;
case MODULE_CHECK ... MAX_CHECK - 1 :
default :
return iint->ima_read_status;
}
}
static void ima_set_cache_status(struct ima_iint_cache *iint,
enum ima_hooks func,
enum integrity_status status)
{
switch (func) {
case MMAP_CHECK:
case MMAP_CHECK_REQPROT:
iint->ima_mmap_status = status;
break ;
case BPRM_CHECK:
iint->ima_bprm_status = status;
break ;
case CREDS_CHECK:
iint->ima_creds_status = status;
break ;
case FILE_CHECK:
case POST_SETATTR:
iint->ima_file_status = status;
break ;
case MODULE_CHECK ... MAX_CHECK - 1 :
default :
iint->ima_read_status = status;
break ;
}
}
static void ima_cache_flags(struct ima_iint_cache *iint, enum ima_hooks func)
{
switch (func) {
case MMAP_CHECK:
case MMAP_CHECK_REQPROT:
iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED);
break ;
case BPRM_CHECK:
iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
break ;
case CREDS_CHECK:
iint->flags |= (IMA_CREDS_APPRAISED | IMA_APPRAISED);
break ;
case FILE_CHECK:
case POST_SETATTR:
iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
break ;
case MODULE_CHECK ... MAX_CHECK - 1 :
default :
iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
break ;
}
}
enum hash_algo ima_get_hash_algo(const struct evm_ima_xattr_data *xattr_value,
int xattr_len)
{
struct signature_v2_hdr *sig;
enum hash_algo ret;
if (!xattr_value || xattr_len < 2 )
/* return default hash algo */
return ima_hash_algo;
switch (xattr_value->type) {
case IMA_VERITY_DIGSIG:
sig = (typeof(sig))xattr_value;
if (sig->version != 3 || xattr_len <= sizeof (*sig) ||
sig->hash_algo >= HASH_ALGO__LAST)
return ima_hash_algo;
return sig->hash_algo;
case EVM_IMA_XATTR_DIGSIG:
sig = (typeof(sig))xattr_value;
if (sig->version != 2 || xattr_len <= sizeof (*sig)
|| sig->hash_algo >= HASH_ALGO__LAST)
return ima_hash_algo;
return sig->hash_algo;
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
ret = xattr_value->data[0 ];
if (ret < HASH_ALGO__LAST)
return ret;
break ;
case IMA_XATTR_DIGEST:
/* this is for backward compatibility */
if (xattr_len == 21 ) {
unsigned int zero = 0 ;
if (!memcmp(&xattr_value->data[16 ], &zero, 4 ))
return HASH_ALGO_MD5;
else
return HASH_ALGO_SHA1;
} else if (xattr_len == 17 )
return HASH_ALGO_MD5;
break ;
}
/* return default hash algo */
return ima_hash_algo;
}
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value, int xattr_len)
{
int ret;
ret = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, XATTR_NAME_IMA,
(char **)xattr_value, xattr_len, GFP_NOFS);
if (ret == -EOPNOTSUPP)
ret = 0 ;
return ret;
}
/*
* calc_file_id_hash - calculate the hash of the ima_file_id struct data
* @ type : xattr type [ enum evm_ima_xattr_type ]
* @ algo : hash algorithm [ enum hash_algo ]
* @ digest : pointer to the digest to be hashed
* @ hash : ( out ) pointer to the hash
*
* IMA signature version 3 disambiguates the data that is signed by
* indirectly signing the hash of the ima_file_id structure data .
*
* Signing the ima_file_id struct is currently only supported for
* IMA_VERITY_DIGSIG type xattrs .
*
* Return 0 on success , error code otherwise .
*/
static int calc_file_id_hash(enum evm_ima_xattr_type type,
enum hash_algo algo, const u8 *digest,
struct ima_digest_data *hash)
{
struct ima_file_id file_id = {
.hash_type = IMA_VERITY_DIGSIG, .hash_algorithm = algo};
unsigned int unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
if (type != IMA_VERITY_DIGSIG)
return -EINVAL;
memcpy(file_id.hash, digest, hash_digest_size[algo]);
hash->algo = algo;
hash->length = hash_digest_size[algo];
return ima_calc_buffer_hash(&file_id, sizeof (file_id) - unused, hash);
}
/*
* xattr_verify - verify xattr digest or signature
*
* Verify whether the hash or signature matches the file contents .
*
* Return 0 on success , error code otherwise .
*/
static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
struct evm_ima_xattr_data *xattr_value, int xattr_len,
enum integrity_status *status, const char **cause)
{
struct ima_max_digest_data hash;
struct signature_v2_hdr *sig;
int rc = -EINVAL, hash_start = 0 ;
int mask;
switch (xattr_value->type) {
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
hash_start = 1 ;
fallthrough;
case IMA_XATTR_DIGEST:
if (*status != INTEGRITY_PASS_IMMUTABLE) {
if (iint->flags & IMA_DIGSIG_REQUIRED) {
if (iint->flags & IMA_VERITY_REQUIRED)
*cause = "verity-signature-required" ;
else
*cause = "IMA-signature-required" ;
*status = INTEGRITY_FAIL;
break ;
}
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
} else {
set_bit(IMA_DIGSIG, &iint->atomic_flags);
}
if (xattr_len - sizeof (xattr_value->type) - hash_start >=
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->data[hash_start],
iint->ima_hash->digest,
iint->ima_hash->length);
else
rc = -EINVAL;
if (rc) {
*cause = "invalid-hash" ;
*status = INTEGRITY_FAIL;
break ;
}
*status = INTEGRITY_PASS;
break ;
case EVM_IMA_XATTR_DIGSIG:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
mask = IMA_DIGSIG_REQUIRED | IMA_VERITY_REQUIRED;
if ((iint->flags & mask) == mask) {
*cause = "verity-signature-required" ;
*status = INTEGRITY_FAIL;
break ;
}
sig = (typeof(sig))xattr_value;
if (sig->version >= 3 ) {
*cause = "invalid-signature-version" ;
*status = INTEGRITY_FAIL;
break ;
}
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
if (rc == -EOPNOTSUPP) {
*status = INTEGRITY_UNKNOWN;
break ;
}
if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
func == KEXEC_KERNEL_CHECK)
rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
if (rc) {
*cause = "invalid-signature" ;
*status = INTEGRITY_FAIL;
} else {
*status = INTEGRITY_PASS;
}
break ;
case IMA_VERITY_DIGSIG:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
if (iint->flags & IMA_DIGSIG_REQUIRED) {
if (!(iint->flags & IMA_VERITY_REQUIRED)) {
*cause = "IMA-signature-required" ;
*status = INTEGRITY_FAIL;
break ;
}
}
sig = (typeof(sig))xattr_value;
if (sig->version != 3 ) {
*cause = "invalid-signature-version" ;
*status = INTEGRITY_FAIL;
break ;
}
rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo,
iint->ima_hash->digest,
container_of(&hash.hdr,
struct ima_digest_data, hdr));
if (rc) {
*cause = "sigv3-hashing-error" ;
*status = INTEGRITY_FAIL;
break ;
}
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len, hash.digest,
hash.hdr.length);
if (rc) {
*cause = "invalid-verity-signature" ;
*status = INTEGRITY_FAIL;
} else {
*status = INTEGRITY_PASS;
}
break ;
default :
*status = INTEGRITY_UNKNOWN;
*cause = "unknown-ima-data" ;
break ;
}
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_check_blacklist - determine if the binary is blacklisted .
*
* Add the hash of the blacklisted binary to the measurement list , based
* on policy .
*
* Returns - EPERM if the hash is blacklisted .
*/
int ima_check_blacklist(struct ima_iint_cache *iint,
const struct modsig *modsig, int pcr)
{
enum hash_algo hash_algo;
const u8 *digest = NULL;
u32 digestsize = 0 ;
int rc = 0 ;
if (!(iint->flags & IMA_CHECK_BLACKLIST))
return 0 ;
if (iint->flags & IMA_MODSIG_ALLOWED && modsig) {
ima_get_modsig_digest(modsig, &hash_algo, &digest, &digestsize);
rc = is_binary_blacklisted(digest, digestsize);
} else if (iint->flags & IMA_DIGSIG_REQUIRED && iint->ima_hash)
rc = is_binary_blacklisted(iint->ima_hash->digest, iint->ima_hash->length);
if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
process_buffer_measurement(&nop_mnt_idmap, NULL, digest, digestsize,
"blacklisted-hash" , NONE,
pcr, NULL, false , NULL, 0 );
return rc;
}
static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file)
{
struct linux_binprm *bprm;
if (func == BPRM_CHECK) {
bprm = container_of(&file, struct linux_binprm, file);
return bprm->is_check;
}
return false ;
}
/*
* ima_appraise_measurement - appraise file measurement
*
* Call evm_verifyxattr ( ) to verify the integrity of ' security . ima ' .
* Assuming success , compare the xattr hash with the collected measurement .
*
* Return 0 on success , error code otherwise
*/
int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, const struct modsig *modsig)
{
static const char op[] = "appraise_data" ;
int audit_msgno = AUDIT_INTEGRITY_DATA;
const char *cause = "unknown" ;
struct dentry *dentry = file_dentry(file);
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 not appraising a modsig, we need an xattr. */
if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
return INTEGRITY_UNKNOWN;
/*
* Unlike any of the other LSM hooks where the kernel enforces file
* integrity , enforcing file integrity for the bprm_creds_for_exec ( )
* LSM hook with the AT_EXECVE_CHECK flag is left up to the discretion
* of the script interpreter ( userspace ) . Differentiate kernel and
* userspace enforced integrity audit messages .
*/
if (is_bprm_creds_for_exec(func, file))
audit_msgno = AUDIT_INTEGRITY_USERSPACE;
/* If reading the xattr failed and there's no modsig, error out. */
if (rc <= 0 && !try_modsig) {
if (rc && rc != -ENODATA)
goto out;
if (iint->flags & IMA_DIGSIG_REQUIRED) {
if (iint->flags & IMA_VERITY_REQUIRED)
cause = "verity-signature-required" ;
else
cause = "IMA-signature-required" ;
} else {
cause = "missing-hash" ;
}
status = INTEGRITY_NOLABEL;
if (file->f_mode & FMODE_CREATED)
iint->flags |= IMA_NEW_FILE;
if ((iint->flags & IMA_NEW_FILE) &&
(!(iint->flags & IMA_DIGSIG_REQUIRED) ||
(inode->i_size == 0 )))
status = INTEGRITY_PASS;
goto out;
}
status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
rc < 0 ? 0 : rc);
switch (status) {
case INTEGRITY_PASS:
case INTEGRITY_PASS_IMMUTABLE:
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 ;
fallthrough;
case INTEGRITY_NOLABEL: /* No security.evm xattr. */
cause = "missing-HMAC" ;
goto out;
case INTEGRITY_FAIL_IMMUTABLE:
set_bit(IMA_DIGSIG, &iint->atomic_flags);
cause = "invalid-fail-immutable" ;
goto out;
case INTEGRITY_FAIL: /* Invalid HMAC/signature. */
cause = "invalid-HMAC" ;
goto out;
default :
WARN_ONCE(true , "Unexpected integrity status %d\n" , status);
}
if (xattr_value)
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 .
* When such filesystems are mounted by an untrusted mounter or on a
* system not willing to accept such a risk , fail the file signature
* verification .
*/
if ((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
((inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) ||
(iint->flags & IMA_FAIL_UNVERIFIABLE_SIGS))) {
status = INTEGRITY_FAIL;
cause = "unverifiable-signature" ;
integrity_audit_msg(audit_msgno, inode, filename,
op, cause, rc, 0 );
} else if (status != INTEGRITY_PASS) {
/* Fix mode, but don't replace file signatures. */
if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
(!xattr_value ||
xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
if (!ima_fix_xattr(dentry, iint))
status = INTEGRITY_PASS;
}
/*
* Permit new files with file / EVM portable signatures , but
* without data .
*/
if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
status = INTEGRITY_PASS;
}
integrity_audit_msg(audit_msgno, inode, filename,
op, cause, rc, 0 );
} else {
ima_cache_flags(iint, func);
}
ima_set_cache_status(iint, func, status);
return status;
}
/*
* ima_update_xattr - update ' security . ima ' hash value
*/
void ima_update_xattr(struct ima_iint_cache *iint, struct file *file)
{
struct dentry *dentry = file_dentry(file);
int rc = 0 ;
/* do not collect and update hash for digital signatures */
if (test_bit(IMA_DIGSIG, &iint->atomic_flags))
return ;
if ((iint->ima_file_status != INTEGRITY_PASS) &&
!(iint->flags & IMA_HASH))
return ;
rc = ima_collect_measurement(iint, file, NULL, 0 , ima_hash_algo, NULL);
if (rc < 0 )
return ;
inode_lock(file_inode(file));
ima_fix_xattr(dentry, iint);
inode_unlock(file_inode(file));
}
/**
* ima_inode_post_setattr - reflect file metadata changes
* @ idmap : idmap of the mount the inode was found from
* @ dentry : pointer to the affected dentry
* @ ia_valid : for the UID and GID status
*
* Changes to a dentry ' s metadata might result in needing to appraise .
*
* This function is called from notify_change ( ) , which expects the caller
* to lock the inode ' s i_mutex .
*/
static void ima_inode_post_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, int ia_valid)
{
struct inode *inode = d_backing_inode(dentry);
struct ima_iint_cache *iint;
int action;
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !(inode->i_opflags & IOP_XATTR))
return ;
action = ima_must_appraise(idmap, inode, MAY_ACCESS, POST_SETATTR);
iint = ima_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);
if (!action)
clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
}
}
/*
* ima_protect_xattr - protect ' security . ima '
*
* Ensure that not just anyone can modify or remove ' security . ima ' .
*/
static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
if (strcmp(xattr_name, XATTR_NAME_IMA) == 0 ) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return 1 ;
}
return 0 ;
}
/*
* ima_reset_appraise_flags - reset ima_iint_cache flags
*
* @ digsig : whether to clear / set IMA_DIGSIG flag , tristate values
* 0 : clear IMA_DIGSIG
* 1 : set IMA_DIGSIG
* - 1 : don ' t change IMA_DIGSIG
*
*/
static void ima_reset_appraise_flags(struct inode *inode, int digsig)
{
struct ima_iint_cache *iint;
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
return ;
iint = ima_iint_find(inode);
if (!iint)
return ;
iint->measured_pcrs = 0 ;
set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);
if (digsig == 1 )
set_bit(IMA_DIGSIG, &iint->atomic_flags);
else if (digsig == 0 )
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
}
/**
* validate_hash_algo ( ) - Block setxattr with unsupported hash algorithms
* @ dentry : object of the setxattr ( )
* @ xattr_value : userland supplied xattr value
* @ xattr_value_len : length of xattr_value
*
* The xattr value is mapped to its hash algorithm , and this algorithm
* must be built in the kernel for the setxattr to be allowed .
*
* Emit an audit message when the algorithm is invalid .
*
* Return : 0 on success , else an error .
*/
static int validate_hash_algo(struct dentry *dentry,
const struct evm_ima_xattr_data *xattr_value,
size_t xattr_value_len)
{
char *path = NULL, *pathbuf = NULL;
enum hash_algo xattr_hash_algo;
const char *errmsg = "unavailable-hash-algorithm" ;
unsigned int allowed_hashes;
xattr_hash_algo = ima_get_hash_algo(xattr_value, xattr_value_len);
allowed_hashes = atomic_read(&ima_setxattr_allowed_hash_algorithms);
if (allowed_hashes) {
/* success if the algorithm is allowed in the ima policy */
if (allowed_hashes & (1 U << xattr_hash_algo))
return 0 ;
/*
* We use a different audit message when the hash algorithm
* is denied by a policy rule , instead of not being built
* in the kernel image
*/
errmsg = "denied-hash-algorithm" ;
} else {
if (likely(xattr_hash_algo == ima_hash_algo))
return 0 ;
/* allow any xattr using an algorithm built in the kernel */
if (crypto_has_alg(hash_algo_name[xattr_hash_algo], 0 , 0 ))
return 0 ;
}
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
if (!pathbuf)
return -EACCES;
path = dentry_path(dentry, pathbuf, PATH_MAX);
integrity_audit_msg(AUDIT_INTEGRITY_DATA, d_inode(dentry), path,
"set_data" , errmsg, -EACCES, 0 );
kfree(pathbuf);
return -EACCES;
}
static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
const char *xattr_name, const void *xattr_value,
size_t xattr_value_len, int flags)
{
const struct evm_ima_xattr_data *xvalue = xattr_value;
int digsig = 0 ;
int result;
int err;
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
if (result == 1 ) {
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
return -EINVAL;
err = validate_hash_algo(dentry, xvalue, xattr_value_len);
if (err)
return err;
digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
} else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0 ) {
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
} else {
digsig = -1 ;
}
if (result == 1 || evm_revalidate_status(xattr_name)) {
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
if (result == 1 )
result = 0 ;
}
return result;
}
static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name, struct posix_acl *kacl)
{
if (evm_revalidate_status(acl_name))
ima_reset_appraise_flags(d_backing_inode(dentry), -1 );
return 0 ;
}
static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
const char *xattr_name)
{
int result, digsig = -1 ;
result = ima_protect_xattr(dentry, xattr_name, NULL, 0 );
if (result == 1 || evm_revalidate_status(xattr_name)) {
if (!strcmp(xattr_name, XATTR_NAME_IMA))
digsig = 0 ;
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
if (result == 1 )
result = 0 ;
}
return result;
}
static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name)
{
return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
}
static struct security_hook_list ima_appraise_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_post_setattr, ima_inode_post_setattr),
LSM_HOOK_INIT(inode_setxattr, ima_inode_setxattr),
LSM_HOOK_INIT(inode_set_acl, ima_inode_set_acl),
LSM_HOOK_INIT(inode_removexattr, ima_inode_removexattr),
LSM_HOOK_INIT(inode_remove_acl, ima_inode_remove_acl),
};
void __init init_ima_appraise_lsm(const struct lsm_id *lsmid)
{
security_add_hooks(ima_appraise_hooks, ARRAY_SIZE(ima_appraise_hooks),
lsmid);
}
Messung V0.5 in Prozent C=96 H=98 G=96
[0.42QuellennavigatorsProjekt 2026-09-28]
2026-10-10