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 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (33 commits) AppArmor: kill unused macros in lsm.c AppArmor: cleanup generated files correctly KEYS: Add an iovec version of KEYCTL_INSTANTIATE KEYS: Add a new keyctl op to reject a key with a specified error code KEYS: Add a key type op to permit the key description to be vetted KEYS: Add an RCU payload dereference macro AppArmor: Cleanup make file to remove cruft and make it easier to read SELinux: implement the new sb_remount LSM hook LSM: Pass -o remount options to the LSM SELinux: Compute SID for the newly created socket SELinux: Socket retains creator role and MLS attribute SELinux: Auto-generate security_is_socket_class TOMOYO: Fix memory leak upon file open. Revert "selinux: simplify ioctl checking" selinux: drop unused packet flow permissions selinux: Fix packet forwarding checks on postrouting selinux: Fix wrong checks for selinux_policycap_netpeer selinux: Fix check for xfrm selinux context algorithm ima: remove unnecessary call to ima_must_measure IMA: remove IMA imbalance checking ...
This commit is contained in:
@@ -6,19 +6,47 @@ apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
resource.o sid.o file.o
|
||||
|
||||
clean-files: capability_names.h af_names.h
|
||||
clean-files := capability_names.h rlim_names.h
|
||||
|
||||
|
||||
# Build a lower case string table of capability names
|
||||
# Transforms lines from
|
||||
# #define CAP_DAC_OVERRIDE 1
|
||||
# to
|
||||
# [1] = "dac_override",
|
||||
quiet_cmd_make-caps = GEN $@
|
||||
cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
|
||||
cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\
|
||||
sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \
|
||||
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\
|
||||
echo "};" >> $@
|
||||
|
||||
|
||||
# Build a lower case string table of rlimit names.
|
||||
# Transforms lines from
|
||||
# #define RLIMIT_STACK 3 /* max stack size */
|
||||
# to
|
||||
# [RLIMIT_STACK] = "stack",
|
||||
#
|
||||
# and build a second integer table (with the second sed cmd), that maps
|
||||
# RLIMIT defines to the order defined in asm-generic/resource.h Thi is
|
||||
# required by policy load to map policy ordering of RLIMITs to internal
|
||||
# ordering for architectures that redefine an RLIMIT.
|
||||
# Transforms lines from
|
||||
# #define RLIMIT_STACK 3 /* max stack size */
|
||||
# to
|
||||
# RLIMIT_STACK,
|
||||
quiet_cmd_make-rlim = GEN $@
|
||||
cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
|
||||
cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\
|
||||
sed $< >> $@ -r -n \
|
||||
-e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\
|
||||
echo "};" >> $@ ;\
|
||||
echo "static const int rlim_map[] = {" >> $@ ;\
|
||||
sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\
|
||||
echo "};" >> $@
|
||||
|
||||
$(obj)/capability.o : $(obj)/capability_names.h
|
||||
$(obj)/resource.o : $(obj)/rlim_names.h
|
||||
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
|
||||
$(call cmd,make-caps)
|
||||
$(obj)/af_names.h : $(srctree)/include/linux/socket.h
|
||||
$(call cmd,make-af)
|
||||
$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
|
||||
$(call cmd,make-rlim)
|
||||
|
||||
@@ -693,11 +693,9 @@ static struct kernel_param_ops param_ops_aalockpolicy = {
|
||||
|
||||
static int param_set_audit(const char *val, struct kernel_param *kp);
|
||||
static int param_get_audit(char *buffer, struct kernel_param *kp);
|
||||
#define param_check_audit(name, p) __param_check(name, p, int)
|
||||
|
||||
static int param_set_mode(const char *val, struct kernel_param *kp);
|
||||
static int param_get_mode(char *buffer, struct kernel_param *kp);
|
||||
#define param_check_mode(name, p) __param_check(name, p, int)
|
||||
|
||||
/* Flag values, also controllable via /sys/module/apparmor/parameters
|
||||
* We define special types as we want to do additional mediation.
|
||||
|
||||
@@ -12,11 +12,6 @@
|
||||
|
||||
#include <linux/security.h>
|
||||
|
||||
static int cap_sysctl(ctl_table *table, int op)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_syslog(int type)
|
||||
{
|
||||
return 0;
|
||||
@@ -59,6 +54,11 @@ static int cap_sb_copy_data(char *orig, char *copy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_sb_remount(struct super_block *sb, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||
{
|
||||
return 0;
|
||||
@@ -118,7 +118,8 @@ static void cap_inode_free_security(struct inode *inode)
|
||||
}
|
||||
|
||||
static int cap_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
char **name, void **value, size_t *len)
|
||||
const struct qstr *qstr, char **name,
|
||||
void **value, size_t *len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -880,7 +881,6 @@ void __init security_fixup_ops(struct security_operations *ops)
|
||||
set_to_cap_if_null(ops, capable);
|
||||
set_to_cap_if_null(ops, quotactl);
|
||||
set_to_cap_if_null(ops, quota_on);
|
||||
set_to_cap_if_null(ops, sysctl);
|
||||
set_to_cap_if_null(ops, syslog);
|
||||
set_to_cap_if_null(ops, settime);
|
||||
set_to_cap_if_null(ops, vm_enough_memory);
|
||||
@@ -892,6 +892,7 @@ void __init security_fixup_ops(struct security_operations *ops)
|
||||
set_to_cap_if_null(ops, sb_alloc_security);
|
||||
set_to_cap_if_null(ops, sb_free_security);
|
||||
set_to_cap_if_null(ops, sb_copy_data);
|
||||
set_to_cap_if_null(ops, sb_remount);
|
||||
set_to_cap_if_null(ops, sb_kern_mount);
|
||||
set_to_cap_if_null(ops, sb_show_options);
|
||||
set_to_cap_if_null(ops, sb_statfs);
|
||||
|
||||
@@ -110,8 +110,7 @@ struct ima_iint_cache {
|
||||
};
|
||||
|
||||
/* LIM API function definitions */
|
||||
int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
|
||||
int mask, int function);
|
||||
int ima_must_measure(struct inode *inode, int mask, int function);
|
||||
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file);
|
||||
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename);
|
||||
|
||||
@@ -105,20 +105,13 @@ err_out:
|
||||
* mask: contains the permission mask
|
||||
* fsmagic: hex value
|
||||
*
|
||||
* Must be called with iint->mutex held.
|
||||
*
|
||||
* Return 0 to measure. Return 1 if already measured.
|
||||
* For matching a DONT_MEASURE policy, no policy, or other
|
||||
* error, return an error code.
|
||||
* Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
|
||||
* or other error, return an error code.
|
||||
*/
|
||||
int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
|
||||
int mask, int function)
|
||||
int ima_must_measure(struct inode *inode, int mask, int function)
|
||||
{
|
||||
int must_measure;
|
||||
|
||||
if (iint && iint->flags & IMA_MEASURED)
|
||||
return 1;
|
||||
|
||||
must_measure = ima_match_policy(inode, function, mask);
|
||||
return must_measure ? 0 : -EACCES;
|
||||
}
|
||||
|
||||
@@ -137,11 +137,6 @@ void ima_inode_free(struct inode *inode)
|
||||
{
|
||||
struct ima_iint_cache *iint;
|
||||
|
||||
if (inode->i_readcount)
|
||||
printk(KERN_INFO "%s: readcount: %u\n", __func__, inode->i_readcount);
|
||||
|
||||
inode->i_readcount = 0;
|
||||
|
||||
if (!IS_IMA(inode))
|
||||
return;
|
||||
|
||||
|
||||
@@ -36,67 +36,17 @@ static int __init hash_setup(char *str)
|
||||
}
|
||||
__setup("ima_hash=", hash_setup);
|
||||
|
||||
struct ima_imbalance {
|
||||
struct hlist_node node;
|
||||
unsigned long fsmagic;
|
||||
};
|
||||
|
||||
/*
|
||||
* ima_limit_imbalance - emit one imbalance message per filesystem type
|
||||
* ima_rdwr_violation_check
|
||||
*
|
||||
* Maintain list of filesystem types that do not measure files properly.
|
||||
* Return false if unknown, true if known.
|
||||
*/
|
||||
static bool ima_limit_imbalance(struct file *file)
|
||||
{
|
||||
static DEFINE_SPINLOCK(ima_imbalance_lock);
|
||||
static HLIST_HEAD(ima_imbalance_list);
|
||||
|
||||
struct super_block *sb = file->f_dentry->d_sb;
|
||||
struct ima_imbalance *entry;
|
||||
struct hlist_node *node;
|
||||
bool found = false;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(entry, node, &ima_imbalance_list, node) {
|
||||
if (entry->fsmagic == sb->s_magic) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (found)
|
||||
goto out;
|
||||
|
||||
entry = kmalloc(sizeof(*entry), GFP_NOFS);
|
||||
if (!entry)
|
||||
goto out;
|
||||
entry->fsmagic = sb->s_magic;
|
||||
spin_lock(&ima_imbalance_lock);
|
||||
/*
|
||||
* we could have raced and something else might have added this fs
|
||||
* to the list, but we don't really care
|
||||
*/
|
||||
hlist_add_head_rcu(&entry->node, &ima_imbalance_list);
|
||||
spin_unlock(&ima_imbalance_lock);
|
||||
printk(KERN_INFO "IMA: unmeasured files on fsmagic: %lX\n",
|
||||
entry->fsmagic);
|
||||
out:
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_counts_get - increment file counts
|
||||
*
|
||||
* Maintain read/write counters for all files, but only
|
||||
* invalidate the PCR for measured files:
|
||||
* Only invalidate the PCR for measured files:
|
||||
* - Opening a file for write when already open for read,
|
||||
* results in a time of measure, time of use (ToMToU) error.
|
||||
* - Opening a file for read when already open for write,
|
||||
* could result in a file measurement error.
|
||||
*
|
||||
*/
|
||||
void ima_counts_get(struct file *file)
|
||||
static void ima_rdwr_violation_check(struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
@@ -104,32 +54,25 @@ void ima_counts_get(struct file *file)
|
||||
int rc;
|
||||
bool send_tomtou = false, send_writers = false;
|
||||
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
if (!S_ISREG(inode->i_mode) || !ima_initialized)
|
||||
return;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
|
||||
if (!ima_initialized)
|
||||
goto out;
|
||||
mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */
|
||||
|
||||
if (mode & FMODE_WRITE) {
|
||||
if (inode->i_readcount && IS_IMA(inode))
|
||||
if (atomic_read(&inode->i_readcount) && IS_IMA(inode))
|
||||
send_tomtou = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ima_must_measure(NULL, inode, MAY_READ, FILE_CHECK);
|
||||
rc = ima_must_measure(inode, MAY_READ, FILE_CHECK);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (atomic_read(&inode->i_writecount) > 0)
|
||||
send_writers = true;
|
||||
out:
|
||||
/* remember the vfs deals with i_writecount */
|
||||
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
inode->i_readcount++;
|
||||
|
||||
spin_unlock(&inode->i_lock);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
if (send_tomtou)
|
||||
ima_add_violation(inode, dentry->d_name.name, "invalid_pcr",
|
||||
@@ -139,71 +82,25 @@ out:
|
||||
"open_writers");
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement ima counts
|
||||
*/
|
||||
static void ima_dec_counts(struct inode *inode, struct file *file)
|
||||
{
|
||||
mode_t mode = file->f_mode;
|
||||
|
||||
assert_spin_locked(&inode->i_lock);
|
||||
|
||||
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
|
||||
if (unlikely(inode->i_readcount == 0)) {
|
||||
if (!ima_limit_imbalance(file)) {
|
||||
printk(KERN_INFO "%s: open/free imbalance (r:%u)\n",
|
||||
__func__, inode->i_readcount);
|
||||
dump_stack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
inode->i_readcount--;
|
||||
}
|
||||
}
|
||||
|
||||
static void ima_check_last_writer(struct ima_iint_cache *iint,
|
||||
struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
mode_t mode = file->f_mode;
|
||||
|
||||
BUG_ON(!mutex_is_locked(&iint->mutex));
|
||||
assert_spin_locked(&inode->i_lock);
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
if (mode & FMODE_WRITE &&
|
||||
atomic_read(&inode->i_writecount) == 1 &&
|
||||
iint->version != inode->i_version)
|
||||
iint->flags &= ~IMA_MEASURED;
|
||||
}
|
||||
|
||||
static void ima_file_free_iint(struct ima_iint_cache *iint, struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
mutex_lock(&iint->mutex);
|
||||
spin_lock(&inode->i_lock);
|
||||
|
||||
ima_dec_counts(inode, file);
|
||||
ima_check_last_writer(iint, inode, file);
|
||||
|
||||
spin_unlock(&inode->i_lock);
|
||||
mutex_unlock(&iint->mutex);
|
||||
}
|
||||
|
||||
static void ima_file_free_noiint(struct inode *inode, struct file *file)
|
||||
{
|
||||
spin_lock(&inode->i_lock);
|
||||
|
||||
ima_dec_counts(inode, file);
|
||||
|
||||
spin_unlock(&inode->i_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_file_free - called on __fput()
|
||||
* @file: pointer to file structure being freed
|
||||
*
|
||||
* Flag files that changed, based on i_version;
|
||||
* and decrement the i_readcount.
|
||||
* Flag files that changed, based on i_version
|
||||
*/
|
||||
void ima_file_free(struct file *file)
|
||||
{
|
||||
@@ -214,12 +111,10 @@ void ima_file_free(struct file *file)
|
||||
return;
|
||||
|
||||
iint = ima_iint_find(inode);
|
||||
if (!iint)
|
||||
return;
|
||||
|
||||
if (iint)
|
||||
ima_file_free_iint(iint, inode, file);
|
||||
else
|
||||
ima_file_free_noiint(inode, file);
|
||||
|
||||
ima_check_last_writer(iint, inode, file);
|
||||
}
|
||||
|
||||
static int process_measurement(struct file *file, const unsigned char *filename,
|
||||
@@ -232,7 +127,7 @@ static int process_measurement(struct file *file, const unsigned char *filename,
|
||||
if (!ima_initialized || !S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
|
||||
rc = ima_must_measure(NULL, inode, mask, function);
|
||||
rc = ima_must_measure(inode, mask, function);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
retry:
|
||||
@@ -246,7 +141,7 @@ retry:
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
|
||||
rc = ima_must_measure(iint, inode, mask, function);
|
||||
rc = iint->flags & IMA_MEASURED ? 1 : 0;
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
@@ -317,6 +212,7 @@ int ima_file_check(struct file *file, int mask)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ima_rdwr_violation_check(file);
|
||||
rc = process_measurement(file, file->f_dentry->d_name.name,
|
||||
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
|
||||
FILE_CHECK);
|
||||
|
||||
@@ -12,8 +12,51 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/slab.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Instantiate a key with the specified compatibility multipart payload and
|
||||
* link the key into the destination keyring if one is given.
|
||||
*
|
||||
* The caller must have the appropriate instantiation permit set for this to
|
||||
* work (see keyctl_assume_authority). No other permissions are required.
|
||||
*
|
||||
* If successful, 0 will be returned.
|
||||
*/
|
||||
long compat_keyctl_instantiate_key_iov(
|
||||
key_serial_t id,
|
||||
const struct compat_iovec __user *_payload_iov,
|
||||
unsigned ioc,
|
||||
key_serial_t ringid)
|
||||
{
|
||||
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
|
||||
long ret;
|
||||
|
||||
if (_payload_iov == 0 || ioc == 0)
|
||||
goto no_payload;
|
||||
|
||||
ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
||||
ARRAY_SIZE(iovstack),
|
||||
iovstack, &iov);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
goto no_payload_free;
|
||||
|
||||
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
|
||||
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
return ret;
|
||||
|
||||
no_payload_free:
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
no_payload:
|
||||
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
||||
}
|
||||
|
||||
/*
|
||||
* The key control system call, 32-bit compatibility version for 64-bit archs
|
||||
*
|
||||
@@ -85,6 +128,13 @@ asmlinkage long compat_sys_keyctl(u32 option,
|
||||
case KEYCTL_SESSION_TO_PARENT:
|
||||
return keyctl_session_to_parent();
|
||||
|
||||
case KEYCTL_REJECT:
|
||||
return keyctl_reject_key(arg2, arg3, arg4, arg5);
|
||||
|
||||
case KEYCTL_INSTANTIATE_IOV:
|
||||
return compat_keyctl_instantiate_key_iov(
|
||||
arg2, compat_ptr(arg3), arg4, arg5);
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -765,8 +765,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
|
||||
size_t asciiblob_len;
|
||||
int ret;
|
||||
|
||||
epayload = rcu_dereference_protected(key->payload.data,
|
||||
rwsem_is_locked(&((struct key *)key)->sem));
|
||||
epayload = rcu_dereference_key(key);
|
||||
|
||||
/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
|
||||
asciiblob_len = epayload->datablob_len + ivsize + 1
|
||||
|
||||
@@ -214,6 +214,14 @@ extern long keyctl_assume_authority(key_serial_t);
|
||||
extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
|
||||
size_t buflen);
|
||||
extern long keyctl_session_to_parent(void);
|
||||
extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
|
||||
extern long keyctl_instantiate_key_iov(key_serial_t,
|
||||
const struct iovec __user *,
|
||||
unsigned, key_serial_t);
|
||||
|
||||
extern long keyctl_instantiate_key_common(key_serial_t,
|
||||
const struct iovec __user *,
|
||||
unsigned, size_t, key_serial_t);
|
||||
|
||||
/*
|
||||
* Debugging key validation
|
||||
|
||||
+19
-8
@@ -249,6 +249,14 @@ struct key *key_alloc(struct key_type *type, const char *desc,
|
||||
if (!desc || !*desc)
|
||||
goto error;
|
||||
|
||||
if (type->vet_description) {
|
||||
ret = type->vet_description(desc);
|
||||
if (ret < 0) {
|
||||
key = ERR_PTR(ret);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
desclen = strlen(desc) + 1;
|
||||
quotalen = desclen + type->def_datalen;
|
||||
|
||||
@@ -503,26 +511,29 @@ int key_instantiate_and_link(struct key *key,
|
||||
EXPORT_SYMBOL(key_instantiate_and_link);
|
||||
|
||||
/**
|
||||
* key_negate_and_link - Negatively instantiate a key and link it into the keyring.
|
||||
* key_reject_and_link - Negatively instantiate a key and link it into the keyring.
|
||||
* @key: The key to instantiate.
|
||||
* @timeout: The timeout on the negative key.
|
||||
* @error: The error to return when the key is hit.
|
||||
* @keyring: Keyring to create a link in on success (or NULL).
|
||||
* @authkey: The authorisation token permitting instantiation.
|
||||
*
|
||||
* Negatively instantiate a key that's in the uninstantiated state and, if
|
||||
* successful, set its timeout and link it in to the destination keyring if one
|
||||
* is supplied. The key and any links to the key will be automatically garbage
|
||||
* collected after the timeout expires.
|
||||
* successful, set its timeout and stored error and link it in to the
|
||||
* destination keyring if one is supplied. The key and any links to the key
|
||||
* will be automatically garbage collected after the timeout expires.
|
||||
*
|
||||
* Negative keys are used to rate limit repeated request_key() calls by causing
|
||||
* them to return -ENOKEY until the negative key expires.
|
||||
* them to return the stored error code (typically ENOKEY) until the negative
|
||||
* key expires.
|
||||
*
|
||||
* If successful, 0 is returned, the authorisation token is revoked and anyone
|
||||
* waiting for the key is woken up. If the key was already instantiated,
|
||||
* -EBUSY will be returned.
|
||||
*/
|
||||
int key_negate_and_link(struct key *key,
|
||||
int key_reject_and_link(struct key *key,
|
||||
unsigned timeout,
|
||||
unsigned error,
|
||||
struct key *keyring,
|
||||
struct key *authkey)
|
||||
{
|
||||
@@ -548,6 +559,7 @@ int key_negate_and_link(struct key *key,
|
||||
atomic_inc(&key->user->nikeys);
|
||||
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
||||
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
|
||||
key->type_data.reject_error = -error;
|
||||
now = current_kernel_time();
|
||||
key->expiry = now.tv_sec + timeout;
|
||||
key_schedule_gc(key->expiry + key_gc_delay);
|
||||
@@ -577,8 +589,7 @@ int key_negate_and_link(struct key *key,
|
||||
|
||||
return ret == 0 ? link_ret : ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(key_negate_and_link);
|
||||
EXPORT_SYMBOL(key_reject_and_link);
|
||||
|
||||
/*
|
||||
* Garbage collect keys in process context so that we don't have to disable
|
||||
|
||||
+134
-9
@@ -912,6 +912,21 @@ static int keyctl_change_reqkey_auth(struct key *key)
|
||||
return commit_creds(new);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the iovec data from userspace
|
||||
*/
|
||||
static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
|
||||
unsigned ioc)
|
||||
{
|
||||
for (; ioc > 0; ioc--) {
|
||||
if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0)
|
||||
return -EFAULT;
|
||||
buffer += iov->iov_len;
|
||||
iov++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a key with the specified payload and link the key into the
|
||||
* destination keyring if one is given.
|
||||
@@ -921,10 +936,11 @@ static int keyctl_change_reqkey_auth(struct key *key)
|
||||
*
|
||||
* If successful, 0 will be returned.
|
||||
*/
|
||||
long keyctl_instantiate_key(key_serial_t id,
|
||||
const void __user *_payload,
|
||||
size_t plen,
|
||||
key_serial_t ringid)
|
||||
long keyctl_instantiate_key_common(key_serial_t id,
|
||||
const struct iovec *payload_iov,
|
||||
unsigned ioc,
|
||||
size_t plen,
|
||||
key_serial_t ringid)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct request_key_auth *rka;
|
||||
@@ -953,7 +969,7 @@ long keyctl_instantiate_key(key_serial_t id,
|
||||
/* pull the payload in if one was supplied */
|
||||
payload = NULL;
|
||||
|
||||
if (_payload) {
|
||||
if (payload_iov) {
|
||||
ret = -ENOMEM;
|
||||
payload = kmalloc(plen, GFP_KERNEL);
|
||||
if (!payload) {
|
||||
@@ -965,8 +981,8 @@ long keyctl_instantiate_key(key_serial_t id,
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(payload, _payload, plen) != 0)
|
||||
ret = copy_from_user_iovec(payload, payload_iov, ioc);
|
||||
if (ret < 0)
|
||||
goto error2;
|
||||
}
|
||||
|
||||
@@ -996,6 +1012,72 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a key with the specified payload and link the key into the
|
||||
* destination keyring if one is given.
|
||||
*
|
||||
* The caller must have the appropriate instantiation permit set for this to
|
||||
* work (see keyctl_assume_authority). No other permissions are required.
|
||||
*
|
||||
* If successful, 0 will be returned.
|
||||
*/
|
||||
long keyctl_instantiate_key(key_serial_t id,
|
||||
const void __user *_payload,
|
||||
size_t plen,
|
||||
key_serial_t ringid)
|
||||
{
|
||||
if (_payload && plen) {
|
||||
struct iovec iov[1] = {
|
||||
[0].iov_base = (void __user *)_payload,
|
||||
[0].iov_len = plen
|
||||
};
|
||||
|
||||
return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
|
||||
}
|
||||
|
||||
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate a key with the specified multipart payload and link the key into
|
||||
* the destination keyring if one is given.
|
||||
*
|
||||
* The caller must have the appropriate instantiation permit set for this to
|
||||
* work (see keyctl_assume_authority). No other permissions are required.
|
||||
*
|
||||
* If successful, 0 will be returned.
|
||||
*/
|
||||
long keyctl_instantiate_key_iov(key_serial_t id,
|
||||
const struct iovec __user *_payload_iov,
|
||||
unsigned ioc,
|
||||
key_serial_t ringid)
|
||||
{
|
||||
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
|
||||
long ret;
|
||||
|
||||
if (_payload_iov == 0 || ioc == 0)
|
||||
goto no_payload;
|
||||
|
||||
ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
||||
ARRAY_SIZE(iovstack), iovstack, &iov);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
goto no_payload_free;
|
||||
|
||||
ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
|
||||
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
return ret;
|
||||
|
||||
no_payload_free:
|
||||
if (iov != iovstack)
|
||||
kfree(iov);
|
||||
no_payload:
|
||||
return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Negatively instantiate the key with the given timeout (in seconds) and link
|
||||
* the key into the destination keyring if one is given.
|
||||
@@ -1012,13 +1094,43 @@ error:
|
||||
* If successful, 0 will be returned.
|
||||
*/
|
||||
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
|
||||
{
|
||||
return keyctl_reject_key(id, timeout, ENOKEY, ringid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Negatively instantiate the key with the given timeout (in seconds) and error
|
||||
* code and link the key into the destination keyring if one is given.
|
||||
*
|
||||
* The caller must have the appropriate instantiation permit set for this to
|
||||
* work (see keyctl_assume_authority). No other permissions are required.
|
||||
*
|
||||
* The key and any links to the key will be automatically garbage collected
|
||||
* after the timeout expires.
|
||||
*
|
||||
* Negative keys are used to rate limit repeated request_key() calls by causing
|
||||
* them to return the specified error code until the negative key expires.
|
||||
*
|
||||
* If successful, 0 will be returned.
|
||||
*/
|
||||
long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
|
||||
key_serial_t ringid)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct request_key_auth *rka;
|
||||
struct key *instkey, *dest_keyring;
|
||||
long ret;
|
||||
|
||||
kenter("%d,%u,%d", id, timeout, ringid);
|
||||
kenter("%d,%u,%u,%d", id, timeout, error, ringid);
|
||||
|
||||
/* must be a valid error code and mustn't be a kernel special */
|
||||
if (error <= 0 ||
|
||||
error >= MAX_ERRNO ||
|
||||
error == ERESTARTSYS ||
|
||||
error == ERESTARTNOINTR ||
|
||||
error == ERESTARTNOHAND ||
|
||||
error == ERESTART_RESTARTBLOCK)
|
||||
return -EINVAL;
|
||||
|
||||
/* the appropriate instantiation authorisation key must have been
|
||||
* assumed before calling this */
|
||||
@@ -1038,7 +1150,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
|
||||
goto error;
|
||||
|
||||
/* instantiate the key and link it into a keyring */
|
||||
ret = key_negate_and_link(rka->target_key, timeout,
|
||||
ret = key_reject_and_link(rka->target_key, timeout, error,
|
||||
dest_keyring, instkey);
|
||||
|
||||
key_put(dest_keyring);
|
||||
@@ -1492,6 +1604,19 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
||||
case KEYCTL_SESSION_TO_PARENT:
|
||||
return keyctl_session_to_parent();
|
||||
|
||||
case KEYCTL_REJECT:
|
||||
return keyctl_reject_key((key_serial_t) arg2,
|
||||
(unsigned) arg3,
|
||||
(unsigned) arg4,
|
||||
(key_serial_t) arg5);
|
||||
|
||||
case KEYCTL_INSTANTIATE_IOV:
|
||||
return keyctl_instantiate_key_iov(
|
||||
(key_serial_t) arg2,
|
||||
(const struct iovec __user *) arg3,
|
||||
(unsigned) arg4,
|
||||
(key_serial_t) arg5);
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
||||
goto error_2;
|
||||
if (key->expiry && now.tv_sec >= key->expiry)
|
||||
goto error_2;
|
||||
key_ref = ERR_PTR(-ENOKEY);
|
||||
key_ref = ERR_PTR(key->type_data.reject_error);
|
||||
if (kflags & (1 << KEY_FLAG_NEGATIVE))
|
||||
goto error_2;
|
||||
goto found;
|
||||
@@ -401,7 +401,7 @@ descend:
|
||||
|
||||
/* we set a different error code if we pass a negative key */
|
||||
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
|
||||
err = -ENOKEY;
|
||||
err = key->type_data.reject_error;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -585,7 +585,7 @@ int wait_for_key_construction(struct key *key, bool intr)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
|
||||
return -ENOKEY;
|
||||
return key->type_data.reject_error;
|
||||
return key_validate(key);
|
||||
}
|
||||
EXPORT_SYMBOL(wait_for_key_construction);
|
||||
|
||||
@@ -1076,8 +1076,7 @@ static long trusted_read(const struct key *key, char __user *buffer,
|
||||
char *bufp;
|
||||
int i;
|
||||
|
||||
p = rcu_dereference_protected(key->payload.data,
|
||||
rwsem_is_locked(&((struct key *)key)->sem));
|
||||
p = rcu_dereference_key(key);
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
if (!buffer || buflen <= 0)
|
||||
|
||||
@@ -184,8 +184,7 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
|
||||
struct user_key_payload *upayload;
|
||||
long ret;
|
||||
|
||||
upayload = rcu_dereference_protected(
|
||||
key->payload.data, rwsem_is_locked(&((struct key *)key)->sem));
|
||||
upayload = rcu_dereference_key(key);
|
||||
ret = upayload->datalen;
|
||||
|
||||
/* we can return the data as is */
|
||||
|
||||
+12
-7
@@ -181,11 +181,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int security_sysctl(struct ctl_table *table, int op)
|
||||
{
|
||||
return security_ops->sysctl(table, op);
|
||||
}
|
||||
|
||||
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
|
||||
{
|
||||
return security_ops->quotactl(cmds, type, id, sb);
|
||||
@@ -271,6 +266,11 @@ int security_sb_copy_data(char *orig, char *copy)
|
||||
}
|
||||
EXPORT_SYMBOL(security_sb_copy_data);
|
||||
|
||||
int security_sb_remount(struct super_block *sb, void *data)
|
||||
{
|
||||
return security_ops->sb_remount(sb, data);
|
||||
}
|
||||
|
||||
int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||
{
|
||||
return security_ops->sb_kern_mount(sb, flags, data);
|
||||
@@ -335,11 +335,13 @@ void security_inode_free(struct inode *inode)
|
||||
}
|
||||
|
||||
int security_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
char **name, void **value, size_t *len)
|
||||
const struct qstr *qstr, char **name,
|
||||
void **value, size_t *len)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(inode)))
|
||||
return -EOPNOTSUPP;
|
||||
return security_ops->inode_init_security(inode, dir, name, value, len);
|
||||
return security_ops->inode_init_security(inode, dir, qstr, name, value,
|
||||
len);
|
||||
}
|
||||
EXPORT_SYMBOL(security_inode_init_security);
|
||||
|
||||
@@ -359,6 +361,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
|
||||
return 0;
|
||||
return security_ops->path_mkdir(dir, dentry, mode);
|
||||
}
|
||||
EXPORT_SYMBOL(security_path_mkdir);
|
||||
|
||||
int security_path_rmdir(struct path *dir, struct dentry *dentry)
|
||||
{
|
||||
@@ -373,6 +376,7 @@ int security_path_unlink(struct path *dir, struct dentry *dentry)
|
||||
return 0;
|
||||
return security_ops->path_unlink(dir, dentry);
|
||||
}
|
||||
EXPORT_SYMBOL(security_path_unlink);
|
||||
|
||||
int security_path_symlink(struct path *dir, struct dentry *dentry,
|
||||
const char *old_name)
|
||||
@@ -399,6 +403,7 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
|
||||
return security_ops->path_rename(old_dir, old_dentry, new_dir,
|
||||
new_dentry);
|
||||
}
|
||||
EXPORT_SYMBOL(security_path_rename);
|
||||
|
||||
int security_path_truncate(struct path *path)
|
||||
{
|
||||
|
||||
+188
-162
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,10 @@
|
||||
#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
|
||||
"write", "associate", "unix_read", "unix_write"
|
||||
|
||||
/*
|
||||
* Note: The name for any socket class should be suffixed by "socket",
|
||||
* and doesn't contain more than one substr of "socket".
|
||||
*/
|
||||
struct security_class_mapping secclass_map[] = {
|
||||
{ "security",
|
||||
{ "compute_av", "compute_create", "compute_member",
|
||||
@@ -132,8 +136,7 @@ struct security_class_mapping secclass_map[] = {
|
||||
{ "appletalk_socket",
|
||||
{ COMMON_SOCK_PERMS, NULL } },
|
||||
{ "packet",
|
||||
{ "send", "recv", "relabelto", "flow_in", "flow_out",
|
||||
"forward_in", "forward_out", NULL } },
|
||||
{ "send", "recv", "relabelto", "forward_in", "forward_out", NULL } },
|
||||
{ "key",
|
||||
{ "view", "read", "write", "search", "link", "setattr", "create",
|
||||
NULL } },
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef _SELINUX_SECURITY_H_
|
||||
#define _SELINUX_SECURITY_H_
|
||||
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/types.h>
|
||||
#include "flask.h"
|
||||
@@ -28,13 +29,14 @@
|
||||
#define POLICYDB_VERSION_POLCAP 22
|
||||
#define POLICYDB_VERSION_PERMISSIVE 23
|
||||
#define POLICYDB_VERSION_BOUNDARY 24
|
||||
#define POLICYDB_VERSION_FILENAME_TRANS 25
|
||||
|
||||
/* Range of policy versions we understand*/
|
||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||
#else
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS
|
||||
#endif
|
||||
|
||||
/* Mask for just the mount related flags */
|
||||
@@ -106,8 +108,8 @@ void security_compute_av(u32 ssid, u32 tsid,
|
||||
void security_compute_av_user(u32 ssid, u32 tsid,
|
||||
u16 tclass, struct av_decision *avd);
|
||||
|
||||
int security_transition_sid(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 *out_sid);
|
||||
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
|
||||
const struct qstr *qstr, u32 *out_sid);
|
||||
|
||||
int security_transition_sid_user(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 *out_sid);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user