Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security subsystem updates from James Morris:
 "Highlights:

   - TPM core and driver updates/fixes
   - IPv6 security labeling (CALIPSO)
   - Lots of Apparmor fixes
   - Seccomp: remove 2-phase API, close hole where ptrace can change
     syscall #"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (156 commits)
  apparmor: fix SECURITY_APPARMOR_HASH_DEFAULT parameter handling
  tpm: Add TPM 2.0 support to the Nuvoton i2c driver (NPCT6xx family)
  tpm: Factor out common startup code
  tpm: use devm_add_action_or_reset
  tpm2_i2c_nuvoton: add irq validity check
  tpm: read burstcount from TPM_STS in one 32-bit transaction
  tpm: fix byte-order for the value read by tpm2_get_tpm_pt
  tpm_tis_core: convert max timeouts from msec to jiffies
  apparmor: fix arg_size computation for when setprocattr is null terminated
  apparmor: fix oops, validate buffer size in apparmor_setprocattr()
  apparmor: do not expose kernel stack
  apparmor: fix module parameters can be changed after policy is locked
  apparmor: fix oops in profile_unpack() when policy_db is not present
  apparmor: don't check for vmalloc_addr if kvzalloc() failed
  apparmor: add missing id bounds check on dfa verification
  apparmor: allow SYS_CAP_RESOURCE to be sufficient to prlimit another task
  apparmor: use list_next_entry instead of list_entry_next
  apparmor: fix refcount race when finding a child profile
  apparmor: fix ref count leak when profile sha1 hash is read
  apparmor: check that xindex is in trans_table bounds
  ...
This commit is contained in:
Linus Torvalds
2016-07-29 17:38:46 -07:00
126 changed files with 7294 additions and 2144 deletions
+2
View File
@@ -79,6 +79,7 @@ static void iint_free(struct integrity_iint_cache *iint)
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
iint->measured_pcrs = 0;
kmem_cache_free(iint_cache, iint);
}
@@ -159,6 +160,7 @@ static void init_once(void *foo)
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
iint->measured_pcrs = 0;
}
static int __init integrity_iintcache_init(void)
+7 -4
View File
@@ -88,6 +88,7 @@ struct ima_template_desc {
};
struct ima_template_entry {
int pcr;
u8 digest[TPM_DIGEST_SIZE]; /* sha1 or md5 measurement hash */
struct ima_template_desc *template_desc; /* template descriptor */
u32 template_data_len;
@@ -154,7 +155,8 @@ enum ima_hooks {
};
/* LIM API function definitions */
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func);
int ima_get_action(struct inode *inode, int mask,
enum ima_hooks func, int *pcr);
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file, void *buf, loff_t size,
@@ -162,19 +164,20 @@ 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 xattr_len, int pcr);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_entry **entry);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode, const unsigned char *filename);
struct inode *inode,
const unsigned char *filename, int pcr);
void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(const struct path *path, char **pathbuf);
/* IMA policy related functions */
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
int flags, int *pcr);
void ima_init_policy(void);
void ima_update_policy(void);
void ima_update_policy_flag(void);
+13 -8
View File
@@ -87,7 +87,7 @@ out:
*/
int ima_store_template(struct ima_template_entry *entry,
int violation, struct inode *inode,
const unsigned char *filename)
const unsigned char *filename, int pcr)
{
static const char op[] = "add_template_measure";
static const char audit_cause[] = "hashing_error";
@@ -114,6 +114,7 @@ int ima_store_template(struct ima_template_entry *entry,
}
memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
}
entry->pcr = pcr;
result = ima_add_template_entry(entry, violation, op, inode, filename);
return result;
}
@@ -144,7 +145,8 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
result = -ENOMEM;
goto err_out;
}
result = ima_store_template(entry, violation, inode, filename);
result = ima_store_template(entry, violation, inode,
filename, CONFIG_IMA_MEASURE_PCR_IDX);
if (result < 0)
ima_free_template_entry(entry);
err_out:
@@ -157,6 +159,7 @@ err_out:
* @inode: pointer to inode to measure
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
* @func: caller identifier
* @pcr: pointer filled in if matched measure policy sets pcr=
*
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
@@ -168,13 +171,13 @@ err_out:
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func)
int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
flags &= ima_policy_flag;
return ima_match_policy(inode, func, mask, flags);
return ima_match_policy(inode, func, mask, flags, pcr);
}
/*
@@ -252,7 +255,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 xattr_len, int pcr)
{
static const char op[] = "add_template_measure";
static const char audit_cause[] = "ENOMEM";
@@ -263,7 +266,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
xattr_len, NULL};
int violation = 0;
if (iint->flags & IMA_MEASURED)
if (iint->measured_pcrs & (0x1 << pcr))
return;
result = ima_alloc_init_template(&event_data, &entry);
@@ -273,9 +276,11 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
return;
}
result = ima_store_template(entry, violation, inode, filename);
if (!result || result == -EEXIST)
result = ima_store_template(entry, violation, inode, filename, pcr);
if (!result || result == -EEXIST) {
iint->flags |= IMA_MEASURED;
iint->measured_pcrs |= (0x1 << pcr);
}
if (result < 0)
ima_free_template_entry(entry);
}
+2 -1
View File
@@ -41,7 +41,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
if (!ima_appraise)
return 0;
return ima_match_policy(inode, func, mask, IMA_APPRAISE);
return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL);
}
static int ima_fix_xattr(struct dentry *dentry,
@@ -370,6 +370,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
return;
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
if (digsig)
iint->flags |= IMA_DIGSIG;
return;
+4 -5
View File
@@ -123,7 +123,6 @@ static int ima_measurements_show(struct seq_file *m, void *v)
struct ima_template_entry *e;
char *template_name;
int namelen;
u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX;
bool is_ima_template = false;
int i;
@@ -137,10 +136,10 @@ static int ima_measurements_show(struct seq_file *m, void *v)
/*
* 1st: PCRIndex
* PCR used is always the same (config option) in
* little-endian format
* PCR used defaults to the same (config option) in
* little-endian format, unless set in policy
*/
ima_putc(m, &pcr, sizeof(pcr));
ima_putc(m, &e->pcr, sizeof(e->pcr));
/* 2nd: template digest */
ima_putc(m, e->digest, TPM_DIGEST_SIZE);
@@ -219,7 +218,7 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
e->template_desc->name : e->template_desc->fmt;
/* 1st: PCR used (config option) */
seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX);
seq_printf(m, "%2d ", e->pcr);
/* 2nd: SHA1 template hash */
ima_print_digest(m, e->digest, TPM_DIGEST_SIZE);
+2 -1
View File
@@ -79,7 +79,8 @@ static int __init ima_add_boot_aggregate(void)
}
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name);
boot_aggregate_name,
CONFIG_IMA_MEASURE_PCR_IDX);
if (result < 0) {
ima_free_template_entry(entry);
audit_cause = "store_entry";
+9 -3
View File
@@ -125,6 +125,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
if ((iint->version != inode->i_version) ||
(iint->flags & IMA_NEW_FILE)) {
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
iint->measured_pcrs = 0;
if (iint->flags & IMA_APPRAISE)
ima_update_xattr(iint, file);
}
@@ -162,6 +163,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
char *pathbuf = NULL;
const char *pathname = NULL;
int rc = -ENOMEM, action, must_appraise;
int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
struct evm_ima_xattr_data *xattr_value = NULL;
int xattr_len = 0;
bool violation_check;
@@ -174,7 +176,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
* bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask.
*/
action = ima_get_action(inode, mask, func);
action = ima_get_action(inode, mask, func, &pcr);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
@@ -209,7 +211,11 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
*/
iint->flags |= action;
action &= IMA_DO_MASK;
action &= ~((iint->flags & IMA_DONE_MASK) >> 1);
action &= ~((iint->flags & (IMA_DONE_MASK ^ IMA_MEASURED)) >> 1);
/* If target pcr is already measured, unset IMA_MEASURE action */
if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr)))
action ^= IMA_MEASURE;
/* Nothing to do, just return existing appraised status */
if (!action) {
@@ -238,7 +244,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len);
xattr_value, xattr_len, pcr);
if (action & IMA_APPRAISE_SUBMASK)
rc = ima_appraise_measurement(func, iint, file, pathname,
xattr_value, xattr_len, opened);
+33 -2
View File
@@ -32,6 +32,7 @@
#define IMA_FSUUID 0x0020
#define IMA_INMASK 0x0040
#define IMA_EUID 0x0080
#define IMA_PCR 0x0100
#define UNKNOWN 0
#define MEASURE 0x0001 /* same as IMA_MEASURE */
@@ -40,6 +41,9 @@
#define DONT_APPRAISE 0x0008
#define AUDIT 0x0040
#define INVALID_PCR(a) (((a) < 0) || \
(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8))
int ima_policy_flag;
static int temp_ima_appraise;
@@ -60,6 +64,7 @@ struct ima_rule_entry {
u8 fsuuid[16];
kuid_t uid;
kuid_t fowner;
int pcr;
struct {
void *rule; /* LSM file metadata specific */
void *args_p; /* audit value */
@@ -319,6 +324,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @inode: pointer to an inode for which the policy decision is being made
* @func: IMA hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
* @pcr: set the pcr to extend
*
* Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
* conditions.
@@ -328,7 +334,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* than writes so ima_match_policy() is classical RCU candidate.
*/
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags)
int flags, int *pcr)
{
struct ima_rule_entry *entry;
int action = 0, actmask = flags | (flags << 1);
@@ -353,6 +359,9 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
else
actmask &= ~(entry->action | entry->action >> 1);
if ((pcr) && (entry->flags & IMA_PCR))
*pcr = entry->pcr;
if (!actmask)
break;
}
@@ -478,7 +487,8 @@ enum {
Opt_subj_user, Opt_subj_role, Opt_subj_type,
Opt_func, Opt_mask, Opt_fsmagic,
Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner,
Opt_appraise_type, Opt_permit_directio
Opt_appraise_type, Opt_permit_directio,
Opt_pcr
};
static match_table_t policy_tokens = {
@@ -502,6 +512,7 @@ static match_table_t policy_tokens = {
{Opt_fowner, "fowner=%s"},
{Opt_appraise_type, "appraise_type=%s"},
{Opt_permit_directio, "permit_directio"},
{Opt_pcr, "pcr=%s"},
{Opt_err, NULL}
};
@@ -773,6 +784,20 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
break;
case Opt_permit_directio:
entry->flags |= IMA_PERMIT_DIRECTIO;
break;
case Opt_pcr:
if (entry->action != MEASURE) {
result = -EINVAL;
break;
}
ima_log_string(ab, "pcr", args[0].from);
result = kstrtoint(args[0].from, 10, &entry->pcr);
if (result || INVALID_PCR(entry->pcr))
result = -EINVAL;
else
entry->flags |= IMA_PCR;
break;
case Opt_err:
ima_log_string(ab, "UNKNOWN", p);
@@ -1011,6 +1036,12 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, " ");
}
if (entry->flags & IMA_PCR) {
snprintf(tbuf, sizeof(tbuf), "%d", entry->pcr);
seq_printf(m, pt(Opt_pcr), tbuf);
seq_puts(m, " ");
}
if (entry->flags & IMA_FSUUID) {
seq_printf(m, "fsuuid=%pU", entry->fsuuid);
seq_puts(m, " ");
+7 -6
View File
@@ -44,7 +44,8 @@ struct ima_h_table ima_htable = {
static DEFINE_MUTEX(ima_extend_list_mutex);
/* lookup up the digest value in the hash table, and return the entry */
static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
int pcr)
{
struct ima_queue_entry *qe, *ret = NULL;
unsigned int key;
@@ -54,7 +55,7 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
rcu_read_lock();
hlist_for_each_entry_rcu(qe, &ima_htable.queue[key], hnext) {
rc = memcmp(qe->entry->digest, digest_value, TPM_DIGEST_SIZE);
if (rc == 0) {
if ((rc == 0) && (qe->entry->pcr == pcr)) {
ret = qe;
break;
}
@@ -89,14 +90,14 @@ static int ima_add_digest_entry(struct ima_template_entry *entry)
return 0;
}
static int ima_pcr_extend(const u8 *hash)
static int ima_pcr_extend(const u8 *hash, int pcr)
{
int result = 0;
if (!ima_used_chip)
return result;
result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
result = tpm_pcr_extend(TPM_ANY_NUM, pcr, hash);
if (result != 0)
pr_err("Error Communicating to TPM chip, result: %d\n", result);
return result;
@@ -118,7 +119,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
mutex_lock(&ima_extend_list_mutex);
if (!violation) {
memcpy(digest, entry->digest, sizeof(digest));
if (ima_lookup_digest_entry(digest)) {
if (ima_lookup_digest_entry(digest, entry->pcr)) {
audit_cause = "hash_exists";
result = -EEXIST;
goto out;
@@ -135,7 +136,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
if (violation) /* invalidate pcr */
memset(digest, 0xff, sizeof(digest));
tpmresult = ima_pcr_extend(digest);
tpmresult = ima_pcr_extend(digest, entry->pcr);
if (tpmresult != 0) {
snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
tpmresult);
+1
View File
@@ -103,6 +103,7 @@ struct integrity_iint_cache {
struct inode *inode; /* back pointer to inode in question */
u64 version; /* track inode changes */
unsigned long flags;
unsigned long measured_pcrs;
enum integrity_status ima_file_status:4;
enum integrity_status ima_mmap_status:4;
enum integrity_status ima_bprm_status:4;