Skip to content

Commit

Permalink
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/…
Browse files Browse the repository at this point in the history
…zohar/linux-integrity into next
  • Loading branch information
James Morris committed Nov 19, 2014
2 parents b10778a + 6fb5032 commit a6aacbd
Show file tree
Hide file tree
Showing 18 changed files with 356 additions and 141 deletions.
4 changes: 4 additions & 0 deletions Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Formats: { "ima" | "ima-ng" }
Default: "ima-ng"

ima_template_fmt=
[IMA] Define a custom template format.
Format: { "field1|...|fieldN" }

ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage
Format: <min_file_size>
Set the minimal file size for using asynchronous hash.
Expand Down
29 changes: 14 additions & 15 deletions Documentation/security/IMA-templates.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,22 @@ Managing templates with these structures is very simple. To support
a new data type, developers define the field identifier and implement
two functions, init() and show(), respectively to generate and display
measurement entries. Defining a new template descriptor requires
specifying the template format, a string of field identifiers separated
by the '|' character. While in the current implementation it is possible
to define new template descriptors only by adding their definition in the
template specific code (ima_template.c), in a future version it will be
possible to register a new template on a running kernel by supplying to IMA
the desired format string. In this version, IMA initializes at boot time
all defined template descriptors by translating the format into an array
of template fields structures taken from the set of the supported ones.
specifying the template format (a string of field identifiers separated
by the '|' character) through the 'ima_template_fmt' kernel command line
parameter. At boot time, IMA initializes the chosen template descriptor
by translating the format into an array of template fields structures taken
from the set of the supported ones.

After the initialization step, IMA will call ima_alloc_init_template()
(new function defined within the patches for the new template management
mechanism) to generate a new measurement entry by using the template
descriptor chosen through the kernel configuration or through the newly
introduced 'ima_template=' kernel command line parameter. It is during this
phase that the advantages of the new architecture are clearly shown:
the latter function will not contain specific code to handle a given template
but, instead, it simply calls the init() method of the template fields
associated to the chosen template descriptor and store the result (pointer
to allocated data and data length) in the measurement entry structure.
introduced 'ima_template' and 'ima_template_fmt' kernel command line parameters.
It is during this phase that the advantages of the new architecture are
clearly shown: the latter function will not contain specific code to handle
a given template but, instead, it simply calls the init() method of the template
fields associated to the chosen template descriptor and store the result
(pointer to allocated data and data length) in the measurement entry structure.

The same mechanism is employed to display measurements entries.
The functions ima[_ascii]_measurements_show() retrieve, for each entry,
Expand Down Expand Up @@ -86,4 +83,6 @@ currently the following methods are supported:
- select a template descriptor among those supported in the kernel
configuration ('ima-ng' is the default choice);
- specify a template descriptor name from the kernel command line through
the 'ima_template=' parameter.
the 'ima_template=' parameter;
- register a new template descriptor with custom format through the kernel
command line parameter 'ima_template_fmt='.
24 changes: 18 additions & 6 deletions fs/read_write.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,23 @@ ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *p

EXPORT_SYMBOL(new_sync_read);

ssize_t __vfs_read(struct file *file, char __user *buf, size_t count,
loff_t *pos)
{
ssize_t ret;

if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
else if (file->f_op->aio_read)
ret = do_sync_read(file, buf, count, pos);
else if (file->f_op->read_iter)
ret = new_sync_read(file, buf, count, pos);
else
ret = -EINVAL;

return ret;
}

ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
Expand All @@ -426,12 +443,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
ret = rw_verify_area(READ, file, pos, count);
if (ret >= 0) {
count = ret;
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
else if (file->f_op->aio_read)
ret = do_sync_read(file, buf, count, pos);
else
ret = new_sync_read(file, buf, count, pos);
ret = __vfs_read(file, buf, count, pos);
if (ret > 0) {
fsnotify_access(file);
add_rchar(current, ret);
Expand Down
1 change: 1 addition & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,7 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
struct iovec *fast_pointer,
struct iovec **ret_pointer);

extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *);
extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
Expand Down
6 changes: 6 additions & 0 deletions include/linux/integrity.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum integrity_status {
#ifdef CONFIG_INTEGRITY
extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode);
extern void integrity_inode_free(struct inode *inode);
extern void __init integrity_load_keys(void);

#else
static inline struct integrity_iint_cache *
Expand All @@ -36,5 +37,10 @@ static inline void integrity_inode_free(struct inode *inode)
{
return;
}

static inline void integrity_load_keys(void)
{
}
#endif /* CONFIG_INTEGRITY */

#endif /* _LINUX_INTEGRITY_H */
6 changes: 5 additions & 1 deletion init/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#include <linux/context_tracking.h>
#include <linux/random.h>
#include <linux/list.h>
#include <linux/integrity.h>

#include <asm/io.h>
#include <asm/bugs.h>
Expand Down Expand Up @@ -1027,8 +1028,11 @@ static noinline void __init kernel_init_freeable(void)
* Ok, we have completed the initial bootup, and
* we're essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*
* rootfs is available now, try loading the public keys
* and default modules
*/

/* rootfs is available now, try loading default modules */
integrity_load_keys();
load_default_modules();
}
38 changes: 36 additions & 2 deletions security/integrity/digsig.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#include <linux/err.h>
#include <linux/sched.h>
#include <linux/rbtree.h>
#include <linux/slab.h>
#include <linux/cred.h>
#include <linux/key-type.h>
#include <linux/digsig.h>
Expand Down Expand Up @@ -63,7 +63,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return -EOPNOTSUPP;
}

int integrity_init_keyring(const unsigned int id)
int __init integrity_init_keyring(const unsigned int id)
{
const struct cred *cred = current_cred();
int err = 0;
Expand All @@ -84,3 +84,37 @@ int integrity_init_keyring(const unsigned int id)
}
return err;
}

int __init integrity_load_x509(const unsigned int id, char *path)
{
key_ref_t key;
char *data;
int rc;

if (!keyring[id])
return -EINVAL;

rc = integrity_read_file(path, &data);
if (rc < 0)
return rc;

key = key_create_or_update(make_key_ref(keyring[id], 1),
"asymmetric",
NULL,
data,
rc,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
pr_err("Problem loading X.509 certificate (%d): %s\n",
rc, path);
} else {
pr_notice("Loaded X.509 cert '%s': %s\n",
key_ref_to_ptr(key)->description, path);
key_ref_put(key);
}
kfree(data);
return 0;
}
11 changes: 8 additions & 3 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,14 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
(const char *)xattr_data, xattr_len,
calc.digest, sizeof(calc.digest));
if (!rc) {
/* we probably want to replace rsa with hmac here */
evm_update_evmxattr(dentry, xattr_name, xattr_value,
xattr_value_len);
/* Replace RSA with HMAC if not mounted readonly and
* not immutable
*/
if (!IS_RDONLY(dentry->d_inode) &&
!IS_IMMUTABLE(dentry->d_inode))
evm_update_evmxattr(dentry, xattr_name,
xattr_value,
xattr_value_len);
}
break;
default:
Expand Down
88 changes: 85 additions & 3 deletions security/integrity/iint.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/rbtree.h>
#include <linux/file.h>
#include <linux/uaccess.h>
#include "integrity.h"

static struct rb_root integrity_iint_tree = RB_ROOT;
static DEFINE_RWLOCK(integrity_iint_lock);
static struct kmem_cache *iint_cache __read_mostly;

int iint_initialized;

/*
* __integrity_iint_find - return the iint associated with an inode
*/
Expand Down Expand Up @@ -166,7 +166,89 @@ static int __init integrity_iintcache_init(void)
iint_cache =
kmem_cache_create("iint_cache", sizeof(struct integrity_iint_cache),
0, SLAB_PANIC, init_once);
iint_initialized = 1;
return 0;
}
security_initcall(integrity_iintcache_init);


/*
* integrity_kernel_read - read data from the file
*
* This is a function for reading file content instead of kernel_read().
* It does not perform locking checks to ensure it cannot be blocked.
* It does not perform security checks because it is irrelevant for IMA.
*
*/
int integrity_kernel_read(struct file *file, loff_t offset,
char *addr, unsigned long count)
{
mm_segment_t old_fs;
char __user *buf = (char __user *)addr;
ssize_t ret;

if (!(file->f_mode & FMODE_READ))
return -EBADF;

old_fs = get_fs();
set_fs(get_ds());
ret = __vfs_read(file, buf, count, &offset);
set_fs(old_fs);

return ret;
}

/*
* integrity_read_file - read entire file content into the buffer
*
* This is function opens a file, allocates the buffer of required
* size, read entire file content to the buffer and closes the file
*
* It is used only by init code.
*
*/
int __init integrity_read_file(const char *path, char **data)
{
struct file *file;
loff_t size;
char *buf;
int rc = -EINVAL;

file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file)) {
rc = PTR_ERR(file);
pr_err("Unable to open file: %s (%d)", path, rc);
return rc;
}

size = i_size_read(file_inode(file));
if (size <= 0)
goto out;

buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
goto out;
}

rc = integrity_kernel_read(file, 0, buf, size);
if (rc < 0)
kfree(buf);
else if (rc != size)
rc = -EIO;
else
*data = buf;
out:
fput(file);
return rc;
}

/*
* integrity_load_keys - load integrity keys hook
*
* Hooks is called from init/main.c:kernel_init_freeable()
* when rootfs is ready
*/
void __init integrity_load_keys(void)
{
ima_load_x509();
}
25 changes: 25 additions & 0 deletions security/integrity/ima/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,28 @@ config IMA_TRUSTED_KEYRING
help
This option requires that all keys added to the .ima
keyring be signed by a key on the system trusted keyring.

config IMA_LOAD_X509
bool "Load X509 certificate onto the '.ima' trusted keyring"
depends on IMA_TRUSTED_KEYRING
default n
help
File signature verification is based on the public keys
loaded on the .ima trusted keyring. These public keys are
X509 certificates signed by a trusted key on the
.system keyring. This option enables X509 certificate
loading from the kernel onto the '.ima' trusted keyring.

config IMA_X509_PATH
string "IMA X509 certificate path"
depends on IMA_LOAD_X509
default "/etc/keys/x509_ima.der"
help
This option defines IMA X509 certificate path.

config IMA_APPRAISE_SIGNED_INIT
bool "Require signed user-space initialization"
depends on IMA_LOAD_X509
default n
help
This option requires user-space init to be signed.
7 changes: 3 additions & 4 deletions security/integrity/ima/ima_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ int ima_get_action(struct inode *inode, int mask, int function)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;

if (!ima_appraise)
flags &= ~IMA_APPRAISE;
flags &= ima_policy_flag;

return ima_match_policy(inode, function, mask, flags);
}
Expand Down Expand Up @@ -325,11 +324,11 @@ const char *ima_d_path(struct path *path, char **pathbuf)
{
char *pathname = NULL;

*pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
*pathbuf = __getname();
if (*pathbuf) {
pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
if (IS_ERR(pathname)) {
kfree(*pathbuf);
__putname(*pathbuf);
*pathbuf = NULL;
pathname = NULL;
}
Expand Down
Loading

0 comments on commit a6aacbd

Please sign in to comment.