Merge commit 'v3.5-rc2' into next
This commit is contained in:
+4
-11
@@ -490,17 +490,9 @@ static int common_mmap(int op, struct file *file, unsigned long prot,
|
||||
return common_file_perm(op, file, mask);
|
||||
}
|
||||
|
||||
static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long addr, unsigned long addr_only)
|
||||
static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* do DAC check */
|
||||
rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
|
||||
if (rc || addr_only)
|
||||
return rc;
|
||||
|
||||
return common_mmap(OP_FMMAP, file, prot, flags);
|
||||
}
|
||||
|
||||
@@ -646,7 +638,8 @@ static struct security_operations apparmor_ops = {
|
||||
.file_permission = apparmor_file_permission,
|
||||
.file_alloc_security = apparmor_file_alloc_security,
|
||||
.file_free_security = apparmor_file_free_security,
|
||||
.file_mmap = apparmor_file_mmap,
|
||||
.mmap_file = apparmor_mmap_file,
|
||||
.mmap_addr = cap_mmap_addr,
|
||||
.file_mprotect = apparmor_file_mprotect,
|
||||
.file_lock = apparmor_file_lock,
|
||||
|
||||
|
||||
@@ -949,7 +949,8 @@ void __init security_fixup_ops(struct security_operations *ops)
|
||||
set_to_cap_if_null(ops, file_alloc_security);
|
||||
set_to_cap_if_null(ops, file_free_security);
|
||||
set_to_cap_if_null(ops, file_ioctl);
|
||||
set_to_cap_if_null(ops, file_mmap);
|
||||
set_to_cap_if_null(ops, mmap_addr);
|
||||
set_to_cap_if_null(ops, mmap_file);
|
||||
set_to_cap_if_null(ops, file_mprotect);
|
||||
set_to_cap_if_null(ops, file_lock);
|
||||
set_to_cap_if_null(ops, file_fcntl);
|
||||
|
||||
+44
-34
@@ -77,12 +77,12 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||
int cap, int audit)
|
||||
{
|
||||
for (;;) {
|
||||
/* The creator of the user namespace has all caps. */
|
||||
if (targ_ns != &init_user_ns && targ_ns->creator == cred->user)
|
||||
/* The owner of the user namespace has all caps. */
|
||||
if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
|
||||
return 0;
|
||||
|
||||
/* Do we have the necessary capabilities? */
|
||||
if (targ_ns == cred->user->user_ns)
|
||||
if (targ_ns == cred->user_ns)
|
||||
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
|
||||
|
||||
/* Have we tried all of the parent namespaces? */
|
||||
@@ -93,7 +93,7 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||
*If you have a capability in a parent user ns, then you have
|
||||
* it over all children user namespaces as well.
|
||||
*/
|
||||
targ_ns = targ_ns->creator->user_ns;
|
||||
targ_ns = targ_ns->parent;
|
||||
}
|
||||
|
||||
/* We never get here */
|
||||
@@ -137,10 +137,10 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
|
||||
rcu_read_lock();
|
||||
cred = current_cred();
|
||||
child_cred = __task_cred(child);
|
||||
if (cred->user->user_ns == child_cred->user->user_ns &&
|
||||
if (cred->user_ns == child_cred->user_ns &&
|
||||
cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
|
||||
goto out;
|
||||
if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE))
|
||||
if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))
|
||||
goto out;
|
||||
ret = -EPERM;
|
||||
out:
|
||||
@@ -169,10 +169,10 @@ int cap_ptrace_traceme(struct task_struct *parent)
|
||||
rcu_read_lock();
|
||||
cred = __task_cred(parent);
|
||||
child_cred = current_cred();
|
||||
if (cred->user->user_ns == child_cred->user->user_ns &&
|
||||
if (cred->user_ns == child_cred->user_ns &&
|
||||
cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
|
||||
goto out;
|
||||
if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE))
|
||||
if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE))
|
||||
goto out;
|
||||
ret = -EPERM;
|
||||
out:
|
||||
@@ -215,7 +215,7 @@ static inline int cap_inh_is_capped(void)
|
||||
/* they are so limited unless the current task has the CAP_SETPCAP
|
||||
* capability
|
||||
*/
|
||||
if (cap_capable(current_cred(), current_cred()->user->user_ns,
|
||||
if (cap_capable(current_cred(), current_cred()->user_ns,
|
||||
CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -473,19 +473,22 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
|
||||
struct cred *new = bprm->cred;
|
||||
bool effective, has_cap = false;
|
||||
int ret;
|
||||
kuid_t root_uid;
|
||||
|
||||
effective = false;
|
||||
ret = get_file_caps(bprm, &effective, &has_cap);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
root_uid = make_kuid(new->user_ns, 0);
|
||||
|
||||
if (!issecure(SECURE_NOROOT)) {
|
||||
/*
|
||||
* If the legacy file capability is set, then don't set privs
|
||||
* for a setuid root binary run by a non-root user. Do set it
|
||||
* for a root user just to cause least surprise to an admin.
|
||||
*/
|
||||
if (has_cap && new->uid != 0 && new->euid == 0) {
|
||||
if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
|
||||
warn_setuid_and_fcaps_mixed(bprm->filename);
|
||||
goto skip;
|
||||
}
|
||||
@@ -496,12 +499,12 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
|
||||
*
|
||||
* If only the real uid is 0, we do not set the effective bit.
|
||||
*/
|
||||
if (new->euid == 0 || new->uid == 0) {
|
||||
if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
|
||||
/* pP' = (cap_bset & ~0) | (pI & ~0) */
|
||||
new->cap_permitted = cap_combine(old->cap_bset,
|
||||
old->cap_inheritable);
|
||||
}
|
||||
if (new->euid == 0)
|
||||
if (uid_eq(new->euid, root_uid))
|
||||
effective = true;
|
||||
}
|
||||
skip:
|
||||
@@ -516,8 +519,8 @@ skip:
|
||||
*
|
||||
* In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
|
||||
*/
|
||||
if ((new->euid != old->uid ||
|
||||
new->egid != old->gid ||
|
||||
if ((!uid_eq(new->euid, old->uid) ||
|
||||
!gid_eq(new->egid, old->gid) ||
|
||||
!cap_issubset(new->cap_permitted, old->cap_permitted)) &&
|
||||
bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
|
||||
/* downgrade; they get no more than they had, and maybe less */
|
||||
@@ -553,7 +556,7 @@ skip:
|
||||
*/
|
||||
if (!cap_isclear(new->cap_effective)) {
|
||||
if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
|
||||
new->euid != 0 || new->uid != 0 ||
|
||||
!uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
|
||||
issecure(SECURE_NOROOT)) {
|
||||
ret = audit_log_bprm_fcaps(bprm, new, old);
|
||||
if (ret < 0)
|
||||
@@ -578,16 +581,17 @@ skip:
|
||||
int cap_bprm_secureexec(struct linux_binprm *bprm)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
kuid_t root_uid = make_kuid(cred->user_ns, 0);
|
||||
|
||||
if (cred->uid != 0) {
|
||||
if (!uid_eq(cred->uid, root_uid)) {
|
||||
if (bprm->cap_effective)
|
||||
return 1;
|
||||
if (!cap_isclear(cred->cap_permitted))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (cred->euid != cred->uid ||
|
||||
cred->egid != cred->gid);
|
||||
return (!uid_eq(cred->euid, cred->uid) ||
|
||||
!gid_eq(cred->egid, cred->gid));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -677,15 +681,21 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
*/
|
||||
static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
|
||||
{
|
||||
if ((old->uid == 0 || old->euid == 0 || old->suid == 0) &&
|
||||
(new->uid != 0 && new->euid != 0 && new->suid != 0) &&
|
||||
kuid_t root_uid = make_kuid(old->user_ns, 0);
|
||||
|
||||
if ((uid_eq(old->uid, root_uid) ||
|
||||
uid_eq(old->euid, root_uid) ||
|
||||
uid_eq(old->suid, root_uid)) &&
|
||||
(!uid_eq(new->uid, root_uid) &&
|
||||
!uid_eq(new->euid, root_uid) &&
|
||||
!uid_eq(new->suid, root_uid)) &&
|
||||
!issecure(SECURE_KEEP_CAPS)) {
|
||||
cap_clear(new->cap_permitted);
|
||||
cap_clear(new->cap_effective);
|
||||
}
|
||||
if (old->euid == 0 && new->euid != 0)
|
||||
if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
|
||||
cap_clear(new->cap_effective);
|
||||
if (old->euid != 0 && new->euid == 0)
|
||||
if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid))
|
||||
new->cap_effective = new->cap_permitted;
|
||||
}
|
||||
|
||||
@@ -718,11 +728,12 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
|
||||
* if not, we might be a bit too harsh here.
|
||||
*/
|
||||
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
|
||||
if (old->fsuid == 0 && new->fsuid != 0)
|
||||
kuid_t root_uid = make_kuid(old->user_ns, 0);
|
||||
if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid))
|
||||
new->cap_effective =
|
||||
cap_drop_fs_set(new->cap_effective);
|
||||
|
||||
if (old->fsuid != 0 && new->fsuid == 0)
|
||||
if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid))
|
||||
new->cap_effective =
|
||||
cap_raise_fs_set(new->cap_effective,
|
||||
new->cap_permitted);
|
||||
@@ -875,7 +886,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
|| ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
||||
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
||||
|| (cap_capable(current_cred(),
|
||||
current_cred()->user->user_ns, CAP_SETPCAP,
|
||||
current_cred()->user_ns, CAP_SETPCAP,
|
||||
SECURITY_CAP_AUDIT) != 0) /*[4]*/
|
||||
/*
|
||||
* [1] no changing of bits that are locked
|
||||
@@ -947,22 +958,15 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
|
||||
}
|
||||
|
||||
/*
|
||||
* cap_file_mmap - check if able to map given addr
|
||||
* @file: unused
|
||||
* @reqprot: unused
|
||||
* @prot: unused
|
||||
* @flags: unused
|
||||
* cap_mmap_addr - check if able to map given addr
|
||||
* @addr: address attempting to be mapped
|
||||
* @addr_only: unused
|
||||
*
|
||||
* If the process is attempting to map memory below dac_mmap_min_addr they need
|
||||
* CAP_SYS_RAWIO. The other parameters to this function are unused by the
|
||||
* capability security module. Returns 0 if this mapping should be allowed
|
||||
* -EPERM if not.
|
||||
*/
|
||||
int cap_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long addr, unsigned long addr_only)
|
||||
int cap_mmap_addr(unsigned long addr)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -975,3 +979,9 @@ int cap_file_mmap(struct file *file, unsigned long reqprot,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cap_mmap_file(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -447,22 +447,16 @@ static struct cftype dev_cgroup_files[] = {
|
||||
.read_seq_string = devcgroup_seq_read,
|
||||
.private = DEVCG_LIST,
|
||||
},
|
||||
{ } /* terminate */
|
||||
};
|
||||
|
||||
static int devcgroup_populate(struct cgroup_subsys *ss,
|
||||
struct cgroup *cgroup)
|
||||
{
|
||||
return cgroup_add_files(cgroup, ss, dev_cgroup_files,
|
||||
ARRAY_SIZE(dev_cgroup_files));
|
||||
}
|
||||
|
||||
struct cgroup_subsys devices_subsys = {
|
||||
.name = "devices",
|
||||
.can_attach = devcgroup_can_attach,
|
||||
.create = devcgroup_create,
|
||||
.destroy = devcgroup_destroy,
|
||||
.populate = devcgroup_populate,
|
||||
.subsys_id = devices_subsys_id,
|
||||
.base_cftypes = dev_cgroup_files,
|
||||
};
|
||||
|
||||
int __devcgroup_inode_permission(struct inode *inode, int mask)
|
||||
|
||||
@@ -38,7 +38,7 @@ static long compat_keyctl_instantiate_key_iov(
|
||||
|
||||
ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
||||
ARRAY_SIZE(iovstack),
|
||||
iovstack, &iov, 1);
|
||||
iovstack, &iov);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/task_work.h>
|
||||
|
||||
#ifdef __KDEBUG
|
||||
#define kenter(FMT, ...) \
|
||||
@@ -148,6 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
|
||||
#define KEY_LOOKUP_FOR_UNLINK 0x04
|
||||
|
||||
extern long join_session_keyring(const char *name);
|
||||
extern void key_change_session_keyring(struct task_work *twork);
|
||||
|
||||
extern struct work_struct key_gc_work;
|
||||
extern unsigned key_gc_delay;
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
|
||||
quotalen = desclen + type->def_datalen;
|
||||
|
||||
/* get hold of the key tracking for this user */
|
||||
user = key_user_lookup(uid, cred->user->user_ns);
|
||||
user = key_user_lookup(uid, cred->user_ns);
|
||||
if (!user)
|
||||
goto no_memory_1;
|
||||
|
||||
|
||||
+37
-40
@@ -84,7 +84,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||
vm = false;
|
||||
if (_payload) {
|
||||
ret = -ENOMEM;
|
||||
payload = kmalloc(plen, GFP_KERNEL);
|
||||
payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
|
||||
if (!payload) {
|
||||
if (plen <= PAGE_SIZE)
|
||||
goto error2;
|
||||
@@ -1110,7 +1110,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
|
||||
goto no_payload;
|
||||
|
||||
ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
|
||||
ARRAY_SIZE(iovstack), iovstack, &iov, 1);
|
||||
ARRAY_SIZE(iovstack), iovstack, &iov);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
@@ -1454,50 +1454,57 @@ long keyctl_get_security(key_serial_t keyid,
|
||||
*/
|
||||
long keyctl_session_to_parent(void)
|
||||
{
|
||||
#ifdef TIF_NOTIFY_RESUME
|
||||
struct task_struct *me, *parent;
|
||||
const struct cred *mycred, *pcred;
|
||||
struct cred *cred, *oldcred;
|
||||
struct task_work *newwork, *oldwork;
|
||||
key_ref_t keyring_r;
|
||||
struct cred *cred;
|
||||
int ret;
|
||||
|
||||
keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
|
||||
if (IS_ERR(keyring_r))
|
||||
return PTR_ERR(keyring_r);
|
||||
|
||||
ret = -ENOMEM;
|
||||
newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
|
||||
if (!newwork)
|
||||
goto error_keyring;
|
||||
|
||||
/* our parent is going to need a new cred struct, a new tgcred struct
|
||||
* and new security data, so we allocate them here to prevent ENOMEM in
|
||||
* our parent */
|
||||
ret = -ENOMEM;
|
||||
cred = cred_alloc_blank();
|
||||
if (!cred)
|
||||
goto error_keyring;
|
||||
goto error_newwork;
|
||||
|
||||
cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
|
||||
keyring_r = NULL;
|
||||
init_task_work(newwork, key_change_session_keyring, cred);
|
||||
|
||||
me = current;
|
||||
rcu_read_lock();
|
||||
write_lock_irq(&tasklist_lock);
|
||||
|
||||
parent = me->real_parent;
|
||||
ret = -EPERM;
|
||||
oldwork = NULL;
|
||||
parent = me->real_parent;
|
||||
|
||||
/* the parent mustn't be init and mustn't be a kernel thread */
|
||||
if (parent->pid <= 1 || !parent->mm)
|
||||
goto not_permitted;
|
||||
goto unlock;
|
||||
|
||||
/* the parent must be single threaded */
|
||||
if (!thread_group_empty(parent))
|
||||
goto not_permitted;
|
||||
goto unlock;
|
||||
|
||||
/* the parent and the child must have different session keyrings or
|
||||
* there's no point */
|
||||
mycred = current_cred();
|
||||
pcred = __task_cred(parent);
|
||||
if (mycred == pcred ||
|
||||
mycred->tgcred->session_keyring == pcred->tgcred->session_keyring)
|
||||
goto already_same;
|
||||
mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
|
||||
ret = 0;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* the parent must have the same effective ownership and mustn't be
|
||||
* SUID/SGID */
|
||||
@@ -1507,50 +1514,40 @@ long keyctl_session_to_parent(void)
|
||||
pcred->gid != mycred->egid ||
|
||||
pcred->egid != mycred->egid ||
|
||||
pcred->sgid != mycred->egid)
|
||||
goto not_permitted;
|
||||
goto unlock;
|
||||
|
||||
/* the keyrings must have the same UID */
|
||||
if ((pcred->tgcred->session_keyring &&
|
||||
pcred->tgcred->session_keyring->uid != mycred->euid) ||
|
||||
mycred->tgcred->session_keyring->uid != mycred->euid)
|
||||
goto not_permitted;
|
||||
goto unlock;
|
||||
|
||||
/* if there's an already pending keyring replacement, then we replace
|
||||
* that */
|
||||
oldcred = parent->replacement_session_keyring;
|
||||
/* cancel an already pending keyring replacement */
|
||||
oldwork = task_work_cancel(parent, key_change_session_keyring);
|
||||
|
||||
/* the replacement session keyring is applied just prior to userspace
|
||||
* restarting */
|
||||
parent->replacement_session_keyring = cred;
|
||||
cred = NULL;
|
||||
set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME);
|
||||
|
||||
ret = task_work_add(parent, newwork, true);
|
||||
if (!ret)
|
||||
newwork = NULL;
|
||||
unlock:
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
rcu_read_unlock();
|
||||
if (oldcred)
|
||||
put_cred(oldcred);
|
||||
return 0;
|
||||
|
||||
already_same:
|
||||
ret = 0;
|
||||
not_permitted:
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
rcu_read_unlock();
|
||||
put_cred(cred);
|
||||
if (oldwork) {
|
||||
put_cred(oldwork->data);
|
||||
kfree(oldwork);
|
||||
}
|
||||
if (newwork) {
|
||||
put_cred(newwork->data);
|
||||
kfree(newwork);
|
||||
}
|
||||
return ret;
|
||||
|
||||
error_newwork:
|
||||
kfree(newwork);
|
||||
error_keyring:
|
||||
key_ref_put(keyring_r);
|
||||
return ret;
|
||||
|
||||
#else /* !TIF_NOTIFY_RESUME */
|
||||
/*
|
||||
* To be removed when TIF_NOTIFY_RESUME has been implemented on
|
||||
* m68k/xtensa
|
||||
*/
|
||||
#warning TIF_NOTIFY_RESUME not implemented
|
||||
return -EOPNOTSUPP;
|
||||
#endif /* !TIF_NOTIFY_RESUME */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -36,7 +36,7 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
|
||||
|
||||
key = key_ref_to_ptr(key_ref);
|
||||
|
||||
if (key->user->user_ns != cred->user->user_ns)
|
||||
if (key->user->user_ns != cred->user_ns)
|
||||
goto use_other_perms;
|
||||
|
||||
/* use the second 8-bits of permissions for keys the caller owns */
|
||||
@@ -53,7 +53,8 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
|
||||
goto use_these_perms;
|
||||
}
|
||||
|
||||
ret = groups_search(cred->group_info, key->gid);
|
||||
ret = groups_search(cred->group_info,
|
||||
make_kgid(current_user_ns(), key->gid));
|
||||
if (ret) {
|
||||
kperm = key->perm >> 8;
|
||||
goto use_these_perms;
|
||||
|
||||
@@ -834,23 +834,17 @@ error:
|
||||
* Replace a process's session keyring on behalf of one of its children when
|
||||
* the target process is about to resume userspace execution.
|
||||
*/
|
||||
void key_replace_session_keyring(void)
|
||||
void key_change_session_keyring(struct task_work *twork)
|
||||
{
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
const struct cred *old = current_cred();
|
||||
struct cred *new = twork->data;
|
||||
|
||||
if (!current->replacement_session_keyring)
|
||||
kfree(twork);
|
||||
if (unlikely(current->flags & PF_EXITING)) {
|
||||
put_cred(new);
|
||||
return;
|
||||
}
|
||||
|
||||
write_lock_irq(&tasklist_lock);
|
||||
new = current->replacement_session_keyring;
|
||||
current->replacement_session_keyring = NULL;
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
|
||||
if (!new)
|
||||
return;
|
||||
|
||||
old = current_cred();
|
||||
new-> uid = old-> uid;
|
||||
new-> euid = old-> euid;
|
||||
new-> suid = old-> suid;
|
||||
@@ -860,7 +854,7 @@ void key_replace_session_keyring(void)
|
||||
new-> sgid = old-> sgid;
|
||||
new->fsgid = old->fsgid;
|
||||
new->user = get_uid(old->user);
|
||||
new->user_ns = new->user->user_ns;
|
||||
new->user_ns = get_user_ns(new->user_ns);
|
||||
new->group_info = get_group_info(old->group_info);
|
||||
|
||||
new->securebits = old->securebits;
|
||||
|
||||
@@ -93,16 +93,9 @@ static void umh_keys_cleanup(struct subprocess_info *info)
|
||||
static int call_usermodehelper_keys(char *path, char **argv, char **envp,
|
||||
struct key *session_keyring, int wait)
|
||||
{
|
||||
gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
|
||||
struct subprocess_info *info =
|
||||
call_usermodehelper_setup(path, argv, envp, gfp_mask);
|
||||
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup,
|
||||
key_get(session_keyring));
|
||||
return call_usermodehelper_exec(info, wait);
|
||||
return call_usermodehelper_fns(path, argv, envp, wait,
|
||||
umh_keys_init, umh_keys_cleanup,
|
||||
key_get(session_keyring));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+46
-5
@@ -20,6 +20,9 @@
|
||||
#include <linux/ima.h>
|
||||
#include <linux/evm.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/personality.h>
|
||||
#include <net/flow.h>
|
||||
|
||||
#define MAX_LSM_EVM_XATTR 2
|
||||
@@ -657,18 +660,56 @@ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
return security_ops->file_ioctl(file, cmd, arg);
|
||||
}
|
||||
|
||||
int security_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long addr, unsigned long addr_only)
|
||||
static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
|
||||
{
|
||||
/*
|
||||
* Does we have PROT_READ and does the application expect
|
||||
* it to imply PROT_EXEC? If not, nothing to talk about...
|
||||
*/
|
||||
if ((prot & (PROT_READ | PROT_EXEC)) != PROT_READ)
|
||||
return prot;
|
||||
if (!(current->personality & READ_IMPLIES_EXEC))
|
||||
return prot;
|
||||
/*
|
||||
* if that's an anonymous mapping, let it.
|
||||
*/
|
||||
if (!file)
|
||||
return prot | PROT_EXEC;
|
||||
/*
|
||||
* ditto if it's not on noexec mount, except that on !MMU we need
|
||||
* BDI_CAP_EXEC_MMAP (== VM_MAYEXEC) in this case
|
||||
*/
|
||||
if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) {
|
||||
#ifndef CONFIG_MMU
|
||||
unsigned long caps = 0;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
if (mapping && mapping->backing_dev_info)
|
||||
caps = mapping->backing_dev_info->capabilities;
|
||||
if (!(caps & BDI_CAP_EXEC_MAP))
|
||||
return prot;
|
||||
#endif
|
||||
return prot | PROT_EXEC;
|
||||
}
|
||||
/* anything on noexec mount won't get PROT_EXEC */
|
||||
return prot;
|
||||
}
|
||||
|
||||
int security_mmap_file(struct file *file, unsigned long prot,
|
||||
unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = security_ops->file_mmap(file, reqprot, prot, flags, addr, addr_only);
|
||||
ret = security_ops->mmap_file(file, prot,
|
||||
mmap_prot(file, prot), flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ima_file_mmap(file, prot);
|
||||
}
|
||||
|
||||
int security_mmap_addr(unsigned long addr)
|
||||
{
|
||||
return security_ops->mmap_addr(addr);
|
||||
}
|
||||
|
||||
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
|
||||
unsigned long prot)
|
||||
{
|
||||
|
||||
@@ -3083,9 +3083,7 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int selinux_file_mmap(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long addr, unsigned long addr_only)
|
||||
static int selinux_mmap_addr(unsigned long addr)
|
||||
{
|
||||
int rc = 0;
|
||||
u32 sid = current_sid();
|
||||
@@ -3104,10 +3102,12 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
|
||||
}
|
||||
|
||||
/* do DAC check on address space usage */
|
||||
rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
|
||||
if (rc || addr_only)
|
||||
return rc;
|
||||
return cap_mmap_addr(addr);
|
||||
}
|
||||
|
||||
static int selinux_mmap_file(struct file *file, unsigned long reqprot,
|
||||
unsigned long prot, unsigned long flags)
|
||||
{
|
||||
if (selinux_checkreqprot)
|
||||
prot = reqprot;
|
||||
|
||||
@@ -5570,7 +5570,8 @@ static struct security_operations selinux_ops = {
|
||||
.file_alloc_security = selinux_file_alloc_security,
|
||||
.file_free_security = selinux_file_free_security,
|
||||
.file_ioctl = selinux_file_ioctl,
|
||||
.file_mmap = selinux_file_mmap,
|
||||
.mmap_file = selinux_mmap_file,
|
||||
.mmap_addr = selinux_mmap_addr,
|
||||
.file_mprotect = selinux_file_mprotect,
|
||||
.file_lock = selinux_file_lock,
|
||||
.file_fcntl = selinux_file_fcntl,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/netfilter_ipv4/ip_queue.h>
|
||||
#include <linux/inet_diag.h>
|
||||
#include <linux/xfrm.h>
|
||||
#include <linux/audit.h>
|
||||
@@ -70,12 +69,6 @@ static struct nlmsg_perm nlmsg_route_perms[] =
|
||||
{ RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
|
||||
};
|
||||
|
||||
static struct nlmsg_perm nlmsg_firewall_perms[] =
|
||||
{
|
||||
{ IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
|
||||
{ IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
|
||||
};
|
||||
|
||||
static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
|
||||
{
|
||||
{ TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
|
||||
@@ -145,12 +138,6 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
|
||||
sizeof(nlmsg_route_perms));
|
||||
break;
|
||||
|
||||
case SECCLASS_NETLINK_FIREWALL_SOCKET:
|
||||
case SECCLASS_NETLINK_IP6FW_SOCKET:
|
||||
err = nlmsg_perm(nlmsg_type, perm, nlmsg_firewall_perms,
|
||||
sizeof(nlmsg_firewall_perms));
|
||||
break;
|
||||
|
||||
case SECCLASS_NETLINK_TCPDIAG_SOCKET:
|
||||
err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms,
|
||||
sizeof(nlmsg_tcpdiag_perms));
|
||||
|
||||
@@ -1259,12 +1259,8 @@ static int sel_make_bools(void)
|
||||
if (!inode)
|
||||
goto out;
|
||||
|
||||
ret = -EINVAL;
|
||||
len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
|
||||
if (len < 0)
|
||||
goto out;
|
||||
|
||||
ret = -ENAMETOOLONG;
|
||||
len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
|
||||
if (len >= PAGE_SIZE)
|
||||
goto out;
|
||||
|
||||
@@ -1557,19 +1553,10 @@ static inline u32 sel_ino_to_perm(unsigned long ino)
|
||||
static ssize_t sel_read_class(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
ssize_t rc, len;
|
||||
char *page;
|
||||
unsigned long ino = file->f_path.dentry->d_inode->i_ino;
|
||||
|
||||
page = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino));
|
||||
rc = simple_read_from_buffer(buf, count, ppos, page, len);
|
||||
free_page((unsigned long)page);
|
||||
|
||||
return rc;
|
||||
char res[TMPBUFLEN];
|
||||
ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
|
||||
return simple_read_from_buffer(buf, count, ppos, res, len);
|
||||
}
|
||||
|
||||
static const struct file_operations sel_class_ops = {
|
||||
@@ -1580,19 +1567,10 @@ static const struct file_operations sel_class_ops = {
|
||||
static ssize_t sel_read_perm(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
ssize_t rc, len;
|
||||
char *page;
|
||||
unsigned long ino = file->f_path.dentry->d_inode->i_ino;
|
||||
|
||||
page = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino));
|
||||
rc = simple_read_from_buffer(buf, count, ppos, page, len);
|
||||
free_page((unsigned long)page);
|
||||
|
||||
return rc;
|
||||
char res[TMPBUFLEN];
|
||||
ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
|
||||
return simple_read_from_buffer(buf, count, ppos, res, len);
|
||||
}
|
||||
|
||||
static const struct file_operations sel_perm_ops = {
|
||||
|
||||
@@ -1171,7 +1171,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_file_mmap :
|
||||
* smack_mmap_file :
|
||||
* Check permissions for a mmap operation. The @file may be NULL, e.g.
|
||||
* if mapping anonymous memory.
|
||||
* @file contains the file structure for file to map (may be NULL).
|
||||
@@ -1180,10 +1180,9 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
|
||||
* @flags contains the operational flags.
|
||||
* Return 0 if permission is granted.
|
||||
*/
|
||||
static int smack_file_mmap(struct file *file,
|
||||
static int smack_mmap_file(struct file *file,
|
||||
unsigned long reqprot, unsigned long prot,
|
||||
unsigned long flags, unsigned long addr,
|
||||
unsigned long addr_only)
|
||||
unsigned long flags)
|
||||
{
|
||||
struct smack_known *skp;
|
||||
struct smack_rule *srp;
|
||||
@@ -1198,11 +1197,6 @@ static int smack_file_mmap(struct file *file,
|
||||
int tmay;
|
||||
int rc;
|
||||
|
||||
/* do DAC check on address space usage */
|
||||
rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
|
||||
if (rc || addr_only)
|
||||
return rc;
|
||||
|
||||
if (file == NULL || file->f_dentry == NULL)
|
||||
return 0;
|
||||
|
||||
@@ -3482,7 +3476,8 @@ struct security_operations smack_ops = {
|
||||
.file_ioctl = smack_file_ioctl,
|
||||
.file_lock = smack_file_lock,
|
||||
.file_fcntl = smack_file_fcntl,
|
||||
.file_mmap = smack_file_mmap,
|
||||
.mmap_file = smack_mmap_file,
|
||||
.mmap_addr = cap_mmap_addr,
|
||||
.file_set_fowner = smack_file_set_fowner,
|
||||
.file_send_sigiotask = smack_file_send_sigiotask,
|
||||
.file_receive = smack_file_receive,
|
||||
|
||||
Reference in New Issue
Block a user