1*2fe5d6deSMimi Zohar /* 2*2fe5d6deSMimi Zohar * Copyright (C) 2011 IBM Corporation 3*2fe5d6deSMimi Zohar * 4*2fe5d6deSMimi Zohar * Author: 5*2fe5d6deSMimi Zohar * Mimi Zohar <zohar@us.ibm.com> 6*2fe5d6deSMimi Zohar * 7*2fe5d6deSMimi Zohar * This program is free software; you can redistribute it and/or modify 8*2fe5d6deSMimi Zohar * it under the terms of the GNU General Public License as published by 9*2fe5d6deSMimi Zohar * the Free Software Foundation, version 2 of the License. 10*2fe5d6deSMimi Zohar */ 11*2fe5d6deSMimi Zohar #include <linux/module.h> 12*2fe5d6deSMimi Zohar #include <linux/file.h> 13*2fe5d6deSMimi Zohar #include <linux/fs.h> 14*2fe5d6deSMimi Zohar #include <linux/xattr.h> 15*2fe5d6deSMimi Zohar #include <linux/magic.h> 16*2fe5d6deSMimi Zohar #include <linux/ima.h> 17*2fe5d6deSMimi Zohar #include <linux/evm.h> 18*2fe5d6deSMimi Zohar 19*2fe5d6deSMimi Zohar #include "ima.h" 20*2fe5d6deSMimi Zohar 21*2fe5d6deSMimi Zohar static int __init default_appraise_setup(char *str) 22*2fe5d6deSMimi Zohar { 23*2fe5d6deSMimi Zohar if (strncmp(str, "off", 3) == 0) 24*2fe5d6deSMimi Zohar ima_appraise = 0; 25*2fe5d6deSMimi Zohar else if (strncmp(str, "fix", 3) == 0) 26*2fe5d6deSMimi Zohar ima_appraise = IMA_APPRAISE_FIX; 27*2fe5d6deSMimi Zohar return 1; 28*2fe5d6deSMimi Zohar } 29*2fe5d6deSMimi Zohar 30*2fe5d6deSMimi Zohar __setup("ima_appraise=", default_appraise_setup); 31*2fe5d6deSMimi Zohar 32*2fe5d6deSMimi Zohar /* 33*2fe5d6deSMimi Zohar * ima_must_appraise - set appraise flag 34*2fe5d6deSMimi Zohar * 35*2fe5d6deSMimi Zohar * Return 1 to appraise 36*2fe5d6deSMimi Zohar */ 37*2fe5d6deSMimi Zohar int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) 38*2fe5d6deSMimi Zohar { 39*2fe5d6deSMimi Zohar return 0; 40*2fe5d6deSMimi Zohar } 41*2fe5d6deSMimi Zohar 42*2fe5d6deSMimi Zohar static void ima_fix_xattr(struct dentry *dentry, 43*2fe5d6deSMimi Zohar struct integrity_iint_cache *iint) 44*2fe5d6deSMimi Zohar { 45*2fe5d6deSMimi Zohar iint->digest[0] = IMA_XATTR_DIGEST; 46*2fe5d6deSMimi Zohar __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, 47*2fe5d6deSMimi Zohar iint->digest, IMA_DIGEST_SIZE + 1, 0); 48*2fe5d6deSMimi Zohar } 49*2fe5d6deSMimi Zohar 50*2fe5d6deSMimi Zohar /* 51*2fe5d6deSMimi Zohar * ima_appraise_measurement - appraise file measurement 52*2fe5d6deSMimi Zohar * 53*2fe5d6deSMimi Zohar * Call evm_verifyxattr() to verify the integrity of 'security.ima'. 54*2fe5d6deSMimi Zohar * Assuming success, compare the xattr hash with the collected measurement. 55*2fe5d6deSMimi Zohar * 56*2fe5d6deSMimi Zohar * Return 0 on success, error code otherwise 57*2fe5d6deSMimi Zohar */ 58*2fe5d6deSMimi Zohar int ima_appraise_measurement(struct integrity_iint_cache *iint, 59*2fe5d6deSMimi Zohar struct file *file, const unsigned char *filename) 60*2fe5d6deSMimi Zohar { 61*2fe5d6deSMimi Zohar struct dentry *dentry = file->f_dentry; 62*2fe5d6deSMimi Zohar struct inode *inode = dentry->d_inode; 63*2fe5d6deSMimi Zohar u8 xattr_value[IMA_DIGEST_SIZE]; 64*2fe5d6deSMimi Zohar enum integrity_status status = INTEGRITY_UNKNOWN; 65*2fe5d6deSMimi Zohar const char *op = "appraise_data"; 66*2fe5d6deSMimi Zohar char *cause = "unknown"; 67*2fe5d6deSMimi Zohar int rc; 68*2fe5d6deSMimi Zohar 69*2fe5d6deSMimi Zohar if (!ima_appraise) 70*2fe5d6deSMimi Zohar return 0; 71*2fe5d6deSMimi Zohar if (!inode->i_op->getxattr) 72*2fe5d6deSMimi Zohar return INTEGRITY_UNKNOWN; 73*2fe5d6deSMimi Zohar 74*2fe5d6deSMimi Zohar if (iint->flags & IMA_APPRAISED) 75*2fe5d6deSMimi Zohar return iint->ima_status; 76*2fe5d6deSMimi Zohar 77*2fe5d6deSMimi Zohar rc = inode->i_op->getxattr(dentry, XATTR_NAME_IMA, xattr_value, 78*2fe5d6deSMimi Zohar IMA_DIGEST_SIZE); 79*2fe5d6deSMimi Zohar if (rc <= 0) { 80*2fe5d6deSMimi Zohar if (rc && rc != -ENODATA) 81*2fe5d6deSMimi Zohar goto out; 82*2fe5d6deSMimi Zohar 83*2fe5d6deSMimi Zohar cause = "missing-hash"; 84*2fe5d6deSMimi Zohar status = 85*2fe5d6deSMimi Zohar (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL; 86*2fe5d6deSMimi Zohar goto out; 87*2fe5d6deSMimi Zohar } 88*2fe5d6deSMimi Zohar 89*2fe5d6deSMimi Zohar status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); 90*2fe5d6deSMimi Zohar if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { 91*2fe5d6deSMimi Zohar if ((status == INTEGRITY_NOLABEL) 92*2fe5d6deSMimi Zohar || (status == INTEGRITY_NOXATTRS)) 93*2fe5d6deSMimi Zohar cause = "missing-HMAC"; 94*2fe5d6deSMimi Zohar else if (status == INTEGRITY_FAIL) 95*2fe5d6deSMimi Zohar cause = "invalid-HMAC"; 96*2fe5d6deSMimi Zohar goto out; 97*2fe5d6deSMimi Zohar } 98*2fe5d6deSMimi Zohar 99*2fe5d6deSMimi Zohar rc = memcmp(xattr_value, iint->digest, IMA_DIGEST_SIZE); 100*2fe5d6deSMimi Zohar if (rc) { 101*2fe5d6deSMimi Zohar status = INTEGRITY_FAIL; 102*2fe5d6deSMimi Zohar cause = "invalid-hash"; 103*2fe5d6deSMimi Zohar print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE, 104*2fe5d6deSMimi Zohar xattr_value, IMA_DIGEST_SIZE); 105*2fe5d6deSMimi Zohar print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE, 106*2fe5d6deSMimi Zohar iint->digest, IMA_DIGEST_SIZE); 107*2fe5d6deSMimi Zohar goto out; 108*2fe5d6deSMimi Zohar } 109*2fe5d6deSMimi Zohar status = INTEGRITY_PASS; 110*2fe5d6deSMimi Zohar iint->flags |= IMA_APPRAISED; 111*2fe5d6deSMimi Zohar out: 112*2fe5d6deSMimi Zohar if (status != INTEGRITY_PASS) { 113*2fe5d6deSMimi Zohar if (ima_appraise & IMA_APPRAISE_FIX) { 114*2fe5d6deSMimi Zohar ima_fix_xattr(dentry, iint); 115*2fe5d6deSMimi Zohar status = INTEGRITY_PASS; 116*2fe5d6deSMimi Zohar } 117*2fe5d6deSMimi Zohar integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, 118*2fe5d6deSMimi Zohar op, cause, rc, 0); 119*2fe5d6deSMimi Zohar } 120*2fe5d6deSMimi Zohar iint->ima_status = status; 121*2fe5d6deSMimi Zohar return status; 122*2fe5d6deSMimi Zohar } 123*2fe5d6deSMimi Zohar 124*2fe5d6deSMimi Zohar /* 125*2fe5d6deSMimi Zohar * ima_update_xattr - update 'security.ima' hash value 126*2fe5d6deSMimi Zohar */ 127*2fe5d6deSMimi Zohar void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) 128*2fe5d6deSMimi Zohar { 129*2fe5d6deSMimi Zohar struct dentry *dentry = file->f_dentry; 130*2fe5d6deSMimi Zohar int rc = 0; 131*2fe5d6deSMimi Zohar 132*2fe5d6deSMimi Zohar rc = ima_collect_measurement(iint, file); 133*2fe5d6deSMimi Zohar if (rc < 0) 134*2fe5d6deSMimi Zohar return; 135*2fe5d6deSMimi Zohar ima_fix_xattr(dentry, iint); 136*2fe5d6deSMimi Zohar } 137*2fe5d6deSMimi Zohar 138*2fe5d6deSMimi Zohar /** 139*2fe5d6deSMimi Zohar * ima_inode_post_setattr - reflect file metadata changes 140*2fe5d6deSMimi Zohar * @dentry: pointer to the affected dentry 141*2fe5d6deSMimi Zohar * 142*2fe5d6deSMimi Zohar * Changes to a dentry's metadata might result in needing to appraise. 143*2fe5d6deSMimi Zohar * 144*2fe5d6deSMimi Zohar * This function is called from notify_change(), which expects the caller 145*2fe5d6deSMimi Zohar * to lock the inode's i_mutex. 146*2fe5d6deSMimi Zohar */ 147*2fe5d6deSMimi Zohar void ima_inode_post_setattr(struct dentry *dentry) 148*2fe5d6deSMimi Zohar { 149*2fe5d6deSMimi Zohar struct inode *inode = dentry->d_inode; 150*2fe5d6deSMimi Zohar struct integrity_iint_cache *iint; 151*2fe5d6deSMimi Zohar int must_appraise, rc; 152*2fe5d6deSMimi Zohar 153*2fe5d6deSMimi Zohar if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) 154*2fe5d6deSMimi Zohar || !inode->i_op->removexattr) 155*2fe5d6deSMimi Zohar return; 156*2fe5d6deSMimi Zohar 157*2fe5d6deSMimi Zohar must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); 158*2fe5d6deSMimi Zohar iint = integrity_iint_find(inode); 159*2fe5d6deSMimi Zohar if (iint) { 160*2fe5d6deSMimi Zohar if (must_appraise) 161*2fe5d6deSMimi Zohar iint->flags |= IMA_APPRAISE; 162*2fe5d6deSMimi Zohar else 163*2fe5d6deSMimi Zohar iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); 164*2fe5d6deSMimi Zohar } 165*2fe5d6deSMimi Zohar if (!must_appraise) 166*2fe5d6deSMimi Zohar rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); 167*2fe5d6deSMimi Zohar return; 168*2fe5d6deSMimi Zohar } 169