You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "In this release: - PKCS#7 parser for the key management subsystem from David Howells - appoint Kees Cook as seccomp maintainer - bugfixes and general maintenance across the subsystem" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (94 commits) X.509: Need to export x509_request_asymmetric_key() netlabel: shorter names for the NetLabel catmap funcs/structs netlabel: fix the catmap walking functions netlabel: fix the horribly broken catmap functions netlabel: fix a problem when setting bits below the previously lowest bit PKCS#7: X.509 certificate issuer and subject are mandatory fields in the ASN.1 tpm: simplify code by using %*phN specifier tpm: Provide a generic means to override the chip returned timeouts tpm: missing tpm_chip_put in tpm_get_random() tpm: Properly clean sysfs entries in error path tpm: Add missing tpm_do_selftest to ST33 I2C driver PKCS#7: Use x509_request_asymmetric_key() Revert "selinux: fix the default socket labeling in sock_graft()" X.509: x509_request_asymmetric_keys() doesn't need string length arguments PKCS#7: fix sparse non static symbol warning KEYS: revert encrypted key change ima: add support for measuring and appraising firmware firmware_class: perform new LSM checks security: introduce kernel_fw_from_file hook PKCS#7: Missing inclusion of linux/err.h ...
This commit is contained in:
@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
|
||||
* There is no exception for unconfined as change_hat is not
|
||||
* available.
|
||||
*/
|
||||
if (current->no_new_privs)
|
||||
if (task_no_new_privs(current))
|
||||
return -EPERM;
|
||||
|
||||
/* released below */
|
||||
@@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
|
||||
* no_new_privs is set because this aways results in a reduction
|
||||
* of permissions.
|
||||
*/
|
||||
if (current->no_new_privs && !unconfined(profile)) {
|
||||
if (task_no_new_privs(current) && !unconfined(profile)) {
|
||||
put_cred(cred);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@@ -401,6 +401,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_kernel_fw_from_file(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_kernel_module_request(char *kmod_name)
|
||||
{
|
||||
return 0;
|
||||
@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
|
||||
set_to_cap_if_null(ops, cred_transfer);
|
||||
set_to_cap_if_null(ops, kernel_act_as);
|
||||
set_to_cap_if_null(ops, kernel_create_files_as);
|
||||
set_to_cap_if_null(ops, kernel_fw_from_file);
|
||||
set_to_cap_if_null(ops, kernel_module_request);
|
||||
set_to_cap_if_null(ops, kernel_module_from_file);
|
||||
set_to_cap_if_null(ops, task_fix_setuid);
|
||||
|
||||
+33
-42
@@ -421,6 +421,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
|
||||
cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
|
||||
}
|
||||
|
||||
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
||||
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -822,15 +825,20 @@ int cap_task_setnice(struct task_struct *p, int nice)
|
||||
* Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from
|
||||
* the current task's bounding set. Returns 0 on success, -ve on error.
|
||||
*/
|
||||
static long cap_prctl_drop(struct cred *new, unsigned long cap)
|
||||
static int cap_prctl_drop(unsigned long cap)
|
||||
{
|
||||
struct cred *new;
|
||||
|
||||
if (!ns_capable(current_user_ns(), CAP_SETPCAP))
|
||||
return -EPERM;
|
||||
if (!cap_valid(cap))
|
||||
return -EINVAL;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
cap_lower(new->cap_bset, cap);
|
||||
return 0;
|
||||
return commit_creds(new);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -848,26 +856,17 @@ static long cap_prctl_drop(struct cred *new, unsigned long cap)
|
||||
int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5)
|
||||
{
|
||||
const struct cred *old = current_cred();
|
||||
struct cred *new;
|
||||
long error = 0;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (option) {
|
||||
case PR_CAPBSET_READ:
|
||||
error = -EINVAL;
|
||||
if (!cap_valid(arg2))
|
||||
goto error;
|
||||
error = !!cap_raised(new->cap_bset, arg2);
|
||||
goto no_change;
|
||||
return -EINVAL;
|
||||
return !!cap_raised(old->cap_bset, arg2);
|
||||
|
||||
case PR_CAPBSET_DROP:
|
||||
error = cap_prctl_drop(new, arg2);
|
||||
if (error < 0)
|
||||
goto error;
|
||||
goto changed;
|
||||
return cap_prctl_drop(arg2);
|
||||
|
||||
/*
|
||||
* The next four prctl's remain to assist with transitioning a
|
||||
@@ -889,10 +888,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
* capability-based-privilege environment.
|
||||
*/
|
||||
case PR_SET_SECUREBITS:
|
||||
error = -EPERM;
|
||||
if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
|
||||
& (new->securebits ^ arg2)) /*[1]*/
|
||||
|| ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
||||
if ((((old->securebits & SECURE_ALL_LOCKS) >> 1)
|
||||
& (old->securebits ^ arg2)) /*[1]*/
|
||||
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
||||
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
||||
|| (cap_capable(current_cred(),
|
||||
current_cred()->user_ns, CAP_SETPCAP,
|
||||
@@ -906,46 +904,39 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
*/
|
||||
)
|
||||
/* cannot change a locked bit */
|
||||
goto error;
|
||||
return -EPERM;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
new->securebits = arg2;
|
||||
goto changed;
|
||||
return commit_creds(new);
|
||||
|
||||
case PR_GET_SECUREBITS:
|
||||
error = new->securebits;
|
||||
goto no_change;
|
||||
return old->securebits;
|
||||
|
||||
case PR_GET_KEEPCAPS:
|
||||
if (issecure(SECURE_KEEP_CAPS))
|
||||
error = 1;
|
||||
goto no_change;
|
||||
return !!issecure(SECURE_KEEP_CAPS);
|
||||
|
||||
case PR_SET_KEEPCAPS:
|
||||
error = -EINVAL;
|
||||
if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
|
||||
goto error;
|
||||
error = -EPERM;
|
||||
return -EINVAL;
|
||||
if (issecure(SECURE_KEEP_CAPS_LOCKED))
|
||||
goto error;
|
||||
return -EPERM;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
if (arg2)
|
||||
new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
|
||||
else
|
||||
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
||||
goto changed;
|
||||
return commit_creds(new);
|
||||
|
||||
default:
|
||||
/* No functionality available - continue with default */
|
||||
error = -ENOSYS;
|
||||
goto error;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* Functionality provided */
|
||||
changed:
|
||||
return commit_creds(new);
|
||||
|
||||
no_change:
|
||||
error:
|
||||
abort_creds(new);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/digsig.h>
|
||||
|
||||
@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
|
||||
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
|
||||
"_evm",
|
||||
"_module",
|
||||
#ifndef CONFIG_IMA_TRUSTED_KEYRING
|
||||
"_ima",
|
||||
#else
|
||||
".ima",
|
||||
#endif
|
||||
};
|
||||
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int integrity_init_keyring(const unsigned int id)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int err = 0;
|
||||
|
||||
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
|
||||
KGIDT_INIT(0), cred,
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ |
|
||||
KEY_USR_WRITE | KEY_USR_SEARCH),
|
||||
KEY_ALLOC_NOT_IN_QUOTA, NULL);
|
||||
if (!IS_ERR(keyring[id]))
|
||||
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
|
||||
else {
|
||||
err = PTR_ERR(keyring[id]);
|
||||
pr_info("Can't allocate %s keyring (%d)\n",
|
||||
keyring_name[id], err);
|
||||
keyring[id] = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -123,3 +123,13 @@ config IMA_APPRAISE
|
||||
For more information on integrity appraisal refer to:
|
||||
<http://linux-ima.sourceforge.net>
|
||||
If unsure, say N.
|
||||
|
||||
config IMA_TRUSTED_KEYRING
|
||||
bool "Require all keys on the .ima keyring be signed"
|
||||
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
|
||||
depends on INTEGRITY_ASYMMETRIC_KEYS
|
||||
select KEYS_DEBUG_PROC_KEYS
|
||||
default y
|
||||
help
|
||||
This option requires that all keys added to the .ima
|
||||
keyring be signed by a key on the system trusted keyring.
|
||||
|
||||
@@ -158,7 +158,7 @@ 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, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
|
||||
enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
|
||||
|
||||
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
|
||||
int flags);
|
||||
@@ -171,6 +171,7 @@ void ima_delete_rules(void);
|
||||
#define IMA_APPRAISE_ENFORCE 0x01
|
||||
#define IMA_APPRAISE_FIX 0x02
|
||||
#define IMA_APPRAISE_MODULES 0x04
|
||||
#define IMA_APPRAISE_FIRMWARE 0x08
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE
|
||||
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
|
||||
@@ -249,4 +250,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_IMA_LSM_RULES */
|
||||
|
||||
#ifdef CONFIG_IMA_TRUSTED_KEYRING
|
||||
static inline int ima_init_keyring(const unsigned int id)
|
||||
{
|
||||
return integrity_init_keyring(id);
|
||||
}
|
||||
#else
|
||||
static inline int ima_init_keyring(const unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IMA_TRUSTED_KEYRING */
|
||||
#endif
|
||||
|
||||
@@ -75,6 +75,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
return iint->ima_bprm_status;
|
||||
case MODULE_CHECK:
|
||||
return iint->ima_module_status;
|
||||
case FIRMWARE_CHECK:
|
||||
return iint->ima_firmware_status;
|
||||
case FILE_CHECK:
|
||||
default:
|
||||
return iint->ima_file_status;
|
||||
@@ -94,6 +96,9 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
|
||||
case MODULE_CHECK:
|
||||
iint->ima_module_status = status;
|
||||
break;
|
||||
case FIRMWARE_CHECK:
|
||||
iint->ima_firmware_status = status;
|
||||
break;
|
||||
case FILE_CHECK:
|
||||
default:
|
||||
iint->ima_file_status = status;
|
||||
@@ -113,6 +118,9 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
|
||||
case MODULE_CHECK:
|
||||
iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED);
|
||||
break;
|
||||
case FIRMWARE_CHECK:
|
||||
iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED);
|
||||
break;
|
||||
case FILE_CHECK:
|
||||
default:
|
||||
iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
|
||||
@@ -214,7 +222,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
|
||||
hash_start = 1;
|
||||
case IMA_XATTR_DIGEST:
|
||||
if (iint->flags & IMA_DIGSIG_REQUIRED) {
|
||||
cause = "IMA signature required";
|
||||
cause = "IMA-signature-required";
|
||||
status = INTEGRITY_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/scatterlist.h>
|
||||
@@ -25,7 +27,45 @@
|
||||
#include <crypto/hash_info.h>
|
||||
#include "ima.h"
|
||||
|
||||
struct ahash_completion {
|
||||
struct completion completion;
|
||||
int err;
|
||||
};
|
||||
|
||||
/* minimum file size for ahash use */
|
||||
static unsigned long ima_ahash_minsize;
|
||||
module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644);
|
||||
MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use");
|
||||
|
||||
/* default is 0 - 1 page. */
|
||||
static int ima_maxorder;
|
||||
static unsigned int ima_bufsize = PAGE_SIZE;
|
||||
|
||||
static int param_set_bufsize(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
unsigned long long size;
|
||||
int order;
|
||||
|
||||
size = memparse(val, NULL);
|
||||
order = get_order(size);
|
||||
if (order >= MAX_ORDER)
|
||||
return -EINVAL;
|
||||
ima_maxorder = order;
|
||||
ima_bufsize = PAGE_SIZE << order;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct kernel_param_ops param_ops_bufsize = {
|
||||
.set = param_set_bufsize,
|
||||
.get = param_get_uint,
|
||||
};
|
||||
#define param_check_bufsize(name, p) __param_check(name, p, unsigned int)
|
||||
|
||||
module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644);
|
||||
MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
|
||||
|
||||
static struct crypto_shash *ima_shash_tfm;
|
||||
static struct crypto_ahash *ima_ahash_tfm;
|
||||
|
||||
/**
|
||||
* ima_kernel_read - read file content
|
||||
@@ -93,9 +133,246 @@ static void ima_free_tfm(struct crypto_shash *tfm)
|
||||
crypto_free_shash(tfm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the MD5/SHA1 file digest
|
||||
/**
|
||||
* ima_alloc_pages() - Allocate contiguous pages.
|
||||
* @max_size: Maximum amount of memory to allocate.
|
||||
* @allocated_size: Returned size of actual allocation.
|
||||
* @last_warn: Should the min_size allocation warn or not.
|
||||
*
|
||||
* Tries to do opportunistic allocation for memory first trying to allocate
|
||||
* max_size amount of memory and then splitting that until zero order is
|
||||
* reached. Allocation is tried without generating allocation warnings unless
|
||||
* last_warn is set. Last_warn set affects only last allocation of zero order.
|
||||
*
|
||||
* By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL)
|
||||
*
|
||||
* Return pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size,
|
||||
int last_warn)
|
||||
{
|
||||
void *ptr;
|
||||
int order = ima_maxorder;
|
||||
gfp_t gfp_mask = __GFP_WAIT | __GFP_NOWARN | __GFP_NORETRY;
|
||||
|
||||
if (order)
|
||||
order = min(get_order(max_size), order);
|
||||
|
||||
for (; order; order--) {
|
||||
ptr = (void *)__get_free_pages(gfp_mask, order);
|
||||
if (ptr) {
|
||||
*allocated_size = PAGE_SIZE << order;
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* order is zero - one page */
|
||||
|
||||
gfp_mask = GFP_KERNEL;
|
||||
|
||||
if (!last_warn)
|
||||
gfp_mask |= __GFP_NOWARN;
|
||||
|
||||
ptr = (void *)__get_free_pages(gfp_mask, 0);
|
||||
if (ptr) {
|
||||
*allocated_size = PAGE_SIZE;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
*allocated_size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_free_pages() - Free pages allocated by ima_alloc_pages().
|
||||
* @ptr: Pointer to allocated pages.
|
||||
* @size: Size of allocated buffer.
|
||||
*/
|
||||
static void ima_free_pages(void *ptr, size_t size)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
free_pages((unsigned long)ptr, get_order(size));
|
||||
}
|
||||
|
||||
static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
|
||||
{
|
||||
struct crypto_ahash *tfm = ima_ahash_tfm;
|
||||
int rc;
|
||||
|
||||
if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
|
||||
tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
|
||||
if (!IS_ERR(tfm)) {
|
||||
if (algo == ima_hash_algo)
|
||||
ima_ahash_tfm = tfm;
|
||||
} else {
|
||||
rc = PTR_ERR(tfm);
|
||||
pr_err("Can not allocate %s (reason: %d)\n",
|
||||
hash_algo_name[algo], rc);
|
||||
}
|
||||
}
|
||||
return tfm;
|
||||
}
|
||||
|
||||
static void ima_free_atfm(struct crypto_ahash *tfm)
|
||||
{
|
||||
if (tfm != ima_ahash_tfm)
|
||||
crypto_free_ahash(tfm);
|
||||
}
|
||||
|
||||
static void ahash_complete(struct crypto_async_request *req, int err)
|
||||
{
|
||||
struct ahash_completion *res = req->data;
|
||||
|
||||
if (err == -EINPROGRESS)
|
||||
return;
|
||||
res->err = err;
|
||||
complete(&res->completion);
|
||||
}
|
||||
|
||||
static int ahash_wait(int err, struct ahash_completion *res)
|
||||
{
|
||||
switch (err) {
|
||||
case 0:
|
||||
break;
|
||||
case -EINPROGRESS:
|
||||
case -EBUSY:
|
||||
wait_for_completion(&res->completion);
|
||||
reinit_completion(&res->completion);
|
||||
err = res->err;
|
||||
/* fall through */
|
||||
default:
|
||||
pr_crit_ratelimited("ahash calculation failed: err: %d\n", err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ima_calc_file_hash_atfm(struct file *file,
|
||||
struct ima_digest_data *hash,
|
||||
struct crypto_ahash *tfm)
|
||||
{
|
||||
loff_t i_size, offset;
|
||||
char *rbuf[2] = { NULL, };
|
||||
int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0;
|
||||
struct ahash_request *req;
|
||||
struct scatterlist sg[1];
|
||||
struct ahash_completion res;
|
||||
size_t rbuf_size[2];
|
||||
|
||||
hash->length = crypto_ahash_digestsize(tfm);
|
||||
|
||||
req = ahash_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
init_completion(&res.completion);
|
||||
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
ahash_complete, &res);
|
||||
|
||||
rc = ahash_wait(crypto_ahash_init(req), &res);
|
||||
if (rc)
|
||||
goto out1;
|
||||
|
||||
i_size = i_size_read(file_inode(file));
|
||||
|
||||
if (i_size == 0)
|
||||
goto out2;
|
||||
|
||||
/*
|
||||
* Try to allocate maximum size of memory.
|
||||
* Fail if even a single page cannot be allocated.
|
||||
*/
|
||||
rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1);
|
||||
if (!rbuf[0]) {
|
||||
rc = -ENOMEM;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
/* Only allocate one buffer if that is enough. */
|
||||
if (i_size > rbuf_size[0]) {
|
||||
/*
|
||||
* Try to allocate secondary buffer. If that fails fallback to
|
||||
* using single buffering. Use previous memory allocation size
|
||||
* as baseline for possible allocation size.
|
||||
*/
|
||||
rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0],
|
||||
&rbuf_size[1], 0);
|
||||
}
|
||||
|
||||
if (!(file->f_mode & FMODE_READ)) {
|
||||
file->f_mode |= FMODE_READ;
|
||||
read = 1;
|
||||
}
|
||||
|
||||
for (offset = 0; offset < i_size; offset += rbuf_len) {
|
||||
if (!rbuf[1] && offset) {
|
||||
/* Not using two buffers, and it is not the first
|
||||
* read/request, wait for the completion of the
|
||||
* previous ahash_update() request.
|
||||
*/
|
||||
rc = ahash_wait(ahash_rc, &res);
|
||||
if (rc)
|
||||
goto out3;
|
||||
}
|
||||
/* read buffer */
|
||||
rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
|
||||
rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len);
|
||||
if (rc != rbuf_len)
|
||||
goto out3;
|
||||
|
||||
if (rbuf[1] && offset) {
|
||||
/* Using two buffers, and it is not the first
|
||||
* read/request, wait for the completion of the
|
||||
* previous ahash_update() request.
|
||||
*/
|
||||
rc = ahash_wait(ahash_rc, &res);
|
||||
if (rc)
|
||||
goto out3;
|
||||
}
|
||||
|
||||
sg_init_one(&sg[0], rbuf[active], rbuf_len);
|
||||
ahash_request_set_crypt(req, sg, NULL, rbuf_len);
|
||||
|
||||
ahash_rc = crypto_ahash_update(req);
|
||||
|
||||
if (rbuf[1])
|
||||
active = !active; /* swap buffers, if we use two */
|
||||
}
|
||||
/* wait for the last update request to complete */
|
||||
rc = ahash_wait(ahash_rc, &res);
|
||||
out3:
|
||||
if (read)
|
||||
file->f_mode &= ~FMODE_READ;
|
||||
ima_free_pages(rbuf[0], rbuf_size[0]);
|
||||
ima_free_pages(rbuf[1], rbuf_size[1]);
|
||||
out2:
|
||||
if (!rc) {
|
||||
ahash_request_set_crypt(req, NULL, hash->digest, 0);
|
||||
rc = ahash_wait(crypto_ahash_final(req), &res);
|
||||
}
|
||||
out1:
|
||||
ahash_request_free(req);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ima_calc_file_ahash(struct file *file, struct ima_digest_data *hash)
|
||||
{
|
||||
struct crypto_ahash *tfm;
|
||||
int rc;
|
||||
|
||||
tfm = ima_alloc_atfm(hash->algo);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
rc = ima_calc_file_hash_atfm(file, hash, tfm);
|
||||
|
||||
ima_free_atfm(tfm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ima_calc_file_hash_tfm(struct file *file,
|
||||
struct ima_digest_data *hash,
|
||||
struct crypto_shash *tfm)
|
||||
@@ -156,7 +433,7 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
|
||||
static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
int rc;
|
||||
@@ -172,6 +449,35 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_calc_file_hash - calculate file hash
|
||||
*
|
||||
* Asynchronous hash (ahash) allows using HW acceleration for calculating
|
||||
* a hash. ahash performance varies for different data sizes on different
|
||||
* crypto accelerators. shash performance might be better for smaller files.
|
||||
* The 'ima.ahash_minsize' module parameter allows specifying the best
|
||||
* minimum file size for using ahash on the system.
|
||||
*
|
||||
* If the ima.ahash_minsize parameter is not specified, this function uses
|
||||
* shash for the hash calculation. If ahash fails, it falls back to using
|
||||
* shash.
|
||||
*/
|
||||
int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
|
||||
{
|
||||
loff_t i_size;
|
||||
int rc;
|
||||
|
||||
i_size = i_size_read(file_inode(file));
|
||||
|
||||
if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
|
||||
rc = ima_calc_file_ahash(file, hash);
|
||||
if (!rc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ima_calc_file_shash(file, hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the hash of template data
|
||||
*/
|
||||
|
||||
@@ -88,8 +88,6 @@ static void ima_rdwr_violation_check(struct file *file)
|
||||
if (!S_ISREG(inode->i_mode) || !ima_initialized)
|
||||
return;
|
||||
|
||||
mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */
|
||||
|
||||
if (mode & FMODE_WRITE) {
|
||||
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
|
||||
struct integrity_iint_cache *iint;
|
||||
@@ -104,8 +102,6 @@ static void ima_rdwr_violation_check(struct file *file)
|
||||
send_writers = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
if (!send_tomtou && !send_writers)
|
||||
return;
|
||||
|
||||
@@ -163,7 +159,7 @@ static int process_measurement(struct file *file, const char *filename,
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct integrity_iint_cache *iint;
|
||||
struct ima_template_desc *template_desc = ima_template_desc_current();
|
||||
struct ima_template_desc *template_desc;
|
||||
char *pathbuf = NULL;
|
||||
const char *pathname = NULL;
|
||||
int rc = -ENOMEM, action, must_appraise, _func;
|
||||
@@ -207,6 +203,7 @@ static int process_measurement(struct file *file, const char *filename,
|
||||
goto out_digsig;
|
||||
}
|
||||
|
||||
template_desc = ima_template_desc_current();
|
||||
if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
|
||||
if (action & IMA_APPRAISE_SUBMASK)
|
||||
xattr_ptr = &xattr_value;
|
||||
@@ -322,14 +319,31 @@ int ima_module_check(struct file *file)
|
||||
return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
|
||||
}
|
||||
|
||||
int ima_fw_from_file(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
if (!file) {
|
||||
if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
|
||||
(ima_appraise & IMA_APPRAISE_ENFORCE))
|
||||
return -EACCES; /* INTEGRITY_UNKNOWN */
|
||||
return 0;
|
||||
}
|
||||
return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
|
||||
}
|
||||
|
||||
static int __init init_ima(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
hash_setup(CONFIG_IMA_DEFAULT_HASH);
|
||||
error = ima_init();
|
||||
if (!error)
|
||||
ima_initialized = 1;
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
|
||||
if (error)
|
||||
goto out;
|
||||
ima_initialized = 1;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ static struct ima_rule_entry default_rules[] = {
|
||||
{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID,
|
||||
.flags = IMA_FUNC | IMA_MASK | IMA_UID},
|
||||
{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
|
||||
{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
|
||||
};
|
||||
|
||||
static struct ima_rule_entry default_appraise_rules[] = {
|
||||
@@ -241,6 +242,8 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
|
||||
return IMA_BPRM_APPRAISE;
|
||||
case MODULE_CHECK:
|
||||
return IMA_MODULE_APPRAISE;
|
||||
case FIRMWARE_CHECK:
|
||||
return IMA_FIRMWARE_APPRAISE;
|
||||
case FILE_CHECK:
|
||||
default:
|
||||
return IMA_FILE_APPRAISE;
|
||||
@@ -332,7 +335,7 @@ void __init ima_init_policy(void)
|
||||
void ima_update_policy(void)
|
||||
{
|
||||
static const char op[] = "policy_update";
|
||||
const char *cause = "already exists";
|
||||
const char *cause = "already-exists";
|
||||
int result = 1;
|
||||
int audit_info = 0;
|
||||
|
||||
@@ -486,6 +489,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||
entry->func = FILE_CHECK;
|
||||
else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
|
||||
entry->func = MODULE_CHECK;
|
||||
else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
|
||||
entry->func = FIRMWARE_CHECK;
|
||||
else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
|
||||
|| (strcmp(args[0].from, "MMAP_CHECK") == 0))
|
||||
entry->func = MMAP_CHECK;
|
||||
@@ -636,6 +641,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||
result = -EINVAL;
|
||||
else if (entry->func == MODULE_CHECK)
|
||||
ima_appraise |= IMA_APPRAISE_MODULES;
|
||||
else if (entry->func == FIRMWARE_CHECK)
|
||||
ima_appraise |= IMA_APPRAISE_FIRMWARE;
|
||||
audit_log_format(ab, "res=%d", !result);
|
||||
audit_log_end(ab);
|
||||
return result;
|
||||
@@ -659,7 +666,7 @@ ssize_t ima_parse_add_rule(char *rule)
|
||||
/* Prevent installed policy from changing */
|
||||
if (ima_rules != &ima_default_rules) {
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
|
||||
NULL, op, "already exists",
|
||||
NULL, op, "already-exists",
|
||||
-EACCES, audit_info);
|
||||
return -EACCES;
|
||||
}
|
||||
@@ -685,7 +692,7 @@ ssize_t ima_parse_add_rule(char *rule)
|
||||
if (result) {
|
||||
kfree(entry);
|
||||
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
|
||||
NULL, op, "invalid policy", result,
|
||||
NULL, op, "invalid-policy", result,
|
||||
audit_info);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -46,10 +46,14 @@
|
||||
#define IMA_BPRM_APPRAISED 0x00002000
|
||||
#define IMA_MODULE_APPRAISE 0x00004000
|
||||
#define IMA_MODULE_APPRAISED 0x00008000
|
||||
#define IMA_FIRMWARE_APPRAISE 0x00010000
|
||||
#define IMA_FIRMWARE_APPRAISED 0x00020000
|
||||
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
|
||||
IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE)
|
||||
IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \
|
||||
IMA_FIRMWARE_APPRAISE)
|
||||
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
|
||||
IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED)
|
||||
IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \
|
||||
IMA_FIRMWARE_APPRAISED)
|
||||
|
||||
enum evm_ima_xattr_type {
|
||||
IMA_XATTR_DIGEST = 0x01,
|
||||
@@ -104,6 +108,7 @@ struct integrity_iint_cache {
|
||||
enum integrity_status ima_mmap_status:4;
|
||||
enum integrity_status ima_bprm_status:4;
|
||||
enum integrity_status ima_module_status:4;
|
||||
enum integrity_status ima_firmware_status:4;
|
||||
enum integrity_status evm_status:4;
|
||||
struct ima_digest_data *ima_hash;
|
||||
};
|
||||
@@ -124,6 +129,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
const char *digest, int digestlen);
|
||||
|
||||
int integrity_init_keyring(const unsigned int id);
|
||||
#else
|
||||
|
||||
static inline int integrity_digsig_verify(const unsigned int id,
|
||||
@@ -133,6 +139,10 @@ static inline int integrity_digsig_verify(const unsigned int id,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int integrity_init_keyring(const unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_INTEGRITY_SIGNATURE */
|
||||
|
||||
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
|
||||
|
||||
+25
-16
@@ -34,7 +34,9 @@ MODULE_LICENSE("GPL");
|
||||
struct key_type key_type_big_key = {
|
||||
.name = "big_key",
|
||||
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
|
||||
.instantiate = big_key_instantiate,
|
||||
.preparse = big_key_preparse,
|
||||
.free_preparse = big_key_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.match = user_match,
|
||||
.revoke = big_key_revoke,
|
||||
.destroy = big_key_destroy,
|
||||
@@ -43,11 +45,11 @@ struct key_type key_type_big_key = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Instantiate a big key
|
||||
* Preparse a big key
|
||||
*/
|
||||
int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
int big_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct path *path = (struct path *)&key->payload.data2;
|
||||
struct path *path = (struct path *)&prep->payload;
|
||||
struct file *file;
|
||||
ssize_t written;
|
||||
size_t datalen = prep->datalen;
|
||||
@@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
goto error;
|
||||
|
||||
/* Set an arbitrary quota */
|
||||
ret = key_payload_reserve(key, 16);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
prep->quotalen = 16;
|
||||
|
||||
key->type_data.x[1] = datalen;
|
||||
prep->type_data[1] = (void *)(unsigned long)datalen;
|
||||
|
||||
if (datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||
/* Create a shmem file to store the data in. This will permit the data
|
||||
@@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
file = shmem_kernel_file_setup("", datalen, 0);
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
goto err_quota;
|
||||
goto error;
|
||||
}
|
||||
|
||||
written = kernel_write(file, prep->data, prep->datalen, 0);
|
||||
@@ -93,23 +93,32 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
} else {
|
||||
/* Just store the data in a buffer */
|
||||
void *data = kmalloc(datalen, GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto err_quota;
|
||||
}
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
key->payload.data = memcpy(data, prep->data, prep->datalen);
|
||||
prep->payload[0] = memcpy(data, prep->data, prep->datalen);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_fput:
|
||||
fput(file);
|
||||
err_quota:
|
||||
key_payload_reserve(key, 0);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear preparsement.
|
||||
*/
|
||||
void big_key_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
|
||||
struct path *path = (struct path *)&prep->payload;
|
||||
path_put(path);
|
||||
} else {
|
||||
kfree(prep->payload[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dispose of the links from a revoked keyring
|
||||
* - called with the key sem write-locked
|
||||
|
||||
+44
-5
@@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key,
|
||||
/* disable the authorisation key */
|
||||
if (authkey)
|
||||
key_revoke(authkey);
|
||||
|
||||
if (prep->expiry != TIME_T_MAX) {
|
||||
key->expiry = prep->expiry;
|
||||
key_schedule_gc(prep->expiry + key_gc_delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key,
|
||||
prep.data = data;
|
||||
prep.datalen = datalen;
|
||||
prep.quotalen = key->type->def_datalen;
|
||||
prep.expiry = TIME_T_MAX;
|
||||
if (key->type->preparse) {
|
||||
ret = key->type->preparse(&prep);
|
||||
if (ret < 0)
|
||||
@@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key,
|
||||
if (keyring) {
|
||||
ret = __key_link_begin(keyring, &key->index_key, &edit);
|
||||
if (ret < 0)
|
||||
goto error_free_preparse;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
|
||||
@@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key,
|
||||
if (keyring)
|
||||
__key_link_end(keyring, &key->index_key, edit);
|
||||
|
||||
error_free_preparse:
|
||||
error:
|
||||
if (key->type->preparse)
|
||||
key->type->free_preparse(&prep);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
|
||||
prep.datalen = plen;
|
||||
prep.quotalen = index_key.type->def_datalen;
|
||||
prep.trusted = flags & KEY_ALLOC_TRUSTED;
|
||||
prep.expiry = TIME_T_MAX;
|
||||
if (index_key.type->preparse) {
|
||||
ret = index_key.type->preparse(&prep);
|
||||
if (ret < 0) {
|
||||
key_ref = ERR_PTR(ret);
|
||||
goto error_put_type;
|
||||
goto error_free_prep;
|
||||
}
|
||||
if (!index_key.description)
|
||||
index_key.description = prep.description;
|
||||
@@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||
prep.data = payload;
|
||||
prep.datalen = plen;
|
||||
prep.quotalen = key->type->def_datalen;
|
||||
prep.expiry = TIME_T_MAX;
|
||||
if (key->type->preparse) {
|
||||
ret = key->type->preparse(&prep);
|
||||
if (ret < 0)
|
||||
@@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||
|
||||
up_write(&key->sem);
|
||||
|
||||
error:
|
||||
if (key->type->preparse)
|
||||
key->type->free_preparse(&prep);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(key_update);
|
||||
@@ -1023,6 +1030,38 @@ void key_invalidate(struct key *key)
|
||||
}
|
||||
EXPORT_SYMBOL(key_invalidate);
|
||||
|
||||
/**
|
||||
* generic_key_instantiate - Simple instantiation of a key from preparsed data
|
||||
* @key: The key to be instantiated
|
||||
* @prep: The preparsed data to load.
|
||||
*
|
||||
* Instantiate a key from preparsed data. We assume we can just copy the data
|
||||
* in directly and clear the old pointers.
|
||||
*
|
||||
* This can be pointed to directly by the key type instantiate op pointer.
|
||||
*/
|
||||
int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
ret = key_payload_reserve(key, prep->quotalen);
|
||||
if (ret == 0) {
|
||||
key->type_data.p[0] = prep->type_data[0];
|
||||
key->type_data.p[1] = prep->type_data[1];
|
||||
rcu_assign_keypointer(key, prep->payload[0]);
|
||||
key->payload.data2[1] = prep->payload[1];
|
||||
prep->type_data[0] = NULL;
|
||||
prep->type_data[1] = NULL;
|
||||
prep->payload[0] = NULL;
|
||||
prep->payload[1] = NULL;
|
||||
}
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_key_instantiate);
|
||||
|
||||
/**
|
||||
* register_key_type - Register a type of key.
|
||||
* @ktype: The new key type.
|
||||
|
||||
+18
-3
@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type,
|
||||
return ret;
|
||||
if (ret == 0 || ret >= len)
|
||||
return -EINVAL;
|
||||
if (type[0] == '.')
|
||||
return -EPERM;
|
||||
type[len - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||
if (!*description) {
|
||||
kfree(description);
|
||||
description = NULL;
|
||||
} else if ((description[0] == '.') &&
|
||||
(strncmp(type, "keyring", 7) == 0)) {
|
||||
ret = -EPERM;
|
||||
goto error2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id)
|
||||
key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
|
||||
if (IS_ERR(key_ref)) {
|
||||
ret = PTR_ERR(key_ref);
|
||||
|
||||
/* Root is permitted to invalidate certain special keys */
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
key_ref = lookup_user_key(id, 0, 0);
|
||||
if (IS_ERR(key_ref))
|
||||
goto error;
|
||||
if (test_bit(KEY_FLAG_ROOT_CAN_INVAL,
|
||||
&key_ref_to_ptr(key_ref)->flags))
|
||||
goto invalidate;
|
||||
goto error_put;
|
||||
}
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
invalidate:
|
||||
key_invalidate(key_ref_to_ptr(key_ref));
|
||||
ret = 0;
|
||||
|
||||
error_put:
|
||||
key_ref_put(key_ref);
|
||||
error:
|
||||
kleave(" = %ld", ret);
|
||||
|
||||
+23
-11
@@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc)
|
||||
* can be treated as ordinary keys in addition to having their own special
|
||||
* operations.
|
||||
*/
|
||||
static int keyring_preparse(struct key_preparsed_payload *prep);
|
||||
static void keyring_free_preparse(struct key_preparsed_payload *prep);
|
||||
static int keyring_instantiate(struct key *keyring,
|
||||
struct key_preparsed_payload *prep);
|
||||
static void keyring_revoke(struct key *keyring);
|
||||
@@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring,
|
||||
struct key_type key_type_keyring = {
|
||||
.name = "keyring",
|
||||
.def_datalen = 0,
|
||||
.preparse = keyring_preparse,
|
||||
.free_preparse = keyring_free_preparse,
|
||||
.instantiate = keyring_instantiate,
|
||||
.match = user_match,
|
||||
.revoke = keyring_revoke,
|
||||
@@ -122,6 +126,21 @@ static void keyring_publish_name(struct key *keyring)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparse a keyring payload
|
||||
*/
|
||||
static int keyring_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
return prep->datalen != 0 ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a preparse of a user defined key payload
|
||||
*/
|
||||
static void keyring_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise a keyring.
|
||||
*
|
||||
@@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring)
|
||||
static int keyring_instantiate(struct key *keyring,
|
||||
struct key_preparsed_payload *prep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (prep->datalen == 0) {
|
||||
assoc_array_init(&keyring->keys);
|
||||
/* make the keyring available by name if it has one */
|
||||
keyring_publish_name(keyring);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
assoc_array_init(&keyring->keys);
|
||||
/* make the keyring available by name if it has one */
|
||||
keyring_publish_name(keyring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "internal.h"
|
||||
#include <keys/user-type.h>
|
||||
|
||||
static int request_key_auth_preparse(struct key_preparsed_payload *);
|
||||
static void request_key_auth_free_preparse(struct key_preparsed_payload *);
|
||||
static int request_key_auth_instantiate(struct key *,
|
||||
struct key_preparsed_payload *);
|
||||
static void request_key_auth_describe(const struct key *, struct seq_file *);
|
||||
@@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t);
|
||||
struct key_type key_type_request_key_auth = {
|
||||
.name = ".request_key_auth",
|
||||
.def_datalen = sizeof(struct request_key_auth),
|
||||
.preparse = request_key_auth_preparse,
|
||||
.free_preparse = request_key_auth_free_preparse,
|
||||
.instantiate = request_key_auth_instantiate,
|
||||
.describe = request_key_auth_describe,
|
||||
.revoke = request_key_auth_revoke,
|
||||
@@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = {
|
||||
.read = request_key_auth_read,
|
||||
};
|
||||
|
||||
int request_key_auth_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a request-key authorisation key.
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc);
|
||||
struct key_type key_type_user = {
|
||||
.name = "user",
|
||||
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
|
||||
.instantiate = user_instantiate,
|
||||
.preparse = user_preparse,
|
||||
.free_preparse = user_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.update = user_update,
|
||||
.match = user_match,
|
||||
.revoke = user_revoke,
|
||||
@@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user);
|
||||
struct key_type key_type_logon = {
|
||||
.name = "logon",
|
||||
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
|
||||
.instantiate = user_instantiate,
|
||||
.preparse = user_preparse,
|
||||
.free_preparse = user_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.update = user_update,
|
||||
.match = user_match,
|
||||
.revoke = user_revoke,
|
||||
@@ -58,38 +62,37 @@ struct key_type key_type_logon = {
|
||||
EXPORT_SYMBOL_GPL(key_type_logon);
|
||||
|
||||
/*
|
||||
* instantiate a user defined key
|
||||
* Preparse a user defined key payload
|
||||
*/
|
||||
int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
int user_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct user_key_payload *upayload;
|
||||
size_t datalen = prep->datalen;
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (datalen <= 0 || datalen > 32767 || !prep->data)
|
||||
goto error;
|
||||
return -EINVAL;
|
||||
|
||||
ret = key_payload_reserve(key, datalen);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = -ENOMEM;
|
||||
upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
|
||||
if (!upayload)
|
||||
goto error;
|
||||
return -ENOMEM;
|
||||
|
||||
/* attach the data */
|
||||
prep->quotalen = datalen;
|
||||
prep->payload[0] = upayload;
|
||||
upayload->datalen = datalen;
|
||||
memcpy(upayload->data, prep->data, datalen);
|
||||
rcu_assign_keypointer(key, upayload);
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(user_preparse);
|
||||
|
||||
EXPORT_SYMBOL_GPL(user_instantiate);
|
||||
/*
|
||||
* Free a preparse of a user defined key payload
|
||||
*/
|
||||
void user_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
kfree(prep->payload[0]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(user_free_preparse);
|
||||
|
||||
/*
|
||||
* update a user defined key
|
||||
|
||||
@@ -845,6 +845,17 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
|
||||
return security_ops->kernel_create_files_as(new, inode);
|
||||
}
|
||||
|
||||
int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = security_ops->kernel_fw_from_file(file, buf, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ima_fw_from_file(file, buf, size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(security_kernel_fw_from_file);
|
||||
|
||||
int security_kernel_module_request(char *kmod_name)
|
||||
{
|
||||
return security_ops->kernel_module_request(kmod_name);
|
||||
|
||||
@@ -161,6 +161,17 @@ static int selinux_peerlbl_enabled(void)
|
||||
return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
|
||||
}
|
||||
|
||||
static int selinux_netcache_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netif_flush();
|
||||
sel_netnode_flush();
|
||||
sel_netport_flush();
|
||||
synchronize_net();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the security for the init task
|
||||
*/
|
||||
@@ -5993,6 +6004,9 @@ static __init int selinux_init(void)
|
||||
if (register_security(&selinux_ops))
|
||||
panic("SELinux: Unable to register with kernel.\n");
|
||||
|
||||
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
|
||||
panic("SELinux: Unable to register AVC netcache callback\n");
|
||||
|
||||
if (selinux_enforcing)
|
||||
printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
|
||||
else
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef _SELINUX_NETIF_H_
|
||||
#define _SELINUX_NETIF_H_
|
||||
|
||||
void sel_netif_flush(void);
|
||||
|
||||
int sel_netif_sid(int ifindex, u32 *sid);
|
||||
|
||||
#endif /* _SELINUX_NETIF_H_ */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user