Commit 88265322 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull security subsystem updates from James Morris:
 "Highlights:

   - Integrity: add local fs integrity verification to detect offline
     attacks
   - Integrity: add digital signature verification
   - Simple stacking of Yama with other LSMs (per LSS discussions)
   - IBM vTPM support on ppc64
   - Add new driver for Infineon I2C TIS TPM
   - Smack: add rule revocation for subject labels"

Fixed conflicts with the user namespace support in kernel/auditsc.c and
security/integrity/ima/ima_policy.c.

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (39 commits)
  Documentation: Update git repository URL for Smack userland tools
  ima: change flags container data type
  Smack: setprocattr memory leak fix
  Smack: implement revoking all rules for a subject label
  Smack: remove task_wait() hook.
  ima: audit log hashes
  ima: generic IMA action flag handling
  ima: rename ima_must_appraise_or_measure
  audit: export audit_log_task_info
  tpm: fix tpm_acpi sparse warning on different address spaces
  samples/seccomp: fix 31 bit build on s390
  ima: digital signature verification support
  ima: add support for different security.ima data types
  ima: add ima_inode_setxattr/removexattr function and calls
  ima: add inode_post_setattr call
  ima: replace iint spinblock with rwlock/read_lock
  ima: allocating iint improvements
  ima: add appraise action keywords and default rules
  ima: integrity appraisal extension
  vfs: move ima_file_free before releasing the file
  ...
parents 65b99c74 bf530834
......@@ -12,11 +12,14 @@ Description:
then closing the file. The new policy takes effect after
the file ima/policy is closed.
IMA appraisal, if configured, uses these file measurements
for local measurement appraisal.
rule format: action [condition ...]
action: measure | dont_measure
action: measure | dont_measure | appraise | dont_appraise | audit
condition:= base | lsm
base: [[func=] [mask=] [fsmagic=] [uid=]]
base: [[func=] [mask=] [fsmagic=] [uid=] [fowner]]
lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]]
......@@ -24,36 +27,50 @@ Description:
mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
fsmagic:= hex value
uid:= decimal value
fowner:=decimal value
lsm: are LSM specific
default policy:
# PROC_SUPER_MAGIC
dont_measure fsmagic=0x9fa0
dont_appraise fsmagic=0x9fa0
# SYSFS_MAGIC
dont_measure fsmagic=0x62656572
dont_appraise fsmagic=0x62656572
# DEBUGFS_MAGIC
dont_measure fsmagic=0x64626720
dont_appraise fsmagic=0x64626720
# TMPFS_MAGIC
dont_measure fsmagic=0x01021994
dont_appraise fsmagic=0x01021994
# RAMFS_MAGIC
dont_measure fsmagic=0x858458f6
dont_appraise fsmagic=0x858458f6
# SECURITYFS_MAGIC
dont_measure fsmagic=0x73636673
dont_appraise fsmagic=0x73636673
measure func=BPRM_CHECK
measure func=FILE_MMAP mask=MAY_EXEC
measure func=FILE_CHECK mask=MAY_READ uid=0
appraise fowner=0
The default policy measures all executables in bprm_check,
all files mmapped executable in file_mmap, and all files
open for read by root in do_filp_open.
open for read by root in do_filp_open. The default appraisal
policy appraises all files owned by root.
Examples of LSM specific definitions:
SELinux:
# SELINUX_MAGIC
dont_measure fsmagic=0xF97CFF8C
dont_measure fsmagic=0xf97cff8c
dont_appraise fsmagic=0xf97cff8c
dont_measure obj_type=var_log_t
dont_appraise obj_type=var_log_t
dont_measure obj_type=auditd_log_t
dont_appraise obj_type=auditd_log_t
measure subj_user=system_u func=FILE_CHECK mask=MAY_READ
measure subj_role=system_r func=FILE_CHECK mask=MAY_READ
......
What: /sys/devices/pnp0/<bus-num>/ppi/
Date: August 2012
Kernel Version: 3.6
Contact: xiaoyan.zhang@intel.com
Description:
This folder includes the attributes related with PPI (Physical
Presence Interface). Only if TPM is supported by BIOS, this
folder makes sence. The folder path can be got by command
'find /sys/ -name 'pcrs''. For the detail information of PPI,
please refer to the PPI specification from
http://www.trustedcomputinggroup.org/
What: /sys/devices/pnp0/<bus-num>/ppi/version
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
This attribute shows the version of the PPI supported by the
platform.
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/request
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
This attribute shows the request for an operation to be
executed in the pre-OS environment. It is the only input from
the OS to the pre-OS environment. The request should be an
integer value range from 1 to 160, and 0 means no request.
This file can be read and written.
What: /sys/devices/pnp0/00:<bus-num>/ppi/response
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
This attribute shows the response to the most recent operation
request it acted upon. The format is "<request> <response num>
: <response description>".
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/transition_action
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
This attribute shows the platform-specific action that should
take place in order to transition to the BIOS for execution of
a requested operation. The format is "<action num>: <action
description>".
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/tcg_operations
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
This attribute shows whether it is allowed to request an
operation to be executed in the pre-OS environment by the BIOS
for the requests defined by TCG, i.e. requests from 1 to 22.
The format is "<request> <status num>: <status description>".
This attribute is only supported by PPI version 1.2+.
This file is readonly.
What: /sys/devices/pnp0/<bus-num>/ppi/vs_operations
Date: August 2012
Contact: xiaoyan.zhang@intel.com
Description:
This attribute shows whether it is allowed to request an
operation to be executed in the pre-OS environment by the BIOS
for the verdor specific requests, i.e. requests from 128 to
255. The format is same with tcg_operations. This attribute
is also only supported by PPI version 1.2+.
This file is readonly.
......@@ -1051,6 +1051,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
ihash_entries= [KNL]
Set number of hash buckets for inode cache.
ima_appraise= [IMA] appraise integrity measurements
Format: { "off" | "enforce" | "fix" }
default: "enforce"
ima_appraise_tcb [IMA]
The builtin appraise policy appraises all files
owned by uid=0.
ima_audit= [IMA]
Format: { "0" | "1" }
0 -- integrity auditing messages. (Default)
......
......@@ -28,12 +28,11 @@ Smack kernels use the CIPSO IP option. Some network
configurations are intolerant of IP options and can impede
access to systems that use them as Smack does.
The current git repositories for Smack user space are:
The current git repository for Smack user space is:
git@gitorious.org:meego-platform-security/smackutil.git
git@gitorious.org:meego-platform-security/libsmack.git
git://github.com/smack-team/smack.git
These should make and install on most modern distributions.
This should make and install on most modern distributions.
There are three commands included in smackutil:
smackload - properly formats data for writing to /smack/load
......@@ -194,6 +193,9 @@ onlycap
these capabilities are effective at for processes with any
label. The value is set by writing the desired label to the
file or cleared by writing "-" to the file.
revoke-subject
Writing a Smack label here sets the access to '-' for all access
rules with that subject label.
You can add access rules in /etc/smack/accesses. They take the form:
......
......@@ -1623,6 +1623,63 @@ static void __init prom_instantiate_rtas(void)
}
#ifdef CONFIG_PPC64
/*
* Allocate room for and instantiate Stored Measurement Log (SML)
*/
static void __init prom_instantiate_sml(void)
{
phandle ibmvtpm_node;
ihandle ibmvtpm_inst;
u32 entry = 0, size = 0;
u64 base;
prom_debug("prom_instantiate_sml: start...\n");
ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/ibm,vtpm"));
prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node);
if (!PHANDLE_VALID(ibmvtpm_node))
return;
ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/ibm,vtpm"));
if (!IHANDLE_VALID(ibmvtpm_inst)) {
prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
return;
}
if (call_prom_ret("call-method", 2, 2, &size,
ADDR("sml-get-handover-size"),
ibmvtpm_inst) != 0 || size == 0) {
prom_printf("SML get handover size failed\n");
return;
}
base = alloc_down(size, PAGE_SIZE, 0);
if (base == 0)
prom_panic("Could not allocate memory for sml\n");
prom_printf("instantiating sml at 0x%x...", base);
if (call_prom_ret("call-method", 4, 2, &entry,
ADDR("sml-handover"),
ibmvtpm_inst, size, base) != 0 || entry == 0) {
prom_printf("SML handover failed\n");
return;
}
prom_printf(" done\n");
reserve_mem(base, size);
prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-base",
&base, sizeof(base));
prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-size",
&size, sizeof(size));
prom_debug("sml base = 0x%x\n", base);
prom_debug("sml size = 0x%x\n", (long)size);
prom_debug("prom_instantiate_sml: end...\n");
}
/*
* Allocate room for and initialize TCE tables
*/
......@@ -2916,6 +2973,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
prom_instantiate_opal();
#endif
#ifdef CONFIG_PPC64
/* instantiate sml */
prom_instantiate_sml();
#endif
/*
* On non-powermacs, put all CPUs in spin-loops.
*
......
......@@ -289,3 +289,16 @@ config HW_RANDOM_EXYNOS
module will be called exynos-rng.
If unsure, say Y.
config HW_RANDOM_TPM
tristate "TPM HW Random Number Generator support"
depends on HW_RANDOM && TCG_TPM
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator in the Trusted Platform Module
To compile this driver as a module, choose M here: the
module will be called tpm-rng.
If unsure, say Y.
......@@ -25,3 +25,4 @@ obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
/*
* Copyright (C) 2012 Kent Yoder IBM Corporation
*
* HWRNG interfaces to pull RNG data from a TPM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/hw_random.h>
#include <linux/tpm.h>
#define MODULE_NAME "tpm-rng"
static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
return tpm_get_random(TPM_ANY_NUM, data, max);
}
static struct hwrng tpm_rng = {
.name = MODULE_NAME,
.read = tpm_rng_read,
};
static int __init rng_init(void)
{
return hwrng_register(&tpm_rng);
}
module_init(rng_init);
static void __exit rng_exit(void)
{
hwrng_unregister(&tpm_rng);
}
module_exit(rng_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("RNG driver for TPM devices");
......@@ -33,6 +33,17 @@ config TCG_TIS
from within Linux. To compile this driver as a module, choose
M here; the module will be called tpm_tis.
config TCG_TIS_I2C_INFINEON
tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)"
depends on I2C
---help---
If you have a TPM security chip that is compliant with the
TCG TIS 1.2 TPM specification and Infineon's I2C Protocol Stack
Specification 0.20 say Yes and it will be accessible from within
Linux.
To compile this driver as a module, choose M here; the module
will be called tpm_tis_i2c_infineon.
config TCG_NSC
tristate "National Semiconductor TPM Interface"
depends on X86
......@@ -62,4 +73,12 @@ config TCG_INFINEON
Further information on this driver and the supported hardware
can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/
config TCG_IBMVTPM
tristate "IBM VTPM Interface"
depends on PPC64
---help---
If you have IBM virtual TPM (VTPM) support say Yes and it
will be accessible from within Linux. To compile this driver
as a module, choose M here; the module will be called tpm_ibmvtpm.
endif # TCG_TPM
......@@ -4,8 +4,16 @@
obj-$(CONFIG_TCG_TPM) += tpm.o
ifdef CONFIG_ACPI
obj-$(CONFIG_TCG_TPM) += tpm_bios.o
tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o
else
ifdef CONFIG_TCG_IBMVTPM
obj-$(CONFIG_TCG_TPM) += tpm_bios.o
tpm_bios-objs += tpm_eventlog.o tpm_of.o
endif
endif
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
......@@ -30,12 +30,7 @@
#include <linux/freezer.h>
#include "tpm.h"
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 4096,
TPM_NUM_DEVICES = 256,
};
#include "tpm_eventlog.h"
enum tpm_duration {
TPM_SHORT = 0,
......@@ -482,6 +477,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
#define TPM_INTERNAL_RESULT_SIZE 200
#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
#define TPM_ORD_GET_CAP cpu_to_be32(101)
#define TPM_ORD_GET_RANDOM cpu_to_be32(70)
static const struct tpm_input_header tpm_getcap_header = {
.tag = TPM_TAG_RQU_COMMAND,
......@@ -919,7 +915,7 @@ EXPORT_SYMBOL_GPL(tpm_show_pcrs);
#define READ_PUBEK_RESULT_SIZE 314
#define TPM_ORD_READPUBEK cpu_to_be32(124)
struct tpm_input_header tpm_readpubek_header = {
static struct tpm_input_header tpm_readpubek_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(30),
.ordinal = TPM_ORD_READPUBEK
......@@ -1175,7 +1171,7 @@ int tpm_release(struct inode *inode, struct file *file)
flush_work(&chip->work);
file->private_data = NULL;
atomic_set(&chip->data_pending, 0);
kfree(chip->data_buffer);
kzfree(chip->data_buffer);
clear_bit(0, &chip->is_open);
put_device(chip->dev);
return 0;
......@@ -1227,7 +1223,6 @@ ssize_t tpm_read(struct file *file, char __user *buf,
del_singleshot_timer_sync(&chip->user_read_timer);
flush_work(&chip->work);
ret_size = atomic_read(&chip->data_pending);
atomic_set(&chip->data_pending, 0);
if (ret_size > 0) { /* relay data */
ssize_t orig_ret_size = ret_size;
if (size < ret_size)
......@@ -1242,6 +1237,8 @@ ssize_t tpm_read(struct file *file, char __user *buf,
mutex_unlock(&chip->buffer_mutex);
}
atomic_set(&chip->data_pending, 0);
return ret_size;
}
EXPORT_SYMBOL_GPL(tpm_read);
......@@ -1326,6 +1323,58 @@ int tpm_pm_resume(struct device *dev)
}
EXPORT_SYMBOL_GPL(tpm_pm_resume);
#define TPM_GETRANDOM_RESULT_SIZE 18
static struct tpm_input_header tpm_getrandom_header = {
.tag = TPM_TAG_RQU_COMMAND,
.length = cpu_to_be32(14),
.ordinal = TPM_ORD_GET_RANDOM
};
/**
* tpm_get_random() - Get random bytes from the tpm's RNG
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
* @out: destination buffer for the random bytes
* @max: the max number of bytes to write to @out
*
* Returns < 0 on error and the number of bytes read on success
*/
int tpm_get_random(u32 chip_num, u8 *out, size_t max)
{
struct tpm_chip *chip;
struct tpm_cmd_t tpm_cmd;
u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
int err, total = 0, retries = 5;
u8 *dest = out;
chip = tpm_chip_find_get(chip_num);
if (chip == NULL)
return -ENODEV;
if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
return -EINVAL;
do {
tpm_cmd.header.in = tpm_getrandom_header;
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
err = transmit_cmd(chip, &tpm_cmd,
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
"attempting get random");
if (err)
break;
recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd);
dest += recd;
total += recd;
num_bytes -= recd;
} while (retries-- && total < max);
return total ? total : -EIO;
}
EXPORT_SYMBOL_GPL(tpm_get_random);
/* In case vendor provided release function, call it too.*/
void tpm_dev_vendor_release(struct tpm_chip *chip)
......@@ -1346,7 +1395,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
* Once all references to platform device are down to 0,
* release all allocated structures.
*/
void tpm_dev_release(struct device *dev)
static void tpm_dev_release(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
......@@ -1427,6 +1476,11 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
goto put_device;
}
if (sys_add_ppi(&dev->kobj)) {
misc_deregister(&chip->vendor.miscdev);
goto put_device;
}
chip->bios_dir = tpm_bios_log_setup(devname);
/* Make chip available */
......
......@@ -28,6 +28,12 @@
#include <linux/io.h>
#include <linux/tpm.h>
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 4096,
TPM_NUM_DEVICES = 256,
};
enum tpm_timeout {
TPM_TIMEOUT = 5, /* msecs */
};
......@@ -94,6 +100,7 @@ struct tpm_vendor_specific {
bool timeout_adjusted;
unsigned long duration[3]; /* jiffies */
bool duration_adjusted;
void *data;
wait_queue_head_t read_queue;
wait_queue_head_t int_queue;
......@@ -269,6 +276,21 @@ struct tpm_pcrextend_in {
u8 hash[TPM_DIGEST_SIZE];
}__attribute__((packed));
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
* bytes, but 128 is still a relatively large number of random bytes and
* anything much bigger causes users of struct tpm_cmd_t to start getting
* compiler warnings about stack frame size. */
#define TPM_MAX_RNG_DATA 128
struct tpm_getrandom_out {
__be32 rng_data_len;
u8 rng_data[TPM_MAX_RNG_DATA];
}__attribute__((packed));
struct tpm_getrandom_in {
__be32 num_bytes;
}__attribute__((packed));
typedef union {
struct tpm_getcap_params_out getcap_out;
struct tpm_readpubek_params_out readpubek_out;
......@@ -277,6 +299,8 @@ typedef union {
struct tpm_pcrread_in pcrread_in;
struct tpm_pcrread_out pcrread_out;
struct tpm_pcrextend_in pcrextend_in;
struct tpm_getrandom_in getrandom_in;
struct tpm_getrandom_out getrandom_out;
} tpm_cmd_params;
struct tpm_cmd_t {
......@@ -303,15 +327,12 @@ extern int tpm_pm_suspend(struct device *);
extern int tpm_pm_resume(struct device *);
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
wait_queue_head_t *);
#ifdef CONFIG_ACPI
extern struct dentry ** tpm_bios_log_setup(char *);
extern void tpm_bios_log_teardown(struct dentry **);
extern ssize_t sys_add_ppi(struct kobject *parent);
#else
static inline struct dentry ** tpm_bios_log_setup(char *name)
{
return NULL;
}
static inline void tpm_bios_log_teardown(struct dentry **dir)
static inline ssize_t sys_add_ppi(struct kobject *parent)
{
return 0;
}
#endif
/*
* Copyright (C) 2005 IBM Corporation
*
* Authors:
* Seiji Munetoh <munetoh@jp.ibm.com>
* Stefan Berger <stefanb@us.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Access to the eventlog extended by the TCG BIOS of PC platform
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/seq_file.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <acpi/acpi.h>
#include "tpm.h"
#include "tpm_eventlog.h"
struct acpi_tcpa {
struct acpi_table_header hdr;
u16 platform_class;
union {
struct client_hdr {
u32 log_max_len __attribute__ ((packed));
u64 log_start_addr __attribute__ ((packed));
} client;
struct server_hdr {
u16 reserved;
u64 log_max_len __attribute__ ((packed));
u64 log_start_addr __attribute__ ((packed));
} server;
};
};
/* read binary bios log */
int read_log(struct tpm_bios_log *log)
{
struct acpi_tcpa *buff;
acpi_status status;
void __iomem *virt;
u64 len, start;
if (log->bios_event_log != NULL) {
printk(KERN_ERR
"%s: ERROR - Eventlog already initialized\n",
__func__);
return -EFAULT;
}
/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
status = acpi_get_table(ACPI_SIG_TCPA, 1,
(struct acpi_table_header **)&buff);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
__func__);
return -EIO;
}
switch(buff->platform_class) {
case BIOS_SERVER:
len = buff->server.log_max_len;
start = buff->server.log_start_addr;
break;
case BIOS_CLIENT:
default:
len = buff->client.log_max_len;
start = buff->client.log_start_addr;
break;
}
if (!len) {
printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
return -EIO;
}
/* malloc EventLog space */
log->bios_event_log = kmalloc(len, GFP_KERNEL);
if (!log->bios_event_log) {
printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
__func__);
return -ENOMEM;
}
log->bios_event_log_end = log->bios_event_log + len;
virt = acpi_os_map_memory(start, len);
if (!virt) {
kfree(log->bios_event_log);
printk("%s: ERROR - Unable to map memory\n", __func__);
return -EIO;
}
memcpy_fromio(log->bios_event_log, virt, len);
acpi_os_unmap_memory(virt, len);
return 0;
}
/*
* Copyright (C) 2005 IBM Corporation
* Copyright (C) 2005, 2012 IBM Corporation
*
* Authors:
* Kent Yoder <key@linux.vnet.ibm.com>
* Seiji Munetoh <munetoh@jp.ibm.com>
* Stefan Berger <stefanb@us.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
......@@ -9,7 +10,7 @@
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Access to the eventlog extended by the TCG BIOS of PC platform
* Access to the eventlog created by a system's firmware / BIOS
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -23,67 +24,10 @@
#include <linux/security.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <acpi/acpi.h>
#include "tpm.h"
#define TCG_EVENT_NAME_LEN_MAX 255
#define MAX_TEXT_EVENT 1000 /* Max event string length */
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
enum bios_platform_class {
BIOS_CLIENT = 0x00,
BIOS_SERVER = 0x01,
};
struct tpm_bios_log {
void *bios_event_log;
void *bios_event_log_end;
};
struct acpi_tcpa {
struct acpi_table_header hdr;
u16 platform_class;
union {
struct client_hdr {
u32 log_max_len __attribute__ ((packed));
u64 log_start_addr __attribute__ ((packed));
} client;
struct server_hdr {
u16 reserved;
u64 log_max_len __attribute__ ((packed));
u64 log_start_addr __attribute__ ((packed));
} server;
};
};
struct tcpa_event {
u32 pcr_index;
u32 event_type;
u8 pcr_value[20]; /* SHA1 */
u32 event_size;
u8 event_data[0];
};
#include "tpm.h"
#include "tpm_eventlog.h"
enum tcpa_event_types {
PREBOOT = 0,
POST_CODE,
UNUSED,
NO_ACTION,
SEPARATOR,
ACTION,
EVENT_TAG,
SCRTM_CONTENTS,
SCRTM_VERSION,
CPU_MICROCODE,
PLATFORM_CONFIG_FLAGS,
TABLE_OF_DEVICES,
COMPACT_HASH,
IPL,
IPL_PARTITION_DATA,
NONHOST_CODE,
NONHOST_CONFIG,
NONHOST_INFO,
};
static const char* tcpa_event_type_strings[] = {
"PREBOOT",
......@@ -106,28 +50,6 @@ static const char* tcpa_event_type_strings[] = {
"Non-Host Info"
};
struct tcpa_pc_event {
u32 event_id;
u32 event_size;
u8 event_data[0];
};
enum tcpa_pc_event_ids {
SMBIOS = 1,
BIS_CERT,
POST_BIOS_ROM,
ESCD,
CMOS,
NVRAM,
OPTION_ROM_EXEC,
OPTION_ROM_CONFIG,
OPTION_ROM_MICROCODE = 10,
S_CRTM_VERSION,
S_CRTM_CONTENTS,
POST_CONTENTS,
HOST_TABLE_OF_DEVICES,
};
static const char* tcpa_pc_event_id_strings[] = {
"",
"SMBIOS",
......@@ -358,65 +280,6 @@ static const struct seq_operations tpm_binary_b_measurments_seqops = {
.show = tpm_binary_bios_measurements_show,
};
/* read binary bios log */
static int read_log(struct tpm_bios_log *log)
{
struct acpi_tcpa *buff;
acpi_status status;
struct acpi_table_header *virt;
u64 len, start;
if (log->bios_event_log != NULL) {
printk(KERN_ERR
"%s: ERROR - Eventlog already initialized\n",
__func__);
return -EFAULT;
}
/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
status = acpi_get_table(ACPI_SIG_TCPA, 1,
(struct acpi_table_header **)&buff);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
__func__);
return -EIO;
}
switch(buff->platform_class) {
case BIOS_SERVER:
len = buff->server.log_max_len;
start = buff->server.log_start_addr;
break;
case BIOS_CLIENT:
default:
len = buff->client.log_max_len;
start = buff->client.log_start_addr;
break;
}
if (!len) {
printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
return -EIO;
}
/* malloc EventLog space */
log->bios_event_log = kmalloc(len, GFP_KERNEL);
if (!log->bios_event_log) {
printk("%s: ERROR - Not enough Memory for BIOS measurements\n",
__func__);
return -ENOMEM;
}
log->bios_event_log_end = log->bios_event_log + len;
virt = acpi_os_map_memory(start, len);
memcpy(log->bios_event_log, virt, len);
acpi_os_unmap_memory(virt, len);
return 0;
}
static int tpm_ascii_bios_measurements_open(struct inode *inode,
struct file *file)
{
......
#ifndef __TPM_EVENTLOG_H__
#define __TPM_EVENTLOG_H__
#define TCG_EVENT_NAME_LEN_MAX 255
#define MAX_TEXT_EVENT 1000 /* Max event string length */
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
enum bios_platform_class {
BIOS_CLIENT = 0x00,
BIOS_SERVER = 0x01,
};
struct tpm_bios_log {
void *bios_event_log;
void *bios_event_log_end;
};
struct tcpa_event {
u32 pcr_index;
u32 event_type;
u8 pcr_value[20]; /* SHA1 */
u32 event_size;
u8 event_data[0];
};
enum tcpa_event_types {
PREBOOT = 0,
POST_CODE,
UNUSED,
NO_ACTION,
SEPARATOR,
ACTION,
EVENT_TAG,
SCRTM_CONTENTS,
SCRTM_VERSION,
CPU_MICROCODE,
PLATFORM_CONFIG_FLAGS,
TABLE_OF_DEVICES,
COMPACT_HASH,
IPL,
IPL_PARTITION_DATA,
NONHOST_CODE,
NONHOST_CONFIG,
NONHOST_INFO,
};
struct tcpa_pc_event {
u32 event_id;
u32 event_size;
u8 event_data[0];
};
enum tcpa_pc_event_ids {
SMBIOS = 1,
BIS_CERT,
POST_BIOS_ROM,
ESCD,
CMOS,
NVRAM,
OPTION_ROM_EXEC,
OPTION_ROM_CONFIG,
OPTION_ROM_MICROCODE = 10,
S_CRTM_VERSION,
S_CRTM_CONTENTS,
POST_CONTENTS,
HOST_TABLE_OF_DEVICES,
};
int read_log(struct tpm_bios_log *log);
#if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \
defined(CONFIG_ACPI)
extern struct dentry **tpm_bios_log_setup(char *);
extern void tpm_bios_log_teardown(struct dentry **);
#else
static inline struct dentry **tpm_bios_log_setup(char *name)
{
return NULL;
}
static inline void tpm_bios_log_teardown(struct dentry **dir)
{
}
#endif
#endif
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2012 IBM Corporation
*
* Author: Ashley Lai <adlai@us.ibm.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*
*/
#ifndef __TPM_IBMVTPM_H__
#define __TPM_IBMVTPM_H__
/* vTPM Message Format 1 */
struct ibmvtpm_crq {
u8 valid;
u8 msg;
u16 len;
u32 data;
u64 reserved;
} __attribute__((packed, aligned(8)));
struct ibmvtpm_crq_queue {
struct ibmvtpm_crq *crq_addr;
u32 index;
u32 num_entry;
};
struct ibmvtpm_dev {
struct device *dev;
struct vio_dev *vdev;
struct ibmvtpm_crq_queue crq_queue;
dma_addr_t crq_dma_handle;
spinlock_t lock;
struct tasklet_struct tasklet;
u32 rtce_size;
void __iomem *rtce_buf;
dma_addr_t rtce_dma_handle;
spinlock_t rtce_lock;
struct ibmvtpm_crq crq_res;
u32 vtpm_version;
};
#define CRQ_RES_BUF_SIZE PAGE_SIZE
/* Initialize CRQ */
#define INIT_CRQ_CMD 0xC001000000000000LL /* Init cmd */
#define INIT_CRQ_COMP_CMD 0xC002000000000000LL /* Init complete cmd */
#define INIT_CRQ_RES 0x01 /* Init respond */
#define INIT_CRQ_COMP_RES 0x02 /* Init complete respond */
#define VALID_INIT_CRQ 0xC0 /* Valid command for init crq */
/* vTPM CRQ response is the message type | 0x80 */
#define VTPM_MSG_RES 0x80
#define IBMVTPM_VALID_CMD 0x80
/* vTPM CRQ message types */
#define VTPM_GET_VERSION 0x01
#define VTPM_GET_VERSION_RES (0x01 | VTPM_MSG_RES)
#define VTPM_TPM_COMMAND 0x02
#define VTPM_TPM_COMMAND_RES (0x02 | VTPM_MSG_RES)
#define VTPM_GET_RTCE_BUFFER_SIZE 0x03
#define VTPM_GET_RTCE_BUFFER_SIZE_RES (0x03 | VTPM_MSG_RES)
#define VTPM_PREPARE_TO_SUSPEND 0x04
#define VTPM_PREPARE_TO_SUSPEND_RES (0x04 | VTPM_MSG_RES)
#endif
/*
* Copyright 2012 IBM Corporation
*
* Author: Ashley Lai <adlai@us.ibm.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Read the event log created by the firmware on PPC64
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/slab.h>
#include <linux/of.h>
#include "tpm.h"
#include "tpm_eventlog.h"
int read_log(struct tpm_bios_log *log)
{
struct device_node *np;
const u32 *sizep;
const __be64 *basep;
if (log->bios_event_log != NULL) {
pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
return -EFAULT;
}
np = of_find_node_by_name(NULL, "ibm,vtpm");
if (!np) {
pr_err("%s: ERROR - IBMVTPM not supported\n", __func__);
return -ENODEV;
}
sizep = of_get_property(np, "linux,sml-size", NULL);
if (sizep == NULL) {
pr_err("%s: ERROR - SML size not found\n", __func__);
goto cleanup_eio;
}
if (*sizep == 0) {
pr_err("%s: ERROR - event log area empty\n", __func__);
goto cleanup_eio;
}
basep = of_get_property(np, "linux,sml-base", NULL);
if (basep == NULL) {
pr_err(KERN_ERR "%s: ERROR - SML not found\n", __func__);
goto cleanup_eio;
}
of_node_put(np);
log->bios_event_log = kmalloc(*sizep, GFP_KERNEL);
if (!log->bios_event_log) {
pr_err("%s: ERROR - Not enough memory for BIOS measurements\n",
__func__);
return -ENOMEM;
}
log->bios_event_log_end = log->bios_event_log + *sizep;
memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep);
return 0;
cleanup_eio:
of_node_put(np);
return -EIO;
}
This diff is collapsed.
......@@ -705,6 +705,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
return rc;
}
#if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP)
static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
{
u32 intmask;
......@@ -725,7 +726,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
iowrite32(intmask,
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
}
#endif
#ifdef CONFIG_PNP
static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
......
......@@ -14,6 +14,7 @@
#include <linux/fcntl.h>
#include <linux/security.h>
#include <linux/evm.h>
#include <linux/ima.h>
/**
* inode_change_ok - check if attribute changes to an inode are allowed
......@@ -247,6 +248,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (!error) {
fsnotify_change(dentry, ia_valid);
ima_inode_post_setattr(dentry);
evm_inode_post_setattr(dentry, ia_valid);
}
......
......@@ -243,10 +243,10 @@ static void __fput(struct file *file)
if (file->f_op && file->f_op->fasync)
file->f_op->fasync(-1, file, 0);
}
ima_file_free(file);
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
ima_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL &&
!(file->f_mode & FMODE_PATH))) {
cdev_put(inode->i_cdev);
......
......@@ -296,11 +296,13 @@ vfs_removexattr(struct dentry *dentry, const char *name)
if (error)
return error;
mutex_lock(&inode->i_mutex);
error = security_inode_removexattr(dentry, name);
if (error)
if (error) {
mutex_unlock(&inode->i_mutex);
return error;
}
mutex_lock(&inode->i_mutex);
error = inode->i_op->removexattr(dentry, name);
mutex_unlock(&inode->i_mutex);
......
......@@ -531,6 +531,7 @@ extern int audit_set_loginuid(kuid_t loginuid);
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
extern void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk);
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
extern int __audit_bprm(struct linux_binprm *bprm);
......@@ -642,6 +643,7 @@ extern int audit_signals;
#define audit_get_loginuid(t) (INVALID_UID)
#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
#define audit_log_task_info(b, t) do { ; } while (0)
#define audit_ipc_obj(i) ((void)0)
#define audit_ipc_set_perm(q,u,g,m) ((void)0)
#define audit_bprm(p) ({ 0; })
......
......@@ -39,5 +39,32 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
{
return 0;
}
#endif /* CONFIG_IMA_H */
#ifdef CONFIG_IMA_APPRAISE
extern void ima_inode_post_setattr(struct dentry *dentry);
extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len);
extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name);
#else
static inline void ima_inode_post_setattr(struct dentry *dentry)
{
return;
}
static inline int ima_inode_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len)
{
return 0;
}
static inline int ima_inode_removexattr(struct dentry *dentry,
const char *xattr_name)
{
return 0;
}
#endif /* CONFIG_IMA_APPRAISE_H */
#endif /* _LINUX_IMA_H */
......@@ -22,13 +22,14 @@ enum integrity_status {
/* List of EVM protected security xattrs */
#ifdef CONFIG_INTEGRITY
extern int integrity_inode_alloc(struct inode *inode);
extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
extern void integrity_inode_free(struct inode *inode);
#else
static inline int integrity_inode_alloc(struct inode *inode)
static inline struct integrity_iint_cache *
integrity_inode_get(struct inode *inode)
{
return 0;
return NULL;
}
static inline void integrity_inode_free(struct inode *inode)
......
......@@ -130,8 +130,6 @@ extern void exit_ptrace(struct task_struct *tracer);
#define PTRACE_MODE_READ 0x01
#define PTRACE_MODE_ATTACH 0x02
#define PTRACE_MODE_NOAUDIT 0x04
/* Returns 0 on success, -errno on denial. */
extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
/* Returns true on success, false on denial. */
extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
......
......@@ -3022,5 +3022,36 @@ static inline void free_secdata(void *secdata)
{ }
#endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_YAMA
extern int yama_ptrace_access_check(struct task_struct *child,
unsigned int mode);
extern int yama_ptrace_traceme(struct task_struct *parent);
extern void yama_task_free(struct task_struct *task);
extern int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
#else
static inline int yama_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
return 0;
}
static inline int yama_ptrace_traceme(struct task_struct *parent)
{
return 0;
}
static inline void yama_task_free(struct task_struct *task)
{
}
static inline int yama_task_prctl(int option, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5)
{
return -ENOSYS;
}
#endif /* CONFIG_SECURITY_YAMA */
#endif /* ! __LINUX_SECURITY_H */
......@@ -32,6 +32,7 @@
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
#else
static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
return -ENODEV;
......@@ -42,5 +43,8 @@ static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
return -ENODEV;
}
static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
return -ENODEV;
}
#endif
#endif
......@@ -33,6 +33,9 @@
#define XATTR_EVM_SUFFIX "evm"
#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX
#define XATTR_IMA_SUFFIX "ima"
#define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
......
......@@ -1146,13 +1146,44 @@ void audit_log_task_context(struct audit_buffer *ab)
EXPORT_SYMBOL(audit_log_task_context);
static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
{
const struct cred *cred;
char name[sizeof(tsk->comm)];
struct mm_struct *mm = tsk->mm;
struct vm_area_struct *vma;
char *tty;
if (!ab)
return;
/* tsk == current */
cred = current_cred();
spin_lock_irq(&tsk->sighand->siglock);
if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
tty = tsk->signal->tty->name;
else
tty = "(none)";
spin_unlock_irq(&tsk->sighand->siglock);
audit_log_format(ab,
" ppid=%ld pid=%d auid=%u uid=%u gid=%u"
" euid=%u suid=%u fsuid=%u"
" egid=%u sgid=%u fsgid=%u ses=%u tty=%s",
sys_getppid(),
tsk->pid,
from_kuid(&init_user_ns, tsk->loginuid),
from_kuid(&init_user_ns, cred->uid),
from_kgid(&init_user_ns, cred->gid),
from_kuid(&init_user_ns, cred->euid),
from_kuid(&init_user_ns, cred->suid),
from_kuid(&init_user_ns, cred->fsuid),
from_kgid(&init_user_ns, cred->egid),
from_kgid(&init_user_ns, cred->sgid),
from_kgid(&init_user_ns, cred->fsgid),
tsk->sessionid, tty);
get_task_comm(name, tsk);
audit_log_format(ab, " comm=");
......@@ -1175,6 +1206,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
audit_log_task_context(ab);
}
EXPORT_SYMBOL(audit_log_task_info);
static int audit_log_pid_context(struct audit_context *context, pid_t pid,
kuid_t auid, kuid_t uid, unsigned int sessionid,
u32 sid, char *comm)
......@@ -1580,26 +1613,12 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
const struct cred *cred;
int i, call_panic = 0;
struct audit_buffer *ab;
struct audit_aux_data *aux;
const char *tty;
struct audit_names *n;
/* tsk == current */
context->pid = tsk->pid;
if (!context->ppid)
context->ppid = sys_getppid();
cred = current_cred();
context->uid = cred->uid;
context->gid = cred->gid;
context->euid = cred->euid;
context->suid = cred->suid;
context->fsuid = cred->fsuid;
context->egid = cred->egid;
context->sgid = cred->sgid;
context->fsgid = cred->fsgid;
context->personality = tsk->personality;
ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
......@@ -1614,37 +1633,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
(context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
context->return_code);
spin_lock_irq(&tsk->sighand->siglock);
if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
tty = tsk->signal->tty->name;
else
tty = "(none)";
spin_unlock_irq(&tsk->sighand->siglock);
audit_log_format(ab,
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
" ppid=%d pid=%d auid=%u uid=%u gid=%u"
" euid=%u suid=%u fsuid=%u"
" egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
context->argv[0],
context->argv[1],
context->argv[2],
context->argv[3],
context->name_count,
context->ppid,
context->pid,
from_kuid(&init_user_ns, tsk->loginuid),
from_kuid(&init_user_ns, context->uid),
from_kgid(&init_user_ns, context->gid),
from_kuid(&init_user_ns, context->euid),
from_kuid(&init_user_ns, context->suid),
from_kuid(&init_user_ns, context->fsuid),
from_kgid(&init_user_ns, context->egid),
from_kgid(&init_user_ns, context->sgid),
from_kgid(&init_user_ns, context->fsgid),
tty,
tsk->sessionid);
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d",
context->argv[0],
context->argv[1],
context->argv[2],
context->argv[3],
context->name_count);
audit_log_task_info(ab, tsk);
audit_log_key(ab, context->filterkey);
......
......@@ -180,7 +180,8 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
return has_ns_capability(current, ns, CAP_SYS_PTRACE);
}
int __ptrace_may_access(struct task_struct *task, unsigned int mode)
/* Returns 0 on success, -errno on denial. */
static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
const struct cred *cred = current_cred(), *tcred;
......
......@@ -18,14 +18,22 @@ HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include
bpf-direct-objs := bpf-direct.o
# Try to match the kernel target.
ifeq ($(CONFIG_64BIT),)
HOSTCFLAGS_bpf-direct.o += -m32
HOSTCFLAGS_dropper.o += -m32
HOSTCFLAGS_bpf-helper.o += -m32
HOSTCFLAGS_bpf-fancy.o += -m32
HOSTLOADLIBES_bpf-direct += -m32
HOSTLOADLIBES_bpf-fancy += -m32
HOSTLOADLIBES_dropper += -m32
ifndef CONFIG_64BIT
# s390 has -m31 flag to build 31 bit binaries
ifndef CONFIG_S390
MFLAG = -m32
else
MFLAG = -m31
endif
HOSTCFLAGS_bpf-direct.o += $(MFLAG)
HOSTCFLAGS_dropper.o += $(MFLAG)
HOSTCFLAGS_bpf-helper.o += $(MFLAG)
HOSTCFLAGS_bpf-fancy.o += $(MFLAG)
HOSTLOADLIBES_bpf-direct += $(MFLAG)
HOSTLOADLIBES_bpf-fancy += $(MFLAG)
HOSTLOADLIBES_dropper += $(MFLAG)
endif
# Tell kbuild to always build the programs
......
......@@ -59,6 +59,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count);
#define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label)
#define EXPAND(...) __VA_ARGS__
/* Ensure that we load the logically correct offset. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
#elif __BYTE_ORDER == __BIG_ENDIAN
#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
#else
#error "Unknown endianness"
#endif
/* Map all width-sensitive operations */
#if __BITS_PER_LONG == 32
......@@ -70,21 +80,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count);
#define JLE(x, jt) JLE32(x, EXPAND(jt))
#define JA(x, jt) JA32(x, EXPAND(jt))
#define ARG(i) ARG_32(i)
#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
#elif __BITS_PER_LONG == 64
/* Ensure that we load the logically correct offset. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ENDIAN(_lo, _hi) _lo, _hi
#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define ENDIAN(_lo, _hi) _hi, _lo
#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
#else
#error "Unknown endianness"
#endif
union arg64 {
......
......@@ -33,6 +33,9 @@ char *evm_config_xattrnames[] = {
#endif
#ifdef CONFIG_SECURITY_SMACK
XATTR_NAME_SMACK,
#endif
#ifdef CONFIG_IMA_APPRAISE
XATTR_NAME_IMA,
#endif
XATTR_NAME_CAPS,
NULL
......
......@@ -22,7 +22,7 @@
#include "integrity.h"
static struct rb_root integrity_iint_tree = RB_ROOT;
static DEFINE_SPINLOCK(integrity_iint_lock);
static DEFINE_RWLOCK(integrity_iint_lock);
static struct kmem_cache *iint_cache __read_mostly;
int iint_initialized;
......@@ -35,8 +35,6 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
struct integrity_iint_cache *iint;
struct rb_node *n = integrity_iint_tree.rb_node;
assert_spin_locked(&integrity_iint_lock);
while (n) {
iint = rb_entry(n, struct integrity_iint_cache, rb_node);
......@@ -63,9 +61,9 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
if (!IS_IMA(inode))
return NULL;
spin_lock(&integrity_iint_lock);
read_lock(&integrity_iint_lock);
iint = __integrity_iint_find(inode);
spin_unlock(&integrity_iint_lock);
read_unlock(&integrity_iint_lock);
return iint;
}
......@@ -74,59 +72,53 @@ static void iint_free(struct integrity_iint_cache *iint)
{
iint->version = 0;
iint->flags = 0UL;
iint->ima_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
kmem_cache_free(iint_cache, iint);
}
/**
* integrity_inode_alloc - allocate an iint associated with an inode
* integrity_inode_get - find or allocate an iint associated with an inode
* @inode: pointer to the inode
* @return: allocated iint
*
* Caller must lock i_mutex
*/
int integrity_inode_alloc(struct inode *inode)
struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
{
struct rb_node **p;
struct rb_node *new_node, *parent = NULL;
struct integrity_iint_cache *new_iint, *test_iint;
int rc;
struct rb_node *node, *parent = NULL;
struct integrity_iint_cache *iint, *test_iint;
new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
if (!new_iint)
return -ENOMEM;
iint = integrity_iint_find(inode);
if (iint)
return iint;
new_iint->inode = inode;
new_node = &new_iint->rb_node;
iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
if (!iint)
return NULL;
mutex_lock(&inode->i_mutex); /* i_flags */
spin_lock(&integrity_iint_lock);
write_lock(&integrity_iint_lock);
p = &integrity_iint_tree.rb_node;
while (*p) {
parent = *p;
test_iint = rb_entry(parent, struct integrity_iint_cache,
rb_node);
rc = -EEXIST;
if (inode < test_iint->inode)
p = &(*p)->rb_left;
else if (inode > test_iint->inode)
p = &(*p)->rb_right;
else
goto out_err;
p = &(*p)->rb_right;
}
iint->inode = inode;
node = &iint->rb_node;
inode->i_flags |= S_IMA;
rb_link_node(new_node, parent, p);
rb_insert_color(new_node, &integrity_iint_tree);
rb_link_node(node, parent, p);
rb_insert_color(node, &integrity_iint_tree);
spin_unlock(&integrity_iint_lock);
mutex_unlock(&inode->i_mutex); /* i_flags */
return 0;
out_err:
spin_unlock(&integrity_iint_lock);
mutex_unlock(&inode->i_mutex); /* i_flags */
iint_free(new_iint);
return rc;
write_unlock(&integrity_iint_lock);
return iint;
}
/**
......@@ -142,10 +134,10 @@ void integrity_inode_free(struct inode *inode)
if (!IS_IMA(inode))
return;
spin_lock(&integrity_iint_lock);
write_lock(&integrity_iint_lock);
iint = __integrity_iint_find(inode);
rb_erase(&iint->rb_node, &integrity_iint_tree);
spin_unlock(&integrity_iint_lock);
write_unlock(&integrity_iint_lock);
iint_free(iint);
}
......@@ -157,7 +149,7 @@ static void init_once(void *foo)
memset(iint, 0, sizeof *iint);
iint->version = 0;
iint->flags = 0UL;
mutex_init(&iint->mutex);
iint->ima_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
}
......
......@@ -11,6 +11,7 @@ config IMA
select CRYPTO_SHA1
select TCG_TPM if HAS_IOMEM && !UML
select TCG_TIS if TCG_TPM && X86
select TCG_IBMVTPM if TCG_TPM && PPC64
help
The Trusted Computing Group(TCG) runtime Integrity
Measurement Architecture(IMA) maintains a list of hash
......@@ -55,3 +56,18 @@ config IMA_LSM_RULES
default y
help
Disabling this option will disregard LSM based policy rules.
config IMA_APPRAISE
bool "Appraise integrity measurements"
depends on IMA
default n
help
This option enables local measurement integrity appraisal.
It requires the system to be labeled with a security extended
attribute containing the file hash measurement. To protect
the security extended attributes from offline attack, enable
and configure EVM.
For more information on integrity appraisal refer to:
<http://linux-ima.sourceforge.net>
If unsure, say N.
......@@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o
ima-$(CONFIG_IMA_AUDIT) += ima_audit.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
......@@ -40,6 +40,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
extern int ima_initialized;
extern int ima_used_chip;
extern char *ima_hash;
extern int ima_appraise;
/* IMA inode template definition */
struct ima_template_data {
......@@ -107,11 +108,14 @@ static inline unsigned long ima_hash_key(u8 *digest)
}
/* LIM API function definitions */
int ima_get_action(struct inode *inode, int mask, int function);
int ima_must_measure(struct inode *inode, int mask, int function);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode);
void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show);
......@@ -123,14 +127,45 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK };
enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR };
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask);
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
void ima_init_policy(void);
void ima_update_policy(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename);
int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
#else
static inline int ima_appraise_measurement(struct integrity_iint_cache *iint,
struct file *file,
const unsigned char *filename)
{
return INTEGRITY_UNKNOWN;
}
static inline int ima_must_appraise(struct inode *inode,
enum ima_hooks func, int mask)
{
return 0;
}
static inline void ima_update_xattr(struct integrity_iint_cache *iint,
struct file *file)
{
}
#endif
/* LSM based policy rules require audit */
#ifdef CONFIG_IMA_LSM_RULES
......
......@@ -9,13 +9,17 @@
* License.
*
* File: ima_api.c
* Implements must_measure, collect_measurement, store_measurement,
* and store_template.
* Implements must_appraise_or_measure, collect_measurement,
* appraise_measurement, store_measurement and store_template.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/evm.h>
#include "ima.h"
static const char *IMA_TEMPLATE_NAME = "ima";
/*
......@@ -93,7 +97,7 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
}
/**
* ima_must_measure - measure decision based on policy.
* ima_get_action - appraise & measure decision based on policy.
* @inode: pointer to inode to measure
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
* @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP)
......@@ -105,15 +109,22 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
* mask: contains the permission mask
* fsmagic: hex value
*
* Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
* or other error, return an error code.
*/
int ima_must_measure(struct inode *inode, int mask, int function)
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
int ima_get_action(struct inode *inode, int mask, int function)
{
int must_measure;
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
if (!ima_appraise)
flags &= ~IMA_APPRAISE;
must_measure = ima_match_policy(inode, function, mask);
return must_measure ? 0 : -EACCES;
return ima_match_policy(inode, function, mask, flags);
}
int ima_must_measure(struct inode *inode, int mask, int function)
{
return ima_match_policy(inode, function, mask, IMA_MEASURE);
}
/*
......@@ -129,16 +140,24 @@ int ima_must_measure(struct inode *inode, int mask, int function)
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file)
{
int result = -EEXIST;
struct inode *inode = file->f_dentry->d_inode;
const char *filename = file->f_dentry->d_name.name;
int result = 0;
if (!(iint->flags & IMA_MEASURED)) {
if (!(iint->flags & IMA_COLLECTED)) {
u64 i_version = file->f_dentry->d_inode->i_version;
memset(iint->digest, 0, IMA_DIGEST_SIZE);
result = ima_calc_hash(file, iint->digest);
if (!result)
iint->ima_xattr.type = IMA_XATTR_DIGEST;
result = ima_calc_hash(file, iint->ima_xattr.digest);
if (!result) {
iint->version = i_version;
iint->flags |= IMA_COLLECTED;
}
}
if (result)
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
filename, "collect_data", "failed",
result, 0);
return result;
}
......@@ -167,6 +186,9 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
struct ima_template_entry *entry;
int violation = 0;
if (iint->flags & IMA_MEASURED)
return;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
......@@ -174,7 +196,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
return;
}
memset(&entry->template, 0, sizeof(entry->template));
memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
memcpy(entry->template.digest, iint->ima_xattr.digest, IMA_DIGEST_SIZE);
strcpy(entry->template.file_name,
(strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
file->f_dentry->d_name.name : filename);
......@@ -185,3 +207,33 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
if (result < 0)
kfree(entry);
}
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename)
{
struct audit_buffer *ab;
char hash[(IMA_DIGEST_SIZE * 2) + 1];
int i;
if (iint->flags & IMA_AUDITED)
return;
for (i = 0; i < IMA_DIGEST_SIZE; i++)
hex_byte_pack(hash + (i * 2), iint->ima_xattr.digest[i]);
hash[i * 2] = '\0';
ab = audit_log_start(current->audit_context, GFP_KERNEL,
AUDIT_INTEGRITY_RULE);
if (!ab)
return;
audit_log_format(ab, "file=");
audit_log_untrustedstring(ab, filename);
audit_log_format(ab, " hash=");
audit_log_untrustedstring(ab, hash);
audit_log_task_info(ab, current);
audit_log_end(ab);
iint->flags |= IMA_AUDITED;
}
/*
* Copyright (C) 2011 IBM Corporation
*
* Author:
* Mimi Zohar <zohar@us.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*/
#include <linux/module.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/magic.h>
#include <linux/ima.h>
#include <linux/evm.h>
#include "ima.h"
static int __init default_appraise_setup(char *str)
{
if (strncmp(str, "off", 3) == 0)
ima_appraise = 0;
else if (strncmp(str, "fix", 3) == 0)
ima_appraise = IMA_APPRAISE_FIX;
return 1;
}
__setup("ima_appraise=", default_appraise_setup);
/*
* ima_must_appraise - set appraise flag
*
* Return 1 to appraise
*/
int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask)
{
if (!ima_appraise)
return 0;
return ima_match_policy(inode, func, mask, IMA_APPRAISE);
}
static void ima_fix_xattr(struct dentry *dentry,
struct integrity_iint_cache *iint)
{
iint->ima_xattr.type = IMA_XATTR_DIGEST;
__vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, (u8 *)&iint->ima_xattr,
sizeof iint->ima_xattr, 0);
}
/*
* 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(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
struct evm_ima_xattr_data *xattr_value = NULL;
enum integrity_status status = INTEGRITY_UNKNOWN;
const char *op = "appraise_data";
char *cause = "unknown";
int rc;
if (!ima_appraise)
return 0;
if (!inode->i_op->getxattr)
return INTEGRITY_UNKNOWN;
if (iint->flags & IMA_APPRAISED)
return iint->ima_status;
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value,
0, GFP_NOFS);
if (rc <= 0) {
if (rc && rc != -ENODATA)
goto out;
cause = "missing-hash";
status =
(inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
goto out;
}
status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) {
if ((status == INTEGRITY_NOLABEL)
|| (status == INTEGRITY_NOXATTRS))
cause = "missing-HMAC";
else if (status == INTEGRITY_FAIL)
cause = "invalid-HMAC";
goto out;
}
switch (xattr_value->type) {
case IMA_XATTR_DIGEST:
rc = memcmp(xattr_value->digest, iint->ima_xattr.digest,
IMA_DIGEST_SIZE);
if (rc) {
cause = "invalid-hash";
status = INTEGRITY_FAIL;
print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE,
xattr_value, sizeof(*xattr_value));
print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE,
(u8 *)&iint->ima_xattr,
sizeof iint->ima_xattr);
break;
}
status = INTEGRITY_PASS;
break;
case EVM_IMA_XATTR_DIGSIG:
iint->flags |= IMA_DIGSIG;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
xattr_value->digest, rc - 1,
iint->ima_xattr.digest,
IMA_DIGEST_SIZE);
if (rc == -EOPNOTSUPP) {
status = INTEGRITY_UNKNOWN;
} else if (rc) {
cause = "invalid-signature";
status = INTEGRITY_FAIL;
} else {
status = INTEGRITY_PASS;
}
break;
default:
status = INTEGRITY_UNKNOWN;
cause = "unknown-ima-data";
break;
}
out:
if (status != INTEGRITY_PASS) {
if ((ima_appraise & IMA_APPRAISE_FIX) &&
(!xattr_value ||
xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
ima_fix_xattr(dentry, iint);
status = INTEGRITY_PASS;
}
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
op, cause, rc, 0);
} else {
iint->flags |= IMA_APPRAISED;
}
iint->ima_status = status;
kfree(xattr_value);
return status;
}
/*
* ima_update_xattr - update 'security.ima' hash value
*/
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
{
struct dentry *dentry = file->f_dentry;
int rc = 0;
/* do not collect and update hash for digital signatures */
if (iint->flags & IMA_DIGSIG)
return;
rc = ima_collect_measurement(iint, file);
if (rc < 0)
return;
ima_fix_xattr(dentry, iint);
}
/**
* ima_inode_post_setattr - reflect file metadata changes
* @dentry: pointer to the affected dentry
*
* 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.
*/
void ima_inode_post_setattr(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
struct integrity_iint_cache *iint;
int must_appraise, rc;
if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
|| !inode->i_op->removexattr)
return;
must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
iint = integrity_iint_find(inode);
if (iint) {
if (must_appraise)
iint->flags |= IMA_APPRAISE;
else
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED);
}
if (!must_appraise)
rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
return;
}
/*
* 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;
}
static void ima_reset_appraise_flags(struct inode *inode)
{
struct integrity_iint_cache *iint;
if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode))
return;
iint = integrity_iint_find(inode);
if (!iint)
return;
iint->flags &= ~IMA_DONE_MASK;
return;
}
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
int result;
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
if (result == 1) {
ima_reset_appraise_flags(dentry->d_inode);
result = 0;
}
return result;
}
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1) {
ima_reset_appraise_flags(dentry->d_inode);
result = 0;
}
return result;
}
......@@ -48,7 +48,7 @@ int ima_calc_hash(struct file *file, char *digest)
struct scatterlist sg[1];
loff_t i_size, offset = 0;
char *rbuf;
int rc;
int rc, read = 0;
rc = init_desc(&desc);
if (rc != 0)
......@@ -59,6 +59,10 @@ int ima_calc_hash(struct file *file, char *digest)
rc = -ENOMEM;
goto out;
}
if (!(file->f_mode & FMODE_READ)) {
file->f_mode |= FMODE_READ;
read = 1;
}
i_size = i_size_read(file->f_dentry->d_inode);
while (offset < i_size) {
int rbuf_len;
......@@ -80,6 +84,8 @@ int ima_calc_hash(struct file *file, char *digest)
kfree(rbuf);
if (!rc)
rc = crypto_hash_final(&desc, digest);
if (read)
file->f_mode &= ~FMODE_READ;
out:
crypto_free_hash(desc.tfm);
return rc;
......
......@@ -22,12 +22,19 @@
#include <linux/mount.h>
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/xattr.h>
#include <linux/ima.h>
#include "ima.h"
int ima_initialized;
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise = IMA_APPRAISE_ENFORCE;
#else
int ima_appraise;
#endif
char *ima_hash = "sha1";
static int __init hash_setup(char *str)
{
......@@ -52,7 +59,7 @@ static void ima_rdwr_violation_check(struct file *file)
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
fmode_t mode = file->f_mode;
int rc;
int must_measure;
bool send_tomtou = false, send_writers = false;
unsigned char *pathname = NULL, *pathbuf = NULL;
......@@ -67,8 +74,8 @@ static void ima_rdwr_violation_check(struct file *file)
goto out;
}
rc = ima_must_measure(inode, MAY_READ, FILE_CHECK);
if (rc < 0)
must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK);
if (!must_measure)
goto out;
if (atomic_read(&inode->i_writecount) > 0)
......@@ -100,17 +107,21 @@ static void ima_rdwr_violation_check(struct file *file)
}
static void ima_check_last_writer(struct integrity_iint_cache *iint,
struct inode *inode,
struct file *file)
struct inode *inode, struct file *file)
{
fmode_t mode = file->f_mode;
mutex_lock(&iint->mutex);
if (mode & FMODE_WRITE &&
atomic_read(&inode->i_writecount) == 1 &&
iint->version != inode->i_version)
iint->flags &= ~IMA_MEASURED;
mutex_unlock(&iint->mutex);
if (!(mode & FMODE_WRITE))
return;
mutex_lock(&inode->i_mutex);
if (atomic_read(&inode->i_writecount) == 1 &&
iint->version != inode->i_version) {
iint->flags &= ~IMA_DONE_MASK;
if (iint->flags & IMA_APPRAISE)
ima_update_xattr(iint, file);
}
mutex_unlock(&inode->i_mutex);
}
/**
......@@ -140,28 +151,37 @@ static int process_measurement(struct file *file, const unsigned char *filename,
struct inode *inode = file->f_dentry->d_inode;
struct integrity_iint_cache *iint;
unsigned char *pathname = NULL, *pathbuf = NULL;
int rc = 0;
int rc = -ENOMEM, action, must_appraise;
if (!ima_initialized || !S_ISREG(inode->i_mode))
return 0;
rc = ima_must_measure(inode, mask, function);
if (rc != 0)
return rc;
retry:
iint = integrity_iint_find(inode);
if (!iint) {
rc = integrity_inode_alloc(inode);
if (!rc || rc == -EEXIST)
goto retry;
return rc;
}
/* Determine if in appraise/audit/measurement policy,
* returns IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT bitmask. */
action = ima_get_action(inode, mask, function);
if (!action)
return 0;
mutex_lock(&iint->mutex);
must_appraise = action & IMA_APPRAISE;
rc = iint->flags & IMA_MEASURED ? 1 : 0;
if (rc != 0)
mutex_lock(&inode->i_mutex);
iint = integrity_inode_get(inode);
if (!iint)
goto out;
/* Determine if already appraised/measured based on bitmask
* (IMA_MEASURE, IMA_MEASURED, IMA_APPRAISE, IMA_APPRAISED,
* IMA_AUDIT, IMA_AUDITED) */
iint->flags |= action;
action &= ~((iint->flags & IMA_DONE_MASK) >> 1);
/* Nothing to do, just return existing appraised status */
if (!action) {
if (iint->flags & IMA_APPRAISED)
rc = iint->ima_status;
goto out;
}
rc = ima_collect_measurement(iint, file);
if (rc != 0)
......@@ -177,11 +197,18 @@ static int process_measurement(struct file *file, const unsigned char *filename,
pathname = NULL;
}
}
ima_store_measurement(iint, file, !pathname ? filename : pathname);
if (action & IMA_MEASURE)
ima_store_measurement(iint, file,
!pathname ? filename : pathname);
if (action & IMA_APPRAISE)
rc = ima_appraise_measurement(iint, file,
!pathname ? filename : pathname);
if (action & IMA_AUDIT)
ima_audit_measurement(iint, !pathname ? filename : pathname);
kfree(pathbuf);
out:
mutex_unlock(&iint->mutex);
return rc;
mutex_unlock(&inode->i_mutex);
return (rc && must_appraise) ? -EACCES : 0;
}
/**
......@@ -197,14 +224,14 @@ static int process_measurement(struct file *file, const unsigned char *filename,
*/
int ima_file_mmap(struct file *file, unsigned long prot)
{
int rc;
int rc = 0;
if (!file)
return 0;
if (prot & PROT_EXEC)
rc = process_measurement(file, file->f_dentry->d_name.name,
MAY_EXEC, FILE_MMAP);
return 0;
return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
}
/**
......@@ -228,7 +255,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
(strcmp(bprm->filename, bprm->interp) == 0) ?
bprm->filename : bprm->interp,
MAY_EXEC, BPRM_CHECK);
return 0;
return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
}
/**
......@@ -249,7 +276,7 @@ int ima_file_check(struct file *file, int mask)
rc = process_measurement(file, file->f_dentry->d_name.name,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK);
return 0;
return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
}
EXPORT_SYMBOL_GPL(ima_file_check);
......
This diff is collapsed.
......@@ -15,8 +15,22 @@
#include <linux/integrity.h>
#include <crypto/sha.h>
/* iint action cache flags */
#define IMA_MEASURE 0x0001
#define IMA_MEASURED 0x0002
#define IMA_APPRAISE 0x0004
#define IMA_APPRAISED 0x0008
/*#define IMA_COLLECT 0x0010 do not use this flag */
#define IMA_COLLECTED 0x0020
#define IMA_AUDIT 0x0040
#define IMA_AUDITED 0x0080
/* iint cache flags */
#define IMA_MEASURED 0x01
#define IMA_DIGSIG 0x0100
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT)
#define IMA_DONE_MASK (IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED \
| IMA_COLLECTED)
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,
......@@ -34,9 +48,9 @@ struct integrity_iint_cache {
struct rb_node rb_node; /* rooted in integrity_iint_tree */
struct inode *inode; /* back pointer to inode in question */
u64 version; /* track inode changes */
unsigned char flags;
u8 digest[SHA1_DIGEST_SIZE];
struct mutex mutex; /* protects: version, flags, digest */
unsigned short flags;
struct evm_ima_xattr_data ima_xattr;
enum integrity_status ima_status;
enum integrity_status evm_status;
};
......
......@@ -368,38 +368,6 @@ static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
return rc;
}
/*
* get a random value from TPM
*/
static int tpm_get_random(struct tpm_buf *tb, unsigned char *buf, uint32_t len)
{
int ret;
INIT_BUF(tb);
store16(tb, TPM_TAG_RQU_COMMAND);
store32(tb, TPM_GETRANDOM_SIZE);
store32(tb, TPM_ORD_GETRANDOM);
store32(tb, len);
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, sizeof tb->data);
if (!ret)
memcpy(buf, tb->data + TPM_GETRANDOM_SIZE, len);
return ret;
}
static int my_get_random(unsigned char *buf, int len)
{
struct tpm_buf *tb;
int ret;
tb = kmalloc(sizeof *tb, GFP_KERNEL);
if (!tb)
return -ENOMEM;
ret = tpm_get_random(tb, buf, len);
kfree(tb);
return ret;
}
/*
* Lock a trusted key, by extending a selected PCR.
*
......@@ -413,8 +381,8 @@ static int pcrlock(const int pcrnum)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
ret = my_get_random(hash, SHA1_DIGEST_SIZE);
if (ret < 0)
ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE);
if (ret != SHA1_DIGEST_SIZE)
return ret;
return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
}
......@@ -429,8 +397,8 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
unsigned char ononce[TPM_NONCE_SIZE];
int ret;
ret = tpm_get_random(tb, ononce, TPM_NONCE_SIZE);
if (ret < 0)
ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE)
return ret;
INIT_BUF(tb);
......@@ -524,8 +492,8 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
if (ret < 0)
goto out;
ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
if (ret < 0)
ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE)
goto out;
ordinal = htonl(TPM_ORD_SEAL);
datsize = htonl(datalen);
......@@ -634,8 +602,8 @@ static int tpm_unseal(struct tpm_buf *tb,
ordinal = htonl(TPM_ORD_UNSEAL);
keyhndl = htonl(SRKHANDLE);
ret = tpm_get_random(tb, nonceodd, TPM_NONCE_SIZE);
if (ret < 0) {
ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE) {
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret;
}
......@@ -935,6 +903,7 @@ static int trusted_instantiate(struct key *key, const void *data,
char *datablob;
int ret = 0;
int key_cmd;
size_t key_len;
if (datalen <= 0 || datalen > 32767 || !data)
return -EINVAL;
......@@ -974,8 +943,9 @@ static int trusted_instantiate(struct key *key, const void *data,
pr_info("trusted_key: key_unseal failed (%d)\n", ret);
break;
case Opt_new:
ret = my_get_random(payload->key, payload->key_len);
if (ret < 0) {
key_len = payload->key_len;
ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len);
if (ret != key_len) {
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
......
......@@ -136,11 +136,23 @@ int __init register_security(struct security_operations *ops)
int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
#ifdef CONFIG_SECURITY_YAMA_STACKED
int rc;
rc = yama_ptrace_access_check(child, mode);
if (rc)
return rc;
#endif
return security_ops->ptrace_access_check(child, mode);
}
int security_ptrace_traceme(struct task_struct *parent)
{
#ifdef CONFIG_SECURITY_YAMA_STACKED
int rc;
rc = yama_ptrace_traceme(parent);
if (rc)
return rc;
#endif
return security_ops->ptrace_traceme(parent);
}
......@@ -559,6 +571,9 @@ int security_inode_setxattr(struct dentry *dentry, const char *name,
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
ret = security_ops->inode_setxattr(dentry, name, value, size, flags);
if (ret)
return ret;
ret = ima_inode_setxattr(dentry, name, value, size);
if (ret)
return ret;
return evm_inode_setxattr(dentry, name, value, size);
......@@ -594,6 +609,9 @@ int security_inode_removexattr(struct dentry *dentry, const char *name)
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
ret = security_ops->inode_removexattr(dentry, name);
if (ret)
return ret;
ret = ima_inode_removexattr(dentry, name);
if (ret)
return ret;
return evm_inode_removexattr(dentry, name);
......@@ -761,6 +779,9 @@ int security_task_create(unsigned long clone_flags)
void security_task_free(struct task_struct *task)
{
#ifdef CONFIG_SECURITY_YAMA_STACKED
yama_task_free(task);
#endif
security_ops->task_free(task);
}
......@@ -876,6 +897,12 @@ int security_task_wait(struct task_struct *p)
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
#ifdef CONFIG_SECURITY_YAMA_STACKED
int rc;
rc = yama_task_prctl(option, arg2, arg3, arg4, arg5);
if (rc != -ENOSYS)
return rc;
#endif
return security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
}
......
......@@ -1691,40 +1691,19 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* smack_task_wait - Smack access check for waiting
* @p: task to wait for
*
* Returns 0 if current can wait for p, error code otherwise
* Returns 0
*/
static int smack_task_wait(struct task_struct *p)
{
struct smk_audit_info ad;
char *sp = smk_of_current();
char *tsp = smk_of_forked(task_security(p));
int rc;
/* we don't log here, we can be overriden */
rc = smk_access(tsp, sp, MAY_WRITE, NULL);
if (rc == 0)
goto out_log;
/*
* Allow the operation to succeed if either task
* has privilege to perform operations that might
* account for the smack labels having gotten to
* be different in the first place.
*
* This breaks the strict subject/object access
* control ideal, taking the object's privilege
* state into account in the decision as well as
* the smack value.
* Allow the operation to succeed.
* Zombies are bad.
* In userless environments (e.g. phones) programs
* get marked with SMACK64EXEC and even if the parent
* and child shouldn't be talking the parent still
* may expect to know when the child exits.
*/
if (smack_privileged(CAP_MAC_OVERRIDE) ||
has_capability(p, CAP_MAC_OVERRIDE))
rc = 0;
/* we log only if we didn't get overriden */
out_log:
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
smack_log(tsp, sp, MAY_WRITE, rc, &ad);
return rc;
return 0;
}
/**
......@@ -2705,9 +2684,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
static int smack_setprocattr(struct task_struct *p, char *name,
void *value, size_t size)
{
int rc;
struct task_smack *tsp;
struct task_smack *oldtsp;
struct cred *new;
char *newsmack;
......@@ -2737,21 +2714,13 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (newsmack == smack_known_web.smk_known)
return -EPERM;
oldtsp = p->cred->security;
new = prepare_creds();
if (new == NULL)
return -ENOMEM;
tsp = new_task_smack(newsmack, oldtsp->smk_forked, GFP_KERNEL);
if (tsp == NULL) {
kfree(new);
return -ENOMEM;
}
rc = smk_copy_rules(&tsp->smk_rules, &oldtsp->smk_rules, GFP_KERNEL);
if (rc != 0)
return rc;
tsp = new->security;
tsp->smk_task = newsmack;
new->security = tsp;
commit_creds(new);
return size;
}
......
......@@ -49,6 +49,7 @@ enum smk_inos {
SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */
SMK_ACCESS2 = 16, /* make an access check with long labels */
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
};
/*
......@@ -1991,6 +1992,77 @@ static const struct file_operations smk_access2_ops = {
.llseek = generic_file_llseek,
};
/**
* smk_write_revoke_subj - write() for /smack/revoke-subject
* @file: file pointer
* @buf: data from user space
* @count: bytes sent
* @ppos: where to start - must be 0
*/
static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *data = NULL;
const char *cp = NULL;
struct smack_known *skp;
struct smack_rule *sp;
struct list_head *rule_list;
struct mutex *rule_lock;
int rc = count;
if (*ppos != 0)
return -EINVAL;
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
if (count == 0 || count > SMK_LONGLABEL)
return -EINVAL;
data = kzalloc(count, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
if (copy_from_user(data, buf, count) != 0) {
rc = -EFAULT;
goto free_out;
}
cp = smk_parse_smack(data, count);
if (cp == NULL) {
rc = -EINVAL;
goto free_out;
}
skp = smk_find_entry(cp);
if (skp == NULL) {
rc = -EINVAL;
goto free_out;
}
rule_list = &skp->smk_rules;
rule_lock = &skp->smk_rules_lock;
mutex_lock(rule_lock);
list_for_each_entry_rcu(sp, rule_list, list)
sp->smk_access = 0;
mutex_unlock(rule_lock);
free_out:
kfree(data);
kfree(cp);
return rc;
}
static const struct file_operations smk_revoke_subj_ops = {
.write = smk_write_revoke_subj,
.read = simple_transaction_read,
.release = simple_transaction_release,
.llseek = generic_file_llseek,
};
/**
* smk_fill_super - fill the /smackfs superblock
* @sb: the empty superblock
......@@ -2037,6 +2109,9 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
"access2", &smk_access2_ops, S_IRUGO|S_IWUGO},
[SMK_CIPSO2] = {
"cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR},
[SMK_REVOKE_SUBJ] = {
"revoke-subject", &smk_revoke_subj_ops,
S_IRUGO|S_IWUSR},
/* last one */
{""}
};
......
......@@ -11,3 +11,11 @@ config SECURITY_YAMA
Further information can be found in Documentation/security/Yama.txt.
If you are unsure how to answer this question, answer N.
config SECURITY_YAMA_STACKED
bool "Yama stacked with other LSMs"
depends on SECURITY_YAMA
default n
help
When Yama is built into the kernel, force it to stack with the
selected primary LSM.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment