2008-08-06 15:49:01

by David Howells

[permalink] [raw]
Subject: [PATCH 00/24] Introduce credentials [ver #7]



I've brought my patchset up to date with regards the recent merge melee and
built the patches on top of the next branch of James's security testing tree as
per his request.

A tarball of these patches can be retrieved from:

http://people.redhat.com/~dhowells/cow-creds-7.tar.bz2

I've been testing these patches with the LTP syscalls and SELinux test scripts.

---
There are three parts to this project:

(1) Implement COW credentials.

(2) Pass the cred pointer through the vfs_xxx() functions and suchlike to all
the places that need them.

(3) Document it.

I'm intending to use this code to implement FS-Cache/CacheFiles, but it could
also be used for NFSD.


The associated patches implement (1) and part of (3). Some things to note:

(a) All of {,e,s,fs}{u,g}id and supplementary groups, capabilities, secure
bits, keyrings, and the task security pointer have migrated into struct
cred.

(b) Changing a tasks credentials involves creating a new struct cred (call
prepare_creds()) and then using RCU to change things over (call
commit_creds()).

(c) task_struct::cred is a const struct cred *, as are all pointers that
aren't used specifically for creating new credentials. This catches
places that are changing creds when they shouldn't be at compile time.

To get a new ref on a const cred, use get_cred() which casts away the
const and calls atomic_inc().

(d) It is no longer possible for a task to instantiate another task's
keyrings. The keyrings code tries to make sure that the required keyrings
are present in request_key(), and redirects any attempt to nominate a
process-specific keyring when instantiating a key to whatever keyring was
suggested by sys_request_key() (or it uses the default).

(e) sys_capset() is neutered: it can only affect the caller.

(f) execve() is cleaner. The changes are all worked out in a new set of
credentials, then the whole lot is installed in install_exec_creds() (a
replacement for compute_creds()) in three stages:

(i) The LSM is called - security_bprm_committing_creds() - so that the LSM
can do stuff that must be done before the new creds take effect.
SELinux uses this to call flush_authorized_files() and to flush
rlimits.

(ii) commit_creds() is called to make the actual change.

(iii) The LSM is called again - security_bprm_committed_creds() - so that
the LSM can do stuff that must be done under the new creds. SELinux
uses this to flush signal handlers.

(g) Most of the bprm LSM hooks have been replaced with simplified code
arranged differently.

(h) In struct file, f_uid and f_gid have been replaced by f_cred, which is a
pointer to the opener's credentials at the time of opening.

(i) Credentials are shared where possible. More work should go into this as
it plays it safe when sharing keyrings over non-CLONE_THREAD clones.

(j) The reparent_to_init LSM hook for kernel threads is gone. Kernel threads
now made to share init_cred instead at the start of their life (they may
change this later).

Most of the work is in patch 15 [Subject: CRED: Inaugurate COW credentials].
The description attached to this describes each of the logical changes in more
detail. The preceding patches are preparation.


I'm working on (2) and (3).

These patches compile for make allmodconfig, and I've built and run a kernel on
my x86_64 test box with these patches applied.

The patches are:

(*) 01-fix-PF_SUPERPRIV.diff

Fix PF_SUPERPRIV handling.

(*) 02-keys-disperse-key_ui_h.diff

Disperse the bits of <linux/key_ui.h> and delete the file. The keyfs
filesystem didn't happen, so this isn't necessary.

(*) 03-keys-alter-key-instantiation.diff

Alter the key instantiation code so as to remove the ability to directly
access another process's credentials. The contents of the keyrings
themselves may still change, however. I could implement a COW shadow of
the subscribed keyrings, but I really don't think it's worth it.

(*) 04-cred-neuter-sys_capset.diff

Remove the ability of sys_capset() to affect other processes.

(*) 05-cred-constify-capset-hooks.diff

(*) 06-cred-current-fsugid.diff
(*) 07-cred-current-ugid-eugid.diff

Wrap accesses to most current->*[ug]id and some task->*[ug]id to use
accessor macros to cut down the later patches and to hide RCU locking
where it may be necessary later.

(*) 08-cred-separate-creds.diff

Separate the credentials into cred struct, though that's still embedded in
task_struct at this point.

(*) 09-cred-detach-creds.diff

Detach the struct cred from task_struct, though its lifetime still follows
that of task_struct.

(*) 10-cred-current-wrappers.diff
(*) 11-cred-task-rcu-wrappers.diff
(*) 12-cred-selinux-wrappers.diff

Wrap accesses to current's creds. Wrap accesses to other tasks' creds to
hide the RCU where possible. Add in RCU directly where it is has to be.

(*) 13-cred-pertg-keyrings.diff

Separate the process and session keyrings from signal_struct, and make
them dangle shareably from struct cred instead.

(*) 14-cred-is_single_threaded.diff

Rename is_single_threaded() to is_wq_single_threaded().

(*) 15-cred-selinux-xxx_has_perm.diff

Make {file,inode}_has_perm() take a cred pointer.

(*) 16-cred-dentry_open.diff

Pass a cred pointer through dentry_open().

(*) 17-cred-cow-creds.diff

Do the actual work of COW credentials.

(*) 18-cred-improve-execve.diff

Make execve() take advantage of COW credentials.

(*) 19-cred-prettify-commoncap.diff

Add comments in to commoncap.c and do some other stylistic cleanups.

(*) 20-cred-file-creds.diff

Share the process's credentials with any files it opens.

(*) 21-cred-document.diff

Begin documenting the Linux credentials and the new API.

(*) 22-cred-objsubj-split.diff

Differentiate a task's objective and subjective credentials, thus allowing
kernel services to override the latter.

(*) 23-cred-kernel_service-class.diff

Add an SELinux class for kernel services and enumerate a couple of
operations therein.

(*) 24-cred-kernel-service.diff

Provide helper functions for kernel services that want to override
security details.


2008-08-06 15:40:37

by David Howells

[permalink] [raw]
Subject: [PATCH 12/24] CRED: Wrap access to SELinux's task SID [ver #7]

Wrap access to SELinux's task SID, using task_sid() and current_sid() as
appropriate.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
---

security/selinux/hooks.c | 416 ++++++++++++++++++++++++----------------------
1 files changed, 220 insertions(+), 196 deletions(-)


diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1efc990..27d1779 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -171,10 +171,35 @@ static int cred_alloc_security(struct cred *cred)
return 0;
}

+/*
+ * get the security ID of a task
+ */
+static inline u32 task_sid(const struct task_struct *task)
+{
+ const struct task_security_struct *tsec;
+ u32 sid;
+
+ rcu_read_lock();
+ tsec = __task_cred(task)->security;
+ sid = tsec->sid;
+ rcu_read_unlock();
+ return sid;
+}
+
+/*
+ * get the security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+ const struct task_security_struct *tsec = current_cred()->security;
+
+ return tsec->sid;
+}
+
static int inode_alloc_security(struct inode *inode)
{
- struct task_security_struct *tsec = current->cred->security;
struct inode_security_struct *isec;
+ u32 sid = current_sid();

isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
if (!isec)
@@ -185,7 +210,7 @@ static int inode_alloc_security(struct inode *inode)
isec->inode = inode;
isec->sid = SECINITSID_UNLABELED;
isec->sclass = SECCLASS_FILE;
- isec->task_sid = tsec->sid;
+ isec->task_sid = sid;
inode->i_security = isec;

return 0;
@@ -207,15 +232,15 @@ static void inode_free_security(struct inode *inode)

static int file_alloc_security(struct file *file)
{
- struct task_security_struct *tsec = current->cred->security;
struct file_security_struct *fsec;
+ u32 sid = current_sid();

fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
if (!fsec)
return -ENOMEM;

- fsec->sid = tsec->sid;
- fsec->fown_sid = tsec->sid;
+ fsec->sid = sid;
+ fsec->fown_sid = sid;
file->f_security = fsec;

return 0;
@@ -329,8 +354,9 @@ static match_table_t tokens = {

static int may_context_mount_sb_relabel(u32 sid,
struct superblock_security_struct *sbsec,
- struct task_security_struct *tsec)
+ const struct cred *cred)
{
+ const struct task_security_struct *tsec = cred->security;
int rc;

rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@ -345,8 +371,9 @@ static int may_context_mount_sb_relabel(u32 sid,

static int may_context_mount_inode_relabel(u32 sid,
struct superblock_security_struct *sbsec,
- struct task_security_struct *tsec)
+ const struct cred *cred)
{
+ const struct task_security_struct *tsec = cred->security;
int rc;
rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
@@ -544,8 +571,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
static int selinux_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
+ const struct cred *cred = current_cred();
int rc = 0, i;
- struct task_security_struct *tsec = current->cred->security;
struct superblock_security_struct *sbsec = sb->s_security;
const char *name = sb->s_type->name;
struct inode *inode = sbsec->sb->s_root->d_inode;
@@ -671,8 +698,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,

/* sets the context of the superblock for the fs being mounted. */
if (fscontext_sid) {
-
- rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, tsec);
+ rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
if (rc)
goto out;

@@ -686,12 +712,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
*/
if (context_sid) {
if (!fscontext_sid) {
- rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
+ rc = may_context_mount_sb_relabel(context_sid, sbsec,
+ cred);
if (rc)
goto out;
sbsec->sid = context_sid;
} else {
- rc = may_context_mount_inode_relabel(context_sid, sbsec, tsec);
+ rc = may_context_mount_inode_relabel(context_sid, sbsec,
+ cred);
if (rc)
goto out;
}
@@ -703,7 +731,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}

if (rootcontext_sid) {
- rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, tsec);
+ rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
+ cred);
if (rc)
goto out;

@@ -721,7 +750,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,

if (defcontext_sid != sbsec->def_sid) {
rc = may_context_mount_inode_relabel(defcontext_sid,
- sbsec, tsec);
+ sbsec, cred);
if (rc)
goto out;
}
@@ -1336,18 +1365,23 @@ static inline u32 signal_to_av(int sig)
return perm;
}

-/* Check permission betweeen a pair of tasks, e.g. signal checks,
- fork check, ptrace check, etc. */
-static int task_has_perm(struct task_struct *tsk1,
- struct task_struct *tsk2,
+/*
+ * Check permission betweeen a pair of tasks, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * tsk1 is the actor and tsk2 is the target
+ */
+static int task_has_perm(const struct task_struct *tsk1,
+ const struct task_struct *tsk2,
u32 perms)
{
- struct task_security_struct *tsec1, *tsec2;
+ const struct task_security_struct *__tsec1, *__tsec2;
+ u32 sid1, sid2;

- tsec1 = tsk1->cred->security;
- tsec2 = tsk2->cred->security;
- return avc_has_perm(tsec1->sid, tsec2->sid,
- SECCLASS_PROCESS, perms, NULL);
+ rcu_read_lock();
+ __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid;
+ __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid;
+ rcu_read_unlock();
+ return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
}

#if CAP_LAST_CAP > 63
@@ -1358,13 +1392,11 @@ static int task_has_perm(struct task_struct *tsk1,
static int task_has_capability(struct task_struct *tsk,
int cap)
{
- struct task_security_struct *tsec;
struct avc_audit_data ad;
u16 sclass;
+ u32 sid = task_sid(tsk);
u32 av = CAP_TO_MASK(cap);

- tsec = tsk->cred->security;
-
AVC_AUDIT_DATA_INIT(&ad, CAP);
ad.tsk = tsk;
ad.u.cap = cap;
@@ -1381,18 +1413,16 @@ static int task_has_capability(struct task_struct *tsk,
"SELinux: out of range capability %d\n", cap);
BUG();
}
- return avc_has_perm(tsec->sid, tsec->sid, sclass, av, &ad);
+ return avc_has_perm(sid, sid, sclass, av, &ad);
}

/* Check whether a task is allowed to use a system operation. */
static int task_has_system(struct task_struct *tsk,
u32 perms)
{
- struct task_security_struct *tsec;
-
- tsec = tsk->cred->security;
+ u32 sid = task_sid(tsk);

- return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
+ return avc_has_perm(sid, SECINITSID_KERNEL,
SECCLASS_SYSTEM, perms, NULL);
}

@@ -1404,14 +1434,14 @@ static int inode_has_perm(struct task_struct *tsk,
u32 perms,
struct avc_audit_data *adp)
{
- struct task_security_struct *tsec;
struct inode_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid;

if (unlikely(IS_PRIVATE(inode)))
return 0;

- tsec = tsk->cred->security;
+ sid = task_sid(tsk);
isec = inode->i_security;

if (!adp) {
@@ -1420,7 +1450,7 @@ static int inode_has_perm(struct task_struct *tsk,
ad.u.fs.inode = inode;
}

- return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, adp);
+ return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
}

/* Same as inode_has_perm, but pass explicit audit data containing
@@ -1451,17 +1481,17 @@ static int file_has_perm(struct task_struct *tsk,
struct file *file,
u32 av)
{
- struct task_security_struct *tsec = tsk->cred->security;
struct file_security_struct *fsec = file->f_security;
struct inode *inode = file->f_path.dentry->d_inode;
struct avc_audit_data ad;
+ u32 sid = task_sid(tsk);
int rc;

AVC_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path = file->f_path;

- if (tsec->sid != fsec->sid) {
- rc = avc_has_perm(tsec->sid, fsec->sid,
+ if (sid != fsec->sid) {
+ rc = avc_has_perm(sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -1481,36 +1511,36 @@ static int may_create(struct inode *dir,
struct dentry *dentry,
u16 tclass)
{
- struct task_security_struct *tsec;
+ const struct cred *cred = current_cred();
+ const struct task_security_struct *tsec = cred->security;
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
- u32 newsid;
+ u32 sid, newsid;
struct avc_audit_data ad;
int rc;

- tsec = current->cred->security;
dsec = dir->i_security;
sbsec = dir->i_sb->s_security;

+ sid = tsec->sid;
+ newsid = tsec->create_sid;
+
AVC_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path.dentry = dentry;

- rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR,
+ rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
&ad);
if (rc)
return rc;

- if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
- newsid = tsec->create_sid;
- } else {
- rc = security_transition_sid(tsec->sid, dsec->sid, tclass,
- &newsid);
+ if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+ rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
if (rc)
return rc;
}

- rc = avc_has_perm(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
+ rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;

@@ -1523,11 +1553,9 @@ static int may_create(struct inode *dir,
static int may_create_key(u32 ksid,
struct task_struct *ctx)
{
- struct task_security_struct *tsec;
-
- tsec = ctx->cred->security;
+ u32 sid = task_sid(ctx);

- return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+ return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
}

#define MAY_LINK 0
@@ -1540,13 +1568,12 @@ static int may_link(struct inode *dir,
int kind)

{
- struct task_security_struct *tsec;
struct inode_security_struct *dsec, *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();
u32 av;
int rc;

- tsec = current->cred->security;
dsec = dir->i_security;
isec = dentry->d_inode->i_security;

@@ -1555,7 +1582,7 @@ static int may_link(struct inode *dir,

av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
- rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;

@@ -1575,7 +1602,7 @@ static int may_link(struct inode *dir,
return 0;
}

- rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, av, &ad);
+ rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
return rc;
}

@@ -1584,14 +1611,13 @@ static inline int may_rename(struct inode *old_dir,
struct inode *new_dir,
struct dentry *new_dentry)
{
- struct task_security_struct *tsec;
struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();
u32 av;
int old_is_dir, new_is_dir;
int rc;

- tsec = current->cred->security;
old_dsec = old_dir->i_security;
old_isec = old_dentry->d_inode->i_security;
old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
@@ -1600,16 +1626,16 @@ static inline int may_rename(struct inode *old_dir,
AVC_AUDIT_DATA_INIT(&ad, FS);

ad.u.fs.path.dentry = old_dentry;
- rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR,
+ rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
return rc;
- rc = avc_has_perm(tsec->sid, old_isec->sid,
+ rc = avc_has_perm(sid, old_isec->sid,
old_isec->sclass, FILE__RENAME, &ad);
if (rc)
return rc;
if (old_is_dir && new_dir != old_dir) {
- rc = avc_has_perm(tsec->sid, old_isec->sid,
+ rc = avc_has_perm(sid, old_isec->sid,
old_isec->sclass, DIR__REPARENT, &ad);
if (rc)
return rc;
@@ -1619,13 +1645,13 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH;
if (new_dentry->d_inode)
av |= DIR__REMOVE_NAME;
- rc = avc_has_perm(tsec->sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
if (new_dentry->d_inode) {
new_isec = new_dentry->d_inode->i_security;
new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
- rc = avc_has_perm(tsec->sid, new_isec->sid,
+ rc = avc_has_perm(sid, new_isec->sid,
new_isec->sclass,
(new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
if (rc)
@@ -1641,13 +1667,11 @@ static int superblock_has_perm(struct task_struct *tsk,
u32 perms,
struct avc_audit_data *ad)
{
- struct task_security_struct *tsec;
struct superblock_security_struct *sbsec;
+ u32 sid = task_sid(tsk);

- tsec = tsk->cred->security;
sbsec = sb->s_security;
- return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
- perms, ad);
+ return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
}

/* Convert a Linux mode and permission mask to an access vector. */
@@ -1742,10 +1766,9 @@ static int selinux_ptrace_may_access(struct task_struct *child,
return rc;

if (mode == PTRACE_MODE_READ) {
- struct task_security_struct *tsec = current->cred->security;
- struct task_security_struct *csec = child->cred->security;
- return avc_has_perm(tsec->sid, csec->sid,
- SECCLASS_FILE, FILE__READ, NULL);
+ u32 sid = current_sid();
+ u32 csid = task_sid(child);
+ return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
}

return task_has_perm(current, child, PROCESS__PTRACE);
@@ -1850,15 +1873,14 @@ static int selinux_sysctl(ctl_table *table, int op)
{
int error = 0;
u32 av;
- struct task_security_struct *tsec;
- u32 tsid;
+ u32 tsid, sid;
int rc;

rc = secondary_ops->sysctl(table, op);
if (rc)
return rc;

- tsec = current->cred->security;
+ sid = current_sid();

rc = selinux_sysctl_get_sid(table, (op == 0001) ?
SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1870,7 +1892,7 @@ static int selinux_sysctl(ctl_table *table, int op)
/* The op values are "defined" in sysctl.c, thereby creating
* a bad coupling between this module and sysctl.c */
if (op == 001) {
- error = avc_has_perm(tsec->sid, tsid,
+ error = avc_has_perm(sid, tsid,
SECCLASS_DIR, DIR__SEARCH, NULL);
} else {
av = 0;
@@ -1879,7 +1901,7 @@ static int selinux_sysctl(ctl_table *table, int op)
if (op & 002)
av |= FILE__WRITE;
if (av)
- error = avc_has_perm(tsec->sid, tsid,
+ error = avc_has_perm(sid, tsid,
SECCLASS_FILE, av, NULL);
}

@@ -1965,11 +1987,11 @@ static int selinux_syslog(int type)
static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{
int rc, cap_sys_admin = 0;
- struct task_security_struct *tsec = current->cred->security;
+ u32 sid = current_sid();

rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
if (rc == 0)
- rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
+ rc = avc_has_perm_noaudit(sid, sid,
SECCLASS_CAPABILITY,
CAP_TO_MASK(CAP_SYS_ADMIN),
0,
@@ -2017,7 +2039,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
if (bsec->set)
return 0;

- tsec = current->cred->security;
+ tsec = current_security();
isec = inode->i_security;

/* Default to the current task SID. */
@@ -2082,14 +2104,19 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm)

static int selinux_bprm_secureexec(struct linux_binprm *bprm)
{
- struct task_security_struct *tsec = current->cred->security;
+ const struct cred *cred = current_cred();
+ const struct task_security_struct *tsec = cred->security;
+ u32 sid, osid;
int atsecure = 0;

- if (tsec->osid != tsec->sid) {
+ sid = tsec->sid;
+ osid = tsec->osid;
+
+ if (osid != sid) {
/* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
- atsecure = avc_has_perm(tsec->osid, tsec->sid,
+ atsecure = avc_has_perm(osid, sid,
SECCLASS_PROCESS,
PROCESS__NOATSECURE, NULL);
}
@@ -2205,7 +2232,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)

secondary_ops->bprm_apply_creds(bprm, unsafe);

- tsec = current->cred->security;
+ tsec = current_security();

bsec = bprm->security;
sid = bsec->sid;
@@ -2234,7 +2261,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
rcu_read_lock();
tracer = tracehook_tracer_task(current);
if (likely(tracer != NULL)) {
- sec = tracer->cred->security;
+ sec = __task_cred(tracer)->security;
ptsid = sec->sid;
}
rcu_read_unlock();
@@ -2263,7 +2290,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
struct bprm_security_struct *bsec;
int rc, i;

- tsec = current->cred->security;
+ tsec = current_security();
bsec = bprm->security;

if (bsec->unsafe) {
@@ -2504,21 +2531,22 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value,
size_t *len)
{
- struct task_security_struct *tsec;
+ const struct cred *cred = current_cred();
+ const struct task_security_struct *tsec = cred->security;
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
- u32 newsid, clen;
+ u32 sid, newsid, clen;
int rc;
char *namep = NULL, *context;

- tsec = current->cred->security;
dsec = dir->i_security;
sbsec = dir->i_sb->s_security;

- if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
- newsid = tsec->create_sid;
- } else {
- rc = security_transition_sid(tsec->sid, dsec->sid,
+ sid = tsec->sid;
+ newsid = tsec->create_sid;
+
+ if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+ rc = security_transition_sid(sid, dsec->sid,
inode_mode_to_security_class(inode->i_mode),
&newsid);
if (rc) {
@@ -2696,12 +2724,11 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- struct task_security_struct *tsec = current->cred->security;
struct inode *inode = dentry->d_inode;
struct inode_security_struct *isec = inode->i_security;
struct superblock_security_struct *sbsec;
struct avc_audit_data ad;
- u32 newsid;
+ u32 newsid, sid = current_sid();
int rc = 0;

if (strcmp(name, XATTR_NAME_SELINUX))
@@ -2717,7 +2744,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
AVC_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path.dentry = dentry;

- rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
+ rc = avc_has_perm(sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad);
if (rc)
return rc;
@@ -2731,12 +2758,12 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
if (rc)
return rc;

- rc = avc_has_perm(tsec->sid, newsid, isec->sclass,
+ rc = avc_has_perm(sid, newsid, isec->sclass,
FILE__RELABELTO, &ad);
if (rc)
return rc;

- rc = security_validate_transition(isec->sid, newsid, tsec->sid,
+ rc = security_validate_transition(isec->sid, newsid, sid,
isec->sclass);
if (rc)
return rc;
@@ -2804,7 +2831,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
u32 size;
int error;
char *context = NULL;
- struct task_security_struct *tsec = current->cred->security;
+ struct task_security_struct *tsec = current_security();
struct inode_security_struct *isec = inode->i_security;

if (strcmp(name, XATTR_SELINUX_SUFFIX))
@@ -2915,16 +2942,16 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
static int selinux_file_permission(struct file *file, int mask)
{
struct inode *inode = file->f_path.dentry->d_inode;
- struct task_security_struct *tsec = current->cred->security;
struct file_security_struct *fsec = file->f_security;
struct inode_security_struct *isec = inode->i_security;
+ u32 sid = current_sid();

if (!mask) {
/* No permission to check. Existence test. */
return 0;
}

- if (tsec->sid == fsec->sid && fsec->isid == isec->sid
+ if (sid == fsec->sid && fsec->isid == isec->sid
&& fsec->pseqno == avc_policy_seqno())
return selinux_netlbl_inode_permission(inode, mask);

@@ -2992,8 +3019,7 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
unsigned long addr, unsigned long addr_only)
{
int rc = 0;
- u32 sid = ((struct task_security_struct *)
- (current->cred->security))->sid;
+ u32 sid = current_sid();

if (addr < mmap_min_addr)
rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -3102,12 +3128,10 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,

static int selinux_file_set_fowner(struct file *file)
{
- struct task_security_struct *tsec;
struct file_security_struct *fsec;

- tsec = current->cred->security;
fsec = file->f_security;
- fsec->fown_sid = tsec->sid;
+ fsec->fown_sid = current_sid();

return 0;
}
@@ -3116,14 +3140,13 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
struct file *file;
+ u32 sid = current_sid();
u32 perm;
- struct task_security_struct *tsec;
struct file_security_struct *fsec;

/* struct fown_struct is never outside the context of a struct file */
file = container_of(fown, struct file, f_owner);

- tsec = tsk->cred->security;
fsec = file->f_security;

if (!signum)
@@ -3131,7 +3154,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else
perm = signal_to_av(signum);

- return avc_has_perm(fsec->fown_sid, tsec->sid,
+ return avc_has_perm(fsec->fown_sid, sid,
SECCLASS_PROCESS, perm, NULL);
}

@@ -3186,7 +3209,7 @@ static int selinux_cred_alloc_security(struct cred *cred)
struct task_security_struct *tsec1, *tsec2;
int rc;

- tsec1 = current->cred->security;
+ tsec1 = current_security();

rc = cred_alloc_security(cred);
if (rc)
@@ -3254,8 +3277,7 @@ static int selinux_task_getsid(struct task_struct *p)

static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
{
- struct task_security_struct *tsec = p->cred->security;
- *secid = tsec->sid;
+ *secid = task_sid(p);
}

static int selinux_task_setgroups(struct group_info *group_info)
@@ -3336,7 +3358,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
{
u32 perm;
int rc;
- struct task_security_struct *tsec;

rc = secondary_ops->task_kill(p, info, sig, secid);
if (rc)
@@ -3346,9 +3367,9 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
perm = signal_to_av(sig);
- tsec = p->cred->security;
if (secid)
- rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
+ rc = avc_has_perm(secid, task_sid(p),
+ SECCLASS_PROCESS, perm, NULL);
else
rc = task_has_perm(current, p, perm);
return rc;
@@ -3387,12 +3408,11 @@ static void selinux_task_reparent_to_init(struct task_struct *p)
static void selinux_task_to_inode(struct task_struct *p,
struct inode *inode)
{
- struct task_security_struct *tsec = p->cred->security;
struct inode_security_struct *isec = inode->i_security;
+ u32 sid = task_sid(p);

- isec->sid = tsec->sid;
+ isec->sid = sid;
isec->initialized = 1;
- return;
}

/* Returns error only if unable to parse addresses */
@@ -3631,19 +3651,19 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
u32 perms)
{
struct inode_security_struct *isec;
- struct task_security_struct *tsec;
struct avc_audit_data ad;
+ u32 sid;
int err = 0;

- tsec = task->cred->security;
isec = SOCK_INODE(sock)->i_security;

if (isec->sid == SECINITSID_KERNEL)
goto out;
+ sid = task_sid(task);

AVC_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.sk = sock->sk;
- err = avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
+ err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);

out:
return err;
@@ -3652,18 +3672,20 @@ out:
static int selinux_socket_create(int family, int type,
int protocol, int kern)
{
+ const struct cred *cred = current_cred();
+ const struct task_security_struct *tsec = cred->security;
+ u32 sid, newsid;
+ u16 secclass;
int err = 0;
- struct task_security_struct *tsec;
- u32 newsid;

if (kern)
goto out;

- tsec = current->cred->security;
- newsid = tsec->sockcreate_sid ? : tsec->sid;
- err = avc_has_perm(tsec->sid, newsid,
- socket_type_to_security_class(family, type,
- protocol), SOCKET__CREATE, NULL);
+ sid = tsec->sid;
+ newsid = tsec->sockcreate_sid ?: sid;
+
+ secclass = socket_type_to_security_class(family, type, protocol);
+ err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL);

out:
return err;
@@ -3672,18 +3694,26 @@ out:
static int selinux_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
- int err = 0;
+ const struct cred *cred = current_cred();
+ const struct task_security_struct *tsec = cred->security;
struct inode_security_struct *isec;
- struct task_security_struct *tsec;
struct sk_security_struct *sksec;
- u32 newsid;
+ u32 sid, newsid;
+ int err = 0;
+
+ sid = tsec->sid;
+ newsid = tsec->sockcreate_sid;

isec = SOCK_INODE(sock)->i_security;

- tsec = current->cred->security;
- newsid = tsec->sockcreate_sid ? : tsec->sid;
+ if (kern)
+ isec->sid = SECINITSID_KERNEL;
+ else if (newsid)
+ isec->sid = newsid;
+ else
+ isec->sid = sid;
+
isec->sclass = socket_type_to_security_class(family, type, protocol);
- isec->sid = kern ? SECINITSID_KERNEL : newsid;
isec->initialized = 1;

if (sock->sk) {
@@ -3718,7 +3748,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (family == PF_INET || family == PF_INET6) {
char *addrp;
struct inode_security_struct *isec;
- struct task_security_struct *tsec;
struct avc_audit_data ad;
struct sockaddr_in *addr4 = NULL;
struct sockaddr_in6 *addr6 = NULL;
@@ -3726,7 +3755,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
struct sock *sk = sock->sk;
u32 sid, node_perm;

- tsec = current->cred->security;
isec = SOCK_INODE(sock)->i_security;

if (family == PF_INET) {
@@ -4666,15 +4694,16 @@ static int ipc_alloc_security(struct task_struct *task,
struct kern_ipc_perm *perm,
u16 sclass)
{
- struct task_security_struct *tsec = task->cred->security;
struct ipc_security_struct *isec;
+ u32 sid;

isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
if (!isec)
return -ENOMEM;

+ sid = task_sid(task);
isec->sclass = sclass;
- isec->sid = tsec->sid;
+ isec->sid = sid;
perm->security = isec;

return 0;
@@ -4712,17 +4741,16 @@ static void msg_msg_free_security(struct msg_msg *msg)
static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
u32 perms)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();

- tsec = current->cred->security;
isec = ipc_perms->security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = ipc_perms->key;

- return avc_has_perm(tsec->sid, isec->sid, isec->sclass, perms, &ad);
+ return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
}

static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -4738,22 +4766,21 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
/* message queue security operations */
static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();
int rc;

rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
if (rc)
return rc;

- tsec = current->cred->security;
isec = msq->q_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = msq->q_perm.key;

- rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad);
if (rc) {
ipc_free_security(&msq->q_perm);
@@ -4769,17 +4796,16 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq)

static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();

- tsec = current->cred->security;
isec = msq->q_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = msq->q_perm.key;

- return avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+ return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad);
}

@@ -4813,13 +4839,12 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)

static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
struct avc_audit_data ad;
+ u32 sid = current_sid();
int rc;

- tsec = current->cred->security;
isec = msq->q_perm.security;
msec = msg->security;

@@ -4831,9 +4856,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
* Compute new sid based on current process and
* message queue this message will be stored in
*/
- rc = security_transition_sid(tsec->sid,
- isec->sid,
- SECCLASS_MSG,
+ rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
&msec->sid);
if (rc)
return rc;
@@ -4843,16 +4866,16 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
ad.u.ipc_id = msq->q_perm.key;

/* Can this process write to the queue? */
- rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
MSGQ__WRITE, &ad);
if (!rc)
/* Can this process send the message */
- rc = avc_has_perm(tsec->sid, msec->sid,
- SECCLASS_MSG, MSG__SEND, &ad);
+ rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
+ MSG__SEND, &ad);
if (!rc)
/* Can the message be put in the queue? */
- rc = avc_has_perm(msec->sid, isec->sid,
- SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad);
+ rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
+ MSGQ__ENQUEUE, &ad);

return rc;
}
@@ -4861,23 +4884,22 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
struct task_struct *target,
long type, int mode)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
struct avc_audit_data ad;
+ u32 sid = task_sid(target);
int rc;

- tsec = target->cred->security;
isec = msq->q_perm.security;
msec = msg->security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = msq->q_perm.key;

- rc = avc_has_perm(tsec->sid, isec->sid,
+ rc = avc_has_perm(sid, isec->sid,
SECCLASS_MSGQ, MSGQ__READ, &ad);
if (!rc)
- rc = avc_has_perm(tsec->sid, msec->sid,
+ rc = avc_has_perm(sid, msec->sid,
SECCLASS_MSG, MSG__RECEIVE, &ad);
return rc;
}
@@ -4885,22 +4907,21 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
/* Shared Memory security operations */
static int selinux_shm_alloc_security(struct shmid_kernel *shp)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();
int rc;

rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
if (rc)
return rc;

- tsec = current->cred->security;
isec = shp->shm_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = shp->shm_perm.key;

- rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
+ rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad);
if (rc) {
ipc_free_security(&shp->shm_perm);
@@ -4916,17 +4937,16 @@ static void selinux_shm_free_security(struct shmid_kernel *shp)

static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();

- tsec = current->cred->security;
isec = shp->shm_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = shp->shm_perm.key;

- return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SHM,
+ return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
SHM__ASSOCIATE, &ad);
}

@@ -4984,22 +5004,21 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
/* Semaphore security operations */
static int selinux_sem_alloc_security(struct sem_array *sma)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();
int rc;

rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
if (rc)
return rc;

- tsec = current->cred->security;
isec = sma->sem_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = sma->sem_perm.key;

- rc = avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
+ rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad);
if (rc) {
ipc_free_security(&sma->sem_perm);
@@ -5015,17 +5034,16 @@ static void selinux_sem_free_security(struct sem_array *sma)

static int selinux_sem_associate(struct sem_array *sma, int semflg)
{
- struct task_security_struct *tsec;
struct ipc_security_struct *isec;
struct avc_audit_data ad;
+ u32 sid = current_sid();

- tsec = current->cred->security;
isec = sma->sem_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
ad.u.ipc_id = sma->sem_perm.key;

- return avc_has_perm(tsec->sid, isec->sid, SECCLASS_SEM,
+ return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
SEM__ASSOCIATE, &ad);
}

@@ -5115,7 +5133,7 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
static int selinux_getprocattr(struct task_struct *p,
char *name, char **value)
{
- struct task_security_struct *tsec;
+ const struct task_security_struct *__tsec;
u32 sid;
int error;
unsigned len;
@@ -5126,22 +5144,24 @@ static int selinux_getprocattr(struct task_struct *p,
return error;
}

- tsec = p->cred->security;
+ rcu_read_lock();
+ __tsec = __task_cred(p)->security;

if (!strcmp(name, "current"))
- sid = tsec->sid;
+ sid = __tsec->sid;
else if (!strcmp(name, "prev"))
- sid = tsec->osid;
+ sid = __tsec->osid;
else if (!strcmp(name, "exec"))
- sid = tsec->exec_sid;
+ sid = __tsec->exec_sid;
else if (!strcmp(name, "fscreate"))
- sid = tsec->create_sid;
+ sid = __tsec->create_sid;
else if (!strcmp(name, "keycreate"))
- sid = tsec->keycreate_sid;
+ sid = __tsec->keycreate_sid;
else if (!strcmp(name, "sockcreate"))
- sid = tsec->sockcreate_sid;
+ sid = __tsec->sockcreate_sid;
else
- return -EINVAL;
+ goto invalid;
+ rcu_read_unlock();

if (!sid)
return 0;
@@ -5150,6 +5170,10 @@ static int selinux_getprocattr(struct task_struct *p,
if (error)
return error;
return len;
+
+invalid:
+ rcu_read_unlock();
+ return -EINVAL;
}

static int selinux_setprocattr(struct task_struct *p,
@@ -5254,9 +5278,7 @@ static int selinux_setprocattr(struct task_struct *p,
rcu_read_lock();
tracer = tracehook_tracer_task(p);
if (tracer != NULL) {
- struct task_security_struct *ptsec =
- tracer->cred->security;
- u32 ptsid = ptsec->sid;
+ u32 ptsid = task_sid(tracer);
rcu_read_unlock();
error = avc_has_perm_noaudit(ptsid, sid,
SECCLASS_PROCESS,
@@ -5299,19 +5321,22 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
unsigned long flags)
{
- struct task_security_struct *tsec = tsk->cred->security;
+ const struct task_security_struct *__tsec;
struct key_security_struct *ksec;

ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
if (!ksec)
return -ENOMEM;

- if (tsec->keycreate_sid)
- ksec->sid = tsec->keycreate_sid;
+ rcu_read_lock();
+ __tsec = __task_cred(tsk)->security;
+ if (__tsec->keycreate_sid)
+ ksec->sid = __tsec->keycreate_sid;
else
- ksec->sid = tsec->sid;
- k->security = ksec;
+ ksec->sid = __tsec->sid;
+ rcu_read_unlock();

+ k->security = ksec;
return 0;
}

@@ -5328,13 +5353,8 @@ static int selinux_key_permission(key_ref_t key_ref,
key_perm_t perm)
{
struct key *key;
- struct task_security_struct *tsec;
struct key_security_struct *ksec;
-
- key = key_ref_to_ptr(key_ref);
-
- tsec = ctx->cred->security;
- ksec = key->security;
+ u32 sid;

/* if no specific permissions are requested, we skip the
permission check. No serious, additional covert channels
@@ -5342,8 +5362,12 @@ static int selinux_key_permission(key_ref_t key_ref,
if (perm == 0)
return 0;

- return avc_has_perm(tsec->sid, ksec->sid,
- SECCLASS_KEY, perm, NULL);
+ sid = task_sid(ctx);
+
+ key = key_ref_to_ptr(key_ref);
+ ksec = key->security;
+
+ return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}

static int selinux_key_getsecurity(struct key *key, char **_buffer)

2008-08-06 15:40:54

by David Howells

[permalink] [raw]
Subject: [PATCH 14/24] CRED: Rename is_single_threaded() to is_wq_single_threaded() [ver #7]

Rename is_single_threaded() to is_wq_single_threaded() so that a new
is_single_threaded() can be created that refers to tasks rather than
waitqueues.

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
---

kernel/workqueue.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)


diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 4a26a13..e4e2bd3 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -83,21 +83,21 @@ static cpumask_t cpu_singlethread_map __read_mostly;
static cpumask_t cpu_populated_map __read_mostly;

/* If it's single threaded, it isn't in the list of workqueues. */
-static inline int is_single_threaded(struct workqueue_struct *wq)
+static inline int is_wq_single_threaded(struct workqueue_struct *wq)
{
return wq->singlethread;
}

static const cpumask_t *wq_cpu_map(struct workqueue_struct *wq)
{
- return is_single_threaded(wq)
+ return is_wq_single_threaded(wq)
? &cpu_singlethread_map : &cpu_populated_map;
}

static
struct cpu_workqueue_struct *wq_per_cpu(struct workqueue_struct *wq, int cpu)
{
- if (unlikely(is_single_threaded(wq)))
+ if (unlikely(is_wq_single_threaded(wq)))
cpu = singlethread_cpu;
return per_cpu_ptr(wq->cpu_wq, cpu);
}
@@ -767,7 +767,7 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
{
struct workqueue_struct *wq = cwq->wq;
- const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
+ const char *fmt = is_wq_single_threaded(wq) ? "%s" : "%s/%d";
struct task_struct *p;

p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);

2008-08-06 15:41:43

by David Howells

[permalink] [raw]
Subject: [PATCH 15/24] CRED: Make inode_has_perm() and file_has_perm() take a cred pointer [ver #7]

Make inode_has_perm() and file_has_perm() take a cred pointer rather than a
task pointer.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

security/selinux/hooks.c | 140 ++++++++++++++++++++++++++++++----------------
1 files changed, 92 insertions(+), 48 deletions(-)


diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 27d1779..fb76940 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -172,16 +172,25 @@ static int cred_alloc_security(struct cred *cred)
}

/*
+ * get the security ID of a set of credentials
+ */
+static inline u32 cred_sid(const struct cred *cred)
+{
+ const struct task_security_struct *tsec;
+
+ tsec = cred->security;
+ return tsec->sid;
+}
+
+/*
* get the security ID of a task
*/
static inline u32 task_sid(const struct task_struct *task)
{
- const struct task_security_struct *tsec;
u32 sid;

rcu_read_lock();
- tsec = __task_cred(task)->security;
- sid = tsec->sid;
+ sid = cred_sid(__task_cred(task));
rcu_read_unlock();
return sid;
}
@@ -196,6 +205,8 @@ static inline u32 current_sid(void)
return tsec->sid;
}

+/* Allocate and free functions for each kind of security blob. */
+
static int inode_alloc_security(struct inode *inode)
{
struct inode_security_struct *isec;
@@ -1366,7 +1377,7 @@ static inline u32 signal_to_av(int sig)
}

/*
- * Check permission betweeen a pair of tasks, e.g. signal checks,
+ * Check permission between a pair of tasks, e.g. signal checks,
* fork check, ptrace check, etc.
* tsk1 is the actor and tsk2 is the target
*/
@@ -1429,7 +1440,7 @@ static int task_has_system(struct task_struct *tsk,
/* Check whether a task has a particular permission to an inode.
The 'adp' parameter is optional and allows other audit
data to be passed (e.g. the dentry). */
-static int inode_has_perm(struct task_struct *tsk,
+static int inode_has_perm(const struct cred *cred,
struct inode *inode,
u32 perms,
struct avc_audit_data *adp)
@@ -1441,7 +1452,7 @@ static int inode_has_perm(struct task_struct *tsk,
if (unlikely(IS_PRIVATE(inode)))
return 0;

- sid = task_sid(tsk);
+ sid = cred_sid(cred);
isec = inode->i_security;

if (!adp) {
@@ -1456,17 +1467,18 @@ static int inode_has_perm(struct task_struct *tsk,
/* Same as inode_has_perm, but pass explicit audit data containing
the dentry to help the auditing code to more easily generate the
pathname if needed. */
-static inline int dentry_has_perm(struct task_struct *tsk,
+static inline int dentry_has_perm(const struct cred *cred,
struct vfsmount *mnt,
struct dentry *dentry,
u32 av)
{
struct inode *inode = dentry->d_inode;
struct avc_audit_data ad;
+
AVC_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path.mnt = mnt;
ad.u.fs.path.dentry = dentry;
- return inode_has_perm(tsk, inode, av, &ad);
+ return inode_has_perm(cred, inode, av, &ad);
}

/* Check whether a task can use an open file descriptor to
@@ -1477,14 +1489,14 @@ static inline int dentry_has_perm(struct task_struct *tsk,
has the same SID as the process. If av is zero, then
access to the file is not checked, e.g. for cases
where only the descriptor is affected like seek. */
-static int file_has_perm(struct task_struct *tsk,
- struct file *file,
- u32 av)
+static int file_has_perm(const struct cred *cred,
+ struct file *file,
+ u32 av)
{
struct file_security_struct *fsec = file->f_security;
struct inode *inode = file->f_path.dentry->d_inode;
struct avc_audit_data ad;
- u32 sid = task_sid(tsk);
+ u32 sid = cred_sid(cred);
int rc;

AVC_AUDIT_DATA_INIT(&ad, FS);
@@ -1496,14 +1508,16 @@ static int file_has_perm(struct task_struct *tsk,
FD__USE,
&ad);
if (rc)
- return rc;
+ goto out;
}

/* av is zero if only checking access to the descriptor. */
+ rc = 0;
if (av)
- return inode_has_perm(tsk, inode, av, &ad);
+ rc = inode_has_perm(cred, inode, av, &ad);

- return 0;
+out:
+ return rc;
}

/* Check whether a task can create a file. */
@@ -1662,13 +1676,13 @@ static inline int may_rename(struct inode *old_dir,
}

/* Check whether a task can perform a filesystem operation. */
-static int superblock_has_perm(struct task_struct *tsk,
+static int superblock_has_perm(const struct cred *cred,
struct super_block *sb,
u32 perms,
struct avc_audit_data *ad)
{
struct superblock_security_struct *sbsec;
- u32 sid = task_sid(tsk);
+ u32 sid = cred_sid(cred);

sbsec = sb->s_security;
return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
@@ -1910,6 +1924,7 @@ static int selinux_sysctl(ctl_table *table, int op)

static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
{
+ const struct cred *cred = current_cred();
int rc = 0;

if (!sb)
@@ -1921,14 +1936,12 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
case Q_QUOTAOFF:
case Q_SETINFO:
case Q_SETQUOTA:
- rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD,
- NULL);
+ rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
break;
case Q_GETFMT:
case Q_GETINFO:
case Q_GETQUOTA:
- rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET,
- NULL);
+ rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
break;
default:
rc = 0; /* let the kernel handle invalid cmds */
@@ -1939,7 +1952,9 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)

static int selinux_quota_on(struct dentry *dentry)
{
- return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON);
+ const struct cred *cred = current_cred();
+
+ return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
}

static int selinux_syslog(int type)
@@ -2136,6 +2151,7 @@ extern struct dentry *selinux_null;
/* Derived from fs/exec.c:flush_old_files. */
static inline void flush_unauthorized_files(struct files_struct *files)
{
+ const struct cred *cred = current_cred();
struct avc_audit_data ad;
struct file *file, *devnull = NULL;
struct tty_struct *tty;
@@ -2155,7 +2171,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
file may belong to another process and we are only
interested in the inode-based check here. */
struct inode *inode = file->f_path.dentry->d_inode;
- if (inode_has_perm(current, inode,
+ if (inode_has_perm(cred, inode,
FILE__READ | FILE__WRITE, NULL)) {
drop_tty = 1;
}
@@ -2190,7 +2206,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
file = fget(i);
if (!file)
continue;
- if (file_has_perm(current,
+ if (file_has_perm(cred,
file,
file_to_av(file))) {
sys_close(i);
@@ -2462,6 +2478,7 @@ out:

static int selinux_sb_kern_mount(struct super_block *sb, void *data)
{
+ const struct cred *cred = current_cred();
struct avc_audit_data ad;
int rc;

@@ -2471,16 +2488,17 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)

AVC_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path.dentry = sb->s_root;
- return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
+ return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
}

static int selinux_sb_statfs(struct dentry *dentry)
{
+ const struct cred *cred = current_cred();
struct avc_audit_data ad;

AVC_AUDIT_DATA_INIT(&ad, FS);
ad.u.fs.path.dentry = dentry->d_sb->s_root;
- return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
+ return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}

static int selinux_mount(char *dev_name,
@@ -2489,6 +2507,7 @@ static int selinux_mount(char *dev_name,
unsigned long flags,
void *data)
{
+ const struct cred *cred = current_cred();
int rc;

rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
@@ -2496,22 +2515,23 @@ static int selinux_mount(char *dev_name,
return rc;

if (flags & MS_REMOUNT)
- return superblock_has_perm(current, path->mnt->mnt_sb,
+ return superblock_has_perm(cred, path->mnt->mnt_sb,
FILESYSTEM__REMOUNT, NULL);
else
- return dentry_has_perm(current, path->mnt, path->dentry,
+ return dentry_has_perm(cred, path->mnt, path->dentry,
FILE__MOUNTON);
}

static int selinux_umount(struct vfsmount *mnt, int flags)
{
+ const struct cred *cred = current_cred();
int rc;

rc = secondary_ops->sb_umount(mnt, flags);
if (rc)
return rc;

- return superblock_has_perm(current, mnt->mnt_sb,
+ return superblock_has_perm(cred, mnt->mnt_sb,
FILESYSTEM__UNMOUNT, NULL);
}

@@ -2649,21 +2669,25 @@ static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dent

static int selinux_inode_readlink(struct dentry *dentry)
{
- return dentry_has_perm(current, NULL, dentry, FILE__READ);
+ const struct cred *cred = current_cred();
+
+ return dentry_has_perm(cred, NULL, dentry, FILE__READ);
}

static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
{
+ const struct cred *cred = current_cred();
int rc;

rc = secondary_ops->inode_follow_link(dentry, nameidata);
if (rc)
return rc;
- return dentry_has_perm(current, NULL, dentry, FILE__READ);
+ return dentry_has_perm(cred, NULL, dentry, FILE__READ);
}

static int selinux_inode_permission(struct inode *inode, int mask)
{
+ const struct cred *cred = current_cred();
int rc;

rc = secondary_ops->inode_permission(inode, mask);
@@ -2675,12 +2699,13 @@ static int selinux_inode_permission(struct inode *inode, int mask)
return 0;
}

- return inode_has_perm(current, inode,
+ return inode_has_perm(cred, inode,
open_file_mask_to_av(inode->i_mode, mask), NULL);
}

static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
+ const struct cred *cred = current_cred();
int rc;

rc = secondary_ops->inode_setattr(dentry, iattr);
@@ -2692,18 +2717,22 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)

if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
ATTR_ATIME_SET | ATTR_MTIME_SET))
- return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
+ return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);

- return dentry_has_perm(current, NULL, dentry, FILE__WRITE);
+ return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
}

static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{
- return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
+ const struct cred *cred = current_cred();
+
+ return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
}

static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
{
+ const struct cred *cred = current_cred();
+
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof XATTR_SECURITY_PREFIX - 1)) {
if (!strcmp(name, XATTR_NAME_CAPS)) {
@@ -2718,7 +2747,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)

/* Not an attribute we recognize, so just check the
ordinary setattr permission. */
- return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
+ return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
}

static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
@@ -2803,12 +2832,16 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,

static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
{
- return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
+ const struct cred *cred = current_cred();
+
+ return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
}

static int selinux_inode_listxattr(struct dentry *dentry)
{
- return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
+ const struct cred *cred = current_cred();
+
+ return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
}

static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
@@ -2919,6 +2952,7 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)

static int selinux_revalidate_file_permission(struct file *file, int mask)
{
+ const struct cred *cred = current_cred();
int rc;
struct inode *inode = file->f_path.dentry->d_inode;

@@ -2931,7 +2965,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
mask |= MAY_APPEND;

- rc = file_has_perm(current, file,
+ rc = file_has_perm(cred, file,
file_mask_to_av(inode->i_mode, mask));
if (rc)
return rc;
@@ -2971,6 +3005,7 @@ static void selinux_file_free_security(struct file *file)
static int selinux_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ const struct cred *cred = current_cred();
u32 av = 0;

if (_IOC_DIR(cmd) & _IOC_WRITE)
@@ -2980,11 +3015,13 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
if (!av)
av = FILE__IOCTL;

- return file_has_perm(current, file, av);
+ return file_has_perm(cred, file, av);
}

static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
{
+ const struct cred *cred = current_cred();
+
#ifndef CONFIG_PPC32
if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
/*
@@ -3009,7 +3046,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
if (prot & PROT_EXEC)
av |= FILE__EXECUTE;

- return file_has_perm(current, file, av);
+ return file_has_perm(cred, file, av);
}
return 0;
}
@@ -3038,6 +3075,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
unsigned long reqprot,
unsigned long prot)
{
+ const struct cred *cred = current_cred();
int rc;

rc = secondary_ops->file_mprotect(vma, reqprot, prot);
@@ -3066,7 +3104,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
* modified content. This typically should only
* occur for text relocations.
*/
- rc = file_has_perm(current, vma->vm_file,
+ rc = file_has_perm(cred, vma->vm_file,
FILE__EXECMOD);
}
if (rc)
@@ -3079,12 +3117,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,

static int selinux_file_lock(struct file *file, unsigned int cmd)
{
- return file_has_perm(current, file, FILE__LOCK);
+ const struct cred *cred = current_cred();
+
+ return file_has_perm(cred, file, FILE__LOCK);
}

static int selinux_file_fcntl(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ const struct cred *cred = current_cred();
int err = 0;

switch (cmd) {
@@ -3095,7 +3136,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
}

if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
- err = file_has_perm(current, file, FILE__WRITE);
+ err = file_has_perm(cred, file, FILE__WRITE);
break;
}
/* fall through */
@@ -3105,7 +3146,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
case F_GETOWN:
case F_GETSIG:
/* Just check FD__USE permission */
- err = file_has_perm(current, file, 0);
+ err = file_has_perm(cred, file, 0);
break;
case F_GETLK:
case F_SETLK:
@@ -3119,7 +3160,7 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
err = -EINVAL;
break;
}
- err = file_has_perm(current, file, FILE__LOCK);
+ err = file_has_perm(cred, file, FILE__LOCK);
break;
}

@@ -3160,11 +3201,14 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,

static int selinux_file_receive(struct file *file)
{
- return file_has_perm(current, file, file_to_av(file));
+ const struct cred *cred = current_cred();
+
+ return file_has_perm(cred, file, file_to_av(file));
}

static int selinux_dentry_open(struct file *file)
{
+ const struct cred *cred = current_cred();
struct file_security_struct *fsec;
struct inode *inode;
struct inode_security_struct *isec;
@@ -3188,7 +3232,7 @@ static int selinux_dentry_open(struct file *file)
* new inode label or new policy.
* This check is not redundant - do not remove.
*/
- return inode_has_perm(current, inode, file_to_av(file), NULL);
+ return inode_has_perm(cred, inode, file_to_av(file), NULL);
}

/* task security operations */

2008-08-06 15:41:19

by David Howells

[permalink] [raw]
Subject: [PATCH 19/24] CRED: Prettify commoncap.c [ver #7]

Prettify commoncap.c.

Signed-off-by: David Howells <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Reviewed-by: James Morris <[email protected]>
---

security/commoncap.c | 304 +++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 247 insertions(+), 57 deletions(-)


diff --git a/security/commoncap.c b/security/commoncap.c
index 3da0ada..c91b1af 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -39,16 +39,22 @@ int cap_netlink_recv(struct sk_buff *skb, int cap)
return -EPERM;
return 0;
}
-
EXPORT_SYMBOL(cap_netlink_recv);

-/*
+/**
+ * cap_capable - Determine whether a task has a particular effective capability
+ * @tsk: The task to query
+ * @cap: The capability to check for
+ *
+ * Determine whether the nominated task has the specified capability amongst
+ * its effective set, returning 0 if it does, -ve if it does not.
+ *
* NOTE WELL: cap_capable() cannot be used like the kernel's capable()
- * function. That is, it has the reverse semantics: cap_capable()
- * returns 0 when a task has a capability, but the kernel's capable()
- * returns 1 for this case.
+ * function. That is, it has the reverse semantics: cap_capable() returns 0
+ * when a task has a capability, but the kernel's capable() returns 1 for this
+ * case.
*/
-int cap_capable (struct task_struct *tsk, int cap)
+int cap_capable(struct task_struct *tsk, int cap)
{
__u32 cap_raised;

@@ -59,6 +65,14 @@ int cap_capable (struct task_struct *tsk, int cap)
return cap_raised ? 0 : -EPERM;
}

+/**
+ * cap_settime - Determine whether the current process may set the system clock
+ * @ts: The time to set
+ * @tz: The timezone to set
+ *
+ * Determine whether the current process may set the system clock and timezone
+ * information, returning 0 if permission granted, -ve if denied.
+ */
int cap_settime(struct timespec *ts, struct timezone *tz)
{
if (!capable(CAP_SYS_TIME))
@@ -66,6 +80,15 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
return 0;
}

+/**
+ * cap_ptrace_may_access - Determine whether the current process may access
+ * another
+ * @child: The process to be accessed
+ * @mode: The mode of attachment.
+ *
+ * Determine whether a process may access another, returning 0 if permission
+ * granted, -ve if denied.
+ */
int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
{
int ret = 0;
@@ -79,6 +102,13 @@ int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
return ret;
}

+/**
+ * cap_ptrace_traceme - Determine whether another process may trace the current
+ * @parent: The task proposed to be the tracer
+ *
+ * Determine whether the nominated task is permitted to trace the current
+ * process, returning 0 if permission is granted, -ve if denied.
+ */
int cap_ptrace_traceme(struct task_struct *parent)
{
int ret = 0;
@@ -92,8 +122,18 @@ int cap_ptrace_traceme(struct task_struct *parent)
return ret;
}

-int cap_capget (struct task_struct *target, kernel_cap_t *effective,
- kernel_cap_t *inheritable, kernel_cap_t *permitted)
+/**
+ * cap_capget - Retrieve a task's capability sets
+ * @target: The task from which to retrieve the capability sets
+ * @effective: The place to record the effective set
+ * @inheritable: The place to record the inheritable set
+ * @permitted: The place to record the permitted set
+ *
+ * This function retrieves the capabilities of the nominated task and returns
+ * them to the caller.
+ */
+int cap_capget(struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
const struct cred *cred;

@@ -107,30 +147,35 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,
return 0;
}

-#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
-
+/*
+ * Determine whether the inheritable capabilities are limited to the old
+ * permitted set. Returns 1 if they are limited, 0 if they are not.
+ */
static inline int cap_inh_is_capped(void)
{
- /*
- * Return 1 if changes to the inheritable set are limited
- * to the old permitted set. That is, if the current task
- * does *not* possess the CAP_SETPCAP capability.
- */
- return cap_capable(current, CAP_SETPCAP) != 0;
-}
-
-static inline int cap_limit_ptraced_target(void) { return 1; }
-
-#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES

-static inline int cap_inh_is_capped(void) { return 1; }
-static inline int cap_limit_ptraced_target(void)
-{
- return !capable(CAP_SETPCAP);
+ /* they are so limited unless the current task has the CAP_SETPCAP
+ * capability
+ */
+ if (cap_capable(current, CAP_SETPCAP) == 0)
+ return 0;
+#endif
+ return 1;
}

-#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
-
+/**
+ * cap_capset - Validate and apply proposed changes to current's capabilities
+ * @new: The proposed new credentials; alterations should be made here
+ * @old: The current task's current credentials
+ * @effective: A pointer to the proposed new effective capabilities set
+ * @inheritable: A pointer to the proposed new inheritable capabilities set
+ * @permitted: A pointer to the proposed new permitted capabilities set
+ *
+ * This function validates and applies a proposed mass change to the current
+ * process's capability sets. The changes are made to the proposed new
+ * credentials, and assuming no error, will be committed by the caller of LSM.
+ */
int cap_capset(struct cred *new,
const struct cred *old,
const kernel_cap_t *effective,
@@ -164,6 +209,9 @@ int cap_capset(struct cred *new,
return 0;
}

+/*
+ * Clear proposed capability sets for execve().
+ */
static inline void bprm_clear_caps(struct linux_binprm *bprm)
{
cap_clear(bprm->cred->cap_permitted);
@@ -172,6 +220,17 @@ static inline void bprm_clear_caps(struct linux_binprm *bprm)

#ifdef CONFIG_SECURITY_FILE_CAPABILITIES

+/**
+ * cap_inode_need_killpriv - Determine if inode change affects privileges
+ * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV
+ *
+ * Determine if an inode having a change applied that's marked ATTR_KILL_PRIV
+ * affects the security markings on that inode, and if it is, should
+ * inode_killpriv() be invoked or the change rejected?
+ *
+ * Returns 0 if granted; +ve if granted, but inode_killpriv() is required; and
+ * -ve to deny the change.
+ */
int cap_inode_need_killpriv(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
@@ -186,6 +245,14 @@ int cap_inode_need_killpriv(struct dentry *dentry)
return 1;
}

+/**
+ * cap_inode_killpriv - Erase the security markings on an inode
+ * @dentry: The inode/dentry to alter
+ *
+ * Erase the privilege-enhancing security markings on an inode.
+ *
+ * Returns 0 if successful, -ve on error.
+ */
int cap_inode_killpriv(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
@@ -196,6 +263,9 @@ int cap_inode_killpriv(struct dentry *dentry)
return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
}

+/*
+ * Extract the on-exec-apply capability sets for an executable file.
+ */
static inline int cap_from_disk(struct vfs_cap_data *caps,
struct linux_binprm *bprm, unsigned size,
bool *effective)
@@ -264,7 +334,11 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
return *effective ? ret : 0;
}

-/* Locate any VFS capabilities: */
+/*
+ * Attempt to get the on-exec apply capability sets for an executable file from
+ * its xattrs and, if present, apply them to the proposed credentials being
+ * constructed by execve().
+ */
static int get_file_caps(struct linux_binprm *bprm, bool *effective)
{
struct dentry *dentry;
@@ -324,7 +398,31 @@ static inline int get_file_caps(struct linux_binprm *bprm, bool *effective)
#endif

/*
- * set up the new credentials for an exec'd task
+ * Determine whether a exec'ing process's new permitted capabilities should be
+ * limited to just what it already has.
+ *
+ * This prevents processes that are being ptraced from gaining access to
+ * CAP_SETPCAP, unless the process they're tracing already has it, and the
+ * binary they're executing has filecaps that elevate it.
+ *
+ * Returns 1 if they should be limited, 0 if they are not.
+ */
+static inline int cap_limit_ptraced_target(void)
+{
+#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
+ if (capable(CAP_SETPCAP))
+ return 0;
+#endif
+ return 1;
+}
+
+/**
+ * cap_bprm_set_creds - Set up the proposed credentials for execve().
+ * @bprm: The execution parameters, including the proposed creds
+ *
+ * Set up the proposed credentials for a new execution context being
+ * constructed by execve(). The proposed creds in @bprm->cred is altered,
+ * which won't take effect immediately. Returns 0 if successful, -ve on error.
*/
int cap_bprm_set_creds(struct linux_binprm *bprm)
{
@@ -392,10 +490,15 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
return 0;
}

-/*
- * determine whether a secure execution is required
- * - the creds have been committed at this point, and are no longer available
- * through bprm
+/**
+ * cap_bprm_secureexec - Determine whether a secure execution is required
+ * @bprm: The execution parameters
+ *
+ * Determine whether a secure execution is required, return 1 if it is, and 0
+ * if it is not.
+ *
+ * The credentials have been committed by this point, and so are no longer
+ * available through @bprm->cred.
*/
int cap_bprm_secureexec(struct linux_binprm *bprm)
{
@@ -412,6 +515,20 @@ int cap_bprm_secureexec(struct linux_binprm *bprm)
cred->egid != cred->gid);
}

+/**
+ * cap_inode_setxattr - Determine whether an xattr may be altered
+ * @dentry: The inode/dentry being altered
+ * @name: The name of the xattr to be changed
+ * @value: The value that the xattr will be changed to
+ * @size: The size of value
+ * @flags: The replacement flag
+ *
+ * Determine whether an xattr may be altered or set on an inode, returning 0 if
+ * permission is granted, -ve if denied.
+ *
+ * This is used to make sure security xattrs don't get updated or set by those
+ * who aren't privileged to do so.
+ */
int cap_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
@@ -419,28 +536,42 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
if (!capable(CAP_SETFCAP))
return -EPERM;
return 0;
- } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
+ }
+
+ if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}

+/**
+ * cap_inode_removexattr - Determine whether an xattr may be removed
+ * @dentry: The inode/dentry being altered
+ * @name: The name of the xattr to be changed
+ *
+ * Determine whether an xattr may be removed from an inode, returning 0 if
+ * permission is granted, -ve if denied.
+ *
+ * This is used to make sure security xattrs don't get removed by those who
+ * aren't privileged to remove them.
+ */
int cap_inode_removexattr(struct dentry *dentry, const char *name)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
return -EPERM;
return 0;
- } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
+ }
+
+ if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}

-/* moved from kernel/sys.c. */
-/*
+/*
* cap_emulate_setxuid() fixes the effective / permitted capabilities of
* a process after a call to setuid, setreuid, or setresuid.
*
@@ -454,10 +585,10 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
* 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
* capabilities are set to the permitted capabilities.
*
- * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
+ * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
* never happen.
*
- * -astor
+ * -astor
*
* cevans - New behaviour, Oct '99
* A process may, via prctl(), elect to keep its capabilities when it
@@ -483,35 +614,46 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
new->cap_effective = new->cap_permitted;
}

+/**
+ * cap_task_fix_setuid - Fix up the results of setuid() call
+ * @new: The proposed credentials
+ * @old: The current task's current credentials
+ * @flags: Indications of what has changed
+ *
+ * Fix up the results of setuid() call before the credential changes are
+ * actually applied, returning 0 to grant the changes, -ve to deny them.
+ */
int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
{
switch (flags) {
case LSM_SETID_RE:
case LSM_SETID_ID:
case LSM_SETID_RES:
- /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
+ /* juggle the capabilities to follow [RES]UID changes unless
+ * otherwise suppressed */
if (!issecure(SECURE_NO_SETUID_FIXUP))
cap_emulate_setxuid(new, old);
break;
- case LSM_SETID_FS:
- /* Copied from kernel/sys.c:setfsuid. */

- /*
+ case LSM_SETID_FS:
+ /* juggle the capabilties to follow FSUID changes, unless
+ * otherwise suppressed
+ *
* FIXME - is fsuser used for all CAP_FS_MASK capabilities?
* if not, we might be a bit too harsh here.
*/
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
- if (old->fsuid == 0 && new->fsuid != 0) {
+ if (old->fsuid == 0 && new->fsuid != 0)
new->cap_effective =
cap_drop_fs_set(new->cap_effective);
- }
- if (old->fsuid != 0 && new->fsuid == 0) {
+
+ if (old->fsuid != 0 && new->fsuid == 0)
new->cap_effective =
cap_raise_fs_set(new->cap_effective,
new->cap_permitted);
- }
}
break;
+
default:
return -EINVAL;
}
@@ -544,28 +686,50 @@ static inline int cap_safe_nice(struct task_struct *p)
return 0;
}

-int cap_task_setscheduler (struct task_struct *p, int policy,
+/**
+ * cap_task_setscheduler - Detemine if scheduler policy change is permitted
+ * @p: The task to affect
+ * @policy: The policy to effect
+ * @lp: The parameters to the scheduling policy
+ *
+ * Detemine if the requested scheduler policy change is permitted for the
+ * specified task, returning 0 if permission is granted, -ve if denied.
+ */
+int cap_task_setscheduler(struct task_struct *p, int policy,
struct sched_param *lp)
{
return cap_safe_nice(p);
}

-int cap_task_setioprio (struct task_struct *p, int ioprio)
+/**
+ * cap_task_ioprio - Detemine if I/O priority change is permitted
+ * @p: The task to affect
+ * @ioprio: The I/O priority to set
+ *
+ * Detemine if the requested I/O priority change is permitted for the specified
+ * task, returning 0 if permission is granted, -ve if denied.
+ */
+int cap_task_setioprio(struct task_struct *p, int ioprio)
{
return cap_safe_nice(p);
}

-int cap_task_setnice (struct task_struct *p, int nice)
+/**
+ * cap_task_ioprio - Detemine if task priority change is permitted
+ * @p: The task to affect
+ * @nice: The nice value to set
+ *
+ * Detemine if the requested task priority change is permitted for the
+ * specified task, returning 0 if permission is granted, -ve if denied.
+ */
+int cap_task_setnice(struct task_struct *p, int nice)
{
return cap_safe_nice(p);
}

/*
- * called from kernel/sys.c for prctl(PR_CABSET_DROP)
- * done without task_capability_lock() because it introduces
- * no new races - i.e. only another task doing capget() on
- * this task could get inconsistent info. There can be no
- * racing writer bc a task can only change its own caps.
+ * 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)
{
@@ -594,6 +758,18 @@ int cap_task_setnice (struct task_struct *p, int nice)
}
#endif

+/**
+ * cap_task_prctl - Implement process control functions for this security module
+ * @option: The process control function requested
+ * @arg2, @arg3, @arg4, @arg5: The argument data for this function
+ *
+ * Allow process control functions (sys_prctl()) to alter capabilities; may
+ * also deny access to other functions not otherwise implemented here.
+ *
+ * Returns 0 or +ve on success, -ENOSYS if this function is not implemented
+ * here, other -ve on error. If -ENOSYS is returned, sys_prctl() and other LSM
+ * modules will consider performing the function.
+ */
int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
@@ -699,13 +875,28 @@ error:
return error;
}

-int cap_syslog (int type)
+/**
+ * cap_syslog - Determine whether syslog function is permitted
+ * @type: Function requested
+ *
+ * Determine whether the current process is permitted to use a particular
+ * syslog function, returning 0 if permission is granted, -ve if not.
+ */
+int cap_syslog(int type)
{
if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}

+/**
+ * cap_vm_enough_memory - Determine whether a new virtual mapping is permitted
+ * @mm: The VM space in which the new mapping is to be made
+ * @pages: The size of the mapping
+ *
+ * Determine whether the allocation of a new virtual mapping by the current
+ * task is permitted, returning 0 if permission is granted, -ve if not.
+ */
int cap_vm_enough_memory(struct mm_struct *mm, long pages)
{
int cap_sys_admin = 0;
@@ -714,4 +905,3 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
cap_sys_admin = 1;
return __vm_enough_memory(mm, pages, cap_sys_admin);
}
-

2008-08-06 15:42:00

by David Howells

[permalink] [raw]
Subject: [PATCH 13/24] CRED: Separate per-task-group keyrings from signal_struct [ver #7]

Separate per-task-group keyrings from signal_struct and dangle their anchor
from the cred struct rather than the signal_struct.

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
---

include/linux/cred.h | 16 +++++++
include/linux/key.h | 8 +--
include/linux/sched.h | 6 ---
kernel/cred.c | 61 ++++++++++++++++++++++++++
kernel/fork.c | 8 ---
security/keys/process_keys.c | 99 +++++++++++++++++-------------------------
security/keys/request_key.c | 34 ++++++--------
7 files changed, 132 insertions(+), 100 deletions(-)


diff --git a/include/linux/cred.h b/include/linux/cred.h
index 5c4e098..28e1d0e 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -72,6 +72,21 @@ extern int in_group_p(gid_t);
extern int in_egroup_p(gid_t);

/*
+ * The common credentials for a thread group
+ * - shared by CLONE_THREAD
+ */
+#ifdef CONFIG_KEYS
+struct thread_group_cred {
+ atomic_t usage;
+ pid_t tgid; /* thread group process ID */
+ spinlock_t lock;
+ struct key *session_keyring; /* keyring inherited over fork */
+ struct key *process_keyring; /* keyring private to this process */
+ struct rcu_head rcu; /* RCU deletion hook */
+};
+#endif
+
+/*
* The security context of a task
*
* The parts of the context break down into two categories:
@@ -114,6 +129,7 @@ struct cred {
* keys to */
struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */
+ struct thread_group_cred *tgcred; /* thread-group shared credentials */
#endif
#ifdef CONFIG_SECURITY
void *security; /* subjective LSM security */
diff --git a/include/linux/key.h b/include/linux/key.h
index 599a37c..1a18ae9 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -278,9 +278,7 @@ extern ctl_table key_sysctls[];
*/
extern void switch_uid_keyring(struct user_struct *new_user);
extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
-extern int copy_thread_group_keys(struct task_struct *tsk);
extern void exit_keys(struct task_struct *tsk);
-extern void exit_thread_group_keys(struct signal_struct *tg);
extern int suid_keys(struct task_struct *tsk);
extern int exec_keys(struct task_struct *tsk);
extern void key_fsuid_changed(struct task_struct *tsk);
@@ -289,8 +287,8 @@ extern void key_init(void);

#define __install_session_keyring(keyring) \
({ \
- struct key *old_session = current->signal->session_keyring; \
- current->signal->session_keyring = keyring; \
+ struct key *old_session = current->cred->tgcred->session_keyring; \
+ current->cred->tgcred->session_keyring = keyring; \
old_session; \
})

@@ -307,9 +305,7 @@ extern void key_init(void);
#define switch_uid_keyring(u) do { } while(0)
#define __install_session_keyring(k) NULL
#define copy_keys(f,t) 0
-#define copy_thread_group_keys(t) 0
#define exit_keys(t) do { } while(0)
-#define exit_thread_group_keys(tg) do { } while(0)
#define suid_keys(t) do { } while(0)
#define exec_keys(t) do { } while(0)
#define key_fsuid_changed(t) do { } while(0)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 041b153..7916519 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -529,12 +529,6 @@ struct signal_struct {

struct list_head cpu_timers[3];

- /* keep the process-shared keyrings here so that they do the right
- * thing in threads created with CLONE_THREAD */
-#ifdef CONFIG_KEYS
- struct key *session_keyring; /* keyring inherited over fork */
- struct key *process_keyring; /* keyring private to this process */
-#endif
#ifdef CONFIG_BSD_PROCESS_ACCT
struct pacct_struct pacct; /* per-process accounting information */
#endif
diff --git a/kernel/cred.c b/kernel/cred.c
index 2195841..6090cb6 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -17,6 +17,17 @@
#include <linux/security.h>

/*
+ * The common credentials for the initial task's thread group
+ */
+#ifdef CONFIG_KEYS
+static struct thread_group_cred init_tgcred = {
+ .usage = ATOMIC_INIT(2),
+ .tgid = 0,
+ .lock = SPIN_LOCK_UNLOCKED,
+};
+#endif
+
+/*
* The initial credentials for the initial task
*/
struct cred init_cred = {
@@ -28,9 +39,40 @@ struct cred init_cred = {
.cap_bset = CAP_INIT_BSET,
.user = INIT_USER,
.group_info = &init_groups,
+#ifdef CONFIG_KEYS
+ .tgcred = &init_tgcred,
+#endif
};

/*
+ * Dispose of the shared task group credentials
+ */
+#ifdef CONFIG_KEYS
+static void put_tgcred_rcu(struct rcu_head *rcu)
+{
+ struct thread_group_cred *tgcred =
+ container_of(rcu, struct thread_group_cred, rcu);
+
+ BUG_ON(atomic_read(&tgcred->usage) != 0);
+
+ key_put(tgcred->session_keyring);
+ key_put(tgcred->process_keyring);
+ kfree(tgcred);
+}
+#endif
+
+/*
+ * Release a set of thread group credentials.
+ */
+static void put_tgcred(struct thread_group_cred *tgcred)
+{
+#ifdef CONFIG_KEYS
+ if (atomic_dec_and_test(&tgcred->usage))
+ call_rcu(&tgcred->rcu, put_tgcred_rcu);
+#endif
+}
+
+/*
* The RCU callback to actually dispose of a set of credentials
*/
static void put_cred_rcu(struct rcu_head *rcu)
@@ -41,6 +83,7 @@ static void put_cred_rcu(struct rcu_head *rcu)

key_put(cred->thread_keyring);
key_put(cred->request_key_auth);
+ put_tgcred(cred->tgcred);
put_group_info(cred->group_info);
free_uid(cred->user);
security_cred_free(cred);
@@ -71,12 +114,30 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
if (!pcred)
return -ENOMEM;

+#ifdef CONFIG_KEYS
+ if (clone_flags & CLONE_THREAD) {
+ atomic_inc(&pcred->tgcred->usage);
+ } else {
+ pcred->tgcred = kmalloc(sizeof(struct cred), GFP_KERNEL);
+ if (!pcred->tgcred) {
+ kfree(pcred);
+ return -ENOMEM;
+ }
+ atomic_set(&pcred->tgcred->usage, 1);
+ spin_lock_init(&pcred->tgcred->lock);
+ pcred->tgcred->process_keyring = NULL;
+ pcred->tgcred->session_keyring =
+ key_get(p->cred->tgcred->session_keyring);
+ }
+#endif
+
#ifdef CONFIG_SECURITY
pcred->security = NULL;
#endif

ret = security_cred_alloc(pcred);
if (ret < 0) {
+ put_tgcred(pcred->tgcred);
kfree(pcred);
return ret;
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 8993a45..b3254d5 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -760,7 +760,6 @@ void __cleanup_sighand(struct sighand_struct *sighand)
static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
{
struct signal_struct *sig;
- int ret;

if (clone_flags & CLONE_THREAD) {
atomic_inc(&current->signal->count);
@@ -772,12 +771,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
if (!sig)
return -ENOMEM;

- ret = copy_thread_group_keys(tsk);
- if (ret < 0) {
- kmem_cache_free(signal_cachep, sig);
- return ret;
- }
-
atomic_set(&sig->count, 1);
atomic_set(&sig->live, 1);
init_waitqueue_head(&sig->wait_chldexit);
@@ -835,7 +828,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)

void __cleanup_signal(struct signal_struct *sig)
{
- exit_thread_group_keys(sig);
kmem_cache_free(signal_cachep, sig);
}

diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index d3fa0ae..b0a6060 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -189,7 +189,7 @@ int install_process_keyring(void)

might_sleep();

- if (!tsk->signal->process_keyring) {
+ if (!tsk->cred->tgcred->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid);

keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
@@ -200,12 +200,12 @@ int install_process_keyring(void)
}

/* attach keyring */
- spin_lock_irq(&tsk->sighand->siglock);
- if (!tsk->signal->process_keyring) {
- tsk->signal->process_keyring = keyring;
+ spin_lock_irq(&tsk->cred->tgcred->lock);
+ if (!tsk->cred->tgcred->process_keyring) {
+ tsk->cred->tgcred->process_keyring = keyring;
keyring = NULL;
}
- spin_unlock_irq(&tsk->sighand->siglock);
+ spin_unlock_irq(&tsk->cred->tgcred->lock);

key_put(keyring);
}
@@ -235,11 +235,11 @@ static int install_session_keyring(struct key *keyring)
sprintf(buf, "_ses.%u", tsk->tgid);

flags = KEY_ALLOC_QUOTA_OVERRUN;
- if (tsk->signal->session_keyring)
+ if (tsk->cred->tgcred->session_keyring)
flags = KEY_ALLOC_IN_QUOTA;

- keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
- flags, NULL);
+ keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid,
+ tsk, flags, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
}
@@ -248,10 +248,10 @@ static int install_session_keyring(struct key *keyring)
}

/* install the keyring */
- spin_lock_irq(&tsk->sighand->siglock);
- old = tsk->signal->session_keyring;
- rcu_assign_pointer(tsk->signal->session_keyring, keyring);
- spin_unlock_irq(&tsk->sighand->siglock);
+ spin_lock_irq(&tsk->cred->tgcred->lock);
+ old = tsk->cred->tgcred->session_keyring;
+ rcu_assign_pointer(tsk->cred->tgcred->session_keyring, keyring);
+ spin_unlock_irq(&tsk->cred->tgcred->lock);

/* we're using RCU on the pointer, but there's no point synchronising
* on it if it didn't previously point to anything */
@@ -266,28 +266,6 @@ static int install_session_keyring(struct key *keyring)

/*****************************************************************************/
/*
- * copy the keys in a thread group for fork without CLONE_THREAD
- */
-int copy_thread_group_keys(struct task_struct *tsk)
-{
- key_check(current->thread_group->session_keyring);
- key_check(current->thread_group->process_keyring);
-
- /* no process keyring yet */
- tsk->signal->process_keyring = NULL;
-
- /* same session keyring */
- rcu_read_lock();
- tsk->signal->session_keyring =
- key_get(rcu_dereference(current->signal->session_keyring));
- rcu_read_unlock();
-
- return 0;
-
-} /* end copy_thread_group_keys() */
-
-/*****************************************************************************/
-/*
* copy the keys for fork
*/
int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
@@ -307,17 +285,6 @@ int copy_keys(unsigned long clone_flags, struct task_struct *tsk)

/*****************************************************************************/
/*
- * dispose of thread group keys upon thread group destruction
- */
-void exit_thread_group_keys(struct signal_struct *tg)
-{
- key_put(tg->session_keyring);
- key_put(tg->process_keyring);
-
-} /* end exit_thread_group_keys() */
-
-/*****************************************************************************/
-/*
* dispose of per-thread keys upon thread exit
*/
void exit_keys(struct task_struct *tsk)
@@ -344,10 +311,10 @@ int exec_keys(struct task_struct *tsk)
key_put(old);

/* discard the process keyring from a newly exec'd task */
- spin_lock_irq(&tsk->sighand->siglock);
- old = tsk->signal->process_keyring;
- tsk->signal->process_keyring = NULL;
- spin_unlock_irq(&tsk->sighand->siglock);
+ spin_lock_irq(&tsk->cred->tgcred->lock);
+ old = tsk->cred->tgcred->process_keyring;
+ tsk->cred->tgcred->process_keyring = NULL;
+ spin_unlock_irq(&tsk->cred->tgcred->lock);

key_put(old);

@@ -452,9 +419,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
}

/* search the process keyring second */
- if (context->signal->process_keyring) {
+ if (cred->tgcred->process_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->signal->process_keyring, 1),
+ make_key_ref(cred->tgcred->process_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -473,11 +440,11 @@ key_ref_t search_process_keyrings(struct key_type *type,
}

/* search the session keyring */
- if (context->signal->session_keyring) {
+ if (cred->tgcred->session_keyring) {
rcu_read_lock();
key_ref = keyring_search_aux(
make_key_ref(rcu_dereference(
- context->signal->session_keyring),
+ cred->tgcred->session_keyring),
1),
context, type, description, match);
rcu_read_unlock();
@@ -586,11 +553,13 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
{
struct request_key_auth *rka;
struct task_struct *t = current;
- struct cred *cred = current_cred();
+ struct cred *cred;
struct key *key;
key_ref_t key_ref, skey_ref;
int ret;

+try_again:
+ cred = get_current_cred();
key_ref = ERR_PTR(-ENOKEY);

switch (id) {
@@ -604,6 +573,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
key = ERR_PTR(ret);
goto error;
}
+ goto reget_creds;
}

key = cred->thread_keyring;
@@ -612,7 +582,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
break;

case KEY_SPEC_PROCESS_KEYRING:
- if (!t->signal->process_keyring) {
+ if (!cred->tgcred->process_keyring) {
if (!create)
goto error;

@@ -621,15 +591,16 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
key = ERR_PTR(ret);
goto error;
}
+ goto reget_creds;
}

- key = t->signal->process_keyring;
+ key = cred->tgcred->process_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;

case KEY_SPEC_SESSION_KEYRING:
- if (!t->signal->session_keyring) {
+ if (!cred->tgcred->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_user_keyrings();
@@ -639,10 +610,11 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
cred->user->session_keyring);
if (ret < 0)
goto error;
+ goto reget_creds;
}

rcu_read_lock();
- key = rcu_dereference(t->signal->session_keyring);
+ key = rcu_dereference(cred->tgcred->session_keyring);
atomic_inc(&key->usage);
rcu_read_unlock();
key_ref = make_key_ref(key, 1);
@@ -765,6 +737,12 @@ invalid_key:
key_ref = ERR_PTR(ret);
goto error;

+ /* if we attempted to install a keyring, then it may have caused new
+ * creds to be installed */
+reget_creds:
+ put_cred(cred);
+ goto try_again;
+
} /* end lookup_user_key() */

/*****************************************************************************/
@@ -777,6 +755,7 @@ invalid_key:
long join_session_keyring(const char *name)
{
struct task_struct *tsk = current;
+ struct cred *cred = current->cred;
struct key *keyring;
long ret;

@@ -787,7 +766,7 @@ long join_session_keyring(const char *name)
goto error;

rcu_read_lock();
- ret = rcu_dereference(tsk->signal->session_keyring)->serial;
+ ret = rcu_dereference(cred->tgcred->session_keyring)->serial;
rcu_read_unlock();
goto error;
}
@@ -799,7 +778,7 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, false);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk,
+ keyring = keyring_alloc(name, cred->uid, cred->gid, tsk,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 650cc3e..fe5d4fb 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -66,7 +66,6 @@ static int call_sbin_request_key(struct key_construction *cons,
const char *op,
void *aux)
{
- struct task_struct *tsk = current;
const struct cred *cred = current_cred();
key_serial_t prkey, sskey;
struct key *key = cons->key, *authkey = cons->authkey, *keyring;
@@ -105,18 +104,13 @@ static int call_sbin_request_key(struct key_construction *cons,
cred->thread_keyring->serial : 0);

prkey = 0;
- if (tsk->signal->process_keyring)
- prkey = tsk->signal->process_keyring->serial;
+ if (cred->tgcred->process_keyring)
+ prkey = cred->tgcred->process_keyring->serial;

- sprintf(keyring_str[1], "%d", prkey);
-
- if (tsk->signal->session_keyring) {
- rcu_read_lock();
- sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
- rcu_read_unlock();
- } else {
+ if (cred->tgcred->session_keyring)
+ sskey = rcu_dereference(cred->tgcred->session_keyring)->serial;
+ else
sskey = cred->user->session_keyring->serial;
- }

sprintf(keyring_str[2], "%d", sskey);

@@ -218,7 +212,7 @@ static int construct_key(struct key *key, const void *callout_info,
static void construct_get_dest_keyring(struct key **_dest_keyring)
{
struct request_key_auth *rka;
- struct task_struct *tsk = current;
+ const struct cred *cred = current_cred();
struct key *dest_keyring = *_dest_keyring, *authkey;

kenter("%p", dest_keyring);
@@ -230,11 +224,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
} else {
/* use a default keyring; falling through the cases until we
* find one that we actually have */
- switch (tsk->cred->jit_keyring) {
+ switch (cred->jit_keyring) {
case KEY_REQKEY_DEFL_DEFAULT:
case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
- if (tsk->cred->request_key_auth) {
- authkey = tsk->cred->request_key_auth;
+ if (cred->request_key_auth) {
+ authkey = cred->request_key_auth;
down_read(&authkey->sem);
rka = authkey->payload.data;
if (!test_bit(KEY_FLAG_REVOKED,
@@ -247,19 +241,19 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
}

case KEY_REQKEY_DEFL_THREAD_KEYRING:
- dest_keyring = key_get(tsk->cred->thread_keyring);
+ dest_keyring = key_get(cred->thread_keyring);
if (dest_keyring)
break;

case KEY_REQKEY_DEFL_PROCESS_KEYRING:
- dest_keyring = key_get(tsk->signal->process_keyring);
+ dest_keyring = key_get(cred->tgcred->process_keyring);
if (dest_keyring)
break;

case KEY_REQKEY_DEFL_SESSION_KEYRING:
rcu_read_lock();
dest_keyring = key_get(
- rcu_dereference(tsk->signal->session_keyring));
+ rcu_dereference(cred->tgcred->session_keyring));
rcu_read_unlock();

if (dest_keyring)
@@ -267,11 +261,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)

case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
dest_keyring =
- key_get(tsk->cred->user->session_keyring);
+ key_get(cred->user->session_keyring);
break;

case KEY_REQKEY_DEFL_USER_KEYRING:
- dest_keyring = key_get(tsk->cred->user->uid_keyring);
+ dest_keyring = key_get(cred->user->uid_keyring);
break;

case KEY_REQKEY_DEFL_GROUP_KEYRING:

2008-08-06 15:42:28

by David Howells

[permalink] [raw]
Subject: [PATCH 20/24] CRED: Use creds in file structs [ver #7]

Attach creds to file structs and discard f_uid/f_gid.

file_operations::open() methods (such as hppfs_open()) should use file->f_cred
rather than current_cred(). At the moment file->f_cred will be current_cred()
at this point.

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
---

arch/mips/kernel/vpe.c | 4 ++--
drivers/isdn/hysdn/hysdn_procconf.c | 6 ++++--
fs/coda/file.c | 2 +-
fs/file_table.c | 7 ++++---
fs/hppfs/hppfs.c | 4 ++--
include/linux/fs.h | 2 +-
net/ipv4/netfilter/ipt_LOG.c | 4 ++--
net/ipv6/netfilter/ip6t_LOG.c | 4 ++--
net/netfilter/nfnetlink_log.c | 5 +++--
net/netfilter/xt_owner.c | 16 ++++++++--------
net/sched/cls_flow.c | 4 ++--
11 files changed, 31 insertions(+), 27 deletions(-)


diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 972b2d2..09786e4 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -1085,8 +1085,8 @@ static int vpe_open(struct inode *inode, struct file *filp)
v->load_addr = NULL;
v->len = 0;

- v->uid = filp->f_uid;
- v->gid = filp->f_gid;
+ v->uid = filp->f_cred->fsuid;
+ v->gid = filp->f_cred->fsgid;

#ifdef CONFIG_MIPS_APSP_KSPD
/* get kspd to tell us when a syscall_exit happens */
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 484299b..8f9f491 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -246,7 +246,8 @@ hysdn_conf_open(struct inode *ino, struct file *filep)
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
- filep->f_uid, filep->f_gid, filep->f_mode);
+ filep->f_cred->fsuid, filep->f_cred->fsgid,
+ filep->f_mode);

if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write boot file or conf line */
@@ -331,7 +332,8 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
- filep->f_uid, filep->f_gid, filep->f_mode);
+ filep->f_cred->fsuid, filep->f_cred->fsgid,
+ filep->f_mode);

if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write boot file or conf line */
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 29137ff..5a87699 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -174,7 +174,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);

err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
- coda_flags, coda_file->f_uid);
+ coda_flags, coda_file->f_cred->fsuid);

host_inode = cfi->cfi_container->f_path.dentry->d_inode;
cii = ITOC(coda_inode);
diff --git a/fs/file_table.c b/fs/file_table.c
index 4183190..d2ae1de 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -36,7 +36,9 @@ static struct percpu_counter nr_files __cacheline_aligned_in_smp;

static inline void file_free_rcu(struct rcu_head *head)
{
- struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+ struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+
+ put_cred(f->f_cred);
kmem_cache_free(filp_cachep, f);
}

@@ -121,8 +123,7 @@ struct file *get_empty_filp(void)
INIT_LIST_HEAD(&f->f_u.fu_list);
atomic_long_set(&f->f_count, 1);
rwlock_init(&f->f_owner.lock);
- f->f_uid = cred->fsuid;
- f->f_gid = cred->fsgid;
+ f->f_cred = get_cred(cred);
eventpoll_init_file(f);
/* f->f_version: 0 */
return f;
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 795e2c1..b278f7f 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -426,7 +426,7 @@ static int file_mode(int fmode)

static int hppfs_open(struct inode *inode, struct file *file)
{
- const struct cred *cred = current_cred();
+ const struct cred *cred = file->f_cred;
struct hppfs_private *data;
struct vfsmount *proc_mnt;
struct dentry *proc_dentry;
@@ -490,7 +490,7 @@ static int hppfs_open(struct inode *inode, struct file *file)

static int hppfs_dir_open(struct inode *inode, struct file *file)
{
- const struct cred *cred = current_cred();
+ const struct cred *cred = file->f_cred;
struct hppfs_private *data;
struct vfsmount *proc_mnt;
struct dentry *proc_dentry;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d4e0016..057317c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -824,7 +824,7 @@ struct file {
mode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
- unsigned int f_uid, f_gid;
+ const struct cred *f_cred;
struct file_ra_state f_ra;

u64 f_version;
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 0af1413..dde984a 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -340,8 +340,8 @@ static void dump_packet(const struct nf_loginfo *info,
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file)
printk("UID=%u GID=%u ",
- skb->sk->sk_socket->file->f_uid,
- skb->sk->sk_socket->file->f_gid);
+ skb->sk->sk_socket->file->f_cred->fsuid,
+ skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock);
}

diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 3a23169..8d91b23 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -364,8 +364,8 @@ static void dump_packet(const struct nf_loginfo *info,
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file)
printk("UID=%u GID=%u ",
- skb->sk->sk_socket->file->f_uid,
- skb->sk->sk_socket->file->f_gid);
+ skb->sk->sk_socket->file->f_cred->fsuid,
+ skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock);
}

diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 9a35b57..7659bcf 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -474,8 +474,9 @@ __build_packet_message(struct nfulnl_instance *inst,
if (skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
- __be32 uid = htonl(skb->sk->sk_socket->file->f_uid);
- __be32 gid = htonl(skb->sk->sk_socket->file->f_gid);
+ struct file *file = skb->sk->sk_socket->file;
+ __be32 uid = htonl(file->f_cred->fsuid);
+ __be32 gid = htonl(file->f_cred->fsgid);
/* need to unlock here since NLA_PUT may goto */
read_unlock_bh(&skb->sk->sk_callback_lock);
NLA_PUT_BE32(inst->skb, NFULA_UID, uid);
diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
index 9059c16..b8c53e8 100644
--- a/net/netfilter/xt_owner.c
+++ b/net/netfilter/xt_owner.c
@@ -37,12 +37,12 @@ owner_mt_v0(const struct sk_buff *skb, const struct net_device *in,
return false;

if (info->match & IPT_OWNER_UID)
- if ((filp->f_uid != info->uid) ^
+ if ((filp->f_cred->fsuid != info->uid) ^
!!(info->invert & IPT_OWNER_UID))
return false;

if (info->match & IPT_OWNER_GID)
- if ((filp->f_gid != info->gid) ^
+ if ((filp->f_cred->fsgid != info->gid) ^
!!(info->invert & IPT_OWNER_GID))
return false;

@@ -66,12 +66,12 @@ owner_mt6_v0(const struct sk_buff *skb, const struct net_device *in,
return false;

if (info->match & IP6T_OWNER_UID)
- if ((filp->f_uid != info->uid) ^
+ if ((filp->f_cred->fsuid != info->uid) ^
!!(info->invert & IP6T_OWNER_UID))
return false;

if (info->match & IP6T_OWNER_GID)
- if ((filp->f_gid != info->gid) ^
+ if ((filp->f_cred->fsgid != info->gid) ^
!!(info->invert & IP6T_OWNER_GID))
return false;

@@ -102,14 +102,14 @@ owner_mt(const struct sk_buff *skb, const struct net_device *in,
(XT_OWNER_UID | XT_OWNER_GID)) == 0;

if (info->match & XT_OWNER_UID)
- if ((filp->f_uid >= info->uid_min &&
- filp->f_uid <= info->uid_max) ^
+ if ((filp->f_cred->fsuid >= info->uid_min &&
+ filp->f_cred->fsuid <= info->uid_max) ^
!(info->invert & XT_OWNER_UID))
return false;

if (info->match & XT_OWNER_GID)
- if ((filp->f_gid >= info->gid_min &&
- filp->f_gid <= info->gid_max) ^
+ if ((filp->f_cred->fsgid >= info->gid_min &&
+ filp->f_cred->fsgid <= info->gid_max) ^
!(info->invert & XT_OWNER_GID))
return false;

diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 8f63a1a..95a9b56 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -260,14 +260,14 @@ static u32 flow_get_rtclassid(const struct sk_buff *skb)
static u32 flow_get_skuid(const struct sk_buff *skb)
{
if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
- return skb->sk->sk_socket->file->f_uid;
+ return skb->sk->sk_socket->file->f_cred->fsuid;
return 0;
}

static u32 flow_get_skgid(const struct sk_buff *skb)
{
if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
- return skb->sk->sk_socket->file->f_gid;
+ return skb->sk->sk_socket->file->f_cred->fsgid;
return 0;
}

2008-08-06 15:42:48

by David Howells

[permalink] [raw]
Subject: [PATCH 16/24] CRED: Pass credentials through dentry_open() [ver #7]

Pass credentials through dentry_open() so that the COW creds patch can have
SELinux's flush_unauthorized_files() pass the appropriate creds back to itself
when it opens its null chardev.

The security_dentry_open() call also now takes a creds pointer, as does the
dentry_open hook in struct security_operations.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
---

fs/ecryptfs/ecryptfs_kernel.h | 3 ++-
fs/ecryptfs/kthread.c | 9 +++++----
fs/ecryptfs/main.c | 3 ++-
fs/exportfs/expfs.c | 4 +++-
fs/hppfs/hppfs.c | 6 ++++--
fs/nfsctl.c | 3 ++-
fs/nfsd/nfs4recover.c | 3 ++-
fs/nfsd/vfs.c | 3 ++-
fs/open.c | 17 +++++++++++------
fs/xfs/linux-2.6/xfs_ioctl.c | 3 ++-
include/linux/fs.h | 4 +++-
include/linux/security.h | 7 ++++---
ipc/mqueue.c | 11 +++++++----
security/capability.c | 2 +-
security/security.c | 4 ++--
security/selinux/hooks.c | 15 +++++++++------
16 files changed, 61 insertions(+), 36 deletions(-)


diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index b73fb75..e73414f 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -709,7 +709,8 @@ int ecryptfs_init_kthread(void);
void ecryptfs_destroy_kthread(void);
int ecryptfs_privileged_open(struct file **lower_file,
struct dentry *lower_dentry,
- struct vfsmount *lower_mnt);
+ struct vfsmount *lower_mnt,
+ const struct cred *cred);
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry);

#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
index c440c6b..c6d7a4d 100644
--- a/fs/ecryptfs/kthread.c
+++ b/fs/ecryptfs/kthread.c
@@ -73,7 +73,7 @@ static int ecryptfs_threadfn(void *ignored)
mntget(req->lower_mnt);
(*req->lower_file) = dentry_open(
req->lower_dentry, req->lower_mnt,
- (O_RDWR | O_LARGEFILE));
+ (O_RDWR | O_LARGEFILE), current_cred());
req->flags |= ECRYPTFS_REQ_PROCESSED;
}
wake_up(&req->wait);
@@ -132,7 +132,8 @@ void ecryptfs_destroy_kthread(void)
*/
int ecryptfs_privileged_open(struct file **lower_file,
struct dentry *lower_dentry,
- struct vfsmount *lower_mnt)
+ struct vfsmount *lower_mnt,
+ const struct cred *cred)
{
struct ecryptfs_open_req *req;
int rc = 0;
@@ -143,7 +144,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
dget(lower_dentry);
mntget(lower_mnt);
(*lower_file) = dentry_open(lower_dentry, lower_mnt,
- (O_RDWR | O_LARGEFILE));
+ (O_RDWR | O_LARGEFILE), cred);
if (!IS_ERR(*lower_file))
goto out;
req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
@@ -184,7 +185,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
dget(lower_dentry);
mntget(lower_mnt);
(*lower_file) = dentry_open(lower_dentry, lower_mnt,
- (O_RDONLY | O_LARGEFILE));
+ (O_RDONLY | O_LARGEFILE), cred);
if (IS_ERR(*lower_file)) {
rc = PTR_ERR(*req->lower_file);
(*lower_file) = NULL;
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 448dfd5..00a945b 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -119,6 +119,7 @@ void __ecryptfs_printk(const char *fmt, ...)
*/
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
{
+ const struct cred *cred = current_cred();
struct ecryptfs_inode_info *inode_info =
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
int rc = 0;
@@ -131,7 +132,7 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)

lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
rc = ecryptfs_privileged_open(&inode_info->lower_file,
- lower_dentry, lower_mnt);
+ lower_dentry, lower_mnt, cred);
if (rc || IS_ERR(inode_info->lower_file)) {
printk(KERN_ERR "Error opening lower persistent file "
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index cc91227..5c9de1e 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/namei.h>
+#include <linux/sched.h>

#define dprintk(fmt, args...) do{}while(0)

@@ -250,6 +251,7 @@ static int filldir_one(void * __buf, const char * name, int len,
static int get_name(struct vfsmount *mnt, struct dentry *dentry,
char *name, struct dentry *child)
{
+ const struct cred *cred = current_cred();
struct inode *dir = dentry->d_inode;
int error;
struct file *file;
@@ -264,7 +266,7 @@ static int get_name(struct vfsmount *mnt, struct dentry *dentry,
/*
* Open the directory ...
*/
- file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY);
+ file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY, cred);
error = PTR_ERR(file);
if (IS_ERR(file))
goto out;
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 2b3d182..795e2c1 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -426,6 +426,7 @@ static int file_mode(int fmode)

static int hppfs_open(struct inode *inode, struct file *file)
{
+ const struct cred *cred = current_cred();
struct hppfs_private *data;
struct vfsmount *proc_mnt;
struct dentry *proc_dentry;
@@ -446,7 +447,7 @@ static int hppfs_open(struct inode *inode, struct file *file)

/* XXX This isn't closed anywhere */
data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
- file_mode(file->f_mode));
+ file_mode(file->f_mode), cred);
err = PTR_ERR(data->proc_file);
if (IS_ERR(data->proc_file))
goto out_free1;
@@ -489,6 +490,7 @@ static int hppfs_open(struct inode *inode, struct file *file)

static int hppfs_dir_open(struct inode *inode, struct file *file)
{
+ const struct cred *cred = current_cred();
struct hppfs_private *data;
struct vfsmount *proc_mnt;
struct dentry *proc_dentry;
@@ -502,7 +504,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
proc_dentry = HPPFS_I(inode)->proc_dentry;
proc_mnt = inode->i_sb->s_fs_info;
data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
- file_mode(file->f_mode));
+ file_mode(file->f_mode), cred);
err = PTR_ERR(data->proc_file);
if (IS_ERR(data->proc_file))
goto out_free;
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index aed8145..cc4ef26 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -41,7 +41,8 @@ static struct file *do_open(char *name, int flags)
error = may_open(&nd, MAY_WRITE, FMODE_WRITE);

if (!error)
- return dentry_open(nd.path.dentry, nd.path.mnt, flags);
+ return dentry_open(nd.path.dentry, nd.path.mnt, flags,
+ current_cred());

path_put(&nd.path);
return ERR_PTR(error);
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 6e751e7..7092d37 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -226,7 +226,8 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)

nfs4_save_user(&uid, &gid);

- filp = dentry_open(dget(dir), mntget(rec_dir.path.mnt), O_RDONLY);
+ filp = dentry_open(dget(dir), mntget(rec_dir.path.mnt), O_RDONLY,
+ current_cred());
status = PTR_ERR(filp);
if (IS_ERR(filp))
goto out;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index a1b99c6..a80e82c 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -668,6 +668,7 @@ __be32
nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
int access, struct file **filp)
{
+ const struct cred *cred = current_cred();
struct dentry *dentry;
struct inode *inode;
int flags = O_RDONLY|O_LARGEFILE;
@@ -722,7 +723,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
DQUOT_INIT(inode);
}
*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
- flags);
+ flags, cred);
if (IS_ERR(*filp))
host_err = PTR_ERR(*filp);
out_nfserr:
diff --git a/fs/open.c b/fs/open.c
index a8ddf81..4d0afbe 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -783,7 +783,8 @@ static inline int __get_file_write_access(struct inode *inode,

static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
int flags, struct file *f,
- int (*open)(struct inode *, struct file *))
+ int (*open)(struct inode *, struct file *),
+ const struct cred *cred)
{
struct inode *inode;
int error;
@@ -807,7 +808,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
f->f_op = fops_get(inode->i_fop);
file_move(f, &inode->i_sb->s_files);

- error = security_dentry_open(f);
+ error = security_dentry_open(f, cred);
if (error)
goto cleanup_all;

@@ -882,6 +883,8 @@ cleanup_file:
struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
int (*open)(struct inode *, struct file *))
{
+ const struct cred *cred = current_cred();
+
if (IS_ERR(nd->intent.open.file))
goto out;
if (IS_ERR(dentry))
@@ -889,7 +892,7 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry
nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
nd->intent.open.flags - 1,
nd->intent.open.file,
- open);
+ open, cred);
out:
return nd->intent.open.file;
out_err:
@@ -908,6 +911,7 @@ EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
*/
struct file *nameidata_to_filp(struct nameidata *nd, int flags)
{
+ const struct cred *cred = current_cred();
struct file *filp;

/* Pick up the filp from the open intent */
@@ -915,7 +919,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags)
/* Has the filesystem initialised the file for us? */
if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
- NULL);
+ NULL, cred);
else
path_put(&nd->path);
return filp;
@@ -925,7 +929,8 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags)
* dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
* error.
*/
-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
+struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
+ const struct cred *cred)
{
int error;
struct file *f;
@@ -950,7 +955,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
return ERR_PTR(error);
}

- return __dentry_open(dentry, mnt, flags, f, NULL);
+ return __dentry_open(dentry, mnt, flags, f, NULL, cred);
}
EXPORT_SYMBOL(dentry_open);

diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index acc3fd9..f4c5795 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -256,6 +256,7 @@ xfs_open_by_handle(
struct file *parfilp,
struct inode *parinode)
{
+ const struct cred *cred = current_cred();
int error;
int new_fd;
int permflag;
@@ -322,7 +323,7 @@ xfs_open_by_handle(
mntget(parfilp->f_path.mnt);

/* Create file pointer. */
- filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags);
+ filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags, cred);
if (IS_ERR(filp)) {
put_unused_fd(new_fd);
return -XFS_ERROR(-PTR_ERR(filp));
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9a8397f..d4e0016 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -305,6 +305,7 @@ struct poll_table_struct;
struct kstatfs;
struct vm_area_struct;
struct vfsmount;
+struct cred;

extern void __init inode_init(void);
extern void __init inode_init_early(void);
@@ -1617,7 +1618,8 @@ extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
extern long do_sys_open(int dfd, const char __user *filename, int flags,
int mode);
extern struct file *filp_open(const char *, int, int);
-extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
+ const struct cred *);
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char __user *);

diff --git a/include/linux/security.h b/include/linux/security.h
index a0f5886..27c0fbf 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1398,7 +1398,7 @@ struct security_operations {
int (*file_send_sigiotask) (struct task_struct *tsk,
struct fown_struct *fown, int sig);
int (*file_receive) (struct file *file);
- int (*dentry_open) (struct file *file);
+ int (*dentry_open) (struct file *file, const struct cred *cred);

int (*task_create) (unsigned long clone_flags);
int (*cred_alloc_security) (struct cred *cred);
@@ -1657,7 +1657,7 @@ int security_file_set_fowner(struct file *file);
int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
-int security_dentry_open(struct file *file);
+int security_dentry_open(struct file *file, const struct cred *cred);
int security_task_create(unsigned long clone_flags);
int security_cred_alloc(struct cred *cred);
void security_cred_free(struct cred *cred);
@@ -2160,7 +2160,8 @@ static inline int security_file_receive(struct file *file)
return 0;
}

-static inline int security_dentry_open(struct file *file)
+static inline int security_dentry_open(struct file *file,
+ const struct cred *cred)
{
return 0;
}
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index f020a77..5246c02 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -586,6 +586,7 @@ static int mq_attr_ok(struct mq_attr *attr)
static struct file *do_create(struct dentry *dir, struct dentry *dentry,
int oflag, mode_t mode, struct mq_attr __user *u_attr)
{
+ const struct cred *cred = current_cred();
struct mq_attr attr;
struct file *result;
int ret;
@@ -610,7 +611,7 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
if (ret)
goto out_drop_write;

- result = dentry_open(dentry, mqueue_mnt, oflag);
+ result = dentry_open(dentry, mqueue_mnt, oflag, cred);
/*
* dentry_open() took a persistent mnt_want_write(),
* so we can now drop this one.
@@ -629,8 +630,10 @@ out:
/* Opens existing queue */
static struct file *do_open(struct dentry *dentry, int oflag)
{
-static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
- MAY_READ | MAY_WRITE };
+ const struct cred *cred = current_cred();
+
+ static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
+ MAY_READ | MAY_WRITE };

if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
dput(dentry);
@@ -644,7 +647,7 @@ static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
return ERR_PTR(-EACCES);
}

- return dentry_open(dentry, mqueue_mnt, oflag);
+ return dentry_open(dentry, mqueue_mnt, oflag, cred);
}

asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
diff --git a/security/capability.c b/security/capability.c
index 6c4b513..fac2f61 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -330,7 +330,7 @@ static int cap_file_receive(struct file *file)
return 0;
}

-static int cap_dentry_open(struct file *file)
+static int cap_dentry_open(struct file *file, const struct cred *cred)
{
return 0;
}
diff --git a/security/security.c b/security/security.c
index 23c3c91..1a96ec9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -592,9 +592,9 @@ int security_file_receive(struct file *file)
return security_ops->file_receive(file);
}

-int security_dentry_open(struct file *file)
+int security_dentry_open(struct file *file, const struct cred *cred)
{
- return security_ops->dentry_open(file);
+ return security_ops->dentry_open(file, cred);
}

int security_task_create(unsigned long clone_flags)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index fb76940..d0e399d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2149,9 +2149,9 @@ extern struct vfsmount *selinuxfs_mount;
extern struct dentry *selinux_null;

/* Derived from fs/exec.c:flush_old_files. */
-static inline void flush_unauthorized_files(struct files_struct *files)
+static inline void flush_unauthorized_files(const struct cred *cred,
+ struct files_struct *files)
{
- const struct cred *cred = current_cred();
struct avc_audit_data ad;
struct file *file, *devnull = NULL;
struct tty_struct *tty;
@@ -2220,7 +2220,10 @@ static inline void flush_unauthorized_files(struct files_struct *files)
if (devnull) {
get_file(devnull);
} else {
- devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
+ devnull = dentry_open(
+ dget(selinux_null),
+ mntget(selinuxfs_mount),
+ O_RDWR, cred);
if (IS_ERR(devnull)) {
devnull = NULL;
put_unused_fd(fd);
@@ -2300,6 +2303,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
*/
static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
{
+ const struct cred *cred = current_cred();
struct task_security_struct *tsec;
struct rlimit *rlim, *initrlim;
struct itimerval itimer;
@@ -2317,7 +2321,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
return;

/* Close files for which the new task SID is not authorized. */
- flush_unauthorized_files(current->files);
+ flush_unauthorized_files(cred, current->files);

/* Check whether the new SID can inherit signal state
from the old SID. If not, clear itimers to avoid
@@ -3206,9 +3210,8 @@ static int selinux_file_receive(struct file *file)
return file_has_perm(cred, file, file_to_av(file));
}

-static int selinux_dentry_open(struct file *file)
+static int selinux_dentry_open(struct file *file, const struct cred *cred)
{
- const struct cred *cred = current_cred();
struct file_security_struct *fsec;
struct inode *inode;
struct inode_security_struct *isec;

2008-08-06 15:43:16

by David Howells

[permalink] [raw]
Subject: [PATCH 17/24] CRED: Inaugurate COW credentials [ver #7]

Inaugurate copy-on-write credentials management. This uses RCU to manage the
credentials pointer in the task_struct with respect to accesses by other tasks.
A process may only modify its own credentials, and so does not need locking to
access or modify its own credentials.

A mutex (cred_replace_mutex) is added to the task_struct to control the effect
of PTRACE_ATTACHED on credential calculations, particularly with respect to
execve().

With this patch, the contents of an active credentials struct may not be
changed directly; rather a new set of credentials must be prepared, modified
and committed using something like the following sequence of events:

struct cred *new = prepare_creds();
int ret = blah(new);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);

There are some exceptions to this rule: the keyrings pointed to by the active
credentials may be instantiated - keyrings violate the COW rule as managing
COW keyrings is tricky, given that it is possible for a task to directly alter
the keys in a keyring in use by another task.

This patch and the preceding patches have been tested with the LTP SELinux
testsuite.


This patch makes several logical sets of alteration:

(1) execve().

This now prepares and commits credentials in various places in the
security code rather than altering the current creds directly.

(2) Temporary credential overrides.

do_coredump() and sys_faccessat() now prepare their own credentials and
temporarily override the ones currently on the acting thread, whilst
preventing interference from other threads by holding cred_replace_mutex
on the thread being dumped.

This will be replaced in a future patch by something that hands down the
credentials directly to the functions being called, rather than altering
the task's objective credentials.

(3) LSM interface.

A number of functions have been changed, added or removed:

(*) security_capset_check(), ->capset_check()
(*) security_capset_set(), ->capset_set()

Removed in favour of security_capset().

(*) security_capset(), ->capset()

New. This is passed a pointer to the new creds, a pointer to the old
creds and the proposed capability sets. It should fill in the new
creds or return an error. All pointers, barring the pointer to the
new creds, are now const.

(*) security_bprm_apply_creds(), ->bprm_apply_creds()

Changed; now returns a value, which will cause the process to be
killed if it's an error.

(*) security_task_alloc(), ->task_alloc_security()

Removed in favour of security_prepare_creds().

(*) security_cred_free(), ->cred_free()

New. Free security data attached to cred->security.

(*) security_prepare_creds(), ->cred_prepare()

New. Duplicate any security data attached to cred->security.

(*) security_commit_creds(), ->cred_commit()

New. Apply any security effects for the upcoming installation of new
security by commit_creds().

(*) security_task_post_setuid(), ->task_post_setuid()

Removed in favour of security_task_fix_setuid().

(*) security_task_fix_setuid(), ->task_fix_setuid()

Fix up the proposed new credentials for setuid(). This is used by
cap_set_fix_setuid() to implicitly adjust capabilities in line with
setuid() changes. Changes are made to the new credentials, rather
than the task itself as in security_task_post_setuid().

(*) security_task_reparent_to_init(), ->task_reparent_to_init()

Removed. Instead the task being reparented to init is referred
directly to init's credentials.

NOTE! This results in the loss of some state: SELinux's osid no
longer records the sid of the thread that forked it.

(*) security_key_alloc(), ->key_alloc()
(*) security_key_permission(), ->key_permission()

Changed. These now take cred pointers rather than task pointers to
refer to the security context.

(4) sys_capset().

This has been simplified and uses less locking. The LSM functions it
calls have been merged.

(5) reparent_to_kthreadd().

This gives the current thread the same credentials as init by simply using
commit_thread() to point that way.

(6) __sigqueue_alloc() and switch_uid()

__sigqueue_alloc() can't stop the target task from changing its creds
beneath it, so this function gets a reference to the currently applicable
user_struct which it then passes into the sigqueue struct it returns if
successful.

switch_uid() is now called from commit_creds(), and possibly should be
folded into that. commit_creds() should take care of protecting
__sigqueue_alloc().

(7) [sg]et[ug]id() and co and [sg]et_current_groups.

The set functions now all use prepare_creds(), commit_creds() and
abort_creds() to build and check a new set of credentials before applying
it.

security_task_set[ug]id() is called inside the prepared section. This
guarantees that nothing else will affect the creds until we've finished.

The calling of set_dumpable() has been moved into commit_creds().

Much of the functionality of set_user() has been moved into
commit_creds().

The get functions all simply access the data directly.

(8) security_task_prctl() and cap_task_prctl().

security_task_prctl() has been modified to return -ENOSYS if it doesn't
want to handle a function, or otherwise return the return value directly
rather than through an argument.

Additionally, cap_task_prctl() now prepares a new set of credentials, even
if it doesn't end up using it.

(9) Keyrings.

A number of changes have been made to the keyrings code:

(a) switch_uid_keyring(), copy_keys(), exit_keys() and suid_keys() have
all been dropped and built in to the credentials functions directly.
They may want separating out again later.

(b) key_alloc() and search_process_keyrings() now take a cred pointer
rather than a task pointer to specify the security context.

(c) copy_creds() gives a new thread within the same thread group a new
thread keyring if its parent had one, otherwise it discards the thread
keyring.

(d) The authorisation key now points directly to the credentials to extend
the search into rather pointing to the task that carries them.

(e) Installing thread, process or session keyrings causes a new set of
credentials to be created, even though it's not strictly necessary for
process or session keyrings (they're shared).

(10) Usermode helper.

The usermode helper code now carries a cred struct pointer in its
subprocess_info struct instead of a new session keyring pointer. This set
of credentials is derived from init_cred and installed on the new process
after it has been cloned.

call_usermodehelper_setup() allocates the new credentials and
call_usermodehelper_freeinfo() discards them if they haven't been used. A
special cred function (prepare_usermodeinfo_creds()) is provided
specifically for call_usermodehelper_setup() to call.

call_usermodehelper_setkeys() adjusts the credentials to sport the
supplied keyring as the new session keyring.

(11) SELinux.

SELinux has a number of changes, in addition to those to support the LSM
interface changes mentioned above:

(a) selinux_setprocattr() no longer does its check for whether the
current ptracer can access processes with the new SID inside the lock
that covers getting the ptracer's SID. Whilst this lock ensures that
the check is done with the ptracer pinned, the result is only valid
until the lock is released, so there's no point doing it inside the
lock.

(12) is_single_threaded().

This function has been extracted from selinux_setprocattr() and put into
a file of its own in the lib/ directory as join_session_keyring() now
wants to use it too.

The code in SELinux just checked to see whether a task shared mm_structs
with other tasks (CLONE_VM), but that isn't good enough. We really want
to know if they're part of the same thread group (CLONE_THREAD).

(13) nfsd.

The NFS server daemon now has to use the COW credentials to set the
credentials it is going to use. It really needs to pass the credentials
down to the functions it calls, but it can't do that until other patches
in this series have been applied.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
---

fs/exec.c | 31 ++-
fs/nfsd/auth.c | 92 ++++----
fs/nfsd/nfs4recover.c | 68 ++++--
fs/nfsd/nfsfh.c | 11 +
fs/open.c | 31 +--
include/linux/capability.h | 2
include/linux/cred.h | 44 +++-
include/linux/init_task.h | 2
include/linux/key.h | 24 +-
include/linux/sched.h | 6 -
include/linux/security.h | 178 +++++++--------
init/main.c | 1
kernel/capability.c | 63 ++---
kernel/cred-internals.h | 26 ++
kernel/cred.c | 328 +++++++++++++++++++++++++---
kernel/exit.c | 9 -
kernel/fork.c | 7 -
kernel/kmod.c | 30 ++-
kernel/ptrace.c | 9 +
kernel/signal.c | 10 +
kernel/sys.c | 452 +++++++++++++++++++++-----------------
kernel/user.c | 37 ---
kernel/user_namespace.c | 12 +
lib/Makefile | 2
lib/is_single_threaded.c | 45 ++++
net/rxrpc/ar-key.c | 6 -
security/capability.c | 21 +-
security/commoncap.c | 256 ++++++++++------------
security/keys/internal.h | 17 +
security/keys/key.c | 25 +-
security/keys/keyctl.c | 95 ++++++--
security/keys/keyring.c | 14 +
security/keys/permission.c | 24 +-
security/keys/proc.c | 8 +
security/keys/process_keys.c | 333 ++++++++++++++--------------
security/keys/request_key.c | 29 ++
security/keys/request_key_auth.c | 41 ++-
security/security.c | 58 ++---
security/selinux/hooks.c | 274 ++++++++++++-----------
security/smack/smack_lsm.c | 82 ++++---
40 files changed, 1617 insertions(+), 1186 deletions(-)
create mode 100644 kernel/cred-internals.h
create mode 100644 lib/is_single_threaded.c


diff --git a/fs/exec.c b/fs/exec.c
index 4867ee1..fb7ace1 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1012,13 +1012,12 @@ int flush_old_exec(struct linux_binprm * bprm)
*/
current->mm->task_size = TASK_SIZE;

- if (bprm->e_uid != current_euid() || bprm->e_gid != current_egid()) {
- suid_keys(current);
+ if (bprm->e_uid != current_euid() ||
+ bprm->e_gid != current_egid()) {
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
(bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
- suid_keys(current);
set_dumpable(current->mm, suid_dumpable);
}

@@ -1101,10 +1100,8 @@ void compute_creds(struct linux_binprm *bprm)
{
int unsafe;

- if (bprm->e_uid != current_uid()) {
- suid_keys(current);
+ if (bprm->e_uid != current_uid())
current->pdeath_signal = 0;
- }
exec_keys(current);

task_lock(current);
@@ -1715,8 +1712,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
struct linux_binfmt * binfmt;
struct inode * inode;
struct file * file;
+ const struct cred *old_cred;
+ struct cred *cred;
int retval = 0;
- int fsuid = current_fsuid();
int flag = 0;
int ispipe = 0;
unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1729,12 +1727,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
goto fail;
+
+ cred = prepare_creds();
+ if (!cred) {
+ retval = -ENOMEM;
+ goto fail;
+ }
+
down_write(&mm->mmap_sem);
/*
* If another thread got here first, or we are not dumpable, bail out.
*/
if (mm->core_state || !get_dumpable(mm)) {
up_write(&mm->mmap_sem);
+ put_cred(cred);
goto fail;
}

@@ -1745,12 +1751,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
*/
if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
- current->cred->fsuid = 0; /* Dump root private */
+ cred->fsuid = 0; /* Dump root private */
}

retval = coredump_wait(exit_code, &core_state);
- if (retval < 0)
+ if (retval < 0) {
+ put_cred(cred);
goto fail;
+ }
+
+ old_cred = override_creds(cred);

/*
* Clear any false indication of pending signals that might
@@ -1841,7 +1851,8 @@ fail_unlock:
if (helper_argv)
argv_free(helper_argv);

- current->cred->fsuid = fsuid;
+ revert_creds(old_cred);
+ put_cred(cred);
coredump_finish(mm);
fail:
return retval;
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 808fc03..836ffa1 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,55 +27,67 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)

int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
- struct cred *act_as = current->cred ;
- struct svc_cred cred = rqstp->rq_cred;
+ struct group_info *rqgi;
+ struct group_info *gi;
+ struct cred *new;
int i;
int flags = nfsexp_flags(rqstp, exp);
int ret;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->fsuid = rqstp->rq_cred.cr_uid;
+ new->fsgid = rqstp->rq_cred.cr_gid;
+
+ rqgi = rqstp->rq_cred.cr_group_info;
+
if (flags & NFSEXP_ALLSQUASH) {
- cred.cr_uid = exp->ex_anon_uid;
- cred.cr_gid = exp->ex_anon_gid;
- cred.cr_group_info = groups_alloc(0);
+ new->fsuid = exp->ex_anon_uid;
+ new->fsgid = exp->ex_anon_gid;
+ gi = groups_alloc(0);
} else if (flags & NFSEXP_ROOTSQUASH) {
- struct group_info *gi;
- if (!cred.cr_uid)
- cred.cr_uid = exp->ex_anon_uid;
- if (!cred.cr_gid)
- cred.cr_gid = exp->ex_anon_gid;
- gi = groups_alloc(cred.cr_group_info->ngroups);
- if (gi)
- for (i = 0; i < cred.cr_group_info->ngroups; i++) {
- if (!GROUP_AT(cred.cr_group_info, i))
- GROUP_AT(gi, i) = exp->ex_anon_gid;
- else
- GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
- }
- cred.cr_group_info = gi;
- } else
- get_group_info(cred.cr_group_info);
-
- if (cred.cr_uid != (uid_t) -1)
- act_as->fsuid = cred.cr_uid;
- else
- act_as->fsuid = exp->ex_anon_uid;
- if (cred.cr_gid != (gid_t) -1)
- act_as->fsgid = cred.cr_gid;
- else
- act_as->fsgid = exp->ex_anon_gid;
+ if (!new->fsuid)
+ new->fsuid = exp->ex_anon_uid;
+ if (!new->fsgid)
+ new->fsgid = exp->ex_anon_gid;

- if (!cred.cr_group_info)
- return -ENOMEM;
- ret = set_groups(act_as, cred.cr_group_info);
- put_group_info(cred.cr_group_info);
- if ((cred.cr_uid)) {
- act_as->cap_effective =
- cap_drop_nfsd_set(act_as->cap_effective);
+ gi = groups_alloc(rqgi->ngroups);
+ if (!gi)
+ goto oom;
+
+ for (i = 0; i < rqgi->ngroups; i++) {
+ if (!GROUP_AT(rqgi, i))
+ GROUP_AT(gi, i) = exp->ex_anon_gid;
+ else
+ GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+ }
} else {
- act_as->cap_effective =
- cap_raise_nfsd_set(act_as->cap_effective,
- act_as->cap_permitted);
+ gi = get_group_info(rqgi);
}
+
+ if (new->fsuid == (uid_t) -1)
+ new->fsuid = exp->ex_anon_uid;
+ if (new->fsgid == (gid_t) -1)
+ new->fsgid = exp->ex_anon_gid;
+
+ ret = set_groups(new, gi);
+ put_group_info(gi);
+ if (!ret)
+ goto error;
+
+ if (new->uid)
+ new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
+ else
+ new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
+ return commit_creds(new);
+
+oom:
+ ret = -ENOMEM;
+error:
+ abort_creds(new);
return ret;
}

diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 7092d37..f3a7f35 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -54,20 +54,26 @@
static struct nameidata rec_dir;
static int rec_dir_init = 0;

-static void
-nfs4_save_user(uid_t *saveuid, gid_t *savegid)
+static int
+nfs4_save_creds(const struct cred **original_creds)
{
- *saveuid = current->cred->fsuid;
- *savegid = current->cred->fsgid;
- current->cred->fsuid = 0;
- current->cred->fsgid = 0;
+ struct cred *new;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->fsuid = 0;
+ new->fsgid = 0;
+ *original_creds = override_creds(new);
+ put_cred(new);
+ return 0;
}

static void
-nfs4_reset_user(uid_t saveuid, gid_t savegid)
+nfs4_reset_creds(const struct cred *original)
{
- current->cred->fsuid = saveuid;
- current->cred->fsgid = savegid;
+ revert_creds(original);
}

static void
@@ -129,10 +135,9 @@ nfsd4_sync_rec_dir(void)
int
nfsd4_create_clid_dir(struct nfs4_client *clp)
{
+ const struct cred *original_cred;
char *dname = clp->cl_recdir;
struct dentry *dentry;
- uid_t uid;
- gid_t gid;
int status;

dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -140,7 +145,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || clp->cl_firststate)
return 0;

- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ return status;

/* lock the parent */
mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex);
@@ -168,7 +175,7 @@ out_unlock:
clp->cl_firststate = 1;
nfsd4_sync_rec_dir();
}
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
return status;
}
@@ -211,20 +218,21 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
static int
nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
{
+ const struct cred *original_cred;
struct file *filp;
struct dentry_list_arg dla = {
.parent = dir,
};
struct list_head *dentries = &dla.dentries;
struct dentry_list *child;
- uid_t uid;
- gid_t gid;
int status;

if (!rec_dir_init)
return 0;

- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ return status;

filp = dentry_open(dget(dir), mntget(rec_dir.path.mnt), O_RDONLY,
current_cred());
@@ -250,7 +258,7 @@ out:
dput(child->dentry);
kfree(child);
}
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
return status;
}

@@ -312,8 +320,7 @@ out:
void
nfsd4_remove_clid_dir(struct nfs4_client *clp)
{
- uid_t uid;
- gid_t gid;
+ const struct cred *original_cred;
int status;

if (!rec_dir_init || !clp->cl_firststate)
@@ -323,9 +330,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (status)
goto out;
clp->cl_firststate = 0;
- nfs4_save_user(&uid, &gid);
+
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ goto out;
+
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
if (status == 0)
nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.path.mnt);
@@ -402,16 +413,21 @@ nfsd4_recdir_load(void) {
void
nfsd4_init_recdir(char *rec_dirname)
{
- uid_t uid = 0;
- gid_t gid = 0;
- int status;
+ const struct cred *original_cred;
+ int status;

printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
rec_dirname);

BUG_ON(rec_dir_init);

- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0) {
+ printk("NFSD: Unable to change credentials to find recovery"
+ " directory: error %d\n",
+ status);
+ return;
+ }

status = path_lookup(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
&rec_dir);
@@ -421,7 +437,7 @@ nfsd4_init_recdir(char *rec_dirname)

if (!status)
rec_dir_init = 1;
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
}

void
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 54be127..8824453 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -186,9 +186,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
* access control settings being in effect, we cannot
* fix that case easily.
*/
- current->cred->cap_effective =
- cap_raise_nfsd_set(current->cred->cap_effective,
- current->cred->cap_permitted);
+ struct cred *new = prepare_creds();
+ if (!new)
+ return nfserrno(-ENOMEM);
+ new->cap_effective =
+ cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
+ put_cred(override_creds(new));
+ put_cred(new);
} else {
error = nfsd_setuser_and_check_port(rqstp, exp);
if (error)
diff --git a/fs/open.c b/fs/open.c
index 4d0afbe..67d0b6e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -425,30 +425,33 @@ out:
*/
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
- struct cred *cred = current->cred;
+ const struct cred *old_cred;
+ struct cred *override_cred;
struct path path;
struct inode *inode;
- int old_fsuid, old_fsgid;
- kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
int res;

if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;

- old_fsuid = cred->fsuid;
- old_fsgid = cred->fsgid;
+ override_cred = prepare_creds();
+ if (!override_cred)
+ return -ENOMEM;

- cred->fsuid = cred->uid;
- cred->fsgid = cred->gid;
+ override_cred->fsuid = override_cred->uid;
+ override_cred->fsgid = override_cred->gid;

if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/* Clear the capabilities if we switch to a non-root user */
- if (current->cred->uid)
- old_cap = cap_set_effective(__cap_empty_set);
+ if (override_cred->uid)
+ cap_clear(override_cred->cap_effective);
else
- old_cap = cap_set_effective(cred->cap_permitted);
+ override_cred->cap_effective =
+ override_cred->cap_permitted;
}

+ old_cred = override_creds(override_cred);
+
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
if (res)
goto out;
@@ -485,12 +488,8 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
out_path_release:
path_put(&path);
out:
- cred->fsuid = old_fsuid;
- cred->fsgid = old_fsgid;
-
- if (!issecure(SECURE_NO_SETUID_FIXUP))
- cap_set_effective(old_cap);
-
+ revert_creds(old_cred);
+ put_cred(override_cred);
return res;
}

diff --git a/include/linux/capability.h b/include/linux/capability.h
index 9d1fe30..a7fe01c 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -501,8 +501,6 @@ extern const kernel_cap_t __cap_empty_set;
extern const kernel_cap_t __cap_full_set;
extern const kernel_cap_t __cap_init_eff_set;

-kernel_cap_t cap_set_effective(const kernel_cap_t pE_new);
-
/**
* has_capability - Determine if a task has a superior capability available
* @t: The task in question
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 28e1d0e..202a82c 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -84,6 +84,8 @@ struct thread_group_cred {
struct key *process_keyring; /* keyring private to this process */
struct rcu_head rcu; /* RCU deletion hook */
};
+
+extern void put_tgcred(struct thread_group_cred *tgcred);
#endif

/*
@@ -137,11 +139,30 @@ struct cred {
struct user_struct *user; /* real user ID subscription */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
- spinlock_t lock; /* lock for pointer changes */
};

extern void __put_cred(struct cred *);
extern int copy_creds(struct task_struct *, unsigned long);
+extern struct cred *prepare_creds(void);
+extern struct cred *prepare_usermodehelper_creds(void);
+extern int commit_creds(struct cred *);
+extern void abort_creds(struct cred *);
+extern const struct cred *override_creds(const struct cred *) __deprecated;
+extern void revert_creds(const struct cred *) __deprecated;
+extern void __init cred_init(void);
+
+/**
+ * get_new_cred - Get a reference on a new set of credentials
+ * @cred: The new credentials to reference
+ *
+ * Get a reference on the specified set of new credentials. The caller must
+ * release the reference.
+ */
+static inline struct cred *get_new_cred(struct cred *cred)
+{
+ atomic_inc(&cred->usage);
+ return cred;
+}

/**
* get_cred - Get a reference on a set of credentials
@@ -150,10 +171,9 @@ extern int copy_creds(struct task_struct *, unsigned long);
* Get a reference on the specified set of credentials. The caller must
* release the reference.
*/
-static inline struct cred *get_cred(struct cred *cred)
+static inline const struct cred *get_cred(const struct cred *cred)
{
- atomic_inc(&cred->usage);
- return cred;
+ return get_new_cred((struct cred *) cred);
}

/**
@@ -166,6 +186,8 @@ static inline struct cred *get_cred(struct cred *cred)
static inline void put_cred(const struct cred *_cred)
{
struct cred *cred = (struct cred *) _cred;
+
+ BUG_ON(atomic_read(&(cred)->usage) <= 0);
if (atomic_dec_and_test(&(cred)->usage))
__put_cred(cred);
}
@@ -250,13 +272,13 @@ static inline void put_cred(const struct cred *_cred)
__groups; \
})

-#define task_cred_xxx(task, xxx) \
-({ \
- __typeof__(task->cred->xxx) ___val; \
- rcu_read_lock(); \
- ___val = __task_cred((task))->xxx; \
- rcu_read_unlock(); \
- ___val; \
+#define task_cred_xxx(task, xxx) \
+({ \
+ __typeof__(((struct cred *)NULL)->xxx) ___val; \
+ rcu_read_lock(); \
+ ___val = __task_cred((task))->xxx; \
+ rcu_read_unlock(); \
+ ___val; \
})

#define task_uid(task) (task_cred_xxx((task), uid))
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 234c24a..e0cc816 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -150,6 +150,8 @@ extern struct cred init_cred;
.sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \
.cred = &init_cred, \
+ .cred_exec_mutex = \
+ __MUTEX_INITIALIZER(tsk.cred_exec_mutex), \
.comm = "swapper", \
.thread = INIT_THREAD, \
.fs = &init_fs, \
diff --git a/include/linux/key.h b/include/linux/key.h
index 1a18ae9..acd4b13 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -73,6 +73,7 @@ struct key;
struct seq_file;
struct user_struct;
struct signal_struct;
+struct cred;

struct key_type;
struct key_owner;
@@ -181,7 +182,7 @@ struct key {
extern struct key *key_alloc(struct key_type *type,
const char *desc,
uid_t uid, gid_t gid,
- struct task_struct *ctx,
+ const struct cred *cred,
key_perm_t perm,
unsigned long flags);

@@ -249,7 +250,7 @@ extern int key_unlink(struct key *keyring,
struct key *key);

extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- struct task_struct *ctx,
+ const struct cred *cred,
unsigned long flags,
struct key *dest);

@@ -276,22 +277,12 @@ extern ctl_table key_sysctls[];
/*
* the userspace interface
*/
-extern void switch_uid_keyring(struct user_struct *new_user);
-extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
-extern void exit_keys(struct task_struct *tsk);
-extern int suid_keys(struct task_struct *tsk);
+extern int install_thread_keyring_to_cred(struct cred *cred);
extern int exec_keys(struct task_struct *tsk);
extern void key_fsuid_changed(struct task_struct *tsk);
extern void key_fsgid_changed(struct task_struct *tsk);
extern void key_init(void);

-#define __install_session_keyring(keyring) \
-({ \
- struct key *old_session = current->cred->tgcred->session_keyring; \
- current->cred->tgcred->session_keyring = keyring; \
- old_session; \
-})
-
#else /* CONFIG_KEYS */

#define key_validate(k) 0
@@ -302,11 +293,8 @@ extern void key_init(void);
#define make_key_ref(k, p) NULL
#define key_ref_to_ptr(k) NULL
#define is_key_possessed(k) 0
-#define switch_uid_keyring(u) do { } while(0)
-#define __install_session_keyring(k) NULL
-#define copy_keys(f,t) 0
-#define exit_keys(t) do { } while(0)
-#define suid_keys(t) do { } while(0)
+#define install_session_keyring(k) NULL
+#define install_thread_keyring_to_cred(c) NULL
#define exec_keys(t) do { } while(0)
#define key_fsuid_changed(t) do { } while(0)
#define key_fsgid_changed(t) do { } while(0)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7916519..fd1126a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1103,7 +1103,8 @@ struct task_struct {
struct list_head cpu_timers[3];

/* process credentials */
- struct cred *cred; /* actual/objective task credentials */
+ const struct cred *cred; /* actual/objective task credentials (COW) */
+ struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */

char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
@@ -1689,7 +1690,6 @@ static inline struct user_struct *get_uid(struct user_struct *u)
return u;
}
extern void free_uid(struct user_struct *);
-extern void switch_uid(struct user_struct *);
extern void release_uids(struct user_namespace *ns);

#include <asm/current.h>
@@ -1839,6 +1839,8 @@ static inline unsigned long wait_task_inactive(struct task_struct *p,
#define for_each_process(p) \
for (p = &init_task ; (p = next_task(p)) != &init_task ; )

+extern bool is_single_threaded(struct task_struct *);
+
/*
* Careful: do_each_thread/while_each_thread is a double loop so
* 'break' will not work as expected - use goto instead.
diff --git a/include/linux/security.h b/include/linux/security.h
index 27c0fbf..fd66260 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -49,24 +49,21 @@ extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
-extern void cap_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
+extern int cap_capset(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
extern int cap_bprm_set_security(struct linux_binprm *bprm);
-extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
-extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
-extern void cap_task_reparent_to_init(struct task_struct *p);
+extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5, long *rc_p);
+ unsigned long arg4, unsigned long arg5);
extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
@@ -166,8 +163,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Compute and set the security attributes of a process being transformed
* by an execve operation based on the old attributes (current->security)
* and the information saved in @bprm->security by the set_security hook.
- * Since this hook function (and its caller) are void, this hook can not
- * return an error. However, it can leave the security attributes of the
+ * Since this function may return an error, in which case the process will
+ * be killed. However, it can leave the security attributes of the
* process unchanged if an access failure occurs at this point.
* bprm_apply_creds is called under task_lock. @unsafe indicates various
* reasons why it may be unsafe to change security state.
@@ -589,15 +586,18 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* manual page for definitions of the @clone_flags.
* @clone_flags contains the flags indicating what should be shared.
* Return 0 if permission is granted.
- * @cred_alloc_security:
- * @cred contains the cred struct for child process.
- * Allocate and attach a security structure to the cred->security field.
- * The security field is initialized to NULL when the task structure is
- * allocated.
- * Return 0 if operation was successful.
* @cred_free:
* @cred points to the credentials.
* Deallocate and clear the cred->security field in a set of credentials.
+ * @cred_prepare:
+ * @new points to the new credentials.
+ * @old points to the original credentials.
+ * @gfp indicates the atomicity of any memory allocations.
+ * Prepare a new set of credentials by copying the data from the old set.
+ * @cred_commit:
+ * @new points to the new credentials.
+ * @old points to the original credentials.
+ * Install a new set of credentials.
* @task_setuid:
* Check permission before setting one or more of the user identity
* attributes of the current process. The @flags parameter indicates
@@ -610,15 +610,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @id2 contains a uid.
* @flags contains one of the LSM_SETID_* values.
* Return 0 if permission is granted.
- * @task_post_setuid:
+ * @task_fix_setuid:
* Update the module's state after setting one or more of the user
* identity attributes of the current process. The @flags parameter
* indicates which of the set*uid system calls invoked this hook. If
- * @flags is LSM_SETID_FS, then @old_ruid is the old fs uid and the other
- * parameters are not used.
- * @old_ruid contains the old real uid (or fs uid if LSM_SETID_FS).
- * @old_euid contains the old effective uid (or -1 if LSM_SETID_FS).
- * @old_suid contains the old saved uid (or -1 if LSM_SETID_FS).
+ * @new is the set of credentials that will be installed. Modifications
+ * should be made to this rather than to @current->cred.
+ * @old is the set of credentials that are being replaces
* @flags contains one of the LSM_SETID_* values.
* Return 0 on success.
* @task_setgid:
@@ -721,13 +719,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @arg3 contains a argument.
* @arg4 contains a argument.
* @arg5 contains a argument.
- * @rc_p contains a pointer to communicate back the forced return code
- * Return 0 if permission is granted, and non-zero if the security module
- * has taken responsibility (setting *rc_p) for the prctl call.
- * @task_reparent_to_init:
- * Set the security attributes in @p->security for a kernel thread that
- * is being reparented to the init task.
- * @p contains the task_struct for the kernel thread.
+ * Return -ENOSYS if no-one wanted to handle this op, any other value to
+ * cause prctl() to return immediately with that value.
* @task_to_inode:
* Set the security attributes for an inode based on an associated task's
* security attributes, e.g. for /proc/pid inodes.
@@ -1004,7 +997,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* See whether a specific operational right is granted to a process on a
* key.
* @key_ref refers to the key (key pointer + possession attribute bit).
- * @context points to the process to provide the context against which to
+ * @cred points to the credentials to provide the context against which to
* evaluate the security data on the key.
* @perm describes the combination of permissions required of this key.
* Return 1 if permission granted, 0 if permission denied and -ve it the
@@ -1166,6 +1159,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @child process.
* Security modules may also want to perform a process tracing check
* during an execve in the set_security or apply_creds hooks of
+ * tracing check during an execve in the bprm_set_creds hook of
* binprm_security_ops if the process is being traced and its security
* attributes would be changed by the execve.
* @child contains the task_struct structure for the target process.
@@ -1189,19 +1183,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set.
* Return 0 if the capability sets were successfully obtained.
- * @capset_check:
- * Check permission before setting the @effective, @inheritable, and
- * @permitted capability sets for the current process.
- * @effective contains the effective capability set.
- * @inheritable contains the inheritable capability set.
- * @permitted contains the permitted capability set.
- * Return 0 if permission is granted.
- * @capset_set:
+ * @capset:
* Set the @effective, @inheritable, and @permitted capability sets for
* the current process.
+ * @new contains the new credentials structure for target process.
+ * @old contains the current credentials structure for target process.
* @effective contains the effective capability set.
* @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set.
+ * Return 0 and update @new if permission is granted.
* @capable:
* Check whether the @tsk process has the @cap capability.
* @tsk contains the task_struct for the process.
@@ -1293,12 +1283,11 @@ struct security_operations {
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
- int (*capset_check) (const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
- void (*capset_set) (const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
+ int (*capset) (struct cred *new,
+ const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, int cap);
int (*acct) (struct file *file);
int (*sysctl) (struct ctl_table *table, int op);
@@ -1310,7 +1299,7 @@ struct security_operations {

int (*bprm_alloc_security) (struct linux_binprm *bprm);
void (*bprm_free_security) (struct linux_binprm *bprm);
- void (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
+ int (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
int (*bprm_set_security) (struct linux_binprm *bprm);
int (*bprm_check_security) (struct linux_binprm *bprm);
@@ -1401,11 +1390,13 @@ struct security_operations {
int (*dentry_open) (struct file *file, const struct cred *cred);

int (*task_create) (unsigned long clone_flags);
- int (*cred_alloc_security) (struct cred *cred);
void (*cred_free) (struct cred *cred);
+ int (*cred_prepare)(struct cred *new, const struct cred *old,
+ gfp_t gfp);
+ void (*cred_commit)(struct cred *new, const struct cred *old);
int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
- int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ ,
- uid_t old_euid, uid_t old_suid, int flags);
+ int (*task_fix_setuid) (struct cred *new, const struct cred *old,
+ int flags);
int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags);
int (*task_setpgid) (struct task_struct *p, pid_t pgid);
int (*task_getpgid) (struct task_struct *p);
@@ -1425,8 +1416,7 @@ struct security_operations {
int (*task_wait) (struct task_struct *p);
int (*task_prctl) (int option, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
- unsigned long arg5, long *rc_p);
- void (*task_reparent_to_init) (struct task_struct *p);
+ unsigned long arg5);
void (*task_to_inode) (struct task_struct *p, struct inode *inode);

int (*ipc_permission) (struct kern_ipc_perm *ipcp, short flag);
@@ -1531,10 +1521,10 @@ struct security_operations {

/* key management security hooks */
#ifdef CONFIG_KEYS
- int (*key_alloc) (struct key *key, struct task_struct *tsk, unsigned long flags);
+ int (*key_alloc) (struct key *key, const struct cred *cred, unsigned long flags);
void (*key_free) (struct key *key);
int (*key_permission) (key_ref_t key_ref,
- struct task_struct *context,
+ const struct cred *cred,
key_perm_t perm);
int (*key_getsecurity)(struct key *key, char **_buffer);
#endif /* CONFIG_KEYS */
@@ -1565,12 +1555,10 @@ int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
-int security_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
-void security_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
+int security_capset(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
int security_capable(struct task_struct *tsk, int cap);
int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op);
@@ -1582,7 +1570,7 @@ int security_vm_enough_memory(long pages);
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
int security_bprm_alloc(struct linux_binprm *bprm);
void security_bprm_free(struct linux_binprm *bprm);
-void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
void security_bprm_post_apply_creds(struct linux_binprm *bprm);
int security_bprm_set(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm);
@@ -1659,11 +1647,12 @@ int security_file_send_sigiotask(struct task_struct *tsk,
int security_file_receive(struct file *file);
int security_dentry_open(struct file *file, const struct cred *cred);
int security_task_create(unsigned long clone_flags);
-int security_cred_alloc(struct cred *cred);
void security_cred_free(struct cred *cred);
+int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
+void security_commit_creds(struct cred *new, const struct cred *old);
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
-int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
- uid_t old_suid, int flags);
+int security_task_fix_setuid(struct cred *new, const struct cred *old,
+ int flags);
int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags);
int security_task_setpgid(struct task_struct *p, pid_t pgid);
int security_task_getpgid(struct task_struct *p);
@@ -1682,8 +1671,7 @@ int security_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid);
int security_task_wait(struct task_struct *p);
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5, long *rc_p);
-void security_task_reparent_to_init(struct task_struct *p);
+ unsigned long arg4, unsigned long arg5);
void security_task_to_inode(struct task_struct *p, struct inode *inode);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
@@ -1758,18 +1746,13 @@ static inline int security_capget(struct task_struct *target,
return cap_capget(target, effective, inheritable, permitted);
}

-static inline int security_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
+static inline int security_capset(struct cred *new,
+ const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
- return cap_capset_check(effective, inheritable, permitted);
-}
-
-static inline void security_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
-{
- cap_capset_set(effective, inheritable, permitted);
+ return cap_capset(new, old, effective, inheritable, permitted);
}

static inline int security_capable(struct task_struct *tsk, int cap)
@@ -1826,9 +1809,9 @@ static inline int security_bprm_alloc(struct linux_binprm *bprm)
static inline void security_bprm_free(struct linux_binprm *bprm)
{ }

-static inline void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+static inline int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
{
- cap_bprm_apply_creds(bprm, unsafe);
+ return cap_bprm_apply_creds(bprm, unsafe);
}

static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm)
@@ -2171,13 +2154,20 @@ static inline int security_task_create(unsigned long clone_flags)
return 0;
}

-static inline int security_cred_alloc(struct cred *cred)
+static inline void security_cred_free(struct cred *cred)
+{ }
+
+static inline int security_prepare_creds(struct cred *new,
+ const struct cred *old,
+ gfp_t gfp)
{
return 0;
}

-static inline void security_cred_free(struct cred *cred)
-{ }
+static inline void security_commit_creds(struct cred *new,
+ const struct cred *old)
+{
+}

static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
int flags)
@@ -2185,10 +2175,11 @@ static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
return 0;
}

-static inline int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
- uid_t old_suid, int flags)
+static inline int security_task_fix_setuid(struct cred *new,
+ const struct cred *old,
+ int flags)
{
- return cap_task_post_setuid(old_ruid, old_euid, old_suid, flags);
+ return cap_task_fix_setuid(new, old, flags);
}

static inline int security_task_setgid(gid_t id0, gid_t id1, gid_t id2,
@@ -2275,14 +2266,9 @@ static inline int security_task_wait(struct task_struct *p)
static inline int security_task_prctl(int option, unsigned long arg2,
unsigned long arg3,
unsigned long arg4,
- unsigned long arg5, long *rc_p)
-{
- return cap_task_prctl(option, arg2, arg3, arg3, arg5, rc_p);
-}
-
-static inline void security_task_reparent_to_init(struct task_struct *p)
+ unsigned long arg5)
{
- cap_task_reparent_to_init(p);
+ return cap_task_prctl(option, arg2, arg3, arg3, arg5);
}

static inline void security_task_to_inode(struct task_struct *p, struct inode *inode)
@@ -2727,16 +2713,16 @@ static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi
#ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY

-int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long flags);
+int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags);
void security_key_free(struct key *key);
int security_key_permission(key_ref_t key_ref,
- struct task_struct *context, key_perm_t perm);
+ const struct cred *cred, key_perm_t perm);
int security_key_getsecurity(struct key *key, char **_buffer);

#else

static inline int security_key_alloc(struct key *key,
- struct task_struct *tsk,
+ const struct cred *cred,
unsigned long flags)
{
return 0;
@@ -2747,7 +2733,7 @@ static inline void security_key_free(struct key *key)
}

static inline int security_key_permission(key_ref_t key_ref,
- struct task_struct *context,
+ const struct cred *cred,
key_perm_t perm)
{
return 0;
diff --git a/init/main.c b/init/main.c
index 9c3b68b..3f1eca7 100644
--- a/init/main.c
+++ b/init/main.c
@@ -665,6 +665,7 @@ asmlinkage void __init start_kernel(void)
efi_enter_virtual_mode();
#endif
thread_info_cache_init();
+ cred_init();
fork_init(num_physpages);
proc_caches_init();
buffer_init();
diff --git a/kernel/capability.c b/kernel/capability.c
index 758bfe1..6465ab7 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -14,12 +14,7 @@
#include <linux/syscalls.h>
#include <linux/pid_namespace.h>
#include <asm/uaccess.h>
-
-/*
- * This lock protects task->cap_* for all tasks including current.
- * Locking rule: acquire this prior to tasklist_lock.
- */
-static DEFINE_SPINLOCK(task_capability_lock);
+#include "cred-internals.h"

/*
* Leveraged for setting/resetting capabilities
@@ -116,12 +111,11 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
}

/*
- * If we have configured with filesystem capability support, then the
- * only thing that can change the capabilities of the current process
- * is the current process. As such, we can't be in this code at the
- * same time as we are in the process of setting capabilities in this
- * process. The net result is that we can limit our use of locks to
- * when we are reading the caps of another process.
+ * The only thing that can change the capabilities of the current
+ * process is the current process. As such, we can't be in this code
+ * at the same time as we are in the process of setting capabilities
+ * in this process. The net result is that we can limit our use of
+ * locks to when we are reading the caps of another process.
*/
static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
kernel_cap_t *pIp, kernel_cap_t *pPp)
@@ -131,7 +125,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
if (pid && (pid != task_pid_vnr(current))) {
struct task_struct *target;

- spin_lock(&task_capability_lock);
read_lock(&tasklist_lock);

target = find_task_by_vpid(pid);
@@ -141,34 +134,12 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
ret = security_capget(target, pEp, pIp, pPp);

read_unlock(&tasklist_lock);
- spin_unlock(&task_capability_lock);
} else
ret = security_capget(current, pEp, pIp, pPp);

return ret;
}

-/*
- * Atomically modify the effective capabilities returning the original
- * value. No permission check is performed here - it is assumed that the
- * caller is permitted to set the desired effective capabilities.
- */
-kernel_cap_t cap_set_effective(const kernel_cap_t pE_new)
-{
- kernel_cap_t pE_old;
-
- spin_lock(&task_capability_lock);
-
- pE_old = current->cred->cap_effective;
- current->cred->cap_effective = pE_new;
-
- spin_unlock(&task_capability_lock);
-
- return pE_old;
-}
-
-EXPORT_SYMBOL(cap_set_effective);
-
/**
* sys_capget - get the capabilities of a given process.
* @header: pointer to struct that contains capability version and
@@ -196,7 +167,6 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
return -EINVAL;

ret = cap_get_target_pid(pid, &pE, &pI, &pP);
-
if (!ret) {
struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
unsigned i;
@@ -258,6 +228,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
unsigned i, tocopy;
kernel_cap_t inheritable, permitted, effective;
+ struct cred *new;
int ret;
pid_t pid;

@@ -272,10 +243,9 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
if (pid != 0 && pid != task_pid_vnr(current))
return -EPERM;

- if (copy_from_user(&kdata, data, tocopy
- * sizeof(struct __user_cap_data_struct))) {
+ if (copy_from_user(&kdata, data,
+ tocopy * sizeof(struct __user_cap_data_struct)))
return -EFAULT;
- }

for (i = 0; i < tocopy; i++) {
effective.cap[i] = kdata[i].effective;
@@ -289,13 +259,18 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
i++;
}

- spin_lock(&task_capability_lock);
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;

- ret = security_capset_check(&effective, &inheritable, &permitted);
- if (!ret)
- security_capset_set(&effective, &inheritable, &permitted);
+ ret = security_capset(new, current_cred(),
+ &effective, &inheritable, &permitted);
+ if (ret < 0)
+ goto error;
+ return commit_creds(new);

- spin_unlock(&task_capability_lock);
+error:
+ abort_creds(new);
return ret;
}

diff --git a/kernel/cred-internals.h b/kernel/cred-internals.h
new file mode 100644
index 0000000..f16312a
--- /dev/null
+++ b/kernel/cred-internals.h
@@ -0,0 +1,26 @@
+/* Internal credentials stuff
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+/*
+ * cred.c
+ */
+extern struct cred *alloc_creds(const struct cred *, gfp_t);
+
+/*
+ * user.c
+ */
+static inline void sched_switch_user(struct task_struct *p)
+{
+#ifdef CONFIG_USER_SCHED
+ sched_move_task(p);
+#endif /* CONFIG_USER_SCHED */
+}
+
diff --git a/kernel/cred.c b/kernel/cred.c
index 6090cb6..7a4d311 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -15,6 +15,10 @@
#include <linux/keyctl.h>
#include <linux/init_task.h>
#include <linux/security.h>
+#include <linux/cn_proc.h>
+#include "cred-internals.h"
+
+static struct kmem_cache *cred_jar;

/*
* The common credentials for the initial task's thread group
@@ -64,7 +68,7 @@ static void put_tgcred_rcu(struct rcu_head *rcu)
/*
* Release a set of thread group credentials.
*/
-static void put_tgcred(struct thread_group_cred *tgcred)
+void put_tgcred(struct thread_group_cred *tgcred)
{
#ifdef CONFIG_KEYS
if (atomic_dec_and_test(&tgcred->usage))
@@ -79,77 +83,329 @@ static void put_cred_rcu(struct rcu_head *rcu)
{
struct cred *cred = container_of(rcu, struct cred, rcu);

- BUG_ON(atomic_read(&cred->usage) != 0);
+ if (atomic_read(&cred->usage) != 0)
+ panic("CRED: put_cred_rcu() sees %p with usage %d\n",
+ cred, atomic_read(&cred->usage));

+ security_cred_free(cred);
key_put(cred->thread_keyring);
key_put(cred->request_key_auth);
put_tgcred(cred->tgcred);
put_group_info(cred->group_info);
free_uid(cred->user);
- security_cred_free(cred);
- kfree(cred);
+ kmem_cache_free(cred_jar, cred);
}

/**
* __put_cred - Destroy a set of credentials
- * @sec: The record to release
+ * @cred: The record to release
*
* Destroy a set of credentials on which no references remain.
*/
void __put_cred(struct cred *cred)
{
+ BUG_ON(atomic_read(&cred->usage) != 0);
+
call_rcu(&cred->rcu, put_cred_rcu);
}
EXPORT_SYMBOL(__put_cred);

/*
+ * Allocate new credentials
+ */
+struct cred *alloc_creds(const struct cred *old, gfp_t gfp)
+{
+ struct cred *new;
+
+ new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
+ if (!new)
+ return NULL;
+ if (old)
+ memcpy(new, old, sizeof(struct cred));
+ return new;
+}
+
+/**
+ * prepare_creds - Prepare a new set of credentials for modification
+ *
+ * Prepare a new set of task credentials for modification. A task's creds
+ * shouldn't generally be modified directly, therefore this function is used to
+ * prepare a new copy, which the caller then modifies and then commits by
+ * calling commit_creds().
+ *
+ * Returns a pointer to the new creds-to-be if successful, NULL otherwise.
+ *
+ * Call commit_creds() or abort_creds() to clean up.
+ */
+struct cred *prepare_creds(void)
+{
+ struct task_struct *task = current;
+ const struct cred *old;
+ struct cred *new;
+
+ BUG_ON(atomic_read(&task->cred->usage) < 1);
+
+ new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
+ if (!new)
+ return NULL;
+
+ old = task->cred;
+ memcpy(new, old, sizeof(struct cred));
+
+ atomic_set(&new->usage, 1);
+ get_group_info(new->group_info);
+ get_uid(new->user);
+
+#ifdef CONFIG_KEYS
+ key_get(new->thread_keyring);
+ key_get(new->request_key_auth);
+ atomic_inc(&new->tgcred->usage);
+#endif
+
+#ifdef CONFIG_SECURITY
+ new->security = NULL;
+#endif
+
+ if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
+ goto error;
+ return new;
+
+error:
+ abort_creds(new);
+ return NULL;
+}
+EXPORT_SYMBOL(prepare_creds);
+
+/*
+ * prepare new credentials for the usermode helper dispatcher
+ */
+struct cred *prepare_usermodehelper_creds(void)
+{
+#ifdef CONFIG_KEYS
+ struct thread_group_cred *tgcred = NULL;
+#endif
+ struct cred *new;
+
+#ifdef CONFIG_KEYS
+ tgcred = kzalloc(sizeof(*new->tgcred), GFP_ATOMIC);
+ if (!tgcred)
+ return NULL;
+#endif
+
+ new = kmem_cache_alloc(cred_jar, GFP_ATOMIC);
+ if (!new)
+ return NULL;
+
+ memcpy(new, &init_cred, sizeof(struct cred));
+
+ atomic_set(&new->usage, 1);
+ get_group_info(new->group_info);
+ get_uid(new->user);
+
+#ifdef CONFIG_KEYS
+ new->thread_keyring = NULL;
+ new->request_key_auth = NULL;
+ new->jit_keyring = KEY_REQKEY_DEFL_DEFAULT;
+
+ atomic_set(&tgcred->usage, 1);
+ spin_lock_init(&tgcred->lock);
+ new->tgcred = tgcred;
+#endif
+
+#ifdef CONFIG_SECURITY
+ new->security = NULL;
+#endif
+ if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
+ goto error;
+
+ BUG_ON(atomic_read(&new->usage) != 1);
+ return new;
+
+error:
+ put_cred(new);
+ return NULL;
+}
+
+/*
* Copy credentials for the new process created by fork()
+ *
+ * We share if we can, but under some circumstances we have to generate a new
+ * set.
*/
int copy_creds(struct task_struct *p, unsigned long clone_flags)
{
- struct cred *pcred;
- int ret;
+ struct thread_group_cred *tgcred;
+ struct cred *new;
+
+ mutex_init(&p->cred_exec_mutex);

- pcred = kmemdup(p->cred, sizeof(*p->cred), GFP_KERNEL);
- if (!pcred)
+ if (!p->cred->thread_keyring && clone_flags & CLONE_THREAD) {
+ get_cred(p->cred);
+ return 0;
+ }
+
+ new = prepare_creds();
+ if (!new)
return -ENOMEM;

#ifdef CONFIG_KEYS
- if (clone_flags & CLONE_THREAD) {
- atomic_inc(&pcred->tgcred->usage);
- } else {
- pcred->tgcred = kmalloc(sizeof(struct cred), GFP_KERNEL);
- if (!pcred->tgcred) {
- kfree(pcred);
+ /* new threads get their own thread keyrings if their parent already
+ * had one */
+ if (new->thread_keyring) {
+ key_put(new->thread_keyring);
+ new->thread_keyring = NULL;
+ if (clone_flags & CLONE_THREAD)
+ install_thread_keyring_to_cred(new);
+ }
+
+ /* we share the process and session keyrings between all the threads in
+ * a process - this is slightly icky as we violate COW credentials a
+ * bit */
+ if (!(clone_flags & CLONE_THREAD)) {
+ tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+ if (!tgcred) {
+ put_cred(new);
return -ENOMEM;
}
- atomic_set(&pcred->tgcred->usage, 1);
- spin_lock_init(&pcred->tgcred->lock);
- pcred->tgcred->process_keyring = NULL;
- pcred->tgcred->session_keyring =
- key_get(p->cred->tgcred->session_keyring);
+ atomic_set(&tgcred->usage, 1);
+ spin_lock_init(&tgcred->lock);
+ tgcred->process_keyring = NULL;
+ tgcred->session_keyring = key_get(new->tgcred->session_keyring);
+
+ put_tgcred(new->tgcred);
+ new->tgcred = tgcred;
}
#endif

-#ifdef CONFIG_SECURITY
- pcred->security = NULL;
-#endif
+ atomic_inc(&new->user->processes);
+ p->cred = new;
+ return 0;
+}

- ret = security_cred_alloc(pcred);
- if (ret < 0) {
- put_tgcred(pcred->tgcred);
- kfree(pcred);
- return ret;
+/**
+ * commit_creds - Install new credentials upon the current task
+ * @new: The credentials to be assigned
+ *
+ * Install a new set of credentials to the current task, using RCU to replace
+ * the old set.
+ *
+ * This function eats the caller's reference to the new credentials.
+ *
+ * Always returns 0 thus allowing this function to be tail-called at the end
+ * of, say, sys_setgid().
+ */
+int commit_creds(struct cred *new)
+{
+ struct task_struct *task = current;
+ const struct cred *old;
+
+ BUG_ON(atomic_read(&new->usage) < 1);
+ BUG_ON(atomic_read(&task->cred->usage) < 1);
+
+ old = task->cred;
+ security_commit_creds(new, old);
+
+ /* dumpability changes */
+ if (old->euid != new->euid ||
+ old->egid != new->egid ||
+ old->fsuid != new->fsuid ||
+ old->fsgid != new->fsgid ||
+ !cap_issubset(new->cap_permitted, old->cap_permitted)) {
+ set_dumpable(task->mm, suid_dumpable);
+ task->pdeath_signal = 0;
+ smp_wmb();
}

- atomic_set(&pcred->usage, 1);
- get_group_info(pcred->group_info);
- get_uid(pcred->user);
- key_get(pcred->thread_keyring);
- key_get(pcred->request_key_auth);
+ /* alter the thread keyring */
+ if (new->fsuid != old->fsuid)
+ key_fsuid_changed(task);
+ if (new->fsgid != old->fsgid)
+ key_fsgid_changed(task);
+
+ /* do it
+ * - What if a process setreuid()'s and this brings the
+ * new uid over his NPROC rlimit? We can check this now
+ * cheaply with the new uid cache, so if it matters
+ * we should be checking for it. -DaveM
+ */
+ if (new->user != old->user)
+ atomic_inc(&new->user->processes);
+ rcu_assign_pointer(task->cred, new);
+ if (new->user != old->user)
+ atomic_dec(&old->user->processes);
+
+ sched_switch_user(task);
+
+ /* send notifications */
+ if (new->uid != old->uid ||
+ new->euid != old->euid ||
+ new->suid != old->suid ||
+ new->fsuid != old->fsuid)
+ proc_id_connector(task, PROC_EVENT_UID);
+
+ if (new->gid != old->gid ||
+ new->egid != old->egid ||
+ new->sgid != old->sgid ||
+ new->fsgid != old->fsgid)
+ proc_id_connector(task, PROC_EVENT_GID);

- /* RCU assignment is unneeded here as no-one can have accessed this
- * pointer yet, barring us */
- p->cred = pcred;
+ put_cred(old);
return 0;
}
+EXPORT_SYMBOL(commit_creds);
+
+/**
+ * abort_creds - Discard a set of credentials and unlock the current task
+ * @new: The credentials that were going to be applied
+ *
+ * Discard a set of credentials that were under construction and unlock the
+ * current task.
+ */
+void abort_creds(struct cred *new)
+{
+ BUG_ON(atomic_read(&new->usage) < 1);
+ put_cred(new);
+}
+EXPORT_SYMBOL(abort_creds);
+
+/**
+ * override_creds - Temporarily override the current process's credentials
+ * @new: The credentials to be assigned
+ *
+ * Install a set of temporary override credentials on the current process,
+ * returning the old set for later reversion.
+ */
+const struct cred *override_creds(const struct cred *new)
+{
+ const struct cred *old = current->cred;
+
+ rcu_assign_pointer(current->cred, get_cred(new));
+ return old;
+}
+EXPORT_SYMBOL(override_creds);
+
+/**
+ * revert_creds - Revert a temporary credentials override
+ * @old: The credentials to be restored
+ *
+ * Revert a temporary set of override credentials to an old set, discarding the
+ * override set.
+ */
+extern void revert_creds(const struct cred *old)
+{
+ const struct cred *override = current->cred;
+
+ rcu_assign_pointer(current->cred, old);
+ put_cred(override);
+}
+EXPORT_SYMBOL(revert_creds);
+
+/*
+ * initialise the credentials stuff
+ */
+void __init cred_init(void)
+{
+ /* allocate a slab in which we can store credentials */
+ cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred),
+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+}
diff --git a/kernel/exit.c b/kernel/exit.c
index 9bce79b..62dc559 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -47,11 +47,13 @@
#include <linux/blkdev.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/tracehook.h>
+#include <linux/init_task.h>

#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
+#include "cred-internals.h"

static void exit_mm(struct task_struct * tsk);

@@ -337,12 +339,12 @@ static void reparent_to_kthreadd(void)
/* cpus_allowed? */
/* rt_priority? */
/* signals? */
- security_task_reparent_to_init(current);
memcpy(current->signal->rlim, init_task.signal->rlim,
sizeof(current->signal->rlim));
- atomic_inc(&(INIT_USER->__count));
+
+ atomic_inc(&init_cred.usage);
+ commit_creds(&init_cred);
write_unlock_irq(&tasklist_lock);
- switch_uid(INIT_USER);
}

void __set_special_pids(struct pid *pid)
@@ -1085,7 +1087,6 @@ NORET_TYPE void do_exit(long code)
check_stack_usage();
exit_thread();
cgroup_exit(tsk, 1);
- exit_keys(tsk);

if (group_dead && tsk->signal->leader)
disassociate_ctty(1);
diff --git a/kernel/fork.c b/kernel/fork.c
index b3254d5..a7cf83a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1055,10 +1055,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto bad_fork_cleanup_sighand;
if ((retval = copy_mm(clone_flags, p)))
goto bad_fork_cleanup_signal;
- if ((retval = copy_keys(clone_flags, p)))
- goto bad_fork_cleanup_mm;
if ((retval = copy_namespaces(clone_flags, p)))
- goto bad_fork_cleanup_keys;
+ goto bad_fork_cleanup_mm;
if ((retval = copy_io(clone_flags, p)))
goto bad_fork_cleanup_namespaces;
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
@@ -1237,8 +1235,6 @@ bad_fork_cleanup_io:
put_io_context(p->io_context);
bad_fork_cleanup_namespaces:
exit_task_namespaces(p);
-bad_fork_cleanup_keys:
- exit_keys(p);
bad_fork_cleanup_mm:
if (p->mm)
mmput(p->mm);
@@ -1266,6 +1262,7 @@ bad_fork_cleanup_cgroup:
bad_fork_cleanup_put_domain:
module_put(task_thread_info(p)->exec_domain->module);
bad_fork_cleanup_count:
+ atomic_dec(&p->cred->user->processes);
put_cred(p->cred);
bad_fork_free:
free_task(p);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 27e02e6..873ba4e 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -118,10 +118,10 @@ EXPORT_SYMBOL(request_module);
struct subprocess_info {
struct work_struct work;
struct completion *complete;
+ struct cred *cred;
char *path;
char **argv;
char **envp;
- struct key *ring;
enum umh_wait wait;
int retval;
struct file *stdin;
@@ -134,19 +134,20 @@ struct subprocess_info {
static int ____call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
- struct key *new_session, *old_session;
int retval;

- /* Unblock all signals and set the session keyring. */
- new_session = key_get(sub_info->ring);
+ BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+
+ /* Unblock all signals */
spin_lock_irq(&current->sighand->siglock);
- old_session = __install_session_keyring(new_session);
flush_signal_handlers(current, 1);
sigemptyset(&current->blocked);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);

- key_put(old_session);
+ /* Install the credentials */
+ commit_creds(sub_info->cred);
+ sub_info->cred = NULL;

/* Install input pipe when needed */
if (sub_info->stdin) {
@@ -185,6 +186,8 @@ void call_usermodehelper_freeinfo(struct subprocess_info *info)
{
if (info->cleanup)
(*info->cleanup)(info->argv, info->envp);
+ if (info->cred)
+ put_cred(info->cred);
kfree(info);
}
EXPORT_SYMBOL(call_usermodehelper_freeinfo);
@@ -240,6 +243,8 @@ static void __call_usermodehelper(struct work_struct *work)
pid_t pid;
enum umh_wait wait = sub_info->wait;

+ BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+
/* CLONE_VFORK: wait until the usermode helper has execve'd
* successfully We need the data structures to stay around
* until that is done. */
@@ -370,6 +375,9 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
sub_info->path = path;
sub_info->argv = argv;
sub_info->envp = envp;
+ sub_info->cred = prepare_usermodehelper_creds();
+ if (!sub_info->cred)
+ return NULL;

out:
return sub_info;
@@ -384,7 +392,13 @@ EXPORT_SYMBOL(call_usermodehelper_setup);
void call_usermodehelper_setkeys(struct subprocess_info *info,
struct key *session_keyring)
{
- info->ring = session_keyring;
+#ifdef CONFIG_KEYS
+ struct thread_group_cred *tgcred = info->cred->tgcred;
+ key_put(tgcred->session_keyring);
+ tgcred->session_keyring = key_get(session_keyring);
+#else
+ BUG();
+#endif
}
EXPORT_SYMBOL(call_usermodehelper_setkeys);

@@ -452,6 +466,8 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
DECLARE_COMPLETION_ONSTACK(done);
int retval = 0;

+ BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+
helper_lock();
if (sub_info->path[0] == '\0')
goto out;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index ed65d9f..893a099 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -171,6 +171,14 @@ int ptrace_attach(struct task_struct *task)
if (same_thread_group(task, current))
goto out;

+ /* Protect exec's credential calculations against our interference;
+ * SUID, SGID and LSM creds get determined differently under ptrace.
+ */
+ retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+ if (retval < 0)
+ goto out;
+
+ retval = -EPERM;
repeat:
/*
* Nasty, nasty.
@@ -210,6 +218,7 @@ repeat:
bad:
write_unlock_irqrestore(&tasklist_lock, flags);
task_unlock(task);
+ mutex_unlock(&current->cred_exec_mutex);
out:
return retval;
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 2632d94..911dcd2 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -179,7 +179,7 @@ int next_signal(struct sigpending *pending, sigset_t *mask)
/*
* allocate a new signal queue record
* - this may be called without locks if and only if t == current, otherwise an
- * appopriate lock must be held to protect t's user_struct
+ * appopriate lock must be held to stop the target task from exiting
*/
static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
int override_rlimit)
@@ -193,7 +193,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
* caller must be holding the RCU readlock (by way of a spinlock) and
* we use RCU protection here
*/
- user = __task_cred(t)->user;
+ user = get_uid(__task_cred(t)->user);
atomic_inc(&user->sigpending);
if (override_rlimit ||
atomic_read(&user->sigpending) <=
@@ -201,12 +201,14 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
q = kmem_cache_alloc(sigqueue_cachep, flags);
if (unlikely(q == NULL)) {
atomic_dec(&user->sigpending);
+ free_uid(user);
} else {
INIT_LIST_HEAD(&q->list);
q->flags = 0;
- q->user = get_uid(user);
+ q->user = user;
}
- return(q);
+
+ return q;
}

static void __sigqueue_free(struct sigqueue *q)
diff --git a/kernel/sys.c b/kernel/sys.c
index 4c4ac7a..becd67d 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -180,7 +180,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = cred->user;
+ user = (struct user_struct *) cred->user;
if (!who)
who = cred->uid;
else if ((who != cred->uid) &&
@@ -479,47 +479,48 @@ void ctrl_alt_del(void)
*/
asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
{
- struct cred *cred = current->cred;
- int old_rgid = cred->gid;
- int old_egid = cred->egid;
- int new_rgid = old_rgid;
- int new_egid = old_egid;
+ const struct cred *old;
+ struct cred *new;
int retval;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ old = current_cred();
+
retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
if (retval)
- return retval;
+ goto error;

+ retval = -EPERM;
if (rgid != (gid_t) -1) {
- if ((old_rgid == rgid) ||
- (cred->egid == rgid) ||
+ if (old->gid == rgid ||
+ old->egid == rgid ||
capable(CAP_SETGID))
- new_rgid = rgid;
+ new->gid = rgid;
else
- return -EPERM;
+ goto error;
}
if (egid != (gid_t) -1) {
- if ((old_rgid == egid) ||
- (cred->egid == egid) ||
- (cred->sgid == egid) ||
+ if (old->gid == egid ||
+ old->egid == egid ||
+ old->sgid == egid ||
capable(CAP_SETGID))
- new_egid = egid;
+ new->egid = egid;
else
- return -EPERM;
- }
- if (new_egid != old_egid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
+ goto error;
}
+
if (rgid != (gid_t) -1 ||
- (egid != (gid_t) -1 && egid != old_rgid))
- cred->sgid = new_egid;
- cred->fsgid = new_egid;
- cred->egid = new_egid;
- cred->gid = new_rgid;
- key_fsgid_changed(current);
- proc_id_connector(current, PROC_EVENT_GID);
- return 0;
+ (egid != (gid_t) -1 && egid != old->gid))
+ new->sgid = new->egid;
+ new->fsgid = new->egid;
+
+ return commit_creds(new);
+
+error:
+ abort_creds(new);
+ return retval;
}

/*
@@ -529,40 +530,42 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
*/
asmlinkage long sys_setgid(gid_t gid)
{
- struct cred *cred = current->cred;
- int old_egid = cred->egid;
+ const struct cred *old;
+ struct cred *new;
int retval;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ old = current_cred();
+
retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
if (retval)
- return retval;
+ goto error;

- if (capable(CAP_SETGID)) {
- if (old_egid != gid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
- }
- cred->gid = cred->egid = cred->sgid = cred->fsgid = gid;
- } else if ((gid == cred->gid) || (gid == cred->sgid)) {
- if (old_egid != gid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
- }
- cred->egid = cred->fsgid = gid;
- }
+ retval = -EPERM;
+ if (capable(CAP_SETGID))
+ new->gid = new->egid = new->sgid = new->fsgid = gid;
+ else if (gid == old->gid || gid == old->sgid)
+ new->egid = new->fsgid = gid;
else
- return -EPERM;
+ goto error;

- key_fsgid_changed(current);
- proc_id_connector(current, PROC_EVENT_GID);
- return 0;
+ return commit_creds(new);
+
+error:
+ abort_creds(new);
+ return retval;
}

-static int set_user(uid_t new_ruid, int dumpclear)
+/*
+ * change the user struct in a credentials set to match the new UID
+ */
+static int set_user(struct cred *new)
{
struct user_struct *new_user;

- new_user = alloc_uid(current->nsproxy->user_ns, new_ruid);
+ new_user = alloc_uid(current->nsproxy->user_ns, new->uid);
if (!new_user)
return -EAGAIN;

@@ -573,13 +576,8 @@ static int set_user(uid_t new_ruid, int dumpclear)
return -EAGAIN;
}

- switch_uid(new_user);
-
- if (dumpclear) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
- }
- current->cred->uid = new_ruid;
+ free_uid(new->user);
+ new->user = new_user;
return 0;
}

@@ -600,55 +598,56 @@ static int set_user(uid_t new_ruid, int dumpclear)
*/
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
{
- struct cred *cred = current->cred;
- int old_ruid, old_euid, old_suid, new_ruid, new_euid;
+ const struct cred *old;
+ struct cred *new;
int retval;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ old = current_cred();
+
retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
if (retval)
- return retval;
-
- new_ruid = old_ruid = cred->uid;
- new_euid = old_euid = cred->euid;
- old_suid = cred->suid;
+ goto error;

+ retval = -EPERM;
if (ruid != (uid_t) -1) {
- new_ruid = ruid;
- if ((old_ruid != ruid) &&
- (cred->euid != ruid) &&
+ new->uid = ruid;
+ if (old->uid != ruid &&
+ old->euid != ruid &&
!capable(CAP_SETUID))
- return -EPERM;
+ goto error;
}

if (euid != (uid_t) -1) {
- new_euid = euid;
- if ((old_ruid != euid) &&
- (cred->euid != euid) &&
- (cred->suid != euid) &&
+ new->euid = euid;
+ if (old->uid != euid &&
+ old->euid != euid &&
+ old->suid != euid &&
!capable(CAP_SETUID))
- return -EPERM;
+ goto error;
}

- if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
- return -EAGAIN;
+ retval = -EAGAIN;
+ if (new->uid != old->uid && set_user(new) < 0)
+ goto error;

- if (new_euid != old_euid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
- }
- cred->fsuid = cred->euid = new_euid;
if (ruid != (uid_t) -1 ||
- (euid != (uid_t) -1 && euid != old_ruid))
- cred->suid = cred->euid;
- cred->fsuid = cred->euid;
+ (euid != (uid_t) -1 && euid != old->uid))
+ new->suid = new->euid;
+ new->fsuid = new->euid;

- key_fsuid_changed(current);
- proc_id_connector(current, PROC_EVENT_UID);
-
- return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
-}
+ retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
+ if (retval < 0)
+ goto error;

+ return commit_creds(new);

+error:
+ abort_creds(new);
+ return retval;
+}

/*
* setuid() is implemented like SysV with SAVED_IDS
@@ -663,37 +662,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
*/
asmlinkage long sys_setuid(uid_t uid)
{
- struct cred *cred = current->cred;
- int old_euid = cred->euid;
- int old_ruid, old_suid, new_suid;
+ const struct cred *old;
+ struct cred *new;
int retval;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ old = current_cred();
+
retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
if (retval)
- return retval;
+ goto error;

- old_ruid = cred->uid;
- old_suid = cred->suid;
- new_suid = old_suid;
-
+ retval = -EPERM;
if (capable(CAP_SETUID)) {
- if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
- return -EAGAIN;
- new_suid = uid;
- } else if ((uid != cred->uid) && (uid != new_suid))
- return -EPERM;
-
- if (old_euid != uid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
+ new->suid = new->uid = uid;
+ if (uid != old->uid && set_user(new) < 0) {
+ retval = -EAGAIN;
+ goto error;
+ }
+ } else if (uid != old->uid && uid != new->suid) {
+ goto error;
}
- cred->fsuid = cred->euid = uid;
- cred->suid = new_suid;

- key_fsuid_changed(current);
- proc_id_connector(current, PROC_EVENT_UID);
+ new->fsuid = new->euid = uid;
+
+ retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
+ if (retval < 0)
+ goto error;

- return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
+ return commit_creds(new);
+
+error:
+ abort_creds(new);
+ return retval;
}


@@ -703,47 +706,53 @@ asmlinkage long sys_setuid(uid_t uid)
*/
asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
{
- struct cred *cred = current->cred;
- int old_ruid = cred->uid;
- int old_euid = cred->euid;
- int old_suid = cred->suid;
+ const struct cred *old;
+ struct cred *new;
int retval;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
if (retval)
- return retval;
+ goto error;
+ old = current_cred();

+ retval = -EPERM;
if (!capable(CAP_SETUID)) {
- if ((ruid != (uid_t) -1) && (ruid != cred->uid) &&
- (ruid != cred->euid) && (ruid != cred->suid))
- return -EPERM;
- if ((euid != (uid_t) -1) && (euid != cred->uid) &&
- (euid != cred->euid) && (euid != cred->suid))
- return -EPERM;
- if ((suid != (uid_t) -1) && (suid != cred->uid) &&
- (suid != cred->euid) && (suid != cred->suid))
- return -EPERM;
+ if (ruid != (uid_t) -1 && ruid != old->uid &&
+ ruid != old->euid && ruid != old->suid)
+ goto error;
+ if (euid != (uid_t) -1 && euid != old->uid &&
+ euid != old->euid && euid != old->suid)
+ goto error;
+ if (suid != (uid_t) -1 && suid != old->uid &&
+ suid != old->euid && suid != old->suid)
+ goto error;
}
+
+ retval = -EAGAIN;
if (ruid != (uid_t) -1) {
- if (ruid != cred->uid &&
- set_user(ruid, euid != cred->euid) < 0)
- return -EAGAIN;
- }
- if (euid != (uid_t) -1) {
- if (euid != cred->euid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
- }
- cred->euid = euid;
+ new->uid = ruid;
+ if (ruid != old->uid && set_user(new) < 0)
+ goto error;
}
- cred->fsuid = cred->euid;
+ if (euid != (uid_t) -1)
+ new->euid = euid;
if (suid != (uid_t) -1)
- cred->suid = suid;
+ new->suid = suid;
+ new->fsuid = new->euid;
+
+ retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
+ if (retval < 0)
+ goto error;

- key_fsuid_changed(current);
- proc_id_connector(current, PROC_EVENT_UID);
+ return commit_creds(new);

- return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
+error:
+ abort_creds(new);
+ return retval;
}

asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
@@ -763,40 +772,45 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us
*/
asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{
- struct cred *cred = current->cred;
+ const struct cred *old;
+ struct cred *new;
int retval;

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ old = current_cred();
+
retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
if (retval)
- return retval;
+ goto error;

+ retval = -EPERM;
if (!capable(CAP_SETGID)) {
- if ((rgid != (gid_t) -1) && (rgid != cred->gid) &&
- (rgid != cred->egid) && (rgid != cred->sgid))
- return -EPERM;
- if ((egid != (gid_t) -1) && (egid != cred->gid) &&
- (egid != cred->egid) && (egid != cred->sgid))
- return -EPERM;
- if ((sgid != (gid_t) -1) && (sgid != cred->gid) &&
- (sgid != cred->egid) && (sgid != cred->sgid))
- return -EPERM;
- }
- if (egid != (gid_t) -1) {
- if (egid != cred->egid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
- }
- cred->egid = egid;
+ if (rgid != (gid_t) -1 && rgid != old->gid &&
+ rgid != old->egid && rgid != old->sgid)
+ goto error;
+ if (egid != (gid_t) -1 && egid != old->gid &&
+ egid != old->egid && egid != old->sgid)
+ goto error;
+ if (sgid != (gid_t) -1 && sgid != old->gid &&
+ sgid != old->egid && sgid != old->sgid)
+ goto error;
}
- cred->fsgid = cred->egid;
+
if (rgid != (gid_t) -1)
- cred->gid = rgid;
+ new->gid = rgid;
+ if (egid != (gid_t) -1)
+ new->egid = egid;
if (sgid != (gid_t) -1)
- cred->sgid = sgid;
+ new->sgid = sgid;
+ new->fsgid = new->egid;

- key_fsgid_changed(current);
- proc_id_connector(current, PROC_EVENT_GID);
- return 0;
+ return commit_creds(new);
+
+error:
+ abort_creds(new);
+ return retval;
}

asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid)
@@ -820,28 +834,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us
*/
asmlinkage long sys_setfsuid(uid_t uid)
{
- struct cred *cred = current->cred;
- int old_fsuid;
+ const struct cred *old;
+ struct cred *new;
+ uid_t old_fsuid;
+
+ new = prepare_creds();
+ if (!new)
+ return current_fsuid();
+ old = current_cred();
+ old_fsuid = old->fsuid;

- old_fsuid = cred->fsuid;
- if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
- return old_fsuid;
+ if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
+ goto error;

- if (uid == cred->uid || uid == cred->euid ||
- uid == cred->suid || uid == cred->fsuid ||
+ if (uid == old->uid || uid == old->euid ||
+ uid == old->suid || uid == old->fsuid ||
capable(CAP_SETUID)) {
if (uid != old_fsuid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
+ new->fsuid = uid;
+ if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
+ goto change_okay;
}
- cred->fsuid = uid;
}

- key_fsuid_changed(current);
- proc_id_connector(current, PROC_EVENT_UID);
-
- security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
+error:
+ abort_creds(new);
+ return old_fsuid;

+change_okay:
+ commit_creds(new);
return old_fsuid;
}

@@ -850,24 +871,34 @@ asmlinkage long sys_setfsuid(uid_t uid)
*/
asmlinkage long sys_setfsgid(gid_t gid)
{
- struct cred *cred = current->cred;
- int old_fsgid;
+ const struct cred *old;
+ struct cred *new;
+ gid_t old_fsgid;
+
+ new = prepare_creds();
+ if (!new)
+ return current_fsgid();
+ old = current_cred();
+ old_fsgid = old->fsgid;

- old_fsgid = cred->fsgid;
if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
- return old_fsgid;
+ goto error;

- if (gid == cred->gid || gid == cred->egid ||
- gid == cred->sgid || gid == cred->fsgid ||
+ if (gid == old->gid || gid == old->egid ||
+ gid == old->sgid || gid == old->fsgid ||
capable(CAP_SETGID)) {
if (gid != old_fsgid) {
- set_dumpable(current->mm, suid_dumpable);
- smp_wmb();
+ new->fsgid = gid;
+ goto change_okay;
}
- cred->fsgid = gid;
- key_fsgid_changed(current);
- proc_id_connector(current, PROC_EVENT_GID);
}
+
+error:
+ abort_creds(new);
+ return old_fsgid;
+
+change_okay:
+ commit_creds(new);
return old_fsgid;
}

@@ -1148,7 +1179,7 @@ EXPORT_SYMBOL(groups_free);

/* export the group_info to a user-space array */
static int groups_to_user(gid_t __user *grouplist,
- struct group_info *group_info)
+ const struct group_info *group_info)
{
int i;
unsigned int count = group_info->ngroups;
@@ -1239,31 +1270,25 @@ int groups_search(const struct group_info *group_info, gid_t grp)
}

/**
- * set_groups - Change a group subscription in a security record
- * @sec: The security record to alter
- * @group_info: The group list to impose
+ * set_groups - Change a group subscription in a set of credentials
+ * @new: The newly prepared set of credentials to alter
+ * @group_info: The group list to install
*
- * Validate a group subscription and, if valid, impose it upon a task security
- * record.
+ * Validate a group subscription and, if valid, insert it into a set
+ * of credentials.
*/
-int set_groups(struct cred *cred, struct group_info *group_info)
+int set_groups(struct cred *new, struct group_info *group_info)
{
int retval;
- struct group_info *old_info;

retval = security_task_setgroups(group_info);
if (retval)
return retval;

+ put_group_info(new->group_info);
groups_sort(group_info);
get_group_info(group_info);
-
- spin_lock(&cred->lock);
- old_info = cred->group_info;
- cred->group_info = group_info;
- spin_unlock(&cred->lock);
-
- put_group_info(old_info);
+ new->group_info = group_info;
return 0;
}

@@ -1278,7 +1303,20 @@ EXPORT_SYMBOL(set_groups);
*/
int set_current_groups(struct group_info *group_info)
{
- return set_groups(current->cred, group_info);
+ struct cred *new;
+ int ret;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ ret = set_groups(new, group_info);
+ if (ret < 0) {
+ abort_creds(new);
+ return ret;
+ }
+
+ return commit_creds(new);
}

EXPORT_SYMBOL(set_current_groups);
@@ -1675,11 +1713,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
{
struct task_struct *me = current;
unsigned char comm[sizeof(me->comm)];
- long uninitialized_var(error);
+ long error;

- if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
+ error = security_task_prctl(option, arg2, arg3, arg4, arg5);
+ if (error != -ENOSYS)
return error;

+ error = 0;
switch (option) {
case PR_SET_PDEATHSIG:
if (!valid_signal(arg2)) {
diff --git a/kernel/user.c b/kernel/user.c
index 9c9e27b..ed4dc57 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/user_namespace.h>
+#include "cred-internals.h"

struct user_namespace init_user_ns = {
.kref = {
@@ -104,16 +105,10 @@ static int sched_create_user(struct user_struct *up)
return rc;
}

-static void sched_switch_user(struct task_struct *p)
-{
- sched_move_task(p);
-}
-
#else /* CONFIG_USER_SCHED */

static void sched_destroy_user(struct user_struct *up) { }
static int sched_create_user(struct user_struct *up) { return 0; }
-static void sched_switch_user(struct task_struct *p) { }

#endif /* CONFIG_USER_SCHED */

@@ -448,36 +443,6 @@ out_unlock:
return NULL;
}

-void switch_uid(struct user_struct *new_user)
-{
- struct user_struct *old_user;
-
- /* What if a process setreuid()'s and this brings the
- * new uid over his NPROC rlimit? We can check this now
- * cheaply with the new uid cache, so if it matters
- * we should be checking for it. -DaveM
- */
- old_user = current->cred->user;
- atomic_inc(&new_user->processes);
- atomic_dec(&old_user->processes);
- switch_uid_keyring(new_user);
- current->cred->user = new_user;
- sched_switch_user(current);
-
- /*
- * We need to synchronize with __sigqueue_alloc()
- * doing a get_uid(p->user).. If that saw the old
- * user value, we need to wait until it has exited
- * its critical region before we can free the old
- * structure.
- */
- smp_mb();
- spin_unlock_wait(&current->sighand->siglock);
-
- free_uid(old_user);
- suid_keys(current);
-}
-
#ifdef CONFIG_USER_NS
void release_uids(struct user_namespace *ns)
{
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index edbe9f1..6904f0b 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -20,6 +20,7 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
{
struct user_namespace *ns;
struct user_struct *new_user;
+ struct cred *new;
int n;

ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
@@ -46,7 +47,16 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
return ERR_PTR(-ENOMEM);
}

- switch_uid(new_user);
+ /* Install the new user */
+ new = prepare_creds();
+ if (!new) {
+ free_uid(new_user);
+ free_uid(ns->root_user);
+ kfree(ns);
+ }
+ free_uid(new->user);
+ new->user = new_user;
+ commit_creds(new);
return ns;
}

diff --git a/lib/Makefile b/lib/Makefile
index 3b1f94b..2cd51bc 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -11,7 +11,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
rbtree.o radix-tree.o dump_stack.o \
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o irq_regs.o reciprocal_div.o argv_split.o \
- proportions.o prio_heap.o ratelimit.o show_mem.o
+ proportions.o prio_heap.o ratelimit.o show_mem.o is_single_threaded.o

lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c
new file mode 100644
index 0000000..f1ed2fe
--- /dev/null
+++ b/lib/is_single_threaded.c
@@ -0,0 +1,45 @@
+/* Function to determine if a thread group is single threaded or not
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ * - Derived from security/selinux/hooks.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+
+/**
+ * is_single_threaded - Determine if a thread group is single-threaded or not
+ * @p: A task in the thread group in question
+ *
+ * This returns true if the thread group to which a task belongs is single
+ * threaded, false if it is not.
+ */
+bool is_single_threaded(struct task_struct *p)
+{
+ struct task_struct *g, *t;
+ struct mm_struct *mm = p->mm;
+
+ if (atomic_read(&p->signal->count) != 1)
+ goto no;
+
+ if (atomic_read(&p->mm->mm_users) != 1) {
+ read_lock(&tasklist_lock);
+ do_each_thread(g, t) {
+ if (t->mm == mm && t != p)
+ goto no_unlock;
+ } while_each_thread(g, t);
+ read_unlock(&tasklist_lock);
+ }
+
+ return true;
+
+no_unlock:
+ read_unlock(&tasklist_lock);
+no:
+ return false;
+}
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index 9a8ff68..ad8c7a7 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -287,6 +287,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
time_t expiry,
u32 kvno)
{
+ const struct cred *cred = current_cred();
struct key *key;
int ret;

@@ -297,7 +298,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,

_enter("");

- key = key_alloc(&key_type_rxrpc, "x", 0, 0, current, 0,
+ key = key_alloc(&key_type_rxrpc, "x", 0, 0, cred, 0,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
@@ -340,10 +341,11 @@ EXPORT_SYMBOL(rxrpc_get_server_data_key);
*/
struct key *rxrpc_get_null_key(const char *keyname)
{
+ const struct cred *cred = current_cred();
struct key *key;
int ret;

- key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
+ key = key_alloc(&key_type_rxrpc, keyname, 0, 0, cred,
KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key))
return key;
diff --git a/security/capability.c b/security/capability.c
index fac2f61..efeb6d9 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -340,12 +340,16 @@ static int cap_task_create(unsigned long clone_flags)
return 0;
}

-static int cap_cred_alloc_security(struct cred *cred)
+static void cap_cred_free(struct cred *cred)
+{
+}
+
+static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp)
{
return 0;
}

-static void cap_cred_free(struct cred *cred)
+static void cap_cred_commit(struct cred *new, const struct cred *old)
{
}

@@ -750,7 +754,7 @@ static void cap_release_secctx(char *secdata, u32 seclen)
}

#ifdef CONFIG_KEYS
-static int cap_key_alloc(struct key *key, struct task_struct *ctx,
+static int cap_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
return 0;
@@ -760,7 +764,7 @@ static void cap_key_free(struct key *key)
{
}

-static int cap_key_permission(key_ref_t key_ref, struct task_struct *context,
+static int cap_key_permission(key_ref_t key_ref, const struct cred *cred,
key_perm_t perm)
{
return 0;
@@ -814,8 +818,7 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, ptrace_may_access);
set_to_cap_if_null(ops, ptrace_traceme);
set_to_cap_if_null(ops, capget);
- set_to_cap_if_null(ops, capset_check);
- set_to_cap_if_null(ops, capset_set);
+ set_to_cap_if_null(ops, capset);
set_to_cap_if_null(ops, acct);
set_to_cap_if_null(ops, capable);
set_to_cap_if_null(ops, quotactl);
@@ -890,10 +893,11 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, file_receive);
set_to_cap_if_null(ops, dentry_open);
set_to_cap_if_null(ops, task_create);
- set_to_cap_if_null(ops, cred_alloc_security);
set_to_cap_if_null(ops, cred_free);
+ set_to_cap_if_null(ops, cred_prepare);
+ set_to_cap_if_null(ops, cred_commit);
set_to_cap_if_null(ops, task_setuid);
- set_to_cap_if_null(ops, task_post_setuid);
+ set_to_cap_if_null(ops, task_fix_setuid);
set_to_cap_if_null(ops, task_setgid);
set_to_cap_if_null(ops, task_setpgid);
set_to_cap_if_null(ops, task_getpgid);
@@ -910,7 +914,6 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, task_wait);
set_to_cap_if_null(ops, task_kill);
set_to_cap_if_null(ops, task_prctl);
- set_to_cap_if_null(ops, task_reparent_to_init);
set_to_cap_if_null(ops, task_to_inode);
set_to_cap_if_null(ops, ipc_permission);
set_to_cap_if_null(ops, ipc_getsecid);
diff --git a/security/commoncap.c b/security/commoncap.c
index d6456b0..1ae99fa 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -71,8 +71,8 @@ int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
int ret = 0;

rcu_read_lock();
- if (!cap_issubset(child->cred->cap_permitted,
- current->cred->cap_permitted) &&
+ if (!cap_issubset(__task_cred(child)->cap_permitted,
+ current_cred()->cap_permitted) &&
!capable(CAP_SYS_PTRACE))
ret = -EPERM;
rcu_read_unlock();
@@ -84,8 +84,8 @@ int cap_ptrace_traceme(struct task_struct *parent)
int ret = 0;

rcu_read_lock();
- if (!cap_issubset(current->cred->cap_permitted,
- parent->cred->cap_permitted) &&
+ if (!cap_issubset(current_cred()->cap_permitted,
+ __task_cred(parent)->cap_permitted) &&
!has_capability(parent, CAP_SYS_PTRACE))
ret = -EPERM;
rcu_read_unlock();
@@ -116,7 +116,7 @@ static inline int cap_inh_is_capped(void)
* to the old permitted set. That is, if the current task
* does *not* possess the CAP_SETPCAP capability.
*/
- return (cap_capable(current, CAP_SETPCAP) != 0);
+ return cap_capable(current, CAP_SETPCAP) != 0;
}

static inline int cap_limit_ptraced_target(void) { return 1; }
@@ -131,52 +131,39 @@ static inline int cap_limit_ptraced_target(void)

#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */

-int cap_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
+int cap_capset(struct cred *new,
+ const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
- const struct cred *cred = current->cred;
-
- if (cap_inh_is_capped()
- && !cap_issubset(*inheritable,
- cap_combine(cred->cap_inheritable,
- cred->cap_permitted))) {
+ if (cap_inh_is_capped() &&
+ !cap_issubset(*inheritable,
+ cap_combine(old->cap_inheritable,
+ old->cap_permitted)))
/* incapable of using this inheritable set */
return -EPERM;
- }
+
if (!cap_issubset(*inheritable,
- cap_combine(cred->cap_inheritable,
- cred->cap_bset))) {
+ cap_combine(old->cap_inheritable,
+ old->cap_bset)))
/* no new pI capabilities outside bounding set */
return -EPERM;
- }

/* verify restrictions on target's new Permitted set */
- if (!cap_issubset (*permitted,
- cap_combine (cred->cap_permitted,
- cred->cap_permitted))) {
+ if (!cap_issubset(*permitted, old->cap_permitted))
return -EPERM;
- }

/* verify the _new_Effective_ is a subset of the _new_Permitted_ */
- if (!cap_issubset (*effective, *permitted)) {
+ if (!cap_issubset(*effective, *permitted))
return -EPERM;
- }

+ new->cap_effective = *effective;
+ new->cap_inheritable = *inheritable;
+ new->cap_permitted = *permitted;
return 0;
}

-void cap_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
-{
- struct cred *cred = current->cred;
-
- cred->cap_effective = *effective;
- cred->cap_inheritable = *inheritable;
- cred->cap_permitted = *permitted;
-}
-
static inline void bprm_clear_caps(struct linux_binprm *bprm)
{
cap_clear(bprm->cap_post_exec_permitted);
@@ -365,46 +352,52 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
return ret;
}

-void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
+int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- struct cred *cred = current->cred;
+ const struct cred *old = current_cred();
+ struct cred *new;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;

- if (bprm->e_uid != cred->uid || bprm->e_gid != cred->gid ||
+ if (bprm->e_uid != old->uid || bprm->e_gid != old->gid ||
!cap_issubset(bprm->cap_post_exec_permitted,
- cred->cap_permitted)) {
+ old->cap_permitted)) {
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;

if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
if (!capable(CAP_SETUID)) {
- bprm->e_uid = cred->uid;
- bprm->e_gid = cred->gid;
+ bprm->e_uid = old->uid;
+ bprm->e_gid = old->gid;
}
if (cap_limit_ptraced_target()) {
bprm->cap_post_exec_permitted = cap_intersect(
bprm->cap_post_exec_permitted,
- cred->cap_permitted);
+ new->cap_permitted);
}
}
}

- cred->suid = cred->euid = cred->fsuid = bprm->e_uid;
- cred->sgid = cred->egid = cred->fsgid = bprm->e_gid;
+ new->suid = new->euid = new->fsuid = bprm->e_uid;
+ new->sgid = new->egid = new->fsgid = bprm->e_gid;

/* For init, we want to retain the capabilities set
* in the init_task struct. Thus we skip the usual
* capability rules */
if (!is_global_init(current)) {
- cred->cap_permitted = bprm->cap_post_exec_permitted;
+ new->cap_permitted = bprm->cap_post_exec_permitted;
if (bprm->cap_effective)
- cred->cap_effective = bprm->cap_post_exec_permitted;
+ new->cap_effective = bprm->cap_post_exec_permitted;
else
- cap_clear(cred->cap_effective);
+ cap_clear(new->cap_effective);
}

/* AUD: Audit candidate if cred->cap_effective is set */

- cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+ new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+ return commit_creds(new);
}

int cap_bprm_secureexec (struct linux_binprm *bprm)
@@ -479,65 +472,49 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
* files..
* Thanks to Olaf Kirch and Peter Benie for spotting this.
*/
-static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
- int old_suid)
+static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
{
- struct cred *cred = current->cred;
-
- if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
- (cred->uid != 0 && cred->euid != 0 && cred->suid != 0) &&
+ if ((old->uid == 0 || old->euid == 0 || old->suid == 0) &&
+ (new->uid != 0 && new->euid != 0 && new->suid != 0) &&
!issecure(SECURE_KEEP_CAPS)) {
- cap_clear(cred->cap_permitted);
- cap_clear(cred->cap_effective);
- }
- if (old_euid == 0 && cred->euid != 0) {
- cap_clear(cred->cap_effective);
- }
- if (old_euid != 0 && cred->euid == 0) {
- cred->cap_effective = cred->cap_permitted;
+ cap_clear(new->cap_permitted);
+ cap_clear(new->cap_effective);
}
+ if (old->euid == 0 && new->euid != 0)
+ cap_clear(new->cap_effective);
+ if (old->euid != 0 && new->euid == 0)
+ new->cap_effective = new->cap_permitted;
}

-int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
- int flags)
+int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
{
- struct cred *cred = current->cred;
-
switch (flags) {
case LSM_SETID_RE:
case LSM_SETID_ID:
case LSM_SETID_RES:
/* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
- if (!issecure (SECURE_NO_SETUID_FIXUP)) {
- cap_emulate_setxuid (old_ruid, old_euid, old_suid);
- }
+ if (!issecure(SECURE_NO_SETUID_FIXUP))
+ cap_emulate_setxuid(new, old);
break;
case LSM_SETID_FS:
- {
- uid_t old_fsuid = old_ruid;
-
- /* Copied from kernel/sys.c:setfsuid. */
+ /* Copied from kernel/sys.c:setfsuid. */

- /*
- * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
- * if not, we might be a bit too harsh here.
- */
-
- if (!issecure (SECURE_NO_SETUID_FIXUP)) {
- if (old_fsuid == 0 && cred->fsuid != 0) {
- cred->cap_effective =
- cap_drop_fs_set(
- cred->cap_effective);
- }
- if (old_fsuid != 0 && cred->fsuid == 0) {
- cred->cap_effective =
- cap_raise_fs_set(
- cred->cap_effective,
- cred->cap_permitted);
- }
+ /*
+ * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
+ * if not, we might be a bit too harsh here.
+ */
+ if (!issecure(SECURE_NO_SETUID_FIXUP)) {
+ if (old->fsuid == 0 && new->fsuid != 0) {
+ new->cap_effective =
+ cap_drop_fs_set(new->cap_effective);
+ }
+ if (old->fsuid != 0 && new->fsuid == 0) {
+ new->cap_effective =
+ cap_raise_fs_set(new->cap_effective,
+ new->cap_permitted);
}
- break;
}
+ break;
default:
return -EINVAL;
}
@@ -593,13 +570,14 @@ int cap_task_setnice (struct task_struct *p, int nice)
* this task could get inconsistent info. There can be no
* racing writer bc a task can only change its own caps.
*/
-static long cap_prctl_drop(unsigned long cap)
+static long cap_prctl_drop(struct cred *new, unsigned long cap)
{
if (!capable(CAP_SETPCAP))
return -EPERM;
if (!cap_valid(cap))
return -EINVAL;
- cap_lower(current->cred->cap_bset, cap);
+
+ cap_lower(new->cap_bset, cap);
return 0;
}

@@ -620,22 +598,29 @@ int cap_task_setnice (struct task_struct *p, int nice)
#endif

int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5, long *rc_p)
+ unsigned long arg4, unsigned long arg5)
{
- struct cred *cred = 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))
- error = -EINVAL;
- else
- error = !!cap_raised(cred->cap_bset, arg2);
- break;
+ goto error;
+ error = !!cap_raised(new->cap_bset, arg2);
+ goto no_change;
+
#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
case PR_CAPBSET_DROP:
- error = cap_prctl_drop(arg2);
- break;
+ error = cap_prctl_drop(new, arg2);
+ if (error < 0)
+ goto error;
+ goto changed;

/*
* The next four prctl's remain to assist with transitioning a
@@ -657,12 +642,12 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
* capability-based-privilege environment.
*/
case PR_SET_SECUREBITS:
- if ((((cred->securebits & SECURE_ALL_LOCKS) >> 1)
- & (cred->securebits ^ arg2)) /*[1]*/
- || ((cred->securebits & SECURE_ALL_LOCKS
- & ~arg2)) /*[2]*/
- || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
- || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/
+ error = -EPERM;
+ if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
+ & (new->securebits ^ arg2)) /*[1]*/
+ || (new->securebits & SECURE_ALL_LOCKS & ~arg2) /*[2]*/
+ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
+ || (cap_capable(current, CAP_SETPCAP) != 0) /*[4]*/
/*
* [1] no changing of bits that are locked
* [2] no unlocking of locks
@@ -670,50 +655,51 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
* [4] doing anything requires privilege (go read about
* the "sendmail capabilities bug")
*/
- error = -EPERM; /* cannot change a locked bit */
- } else {
- cred->securebits = arg2;
- }
- break;
+ )
+ /* cannot change a locked bit */
+ goto error;
+ new->securebits = arg2;
+ goto changed;
+
case PR_GET_SECUREBITS:
- error = cred->securebits;
- break;
+ error = new->securebits;
+ goto no_change;

#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */

case PR_GET_KEEPCAPS:
if (issecure(SECURE_KEEP_CAPS))
error = 1;
- break;
+ goto no_change;
+
case PR_SET_KEEPCAPS:
+ error = -EINVAL;
if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
- error = -EINVAL;
- else if (issecure(SECURE_KEEP_CAPS_LOCKED))
- error = -EPERM;
- else if (arg2)
- cred->securebits |= issecure_mask(SECURE_KEEP_CAPS);
+ goto error;
+ error = -EPERM;
+ if (issecure(SECURE_KEEP_CAPS_LOCKED))
+ goto error;
+ if (arg2)
+ new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
else
- cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
- break;
+ new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+ goto changed;

default:
/* No functionality available - continue with default */
- return 0;
+ error = -ENOSYS;
+ goto error;
}

/* Functionality provided */
- *rc_p = error;
- return 1;
-}
-
-void cap_task_reparent_to_init (struct task_struct *p)
-{
- struct cred *cred = p->cred;
-
- cap_set_init_eff(cred->cap_effective);
- cap_clear(cred->cap_inheritable);
- cap_set_full(cred->cap_permitted);
- p->cred->securebits = SECUREBITS_DEFAULT;
+changed:
+ return commit_creds(new);
+
+no_change:
+ error = 0;
+error:
+ abort_creds(new);
+ return error;
}

int cap_syslog (int type)
diff --git a/security/keys/internal.h b/security/keys/internal.h
index cb8c678..191f5e5 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -12,6 +12,7 @@
#ifndef _INTERNAL_H
#define _INTERNAL_H

+#include <linux/sched.h>
#include <linux/key-type.h>

static inline __attribute__((format(printf, 1, 2)))
@@ -25,7 +26,7 @@ void no_printk(const char *fmt, ...)
#define kleave(FMT, ...) \
printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
#define kdebug(FMT, ...) \
- printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__)
+ printk(KERN_DEBUG " "FMT"\n", ##__VA_ARGS__)
#else
#define kenter(FMT, ...) \
no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__)
@@ -97,7 +98,7 @@ extern struct key *keyring_search_instkey(struct key *keyring,
typedef int (*key_match_func_t)(const struct key *, const void *);

extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
- struct task_struct *tsk,
+ const struct cred *cred,
struct key_type *type,
const void *description,
key_match_func_t match);
@@ -105,12 +106,12 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
- struct task_struct *tsk);
+ const struct cred *cred);

extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);

-extern int install_thread_keyring(void);
-extern int install_process_keyring(void);
+extern int install_thread_keyring_to_cred(struct cred *);
+extern int install_process_keyring_to_cred(struct cred *);

extern struct key *request_key_and_link(struct key_type *type,
const char *description,
@@ -129,12 +130,12 @@ extern long join_session_keyring(const char *name);
* check to see whether permission is granted to use a key in the desired way
*/
extern int key_task_permission(const key_ref_t key_ref,
- struct task_struct *context,
+ const struct cred *cred,
key_perm_t perm);

static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
{
- return key_task_permission(key_ref, current, perm);
+ return key_task_permission(key_ref, current_cred(), perm);
}

/* required permissions */
@@ -152,7 +153,7 @@ static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
struct request_key_auth {
struct key *target_key;
struct key *dest_keyring;
- struct task_struct *context;
+ const struct cred *cred;
void *callout_info;
size_t callout_len;
pid_t pid;
diff --git a/security/keys/key.c b/security/keys/key.c
index a6ca39e..f76c8a5 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -218,7 +218,7 @@ serial_exists:
* instantiate the key or discard it before returning
*/
struct key *key_alloc(struct key_type *type, const char *desc,
- uid_t uid, gid_t gid, struct task_struct *ctx,
+ uid_t uid, gid_t gid, const struct cred *cred,
key_perm_t perm, unsigned long flags)
{
struct key_user *user = NULL;
@@ -294,7 +294,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
#endif

/* let the security module know about the key */
- ret = security_key_alloc(key, ctx, flags);
+ ret = security_key_alloc(key, cred, flags);
if (ret < 0)
goto security_error;

@@ -391,7 +391,7 @@ static int __key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
struct key *keyring,
- struct key *instkey)
+ struct key *authkey)
{
int ret, awaken;

@@ -421,8 +421,8 @@ static int __key_instantiate_and_link(struct key *key,
ret = __key_link(keyring, key);

/* disable the authorisation key */
- if (instkey)
- key_revoke(instkey);
+ if (authkey)
+ key_revoke(authkey);
}
}

@@ -444,14 +444,14 @@ int key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
struct key *keyring,
- struct key *instkey)
+ struct key *authkey)
{
int ret;

if (keyring)
down_write(&keyring->sem);

- ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
+ ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey);

if (keyring)
up_write(&keyring->sem);
@@ -469,7 +469,7 @@ EXPORT_SYMBOL(key_instantiate_and_link);
int key_negate_and_link(struct key *key,
unsigned timeout,
struct key *keyring,
- struct key *instkey)
+ struct key *authkey)
{
struct timespec now;
int ret, awaken;
@@ -504,8 +504,8 @@ int key_negate_and_link(struct key *key,
ret = __key_link(keyring, key);

/* disable the authorisation key */
- if (instkey)
- key_revoke(instkey);
+ if (authkey)
+ key_revoke(authkey);
}

mutex_unlock(&key_construction_mutex);
@@ -743,6 +743,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_perm_t perm,
unsigned long flags)
{
+ const struct cred *cred = current_cred();
struct key_type *ktype;
struct key *keyring, *key = NULL;
key_ref_t key_ref;
@@ -802,8 +803,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
}

/* allocate a new key */
- key = key_alloc(ktype, description, current_fsuid(), current_fsgid(),
- current, perm, flags);
+ key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
+ perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_CAST(key);
goto error_3;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 8833b44..7c72baa 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -866,6 +866,23 @@ static long get_instantiation_keyring(key_serial_t ringid,
return -ENOKEY;
}

+/*
+ * change the request_key authorisation key on the current process
+ */
+static int keyctl_change_reqkey_auth(struct key *key)
+{
+ struct cred *new;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ key_put(new->request_key_auth);
+ new->request_key_auth = key_get(key);
+
+ return commit_creds(new);
+}
+
/*****************************************************************************/
/*
* instantiate the key with the specified payload, and, if one is given, link
@@ -876,12 +893,15 @@ long keyctl_instantiate_key(key_serial_t id,
size_t plen,
key_serial_t ringid)
{
+ const struct cred *cred = current_cred();
struct request_key_auth *rka;
struct key *instkey, *dest_keyring;
void *payload;
long ret;
bool vm = false;

+ kenter("%d,,%zu,%d", id, plen, ringid);
+
ret = -EINVAL;
if (plen > 1024 * 1024 - 1)
goto error;
@@ -889,7 +909,7 @@ long keyctl_instantiate_key(key_serial_t id,
/* the appropriate instantiation authorisation key must have been
* assumed before calling this */
ret = -EPERM;
- instkey = current->cred->request_key_auth;
+ instkey = cred->request_key_auth;
if (!instkey)
goto error;

@@ -931,10 +951,8 @@ long keyctl_instantiate_key(key_serial_t id,

/* discard the assumed authority if it's just been disabled by
* instantiation of the key */
- if (ret == 0) {
- key_put(current->cred->request_key_auth);
- current->cred->request_key_auth = NULL;
- }
+ if (ret == 0)
+ keyctl_change_reqkey_auth(NULL);

error2:
if (!vm)
@@ -953,14 +971,17 @@ error:
*/
long keyctl_negate_key(key_serial_t id, unsigned timeout, 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);
+
/* the appropriate instantiation authorisation key must have been
* assumed before calling this */
ret = -EPERM;
- instkey = current->cred->request_key_auth;
+ instkey = cred->request_key_auth;
if (!instkey)
goto error;

@@ -982,10 +1003,8 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)

/* discard the assumed authority if it's just been disabled by
* instantiation of the key */
- if (ret == 0) {
- key_put(current->cred->request_key_auth);
- current->cred->request_key_auth = NULL;
- }
+ if (ret == 0)
+ keyctl_change_reqkey_auth(NULL);

error:
return ret;
@@ -999,36 +1018,56 @@ error:
*/
long keyctl_set_reqkey_keyring(int reqkey_defl)
{
- struct cred *cred = current->cred;
- int ret;
+ struct cred *new;
+ int ret, old_setting;
+
+ old_setting = current_cred_xxx(jit_keyring);
+
+ if (reqkey_defl == KEY_REQKEY_DEFL_NO_CHANGE)
+ return old_setting;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;

switch (reqkey_defl) {
case KEY_REQKEY_DEFL_THREAD_KEYRING:
- ret = install_thread_keyring();
+ ret = install_thread_keyring_to_cred(new);
if (ret < 0)
- return ret;
+ goto error;
goto set;

case KEY_REQKEY_DEFL_PROCESS_KEYRING:
- ret = install_process_keyring();
- if (ret < 0)
- return ret;
+ ret = install_process_keyring_to_cred(new);
+ if (ret < 0) {
+ if (ret != -EEXIST)
+ goto error;
+ ret = 0;
+ }
+ goto set;

case KEY_REQKEY_DEFL_DEFAULT:
case KEY_REQKEY_DEFL_SESSION_KEYRING:
case KEY_REQKEY_DEFL_USER_KEYRING:
case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
- set:
- cred->jit_keyring = reqkey_defl;
+ case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
+ goto set;

case KEY_REQKEY_DEFL_NO_CHANGE:
- return cred->jit_keyring;
-
case KEY_REQKEY_DEFL_GROUP_KEYRING:
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}

+set:
+ new->jit_keyring = reqkey_defl;
+ commit_creds(new);
+ return old_setting;
+error:
+ abort_creds(new);
+ return -EINVAL;
+
} /* end keyctl_set_reqkey_keyring() */

/*****************************************************************************/
@@ -1087,9 +1126,7 @@ long keyctl_assume_authority(key_serial_t id)

/* we divest ourselves of authority if given an ID of 0 */
if (id == 0) {
- key_put(current->cred->request_key_auth);
- current->cred->request_key_auth = NULL;
- ret = 0;
+ ret = keyctl_change_reqkey_auth(NULL);
goto error;
}

@@ -1104,10 +1141,12 @@ long keyctl_assume_authority(key_serial_t id)
goto error;
}

- key_put(current->cred->request_key_auth);
- current->cred->request_key_auth = authkey;
- ret = authkey->serial;
+ ret = keyctl_change_reqkey_auth(authkey);
+ if (ret < 0)
+ goto error;
+ key_put(authkey);

+ ret = authkey->serial;
error:
return ret;

diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index fdf75f9..ed85157 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -245,14 +245,14 @@ static long keyring_read(const struct key *keyring,
* allocate a keyring and link into the destination keyring
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- struct task_struct *ctx, unsigned long flags,
+ const struct cred *cred, unsigned long flags,
struct key *dest)
{
struct key *keyring;
int ret;

keyring = key_alloc(&key_type_keyring, description,
- uid, gid, ctx,
+ uid, gid, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
flags);

@@ -281,7 +281,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
* - we propagate the possession attribute from the keyring ref to the key ref
*/
key_ref_t keyring_search_aux(key_ref_t keyring_ref,
- struct task_struct *context,
+ const struct cred *cred,
struct key_type *type,
const void *description,
key_match_func_t match)
@@ -304,7 +304,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
key_check(keyring);

/* top keyring must have search permission to begin the search */
- err = key_task_permission(keyring_ref, context, KEY_SEARCH);
+ err = key_task_permission(keyring_ref, cred, KEY_SEARCH);
if (err < 0) {
key_ref = ERR_PTR(err);
goto error;
@@ -377,7 +377,7 @@ descend:

/* key must have search permissions */
if (key_task_permission(make_key_ref(key, possessed),
- context, KEY_SEARCH) < 0)
+ cred, KEY_SEARCH) < 0)
continue;

/* we set a different error code if we pass a negative key */
@@ -404,7 +404,7 @@ ascend:
continue;

if (key_task_permission(make_key_ref(key, possessed),
- context, KEY_SEARCH) < 0)
+ cred, KEY_SEARCH) < 0)
continue;

/* stack the current position */
@@ -459,7 +459,7 @@ key_ref_t keyring_search(key_ref_t keyring,
if (!type->match)
return ERR_PTR(-ENOKEY);

- return keyring_search_aux(keyring, current,
+ return keyring_search_aux(keyring, current->cred,
type, description, type->match);

} /* end keyring_search() */
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 13c3616..5d9fc7b 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -14,24 +14,27 @@
#include "internal.h"

/*****************************************************************************/
-/*
- * check to see whether permission is granted to use a key in the desired way,
- * but permit the security modules to override
+/**
+ * key_task_permission - Check a key can be used
+ * @key_ref: The key to check
+ * @cred: The credentials to use
+ * @perm: The permissions to check for
+ *
+ * Check to see whether permission is granted to use a key in the desired way,
+ * but permit the security modules to override.
+ *
+ * The caller must hold either a ref on cred or must hold the RCU readlock or a
+ * spinlock.
*/
-int key_task_permission(const key_ref_t key_ref,
- struct task_struct *context,
+int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
key_perm_t perm)
{
- const struct cred *cred;
struct key *key;
key_perm_t kperm;
int ret;

key = key_ref_to_ptr(key_ref);

- rcu_read_lock();
- cred = __task_cred(context);
-
/* use the second 8-bits of permissions for keys the caller owns */
if (key->uid == cred->fsuid) {
kperm = key->perm >> 16;
@@ -57,7 +60,6 @@ int key_task_permission(const key_ref_t key_ref,
kperm = key->perm;

use_these_perms:
- rcu_read_lock();

/* use the top 8-bits of permissions for keys the caller possesses
* - possessor permissions are additive with other permissions
@@ -71,7 +73,7 @@ use_these_perms:
return -EACCES;

/* let LSM be the final arbiter */
- return security_key_permission(key_ref, context, perm);
+ return security_key_permission(key_ref, cred, perm);

} /* end key_task_permission() */

diff --git a/security/keys/proc.c b/security/keys/proc.c
index f619170..7f508de 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -136,8 +136,12 @@ static int proc_keys_show(struct seq_file *m, void *v)
int rc;

/* check whether the current task is allowed to view the key (assuming
- * non-possession) */
- rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW);
+ * non-possession)
+ * - the caller holds a spinlock, and thus the RCU read lock, making our
+ * access to __current_cred() safe
+ */
+ rc = key_task_permission(make_key_ref(key, 0), current_cred(),
+ KEY_VIEW);
if (rc < 0)
return 0;

diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index b0a6060..c8d8f3c 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -42,11 +42,15 @@ struct key_user root_key_user = {
*/
static int install_user_keyrings(void)
{
- struct user_struct *user = current_user();
+ struct user_struct *user;
+ const struct cred *cred;
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;

+ cred = current_cred();
+ user = cred->user;
+
kenter("%p{%u}", user, user->uid);

if (user->uid_keyring) {
@@ -67,7 +71,7 @@ static int install_user_keyrings(void)
uid_keyring = find_keyring_by_name(buf, true);
if (IS_ERR(uid_keyring)) {
uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
- current, KEY_ALLOC_IN_QUOTA,
+ cred, KEY_ALLOC_IN_QUOTA,
NULL);
if (IS_ERR(uid_keyring)) {
ret = PTR_ERR(uid_keyring);
@@ -83,8 +87,7 @@ static int install_user_keyrings(void)
if (IS_ERR(session_keyring)) {
session_keyring =
keyring_alloc(buf, user->uid, (gid_t) -1,
- current, KEY_ALLOC_IN_QUOTA,
- NULL);
+ cred, KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error_release;
@@ -116,142 +119,128 @@ error:
return ret;
}

-/*****************************************************************************/
/*
- * deal with the UID changing
+ * install a fresh thread keyring directly to new credentials
*/
-void switch_uid_keyring(struct user_struct *new_user)
+int install_thread_keyring_to_cred(struct cred *new)
{
-#if 0 /* do nothing for now */
- struct key *old;
-
- /* switch to the new user's session keyring if we were running under
- * root's default session keyring */
- if (new_user->uid != 0 &&
- current->session_keyring == &root_session_keyring
- ) {
- atomic_inc(&new_user->session_keyring->usage);
-
- task_lock(current);
- old = current->session_keyring;
- current->session_keyring = new_user->session_keyring;
- task_unlock(current);
+ struct key *keyring;

- key_put(old);
- }
-#endif
+ keyring = keyring_alloc("_tid", new->uid, new->gid, new,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
+ if (IS_ERR(keyring))
+ return PTR_ERR(keyring);

-} /* end switch_uid_keyring() */
+ new->thread_keyring = keyring;
+ return 0;
+}

-/*****************************************************************************/
/*
* install a fresh thread keyring, discarding the old one
*/
-int install_thread_keyring(void)
+static int install_thread_keyring(void)
{
- struct task_struct *tsk = current;
- struct key *keyring, *old;
- char buf[20];
+ struct cred *new;
int ret;

- sprintf(buf, "_tid.%u", tsk->pid);
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;

- keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
- KEY_ALLOC_QUOTA_OVERRUN, NULL);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
- goto error;
+ BUG_ON(new->thread_keyring);
+
+ ret = install_thread_keyring_to_cred(new);
+ if (ret < 0) {
+ abort_creds(new);
+ return ret;
}

- task_lock(tsk);
- old = tsk->cred->thread_keyring;
- tsk->cred->thread_keyring = keyring;
- task_unlock(tsk);
+ return commit_creds(new);
+}

- ret = 0;
+/*
+ * install a process keyring directly to a credentials struct
+ * - returns -EEXIST if there was already a process keyring, 0 if one installed,
+ * and other -ve on any other error
+ */
+int install_process_keyring_to_cred(struct cred *new)
+{
+ struct key *keyring;
+ int ret;

- key_put(old);
-error:
+ if (new->tgcred->process_keyring)
+ return -EEXIST;
+
+ keyring = keyring_alloc("_pid", new->uid, new->gid,
+ new, KEY_ALLOC_QUOTA_OVERRUN, NULL);
+ if (IS_ERR(keyring))
+ return PTR_ERR(keyring);
+
+ spin_lock_irq(&new->tgcred->lock);
+ if (!new->tgcred->process_keyring) {
+ new->tgcred->process_keyring = keyring;
+ keyring = NULL;
+ ret = 0;
+ } else {
+ ret = -EEXIST;
+ }
+ spin_unlock_irq(&new->tgcred->lock);
+ key_put(keyring);
return ret;
+}

-} /* end install_thread_keyring() */
-
-/*****************************************************************************/
/*
* make sure a process keyring is installed
+ * - we
*/
-int install_process_keyring(void)
+static int install_process_keyring(void)
{
- struct task_struct *tsk = current;
- struct key *keyring;
- char buf[20];
+ struct cred *new;
int ret;

- might_sleep();
-
- if (!tsk->cred->tgcred->process_keyring) {
- sprintf(buf, "_pid.%u", tsk->tgid);
-
- keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
- KEY_ALLOC_QUOTA_OVERRUN, NULL);
- if (IS_ERR(keyring)) {
- ret = PTR_ERR(keyring);
- goto error;
- }
-
- /* attach keyring */
- spin_lock_irq(&tsk->cred->tgcred->lock);
- if (!tsk->cred->tgcred->process_keyring) {
- tsk->cred->tgcred->process_keyring = keyring;
- keyring = NULL;
- }
- spin_unlock_irq(&tsk->cred->tgcred->lock);
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;

- key_put(keyring);
+ ret = install_process_keyring_to_cred(new);
+ if (ret < 0) {
+ abort_creds(new);
+ return ret != -EEXIST ?: 0;
}

- ret = 0;
-error:
- return ret;
-
-} /* end install_process_keyring() */
+ return commit_creds(new);
+}

-/*****************************************************************************/
/*
- * install a session keyring, discarding the old one
- * - if a keyring is not supplied, an empty one is invented
+ * install a session keyring directly to a credentials struct
*/
-static int install_session_keyring(struct key *keyring)
+static int install_session_keyring_to_cred(struct cred *cred,
+ struct key *keyring)
{
- struct task_struct *tsk = current;
unsigned long flags;
struct key *old;
- char buf[20];

might_sleep();

/* create an empty session keyring */
if (!keyring) {
- sprintf(buf, "_ses.%u", tsk->tgid);
-
flags = KEY_ALLOC_QUOTA_OVERRUN;
- if (tsk->cred->tgcred->session_keyring)
+ if (cred->tgcred->session_keyring)
flags = KEY_ALLOC_IN_QUOTA;

- keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid,
- tsk, flags, NULL);
+ keyring = keyring_alloc("_ses", cred->uid, cred->gid,
+ cred, flags, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
- }
- else {
+ } else {
atomic_inc(&keyring->usage);
}

/* install the keyring */
- spin_lock_irq(&tsk->cred->tgcred->lock);
- old = tsk->cred->tgcred->session_keyring;
- rcu_assign_pointer(tsk->cred->tgcred->session_keyring, keyring);
- spin_unlock_irq(&tsk->cred->tgcred->lock);
+ spin_lock_irq(&cred->tgcred->lock);
+ old = cred->tgcred->session_keyring;
+ rcu_assign_pointer(cred->tgcred->session_keyring, keyring);
+ spin_unlock_irq(&cred->tgcred->lock);

/* we're using RCU on the pointer, but there's no point synchronising
* on it if it didn't previously point to anything */
@@ -261,38 +250,29 @@ static int install_session_keyring(struct key *keyring)
}

return 0;
+}

-} /* end install_session_keyring() */
-
-/*****************************************************************************/
/*
- * copy the keys for fork
+ * install a session keyring, discarding the old one
+ * - if a keyring is not supplied, an empty one is invented
*/
-int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+static int install_session_keyring(struct key *keyring)
{
- key_check(tsk->cred->thread_keyring);
- key_check(tsk->cred->request_key_auth);
-
- /* no thread keyring yet */
- tsk->cred->thread_keyring = NULL;
-
- /* copy the request_key() authorisation for this thread */
- key_get(tsk->cred->request_key_auth);
-
- return 0;
+ struct cred *new;
+ int ret;

-} /* end copy_keys() */
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;

-/*****************************************************************************/
-/*
- * dispose of per-thread keys upon thread exit
- */
-void exit_keys(struct task_struct *tsk)
-{
- key_put(tsk->cred->thread_keyring);
- key_put(tsk->cred->request_key_auth);
+ ret = install_session_keyring_to_cred(new, NULL);
+ if (ret < 0) {
+ abort_creds(new);
+ return ret;
+ }

-} /* end exit_keys() */
+ return commit_creds(new);
+}

/*****************************************************************************/
/*
@@ -300,38 +280,41 @@ void exit_keys(struct task_struct *tsk)
*/
int exec_keys(struct task_struct *tsk)
{
- struct key *old;
+ struct thread_group_cred *tgcred = NULL;
+ struct cred *new;

- /* newly exec'd tasks don't get a thread keyring */
- task_lock(tsk);
- old = tsk->cred->thread_keyring;
- tsk->cred->thread_keyring = NULL;
- task_unlock(tsk);
+#ifdef CONFIG_KEYS
+ tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+ if (!tgcred)
+ return -ENOMEM;
+#endif

- key_put(old);
+ new = prepare_creds();
+ if (new < 0)
+ return -ENOMEM;

- /* discard the process keyring from a newly exec'd task */
- spin_lock_irq(&tsk->cred->tgcred->lock);
- old = tsk->cred->tgcred->process_keyring;
- tsk->cred->tgcred->process_keyring = NULL;
- spin_unlock_irq(&tsk->cred->tgcred->lock);
+ /* newly exec'd tasks don't get a thread keyring */
+ key_put(new->thread_keyring);
+ new->thread_keyring = NULL;

- key_put(old);
+ /* create a new per-thread-group creds for all this set of threads to
+ * share */
+ memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));

- return 0;
+ atomic_set(&tgcred->usage, 1);
+ spin_lock_init(&tgcred->lock);

-} /* end exec_keys() */
+ /* inherit the session keyring; new process keyring */
+ key_get(tgcred->session_keyring);
+ tgcred->process_keyring = NULL;

-/*****************************************************************************/
-/*
- * deal with SUID programs
- * - we might want to make this invent a new session keyring
- */
-int suid_keys(struct task_struct *tsk)
-{
+ put_tgcred(new->tgcred);
+ new->tgcred = tgcred;
+
+ commit_creds(new);
return 0;

-} /* end suid_keys() */
+} /* end exec_keys() */

/*****************************************************************************/
/*
@@ -376,16 +359,13 @@ void key_fsgid_changed(struct task_struct *tsk)
key_ref_t search_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
- struct task_struct *context)
+ const struct cred *cred)
{
struct request_key_auth *rka;
- struct cred *cred;
key_ref_t key_ref, ret, err;

might_sleep();

- cred = get_task_cred(context);
-
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -401,7 +381,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
if (cred->thread_keyring) {
key_ref = keyring_search_aux(
make_key_ref(cred->thread_keyring, 1),
- context, type, description, match);
+ cred, type, description, match);
if (!IS_ERR(key_ref))
goto found;

@@ -422,7 +402,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
if (cred->tgcred->process_keyring) {
key_ref = keyring_search_aux(
make_key_ref(cred->tgcred->process_keyring, 1),
- context, type, description, match);
+ cred, type, description, match);
if (!IS_ERR(key_ref))
goto found;

@@ -446,7 +426,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
make_key_ref(rcu_dereference(
cred->tgcred->session_keyring),
1),
- context, type, description, match);
+ cred, type, description, match);
rcu_read_unlock();

if (!IS_ERR(key_ref))
@@ -468,7 +448,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
else if (cred->user->session_keyring) {
key_ref = keyring_search_aux(
make_key_ref(cred->user->session_keyring, 1),
- context, type, description, match);
+ cred, type, description, match);
if (!IS_ERR(key_ref))
goto found;

@@ -490,7 +470,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
* - we don't permit access to request_key auth keys via this method
*/
if (cred->request_key_auth &&
- context == current &&
+ cred == current_cred() &&
type != &key_type_request_key_auth
) {
/* defend against the auth key being revoked */
@@ -500,7 +480,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
rka = cred->request_key_auth->payload.data;

key_ref = search_process_keyrings(type, description,
- match, rka->context);
+ match, rka->cred);

up_read(&cred->request_key_auth->sem);

@@ -527,7 +507,6 @@ key_ref_t search_process_keyrings(struct key_type *type,
key_ref = ret ? ret : err;

found:
- put_cred(cred);
return key_ref;

} /* end search_process_keyrings() */
@@ -552,8 +531,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
key_perm_t perm)
{
struct request_key_auth *rka;
- struct task_struct *t = current;
- struct cred *cred;
+ const struct cred *cred;
struct key *key;
key_ref_t key_ref, skey_ref;
int ret;
@@ -608,6 +586,7 @@ try_again:
goto error;
ret = install_session_keyring(
cred->user->session_keyring);
+
if (ret < 0)
goto error;
goto reget_creds;
@@ -693,7 +672,7 @@ try_again:
/* check to see if we possess the key */
skey_ref = search_process_keyrings(key->type, key,
lookup_user_key_possessed,
- current);
+ cred);

if (!IS_ERR(skey_ref)) {
key_put(key);
@@ -725,7 +704,7 @@ try_again:
goto invalid_key;

/* check the permissions */
- ret = key_task_permission(key_ref, t, perm);
+ ret = key_task_permission(key_ref, cred, perm);
if (ret < 0)
goto invalid_key;

@@ -754,21 +733,33 @@ reget_creds:
*/
long join_session_keyring(const char *name)
{
- struct task_struct *tsk = current;
- struct cred *cred = current->cred;
+ const struct cred *old;
+ struct cred *new;
struct key *keyring;
- long ret;
+ long ret, serial;
+
+ /* only permit this if there's a single thread in the thread group -
+ * this avoids us having to adjust the creds on all threads and risking
+ * ENOMEM */
+ if (!is_single_threaded(current))
+ return -EMLINK;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ old = current_cred();

/* if no name is provided, install an anonymous keyring */
if (!name) {
- ret = install_session_keyring(NULL);
+ ret = install_session_keyring_to_cred(new, NULL);
if (ret < 0)
goto error;

- rcu_read_lock();
- ret = rcu_dereference(cred->tgcred->session_keyring)->serial;
- rcu_read_unlock();
- goto error;
+ serial = new->tgcred->session_keyring->serial;
+ ret = commit_creds(new);
+ if (ret == 0)
+ ret = serial;
+ goto okay;
}

/* allow the user to join or create a named keyring */
@@ -778,29 +769,33 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, false);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, cred->uid, cred->gid, tsk,
+ keyring = keyring_alloc(name, old->uid, old->gid, old,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
}
- }
- else if (IS_ERR(keyring)) {
+ } else if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
}

/* we've got a keyring - now to install it */
- ret = install_session_keyring(keyring);
+ ret = install_session_keyring_to_cred(new, keyring);
if (ret < 0)
goto error2;

+ commit_creds(new);
+ mutex_unlock(&key_session_mutex);
+
ret = keyring->serial;
key_put(keyring);
+okay:
+ return ret;

error2:
mutex_unlock(&key_session_mutex);
error:
+ abort_creds(new);
return ret;
-
-} /* end join_session_keyring() */
+}
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index fe5d4fb..18f5d0e 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -79,8 +79,10 @@ static int call_sbin_request_key(struct key_construction *cons,
/* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial);

- keyring = keyring_alloc(desc, current_fsuid(), current_fsgid(), current,
+ cred = get_current_cred();
+ keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
+ put_cred(cred);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error_alloc;
@@ -100,8 +102,7 @@ static int call_sbin_request_key(struct key_construction *cons,

/* we specify the process's default keyrings */
sprintf(keyring_str[0], "%d",
- cred->thread_keyring ?
- cred->thread_keyring->serial : 0);
+ cred->thread_keyring ? cred->thread_keyring->serial : 0);

prkey = 0;
if (cred->tgcred->process_keyring)
@@ -151,8 +152,8 @@ error_link:
key_put(keyring);

error_alloc:
- kleave(" = %d", ret);
complete_request_key(cons, ret);
+ kleave(" = %d", ret);
return ret;
}

@@ -291,6 +292,7 @@ static int construct_alloc_key(struct key_type *type,
struct key_user *user,
struct key **_key)
{
+ const struct cred *cred = current_cred();
struct key *key;
key_ref_t key_ref;

@@ -298,9 +300,8 @@ static int construct_alloc_key(struct key_type *type,

mutex_lock(&user->cons_lock);

- key = key_alloc(type, description,
- current_fsuid(), current_fsgid(), current, KEY_POS_ALL,
- flags);
+ key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
+ KEY_POS_ALL, flags);
if (IS_ERR(key))
goto alloc_failed;

@@ -313,8 +314,7 @@ static int construct_alloc_key(struct key_type *type,
* waited for locks */
mutex_lock(&key_construction_mutex);

- key_ref = search_process_keyrings(type, description, type->match,
- current);
+ key_ref = search_process_keyrings(type, description, type->match, cred);
if (!IS_ERR(key_ref))
goto key_already_present;

@@ -359,6 +359,8 @@ static struct key *construct_key_and_link(struct key_type *type,
struct key *key;
int ret;

+ kenter("");
+
user = key_user_lookup(current_fsuid());
if (!user)
return ERR_PTR(-ENOMEM);
@@ -372,17 +374,21 @@ static struct key *construct_key_and_link(struct key_type *type,
if (ret == 0) {
ret = construct_key(key, callout_info, callout_len, aux,
dest_keyring);
- if (ret < 0)
+ if (ret < 0) {
+ kdebug("cons failed");
goto construction_failed;
+ }
}

key_put(dest_keyring);
+ kleave(" = key %d", key_serial(key));
return key;

construction_failed:
key_negate_and_link(key, key_negative_timeout, NULL, NULL);
key_put(key);
key_put(dest_keyring);
+ kleave(" = %d", ret);
return ERR_PTR(ret);
}

@@ -401,6 +407,7 @@ struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring,
unsigned long flags)
{
+ const struct cred *cred = current_cred();
struct key *key;
key_ref_t key_ref;

@@ -410,7 +417,7 @@ struct key *request_key_and_link(struct key_type *type,

/* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match,
- current);
+ cred);

if (!IS_ERR(key_ref)) {
key = key_ref_to_ptr(key_ref);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 2125579..8674715 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -105,9 +105,9 @@ static void request_key_auth_revoke(struct key *key)

kenter("{%d}", key->serial);

- if (rka->context) {
- put_task_struct(rka->context);
- rka->context = NULL;
+ if (rka->cred) {
+ put_cred(rka->cred);
+ rka->cred = NULL;
}

} /* end request_key_auth_revoke() */
@@ -122,9 +122,9 @@ static void request_key_auth_destroy(struct key *key)

kenter("{%d}", key->serial);

- if (rka->context) {
- put_task_struct(rka->context);
- rka->context = NULL;
+ if (rka->cred) {
+ put_cred(rka->cred);
+ rka->cred = NULL;
}

key_put(rka->target_key);
@@ -143,6 +143,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
size_t callout_len, struct key *dest_keyring)
{
struct request_key_auth *rka, *irka;
+ const struct cred *cred = current->cred;
struct key *authkey = NULL;
char desc[20];
int ret;
@@ -164,28 +165,25 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,

/* see if the calling process is already servicing the key request of
* another process */
- if (current->cred->request_key_auth) {
+ if (cred->request_key_auth) {
/* it is - use that instantiation context here too */
- down_read(&current->cred->request_key_auth->sem);
+ down_read(&cred->request_key_auth->sem);

/* if the auth key has been revoked, then the key we're
* servicing is already instantiated */
- if (test_bit(KEY_FLAG_REVOKED,
- &current->cred->request_key_auth->flags))
+ if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
goto auth_key_revoked;

- irka = current->cred->request_key_auth->payload.data;
- rka->context = irka->context;
+ irka = cred->request_key_auth->payload.data;
+ rka->cred = get_cred(irka->cred);
rka->pid = irka->pid;
- get_task_struct(rka->context);

- up_read(&current->cred->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);
}
else {
/* it isn't - use this process as the context */
- rka->context = current;
+ rka->cred = get_cred(cred);
rka->pid = current->pid;
- get_task_struct(rka->context);
}

rka->target_key = key_get(target);
@@ -197,7 +195,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
sprintf(desc, "%x", target->serial);

authkey = key_alloc(&key_type_request_key_auth, desc,
- current_fsuid(), current_fsgid(), current,
+ cred->fsuid, cred->fsgid, cred,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(authkey)) {
@@ -205,16 +203,16 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
goto error_alloc;
}

- /* construct and attach to the keyring */
+ /* construct the auth key */
ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL);
if (ret < 0)
goto error_inst;

- kleave(" = {%d}", authkey->serial);
+ kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage));
return authkey;

auth_key_revoked:
- up_read(&current->cred->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);
kfree(rka->callout_info);
kfree(rka);
kleave("= -EKEYREVOKED");
@@ -257,6 +255,7 @@ static int key_get_instantiation_authkey_match(const struct key *key,
*/
struct key *key_get_instantiation_authkey(key_serial_t target_id)
{
+ const struct cred *cred = current_cred();
struct key *authkey;
key_ref_t authkey_ref;

@@ -264,7 +263,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
&key_type_request_key_auth,
(void *) (unsigned long) target_id,
key_get_instantiation_authkey_match,
- current);
+ cred);

if (IS_ERR(authkey_ref)) {
authkey = ERR_CAST(authkey_ref);
diff --git a/security/security.c b/security/security.c
index 1a96ec9..c60c334 100644
--- a/security/security.c
+++ b/security/security.c
@@ -145,18 +145,13 @@ int security_capget(struct task_struct *target,
return security_ops->capget(target, effective, inheritable, permitted);
}

-int security_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
+int security_capset(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
- return security_ops->capset_check(effective, inheritable, permitted);
-}
-
-void security_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
-{
- security_ops->capset_set(effective, inheritable, permitted);
+ return security_ops->capset(new, old,
+ effective, inheritable, permitted);
}

int security_capable(struct task_struct *tsk, int cap)
@@ -214,9 +209,9 @@ void security_bprm_free(struct linux_binprm *bprm)
security_ops->bprm_free_security(bprm);
}

-void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
{
- security_ops->bprm_apply_creds(bprm, unsafe);
+ return security_ops->bprm_apply_creds(bprm, unsafe);
}

void security_bprm_post_apply_creds(struct linux_binprm *bprm)
@@ -602,14 +597,19 @@ int security_task_create(unsigned long clone_flags)
return security_ops->task_create(clone_flags);
}

-int security_cred_alloc(struct cred *cred)
+void security_cred_free(struct cred *cred)
{
- return security_ops->cred_alloc_security(cred);
+ security_ops->cred_free(cred);
}

-void security_cred_free(struct cred *cred)
+int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
{
- security_ops->cred_free(cred);
+ return security_ops->cred_prepare(new, old, gfp);
+}
+
+void security_commit_creds(struct cred *new, const struct cred *old)
+{
+ return security_ops->cred_commit(new, old);
}

int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
@@ -617,10 +617,10 @@ int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
return security_ops->task_setuid(id0, id1, id2, flags);
}

-int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
- uid_t old_suid, int flags)
+int security_task_fix_setuid(struct cred *new, const struct cred *old,
+ int flags)
{
- return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, flags);
+ return security_ops->task_fix_setuid(new, old, flags);
}

int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -702,14 +702,9 @@ int security_task_wait(struct task_struct *p)
}

int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5, long *rc_p)
-{
- return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
-}
-
-void security_task_reparent_to_init(struct task_struct *p)
+ unsigned long arg4, unsigned long arg5)
{
- security_ops->task_reparent_to_init(p);
+ return security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
}

void security_task_to_inode(struct task_struct *p, struct inode *inode)
@@ -1109,9 +1104,10 @@ EXPORT_SYMBOL(security_skb_classify_flow);

#ifdef CONFIG_KEYS

-int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long flags)
+int security_key_alloc(struct key *key, const struct cred *cred,
+ unsigned long flags)
{
- return security_ops->key_alloc(key, tsk, flags);
+ return security_ops->key_alloc(key, cred, flags);
}

void security_key_free(struct key *key)
@@ -1120,9 +1116,9 @@ void security_key_free(struct key *key)
}

int security_key_permission(key_ref_t key_ref,
- struct task_struct *context, key_perm_t perm)
+ const struct cred *cred, key_perm_t perm)
{
- return security_ops->key_permission(key_ref, context, perm);
+ return security_ops->key_permission(key_ref, cred, perm);
}

int security_key_getsecurity(struct key *key, char **_buffer)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d0e399d..27441e7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -155,20 +155,20 @@ static int selinux_secmark_enabled(void)
return (atomic_read(&selinux_secmark_refcount) > 0);
}

-/* Allocate and free functions for each kind of security blob. */
-
-static int cred_alloc_security(struct cred *cred)
+/*
+ * initialise the security for the init task
+ */
+static void cred_init_security(void)
{
+ struct cred *cred = (struct cred *) current->cred;
struct task_security_struct *tsec;

tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
if (!tsec)
- return -ENOMEM;
+ panic("SELinux: Failed to initialize initial task.\n");

- tsec->osid = tsec->sid = SECINITSID_UNLABELED;
+ tsec->osid = tsec->sid = SECINITSID_KERNEL;
cred->security = tsec;
-
- return 0;
}

/*
@@ -1377,6 +1377,19 @@ static inline u32 signal_to_av(int sig)
}

/*
+ * Check permission between a pair of credentials
+ * fork check, ptrace check, etc.
+ */
+static int cred_has_perm(const struct cred *actor,
+ const struct cred *target,
+ u32 perms)
+{
+ u32 asid = cred_sid(actor), tsid = cred_sid(target);
+
+ return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
+}
+
+/*
* Check permission between a pair of tasks, e.g. signal checks,
* fork check, ptrace check, etc.
* tsk1 is the actor and tsk2 is the target
@@ -1811,24 +1824,19 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
return secondary_ops->capget(target, effective, inheritable, permitted);
}

-static int selinux_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
+static int selinux_capset(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
int error;

- error = secondary_ops->capset_check(effective, inheritable, permitted);
+ error = secondary_ops->capset(new, old,
+ effective, inheritable, permitted);
if (error)
return error;

- return task_has_perm(current, current, PROCESS__SETCAP);
-}
-
-static void selinux_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted)
-{
- secondary_ops->capset_set(effective, inheritable, permitted);
+ return cred_has_perm(old, new, PROCESS__SETCAP);
}

static int selinux_capable(struct task_struct *tsk, int cap)
@@ -2242,16 +2250,23 @@ static inline void flush_unauthorized_files(const struct cred *cred,
spin_unlock(&files->file_lock);
}

-static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
{
struct task_security_struct *tsec;
struct bprm_security_struct *bsec;
+ struct cred *new;
u32 sid;
int rc;

- secondary_ops->bprm_apply_creds(bprm, unsafe);
+ rc = secondary_ops->bprm_apply_creds(bprm, unsafe);
+ if (rc < 0)
+ return rc;

- tsec = current_security();
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ tsec = new->security;

bsec = bprm->security;
sid = bsec->sid;
@@ -2266,7 +2281,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
PROCESS__SHARE, NULL);
if (rc) {
bsec->unsafe = 1;
- return;
+ goto out;
}
}

@@ -2290,12 +2305,16 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
PROCESS__PTRACE, NULL);
if (rc) {
bsec->unsafe = 1;
- return;
+ goto out;
}
}
}
tsec->sid = sid;
}
+
+out:
+ commit_creds(new);
+ return 0;
}

/*
@@ -2704,7 +2723,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
}

return inode_has_perm(cred, inode,
- open_file_mask_to_av(inode->i_mode, mask), NULL);
+ open_file_mask_to_av(inode->i_mode, mask), NULL);
}

static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -3025,6 +3044,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
{
const struct cred *cred = current_cred();
+ int rc = 0;

#ifndef CONFIG_PPC32
if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
@@ -3033,9 +3053,9 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable.
* This has an additional check.
*/
- int rc = task_has_perm(current, current, PROCESS__EXECMEM);
+ rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
if (rc)
- return rc;
+ goto error;
}
#endif

@@ -3052,7 +3072,9 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared

return file_has_perm(cred, file, av);
}
- return 0;
+
+error:
+ return rc;
}

static int selinux_file_mmap(struct file *file, unsigned long reqprot,
@@ -3094,8 +3116,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
rc = 0;
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
- rc = task_has_perm(current, current,
- PROCESS__EXECHEAP);
+ rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
} else if (!vma->vm_file &&
vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack) {
@@ -3108,8 +3129,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
* modified content. This typically should only
* occur for text relocations.
*/
- rc = file_has_perm(cred, vma->vm_file,
- FILE__EXECMOD);
+ rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
}
if (rc)
return rc;
@@ -3215,6 +3235,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
struct file_security_struct *fsec;
struct inode *inode;
struct inode_security_struct *isec;
+
inode = file->f_path.dentry->d_inode;
fsec = file->f_security;
isec = inode->i_security;
@@ -3251,38 +3272,41 @@ static int selinux_task_create(unsigned long clone_flags)
return task_has_perm(current, current, PROCESS__FORK);
}

-static int selinux_cred_alloc_security(struct cred *cred)
+/*
+ * detach and free the LSM part of a set of credentials
+ */
+static void selinux_cred_free(struct cred *cred)
{
- struct task_security_struct *tsec1, *tsec2;
- int rc;
-
- tsec1 = current_security();
+ struct task_security_struct *tsec = cred->security;
+ cred->security = NULL;
+ kfree(tsec);
+}

- rc = cred_alloc_security(cred);
- if (rc)
- return rc;
- tsec2 = cred->security;
+/*
+ * prepare a new set of credentials for modification
+ */
+static int selinux_cred_prepare(struct cred *new, const struct cred *old,
+ gfp_t gfp)
+{
+ const struct task_security_struct *old_tsec;
+ struct task_security_struct *tsec;

- tsec2->osid = tsec1->osid;
- tsec2->sid = tsec1->sid;
+ old_tsec = old->security;

- /* Retain the exec, fs, key, and sock SIDs across fork */
- tsec2->exec_sid = tsec1->exec_sid;
- tsec2->create_sid = tsec1->create_sid;
- tsec2->keycreate_sid = tsec1->keycreate_sid;
- tsec2->sockcreate_sid = tsec1->sockcreate_sid;
+ tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
+ if (!tsec)
+ return -ENOMEM;

+ new->security = tsec;
return 0;
}

/*
- * detach and free the LSM part of a set of credentials
+ * commit new credentials
*/
-static void selinux_cred_free(struct cred *cred)
+static void selinux_cred_commit(struct cred *new, const struct cred *old)
{
- struct task_security_struct *tsec = cred->security;
- cred->security = NULL;
- kfree(tsec);
+ secondary_ops->cred_commit(new, old);
}

static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
@@ -3296,9 +3320,10 @@ static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
return 0;
}

-static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
+static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
+ int flags)
{
- return secondary_ops->task_post_setuid(id0, id1, id2, flags);
+ return secondary_ops->task_fix_setuid(new, old, flags);
}

static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
@@ -3372,7 +3397,7 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim
/* Control the ability to change the hard limit (whether
lowering or raising it), so that the hard limit can
later be used as a safe reset point for the soft limit
- upon context transitions. See selinux_bprm_apply_creds. */
+ upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
return task_has_perm(current, current, PROCESS__SETRLIMIT);

@@ -3426,13 +3451,12 @@ static int selinux_task_prctl(int option,
unsigned long arg2,
unsigned long arg3,
unsigned long arg4,
- unsigned long arg5,
- long *rc_p)
+ unsigned long arg5)
{
/* The current prctl operations do not appear to require
any SELinux controls since they merely observe or modify
the state of the current process. */
- return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p);
+ return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
}

static int selinux_task_wait(struct task_struct *p)
@@ -3440,18 +3464,6 @@ static int selinux_task_wait(struct task_struct *p)
return task_has_perm(p, current, PROCESS__SIGCHLD);
}

-static void selinux_task_reparent_to_init(struct task_struct *p)
-{
- struct task_security_struct *tsec;
-
- secondary_ops->task_reparent_to_init(p);
-
- tsec = p->cred->security;
- tsec->osid = tsec->sid;
- tsec->sid = SECINITSID_KERNEL;
- return;
-}
-
static void selinux_task_to_inode(struct task_struct *p,
struct inode *inode)
{
@@ -5228,7 +5240,8 @@ static int selinux_setprocattr(struct task_struct *p,
{
struct task_security_struct *tsec;
struct task_struct *tracer;
- u32 sid = 0;
+ struct cred *new;
+ u32 sid = 0, ptsid;
int error;
char *str = value;

@@ -5275,77 +5288,72 @@ static int selinux_setprocattr(struct task_struct *p,
return error;
}

+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
/* Permission checking based on the specified context is
performed during the actual operation (execve,
open/mkdir/...), when we know the full context of the
- operation. See selinux_bprm_set_security for the execve
+ operation. See selinux_bprm_set_creds for the execve
checks and may_create for the file creation checks. The
operation will then fail if the context is not permitted. */
- tsec = p->cred->security;
- if (!strcmp(name, "exec"))
+ tsec = new->security;
+ if (!strcmp(name, "exec")) {
tsec->exec_sid = sid;
- else if (!strcmp(name, "fscreate"))
+ } else if (!strcmp(name, "fscreate")) {
tsec->create_sid = sid;
- else if (!strcmp(name, "keycreate")) {
+ } else if (!strcmp(name, "keycreate")) {
error = may_create_key(sid, p);
if (error)
- return error;
+ goto abort_change;
tsec->keycreate_sid = sid;
- } else if (!strcmp(name, "sockcreate"))
+ } else if (!strcmp(name, "sockcreate")) {
tsec->sockcreate_sid = sid;
- else if (!strcmp(name, "current")) {
- struct av_decision avd;
-
+ } else if (!strcmp(name, "current")) {
+ error = -EINVAL;
if (sid == 0)
- return -EINVAL;
+ goto abort_change;

/* Only allow single threaded processes to change context */
- if (atomic_read(&p->mm->mm_users) != 1) {
- struct task_struct *g, *t;
- struct mm_struct *mm = p->mm;
- read_lock(&tasklist_lock);
- do_each_thread(g, t) {
- if (t->mm == mm && t != p) {
- read_unlock(&tasklist_lock);
- return -EPERM;
- }
- } while_each_thread(g, t);
- read_unlock(&tasklist_lock);
- }
+ error = -EPERM;
+ if (!is_single_threaded(p))
+ goto abort_change;

/* Check permissions for the transition. */
error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL);
if (error)
- return error;
+ goto abort_change;

/* Check for ptracing, and update the task SID if ok.
Otherwise, leave SID unchanged and fail. */
+ ptsid = 0;
task_lock(p);
- rcu_read_lock();
tracer = tracehook_tracer_task(p);
- if (tracer != NULL) {
- u32 ptsid = task_sid(tracer);
- rcu_read_unlock();
- error = avc_has_perm_noaudit(ptsid, sid,
- SECCLASS_PROCESS,
- PROCESS__PTRACE, 0, &avd);
- if (!error)
- tsec->sid = sid;
- task_unlock(p);
- avc_audit(ptsid, sid, SECCLASS_PROCESS,
- PROCESS__PTRACE, &avd, error, NULL);
+ if (tracer)
+ ptsid = task_sid(tracer);
+ task_unlock(p);
+
+ if (tracer) {
+ error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+ PROCESS__PTRACE, NULL);
if (error)
- return error;
- } else {
- rcu_read_unlock();
- tsec->sid = sid;
- task_unlock(p);
+ goto abort_change;
}
- } else
- return -EINVAL;

+ tsec->sid = sid;
+ } else {
+ error = -EINVAL;
+ goto abort_change;
+ }
+
+ commit_creds(new);
return size;
+
+abort_change:
+ abort_creds(new);
+ return error;
}

static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
@@ -5365,23 +5373,21 @@ static void selinux_release_secctx(char *secdata, u32 seclen)

#ifdef CONFIG_KEYS

-static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+static int selinux_key_alloc(struct key *k, const struct cred *cred,
unsigned long flags)
{
- const struct task_security_struct *__tsec;
+ const struct task_security_struct *tsec;
struct key_security_struct *ksec;

ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
if (!ksec)
return -ENOMEM;

- rcu_read_lock();
- __tsec = __task_cred(tsk)->security;
- if (__tsec->keycreate_sid)
- ksec->sid = __tsec->keycreate_sid;
+ tsec = cred->security;
+ if (tsec->keycreate_sid)
+ ksec->sid = tsec->keycreate_sid;
else
- ksec->sid = __tsec->sid;
- rcu_read_unlock();
+ ksec->sid = tsec->sid;

k->security = ksec;
return 0;
@@ -5396,8 +5402,8 @@ static void selinux_key_free(struct key *k)
}

static int selinux_key_permission(key_ref_t key_ref,
- struct task_struct *ctx,
- key_perm_t perm)
+ const struct cred *cred,
+ key_perm_t perm)
{
struct key *key;
struct key_security_struct *ksec;
@@ -5409,7 +5415,7 @@ static int selinux_key_permission(key_ref_t key_ref,
if (perm == 0)
return 0;

- sid = task_sid(ctx);
+ sid = cred_sid(cred);

key = key_ref_to_ptr(key_ref);
ksec = key->security;
@@ -5439,8 +5445,7 @@ static struct security_operations selinux_ops = {
.ptrace_may_access = selinux_ptrace_may_access,
.ptrace_traceme = selinux_ptrace_traceme,
.capget = selinux_capget,
- .capset_check = selinux_capset_check,
- .capset_set = selinux_capset_set,
+ .capset = selinux_capset,
.sysctl = selinux_sysctl,
.capable = selinux_capable,
.quotactl = selinux_quotactl,
@@ -5515,10 +5520,11 @@ static struct security_operations selinux_ops = {
.dentry_open = selinux_dentry_open,

.task_create = selinux_task_create,
- .cred_alloc_security = selinux_cred_alloc_security,
.cred_free = selinux_cred_free,
+ .cred_prepare = selinux_cred_prepare,
+ .cred_commit = selinux_cred_commit,
.task_setuid = selinux_task_setuid,
- .task_post_setuid = selinux_task_post_setuid,
+ .task_fix_setuid = selinux_task_fix_setuid,
.task_setgid = selinux_task_setgid,
.task_setpgid = selinux_task_setpgid,
.task_getpgid = selinux_task_getpgid,
@@ -5535,7 +5541,6 @@ static struct security_operations selinux_ops = {
.task_kill = selinux_task_kill,
.task_wait = selinux_task_wait,
.task_prctl = selinux_task_prctl,
- .task_reparent_to_init = selinux_task_reparent_to_init,
.task_to_inode = selinux_task_to_inode,

.ipc_permission = selinux_ipc_permission,
@@ -5631,8 +5636,6 @@ static struct security_operations selinux_ops = {

static __init int selinux_init(void)
{
- struct task_security_struct *tsec;
-
if (!security_module_enable(&selinux_ops)) {
selinux_enabled = 0;
return 0;
@@ -5646,10 +5649,7 @@ static __init int selinux_init(void)
printk(KERN_INFO "SELinux: Initializing.\n");

/* Set the security state for the initial task. */
- if (cred_alloc_security(current->cred))
- panic("SELinux: Failed to initialize initial task.\n");
- tsec = current->cred->security;
- tsec->osid = tsec->sid = SECINITSID_KERNEL;
+ cred_init_security();

sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3e3dcbf..22e5271 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -104,8 +104,7 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
if (rc != 0)
return rc;

- rc = smk_access(current->cred->security, ctp->cred->security,
- MAY_READWRITE);
+ rc = smk_access(current_security(), task_security(ctp), MAY_READWRITE);
if (rc != 0 && capable(CAP_MAC_OVERRIDE))
return 0;
return rc;
@@ -127,8 +126,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
if (rc != 0)
return rc;

- rc = smk_access(ptp->cred->security, current->cred->security,
- MAY_READWRITE);
+ rc = smk_access(task_security(ptp), current_security(), MAY_READWRITE);
if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
return 0;
return rc;
@@ -977,22 +975,6 @@ static int smack_file_receive(struct file *file)
*/

/**
- * smack_cred_alloc_security - "allocate" a task cred blob
- * @cred: the task creds in need of a blob
- *
- * Smack isn't using copies of blobs. Everyone
- * points to an immutable list. No alloc required.
- * No data copy required.
- *
- * Always returns 0
- */
-static int smack_cred_alloc_security(struct cred *cred)
-{
- cred->security = current_security();
- return 0;
-}
-
-/**
* smack_cred_free - "free" task-level security credentials
* @cred: the credentials in question
*
@@ -1006,6 +988,30 @@ static void smack_cred_free(struct cred *cred)
}

/**
+ * smack_cred_prepare - prepare new set of credentials for modification
+ * @new: the new credentials
+ * @old: the original credentials
+ * @gfp: the atomicity of any memory allocations
+ *
+ * Prepare a new set of credentials for modification.
+ */
+static int smack_cred_prepare(struct cred *new, const struct cred *old,
+ gfp_t gfp)
+{
+ new->security = old->security;
+ return 0;
+}
+
+/*
+ * commit new credentials
+ * @new: the new credentials
+ * @old: the original credentials
+ */
+static void smack_cred_commit(struct cred *new, const struct cred *old)
+{
+}
+
+/**
* smack_task_setpgid - Smack check on setting pgid
* @p: the task object
* @pgid: unused
@@ -2036,6 +2042,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
static int smack_setprocattr(struct task_struct *p, char *name,
void *value, size_t size)
{
+ struct cred *new;
char *newsmack;

/*
@@ -2058,7 +2065,11 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (newsmack == NULL)
return -EINVAL;

- p->cred->security = newsmack;
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+ new->security = newsmack;
+ commit_creds(new);
return size;
}

@@ -2351,17 +2362,17 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
/**
* smack_key_alloc - Set the key security blob
* @key: object
- * @tsk: the task associated with the key
+ * @cred: the credentials to use
* @flags: unused
*
* No allocation required
*
* Returns 0
*/
-static int smack_key_alloc(struct key *key, struct task_struct *tsk,
+static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
- key->security = tsk->cred->security;
+ key->security = cred->security;
return 0;
}

@@ -2379,14 +2390,14 @@ static void smack_key_free(struct key *key)
/*
* smack_key_permission - Smack access on a key
* @key_ref: gets to the object
- * @context: task involved
+ * @cred: the credentials to use
* @perm: unused
*
* Return 0 if the task has read and write to the object,
* an error code otherwise
*/
static int smack_key_permission(key_ref_t key_ref,
- struct task_struct *context, key_perm_t perm)
+ const struct cred *cred, key_perm_t perm)
{
struct key *keyp;

@@ -2402,11 +2413,10 @@ static int smack_key_permission(key_ref_t key_ref,
/*
* This should not occur
*/
- if (context->cred->security == NULL)
+ if (cred->security == NULL)
return -EACCES;

- return smk_access(context->cred->security, keyp->security,
- MAY_READWRITE);
+ return smk_access(cred->security, keyp->security, MAY_READWRITE);
}
#endif /* CONFIG_KEYS */

@@ -2577,8 +2587,7 @@ struct security_operations smack_ops = {
.ptrace_may_access = smack_ptrace_may_access,
.ptrace_traceme = smack_ptrace_traceme,
.capget = cap_capget,
- .capset_check = cap_capset_check,
- .capset_set = cap_capset_set,
+ .capset = cap_capset,
.capable = cap_capable,
.syslog = smack_syslog,
.settime = cap_settime,
@@ -2627,9 +2636,10 @@ struct security_operations smack_ops = {
.file_send_sigiotask = smack_file_send_sigiotask,
.file_receive = smack_file_receive,

- .cred_alloc_security = smack_cred_alloc_security,
.cred_free = smack_cred_free,
- .task_post_setuid = cap_task_post_setuid,
+ .cred_prepare = smack_cred_prepare,
+ .cred_commit = smack_cred_commit,
+ .task_fix_setuid = cap_task_fix_setuid,
.task_setpgid = smack_task_setpgid,
.task_getpgid = smack_task_getpgid,
.task_getsid = smack_task_getsid,
@@ -2642,7 +2652,6 @@ struct security_operations smack_ops = {
.task_movememory = smack_task_movememory,
.task_kill = smack_task_kill,
.task_wait = smack_task_wait,
- .task_reparent_to_init = cap_task_reparent_to_init,
.task_to_inode = smack_task_to_inode,
.task_prctl = cap_task_prctl,

@@ -2718,6 +2727,8 @@ struct security_operations smack_ops = {
*/
static __init int smack_init(void)
{
+ struct cred *cred;
+
if (!security_module_enable(&smack_ops))
return 0;

@@ -2726,7 +2737,8 @@ static __init int smack_init(void)
/*
* Set the security state for the initial task.
*/
- current->cred->security = &smack_known_floor.smk_known;
+ cred = (struct cred *) current->cred;
+ cred->security = &smack_known_floor.smk_known;

/*
* Initialize locks

2008-08-06 15:44:30

by David Howells

[permalink] [raw]
Subject: [PATCH 24/24] CRED: Allow kernel services to override LSM settings for task actions [ver #7]

Allow kernel services to override LSM settings appropriate to the actions
performed by a task by duplicating a set of credentials, modifying it and then
using task_struct::cred to point to it when performing operations on behalf of
a task.

This is used, for example, by CacheFiles which has to transparently access the
cache on behalf of a process that thinks it is doing, say, NFS accesses with a
potentially inappropriate (with respect to accessing the cache) set of
credentials.

This patch provides two LSM hooks for modifying a task security record:

(*) security_kernel_act_as() which allows modification of the security datum
with which a task acts on other objects (most notably files).

(*) security_kernel_create_files_as() which allows modification of the
security datum that is used to initialise the security data on a file that
a task creates.

The patch also provides four new credentials handling functions, which wrap the
LSM functions:

(1) prepare_kernel_cred()

Prepare a set of credentials for a kernel service to use, based either on
a daemon's credentials or on init_cred. All the keyrings are cleared.

(2) set_security_override()

Set the LSM security ID in a set of credentials to a specific security
context, assuming permission from the LSM policy.

(3) set_security_override_from_ctx()

As (2), but takes the security context as a string.

(4) set_create_files_as()

Set the file creation LSM security ID in a set of credentials to be the
same as that on a particular inode.

Signed-off-by: Casey Schaufler <[email protected]> [Smack changes]
Signed-off-by: David Howells <[email protected]>
---

include/linux/cred.h | 6 ++
include/linux/security.h | 28 +++++++++++
kernel/cred.c | 113 ++++++++++++++++++++++++++++++++++++++++++++
security/capability.c | 12 +++++
security/security.c | 10 ++++
security/selinux/hooks.c | 46 ++++++++++++++++++
security/smack/smack_lsm.c | 37 ++++++++++++++
7 files changed, 252 insertions(+), 0 deletions(-)


diff --git a/include/linux/cred.h b/include/linux/cred.h
index 7efcecb..b156ed4 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -18,6 +18,7 @@

struct user_struct;
struct cred;
+struct inode;

/*
* COW Supplementary groups list
@@ -148,6 +149,11 @@ extern int commit_creds(struct cred *);
extern void abort_creds(struct cred *);
extern const struct cred *override_creds(const struct cred *);
extern void revert_creds(const struct cred *);
+extern struct cred *prepare_kernel_cred(struct task_struct *);
+extern int change_create_files_as(struct cred *, struct inode *);
+extern int set_security_override(struct cred *, u32);
+extern int set_security_override_from_ctx(struct cred *, const char *);
+extern int set_create_files_as(struct cred *, struct inode *);
extern void __init cred_init(void);

/**
diff --git a/include/linux/security.h b/include/linux/security.h
index 29a6a32..8317683 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -583,6 +583,19 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @new points to the new credentials.
* @old points to the original credentials.
* Install a new set of credentials.
+ * @kernel_act_as:
+ * Set the credentials for a kernel service to act as (subjective context).
+ * @new points to the credentials to be modified.
+ * @secid specifies the security ID to be set
+ * The current task must be the one that nominated @secid.
+ * Return 0 if successful.
+ * @kernel_create_files_as:
+ * Set the file creation context in a set of credentials to be the same as
+ * the objective context of the specified inode.
+ * @new points to the credentials to be modified.
+ * @inode points to the inode to use as a reference.
+ * The current task must be the one that nominated @inode.
+ * Return 0 if successful.
* @task_setuid:
* Check permission before setting one or more of the user identity
* attributes of the current process. The @flags parameter indicates
@@ -1377,6 +1390,8 @@ struct security_operations {
int (*cred_prepare)(struct cred *new, const struct cred *old,
gfp_t gfp);
void (*cred_commit)(struct cred *new, const struct cred *old);
+ int (*kernel_act_as)(struct cred *new, u32 secid);
+ int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
int (*task_fix_setuid) (struct cred *new, const struct cred *old,
int flags);
@@ -1631,6 +1646,8 @@ int security_task_create(unsigned long clone_flags);
void security_cred_free(struct cred *cred);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_commit_creds(struct cred *new, const struct cred *old);
+int security_kernel_act_as(struct cred *new, u32 secid);
+int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags);
@@ -2140,6 +2157,17 @@ static inline void security_commit_creds(struct cred *new,
{
}

+static inline int security_kernel_act_as(struct cred *cred, u32 secid)
+{
+ return 0;
+}
+
+static inline int security_kernel_create_files_as(struct cred *cred,
+ struct inode *inode)
+{
+ return 0;
+}
+
static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
int flags)
{
diff --git a/kernel/cred.c b/kernel/cred.c
index eff48a4..6e9cfbf 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -467,3 +467,116 @@ void __init cred_init(void)
cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
}
+
+/**
+ * prepare_kernel_cred - Prepare a set of credentials for a kernel service
+ * @daemon: A userspace daemon to be used as a reference
+ *
+ * Prepare a set of credentials for a kernel service. This can then be used to
+ * override a task's own credentials so that work can be done on behalf of that
+ * task that requires a different subjective context.
+ *
+ * @daemon is used to provide a base for the security record, but can be NULL.
+ * If @daemon is supplied, then the security data will be derived from that;
+ * otherwise they'll be set to 0 and no groups, full capabilities and no keys.
+ *
+ * The caller may change these controls afterwards if desired.
+ *
+ * Returns the new credentials or NULL if out of memory.
+ *
+ * Does not take, and does not return holding current->cred_replace_mutex.
+ */
+struct cred *prepare_kernel_cred(struct task_struct *daemon)
+{
+ const struct cred *old;
+ struct cred *new;
+
+ new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
+ if (!new)
+ return NULL;
+
+ if (daemon)
+ old = get_task_cred(daemon);
+ else
+ old = get_cred(&init_cred);
+
+ get_uid(new->user);
+ get_group_info(new->group_info);
+
+#ifdef CONFIG_KEYS
+ atomic_inc(&init_tgcred.usage);
+ new->tgcred = &init_tgcred;
+ new->request_key_auth = NULL;
+ new->thread_keyring = NULL;
+ new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+#endif
+
+#ifdef CONFIG_SECURITY
+ new->security = NULL;
+#endif
+ if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
+ goto error;
+
+ atomic_set(&new->usage, 1);
+ put_cred(old);
+ return new;
+
+error:
+ put_cred(new);
+ return NULL;
+}
+EXPORT_SYMBOL(prepare_kernel_cred);
+
+/**
+ * set_security_override - Set the security ID in a set of credentials
+ * @new: The credentials to alter
+ * @secid: The LSM security ID to set
+ *
+ * Set the LSM security ID in a set of credentials so that the subjective
+ * security is overridden when an alternative set of credentials is used.
+ */
+int set_security_override(struct cred *new, u32 secid)
+{
+ return security_kernel_act_as(new, secid);
+}
+EXPORT_SYMBOL(set_security_override);
+
+/**
+ * set_security_override_from_ctx - Set the security ID in a set of credentials
+ * @new: The credentials to alter
+ * @secctx: The LSM security context to generate the security ID from.
+ *
+ * Set the LSM security ID in a set of credentials so that the subjective
+ * security is overridden when an alternative set of credentials is used. The
+ * security ID is specified in string form as a security context to be
+ * interpreted by the LSM.
+ */
+int set_security_override_from_ctx(struct cred *new, const char *secctx)
+{
+ u32 secid;
+ int ret;
+
+ ret = security_secctx_to_secid(secctx, strlen(secctx), &secid);
+ if (ret < 0)
+ return ret;
+
+ return set_security_override(new, secid);
+}
+EXPORT_SYMBOL(set_security_override_from_ctx);
+
+/**
+ * set_create_files_as - Set the LSM file create context in a set of credentials
+ * @new: The credentials to alter
+ * @inode: The inode to take the context from
+ *
+ * Change the LSM file creation context in a set of credentials to be the same
+ * as the object context of the specified inode, so that the new inodes have
+ * the same MAC context as that inode.
+ */
+int set_create_files_as(struct cred *new, struct inode *inode)
+{
+ new->fsuid = inode->i_uid;
+ new->fsgid = inode->i_gid;
+ return security_kernel_create_files_as(new, inode);
+}
+EXPORT_SYMBOL(set_create_files_as);
diff --git a/security/capability.c b/security/capability.c
index 185804f..b9e3914 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -348,6 +348,16 @@ static void cap_cred_commit(struct cred *new, const struct cred *old)
{
}

+static int cap_kernel_act_as(struct cred *new, u32 secid)
+{
+ return 0;
+}
+
+static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
+{
+ return 0;
+}
+
static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
{
return 0;
@@ -889,6 +899,8 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, cred_free);
set_to_cap_if_null(ops, cred_prepare);
set_to_cap_if_null(ops, cred_commit);
+ 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, task_setuid);
set_to_cap_if_null(ops, task_fix_setuid);
set_to_cap_if_null(ops, task_setgid);
diff --git a/security/security.c b/security/security.c
index 3da7856..4a4f753 100644
--- a/security/security.c
+++ b/security/security.c
@@ -602,6 +602,16 @@ void security_commit_creds(struct cred *new, const struct cred *old)
return security_ops->cred_commit(new, old);
}

+int security_kernel_act_as(struct cred *new, u32 secid)
+{
+ return security_ops->kernel_act_as(new, secid);
+}
+
+int security_kernel_create_files_as(struct cred *new, struct inode *inode)
+{
+ return security_ops->kernel_create_files_as(new, inode);
+}
+
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
{
return security_ops->task_setuid(id0, id1, id2, flags);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 14067df..1d2272b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3282,6 +3282,50 @@ static void selinux_cred_commit(struct cred *new, const struct cred *old)
secondary_ops->cred_commit(new, old);
}

+/*
+ * set the security data for a kernel service
+ * - all the creation contexts are set to unlabelled
+ */
+static int selinux_kernel_act_as(struct cred *new, u32 secid)
+{
+ struct task_security_struct *tsec = new->security;
+ u32 sid = current_sid();
+ int ret;
+
+ ret = avc_has_perm(sid, secid,
+ SECCLASS_KERNEL_SERVICE,
+ KERNEL_SERVICE__USE_AS_OVERRIDE,
+ NULL);
+ if (ret == 0) {
+ tsec->sid = secid;
+ tsec->create_sid = 0;
+ tsec->keycreate_sid = 0;
+ tsec->sockcreate_sid = 0;
+ }
+ return ret;
+}
+
+/*
+ * set the file creation context in a security record to the same as the
+ * objective context of the specified inode
+ */
+static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
+{
+ struct inode_security_struct *isec = inode->i_security;
+ struct task_security_struct *tsec = new->security;
+ u32 sid = current_sid();
+ int ret;
+
+ ret = avc_has_perm(sid, isec->sid,
+ SECCLASS_KERNEL_SERVICE,
+ KERNEL_SERVICE__CREATE_FILES_AS,
+ NULL);
+
+ if (ret == 0)
+ tsec->create_sid = isec->sid;
+ return 0;
+}
+
static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
{
/* Since setuid only affects the current process, and
@@ -5494,6 +5538,8 @@ static struct security_operations selinux_ops = {
.cred_free = selinux_cred_free,
.cred_prepare = selinux_cred_prepare,
.cred_commit = selinux_cred_commit,
+ .kernel_act_as = selinux_kernel_act_as,
+ .kernel_create_files_as = selinux_kernel_create_files_as,
.task_setuid = selinux_task_setuid,
.task_fix_setuid = selinux_task_fix_setuid,
.task_setgid = selinux_task_setgid,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 3cf91f5..808208e 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1012,6 +1012,41 @@ static void smack_cred_commit(struct cred *new, const struct cred *old)
}

/**
+ * smack_kernel_act_as - Set the subjective context in a set of credentials
+ * @new points to the set of credentials to be modified.
+ * @secid specifies the security ID to be set
+ *
+ * Set the security data for a kernel service.
+ */
+static int smack_kernel_act_as(struct cred *new, u32 secid)
+{
+ char *smack = smack_from_secid(secid);
+
+ if (smack == NULL)
+ return -EINVAL;
+
+ new->security = smack;
+ return 0;
+}
+
+/**
+ * smack_kernel_create_files_as - Set the file creation label in a set of creds
+ * @new points to the set of credentials to be modified
+ * @inode points to the inode to use as a reference
+ *
+ * Set the file creation context in a set of credentials to the same
+ * as the objective context of the specified inode
+ */
+static int smack_kernel_create_files_as(struct cred *new,
+ struct inode *inode)
+{
+ struct inode_smack *isp = inode->i_security;
+
+ new->security = isp->smk_inode;
+ return 0;
+}
+
+/**
* smack_task_setpgid - Smack check on setting pgid
* @p: the task object
* @pgid: unused
@@ -2638,6 +2673,8 @@ struct security_operations smack_ops = {
.cred_free = smack_cred_free,
.cred_prepare = smack_cred_prepare,
.cred_commit = smack_cred_commit,
+ .kernel_act_as = smack_kernel_act_as,
+ .kernel_create_files_as = smack_kernel_create_files_as,
.task_fix_setuid = cap_task_fix_setuid,
.task_setpgid = smack_task_setpgid,
.task_getpgid = smack_task_getpgid,

2008-08-06 15:44:04

by David Howells

[permalink] [raw]
Subject: [PATCH 21/24] CRED: Documentation [ver #7]

Document credentials and the new credentials API.

Signed-off-by: David Howells <[email protected]>
---

Documentation/credentials.txt | 563 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 563 insertions(+), 0 deletions(-)
create mode 100644 Documentation/credentials.txt


diff --git a/Documentation/credentials.txt b/Documentation/credentials.txt
new file mode 100644
index 0000000..3caf1ea
--- /dev/null
+++ b/Documentation/credentials.txt
@@ -0,0 +1,563 @@
+ ====================
+ CREDENTIALS IN LINUX
+ ====================
+
+By: David Howells <[email protected]>
+
+Contents:
+
+ (*) Overview.
+
+ (*) Types of credentials.
+
+ (*) File markings.
+
+ (*) Task credentials.
+
+ - Accessing task credentials.
+ - Accessing another task's credentials.
+ - Altering credentials.
+ - Managing credentials.
+
+ (*) Open file credentials.
+
+ (*) Overriding the VFS's use of credentials.
+
+
+========
+OVERVIEW
+========
+
+There are several parts to the security check performed by Linux when one
+object acts upon another:
+
+ (1) Objects.
+
+ Objects are things in the system that may be acted upon directly by
+ userspace programs. Linux has a variety of actionable objects, including:
+
+ - Tasks
+ - Files/inodes
+ - Sockets
+ - Message queues
+ - Shared memory segments
+ - Semaphores
+ - Keys
+
+ As a part of the description of all these objects there is a set of
+ credentials. What's in the set depends on the type of object.
+
+ (2) Object ownership.
+
+ Amongst the credentials of most objects, there will be a subset that
+ indicates the ownership of that object. This is used for resource
+ accounting and limitation (disk quotas and task rlimits for example).
+
+ In a standard UNIX filesystem, for instance, this will be defined by the
+ UID marked on the inode.
+
+ (3) The objective context.
+
+ Also amongst the credentials of those objects, there will be a subset that
+ indicates the 'objective context' of that object. This may or may not be
+ the same set as in (2) - in standard UNIX files, for instance, this is the
+ defined by the UID and the GID marked on the inode.
+
+ The objective context is used as part of the security calculation that is
+ carried out when an object is acted upon.
+
+ (4) Subjects.
+
+ A subject is an object that is acting upon another object.
+
+ Most of the objects in the system are inactive: they don't act on other
+ objects within the system. Processes/tasks are the obvious exception:
+ they do stuff; they access and manipulate things.
+
+ Objects other than tasks may under some circumstances also be subjects.
+ For instance an open file may send SIGIO to a task using the UID and EUID
+ given to it by a task that called fcntl(F_SETOWN) upon it. In this case,
+ the file struct will have a subjective context too.
+
+ (5) The subjective context.
+
+ A subject has an additional interpretation of its credentials. A subset
+ of its credentials forms the 'subjective context'. The subjective context
+ is used as part of the security calculation that is carried out when a
+ subject acts.
+
+ A Linux task, for example, has the FSUID, FSGID and the supplementary
+ group list for when it is acting upon a file - which are quite separate
+ from the real UID and GID that normally form the objective context of the
+ task.
+
+ (6) Actions.
+
+ Linux has a number of actions available that a subject may perform upon an
+ object. The set of actions available depends on the nature of the subject
+ and the object.
+
+ Actions include reading, writing, creating and deleting files; forking or
+ signalling and tracing tasks.
+
+ (7) Rules, access control lists and security calculations.
+
+ When a subject acts upon an object, a security calculation is made. This
+ involves taking the subjective context, the objective context and the
+ action, and searching one or more sets of rules to see whether the subject
+ is granted or denied permission to act in the desired manner on the
+ object, given those contexts.
+
+ There are two main sources of rules:
+
+ (a) Discretionary access control (DAC):
+
+ Sometimes the object will include sets of rules as part of its
+ description. This is an 'Access Control List' or 'ACL'. A Linux file
+ may supply more than one ACL.
+
+ A traditional UNIX file, for example, includes a permissions mask that
+ is an abbreviated ACL with three fixed classes of subject ('user',
+ 'group' and 'other'), each of which may be granted certain privileges
+ ('read', 'write' and 'execute' - whatever those map to for the object
+ in question). UNIX file permissions do not allow the arbitrary
+ specification of subjects, however, and so are of limited use.
+
+ A Linux file might also sport a POSIX ACL. This is a list of rules
+ that grants various permissions to arbitrary subjects.
+
+ (b) Mandatory access control (MAC):
+
+ The system as a whole may have one or more sets of rules that get
+ applied to all subjects and objects, regardless of their source.
+ SELinux and Smack are examples of this.
+
+ In the case of SELinux and Smack, each object is given a label as part
+ of its credentials. When an action is requested, they take the
+ subject label, the object label and the action and look for a rule
+ that says that this action is either granted or denied.
+
+
+====================
+TYPES OF CREDENTIALS
+====================
+
+The Linux kernel supports the following types of credentials:
+
+ (1) Traditional UNIX credentials.
+
+ Real User ID
+ Real Group ID
+
+ The UID and GID are carried by most, if not all, Linux objects, even if in
+ some cases it has to be invented (FAT or CIFS files for example, which are
+ derived from Windows). These (mostly) define the objective context of
+ that object, with tasks being slightly different in some cases.
+
+ Effective, Saved and FS User ID
+ Effective, Saved and FS Group ID
+ Supplementary groups
+
+ These are additional credentials used by tasks only. Usually, an
+ EUID/EGID/GROUPS will be used as the subjective context, and real UID/GID
+ will be used as the objective. For tasks, it should be noted that this is
+ not always true.
+
+ (2) Capabilities.
+
+ Set of permitted capabilities
+ Set of inheritable capabilities
+ Set of effective capabilities
+ Capability bounding set
+
+ These are only carried by tasks. They indicate superior capabilities
+ granted piecemeal to a task that an ordinary task wouldn't otherwise have.
+ These are manipulated implicitly by changes to the traditional UNIX
+ credentials, but can also be manipulated directly by the capset() system
+ call.
+
+ The permitted capabilities are those caps that the process might grant
+ itself to its effective or permitted sets through capset(). This
+ inheritable set might also be so constrained.
+
+ The effective capabilities are the ones that a task is actually allowed to
+ make use of itself.
+
+ The inheritable capabilities are the ones that may get passed across
+ execve().
+
+ The bounding set limits the capabilities that may be inherited across
+ execve(), especially when a binary is executed that will execute as UID 0.
+
+ (3) Secure management flags (securebits).
+
+ These are only carried by tasks. These govern the way the above
+ credentials are manipulated and inherited over certain operations such as
+ execve(). They aren't used directly as objective or subjective
+ credentials.
+
+ (4) Keys and keyrings.
+
+ These are only carried by tasks. They carry and cache security tokens
+ that don't fit into the other standard UNIX credentials. They are for
+ making such things as network filesystem keys available to the file
+ accesses performed by processes, without the necessity of ordinary
+ programs having to know about security details involved.
+
+ Keyrings are a special type of key. They carry sets of other keys and can
+ be searched for the desired key. Each process may subscribe to a number
+ of keyrings:
+
+ Per-thread keying
+ Per-process keyring
+ Per-session keyring
+
+ When a process accesses a key, if not already present, it will normally be
+ cached on one of these keyrings for future accesses to find.
+
+ For more information on using keys, see Documentation/keys.txt.
+
+ (5) LSM
+
+ The Linux Security Module allows extra controls to be placed over the
+ operations that a task may do. Currently Linux supports two main
+ alternate LSM options: SELinux and Smack.
+
+ Both work by labelling the objects in a system and then applying sets of
+ rules (policies) that say what operations a task with one label may do to
+ an object with another label.
+
+ (6) AF_KEY
+
+ This is a socket-based approach to credential management for networking
+ stacks [RFC 2367]. It isn't discussed by this document as it doesn't
+ interact directly with task and file credentials; rather it keeps system
+ level credentials.
+
+
+When a file is opened, part of the opening task's subjective context is
+recorded in the file struct created. This allows operations using that file
+struct to use those credentials instead of the subjective context of the task
+that issued the operation. An example of this would be a file opened on a
+network filesystem where the credentials of the opened file should be presented
+to the server, regardless of who is actually doing a read or a write upon it.
+
+
+=============
+FILE MARKINGS
+=============
+
+Files on disk or obtained over the network may have annotations that form the
+objective security context of that file. Depending on the type of filesystem,
+this may include one or more of the following:
+
+ (*) UNIX UID, GID, mode;
+
+ (*) Windows user ID;
+
+ (*) Access control list;
+
+ (*) LSM security label;
+
+ (*) UNIX exec privilege escalation bits (SUID/SGID);
+
+ (*) File capabilities exec privilege escalation bits.
+
+These are compared to the task's subjective security context, and certain
+operations allowed or disallowed as a result. In the case of execve(), the
+privilege escalation bits come into play, and may allow the resulting process
+extra privileges, based on the annotations on the executable file.
+
+
+================
+TASK CREDENTIALS
+================
+
+In Linux, all of a task's credentials are held in (uid, gid) or through
+(groups, keys, LSM security) a refcounted structure of type 'struct cred'.
+Each task points to its credentials by a pointer called 'cred' in its
+task_struct.
+
+Once a set of credentials has been prepared and committed, it may not be
+changed, barring the following exceptions:
+
+ (1) its reference count may be changed;
+
+ (2) the reference count on the group_info struct it points to may be changed;
+
+ (3) the reference count on the security data it points to may be changed;
+
+ (4) the reference count on any keyrings it points to may be changed;
+
+ (5) any keyrings it points to may be revoked, expired or have their security
+ attributes changed; and
+
+ (6) the contents of any keyrings to which it points may be changed (the whole
+ point of keyrings being a shared set of credentials, modifiable by anyone
+ with appropriate access).
+
+To alter anything in the cred struct, the copy-and-replace principle must be
+adhered to. First take a copy, then alter the copy and then use RCU to change
+the task pointer to make it point to the new copy. There are wrappers to aid
+with this (see below).
+
+A task may only alter its _own_ credentials; it is no longer permitted for a
+task to alter another's credentials. This means the capset() system call is no
+longer permitted to take any PID other than the one of the current process.
+Also keyctl_instantiate() and keyctl_negate() functions no longer permit
+attachment to process-specific keyrings in the requesting process as the
+instantiating process may need to create them.
+
+
+ACCESSING TASK CREDENTIALS
+--------------------------
+
+A task being able to alter only its own credentials permits the current process
+to read or replace its own credentials without the need for any form of locking
+- which simplifies things greatly. It can just call:
+
+ const struct cred *current_cred()
+
+to get a pointer to its credentials structure, and it doesn't have to release
+it afterwards.
+
+There are convenience wrappers for retrieving specific aspects of a task's
+credentials (the value is simply returned in each case):
+
+ uid_t current_uid(void) Current's real UID
+ gid_t current_gid(void) Current's real GID
+ uid_t current_euid(void) Current's effective UID
+ gid_t current_egid(void) Current's effective GID
+ uid_t current_fsuid(void) Current's file access UID
+ gid_t current_fsgid(void) Current's file access GID
+ kernel_cap_t current_cap(void) Current's effective capabilities
+ void *current_security(void) Current's LSM security pointer
+ struct user_struct *current_user(void) Current's user account
+
+There are also convenience wrappers for retrieving specific associated pairs of
+a task's credentials:
+
+ void current_uid_gid(uid_t *, gid_t *);
+ void current_euid_egid(uid_t *, gid_t *);
+ void current_fsuid_fsgid(uid_t *, gid_t *);
+
+which return these pairs of values through their arguments after retrieving
+them from the current task's credentials.
+
+
+In addition, there is a function for obtaining a reference on the current
+process's current set of credentials:
+
+ const struct cred *get_current_cred(void);
+
+and functions for getting references to one of the credentials that don't
+actually live in struct cred:
+
+ struct user_struct *get_current_user(void);
+ struct group_info *get_current_groups(void);
+
+which get references to the current process's user accounting structure and
+supplementary groups list respectively.
+
+Once a reference has been obtained, it must be released with put_cred(),
+free_uid() or put_group_info() as appropriate.
+
+
+ACCESSING ANOTHER TASK'S CREDENTIALS
+------------------------------------
+
+Whilst a task may access its own credentials without the need for locking, the
+same is not true of a task wanting to access another task's credentials. It
+must use the RCU read lock and rcu_dereference().
+
+The rcu_dereference() is wrapped by:
+
+ const struct cred *__task_cred(struct task_struct *task);
+
+This should be used inside the RCU read lock, as in the following example:
+
+ void foo(struct task_struct *t, struct foo_data *f)
+ {
+ const struct cred *tcred;
+ ...
+ rcu_read_lock();
+ tcred = __task_cred(t);
+ f->uid = tcred->uid;
+ f->gid = tcred->gid;
+ f->groups = get_group_info(tcred->groups);
+ rcu_read_unlock();
+ ...
+ }
+
+A function need not get RCU read lock to use __task_cred() if it is holding a
+spinlock at the time as this implicitly holds the RCU read lock.
+
+Should it be necessary to hold another task's credentials for a long period of
+time, and possibly to sleep whilst doing so, then the caller should get a
+reference on them using:
+
+ const struct cred *get_task_cred(struct task_struct *task);
+
+This does all the RCU magic inside of it. The caller must call put_cred() on
+the credentials so obtained when they're finished with.
+
+There are a couple of convenience functions to access bits of another task's
+credentials, hiding the RCU magic from the caller:
+
+ uid_t task_uid(task) Task's real UID
+ uid_t task_euid(task) Task's effective UID
+
+If the caller is holding a spinlock or the RCU read lock at the time anyway,
+then:
+
+ __task_cred(task)->uid
+ __task_cred(task)->euid
+
+should be used instead. Similarly, if multiple aspects of a task's credentials
+need to be accessed, RCU read lock or a spinlock should be used, __task_cred()
+called, the result stored in a temporary pointer and then the credential
+aspects called from that before dropping the lock. This prevents the
+potentially expensive RCU magic from being invoked multiple times.
+
+Should some other single aspect of another task's credentials need to be
+accessed, then this can be used:
+
+ task_cred_xxx(task, member)
+
+where 'member' is a non-pointer member of the cred struct. For instance:
+
+ uid_t task_cred_xxx(task, suid);
+
+will retrieve 'struct cred::suid' from the task, doing the appropriate RCU
+magic. This may not be used for pointer members as what they point to may
+disappear the moment the RCU read lock is dropped.
+
+
+ALTERING CREDENTIALS
+--------------------
+
+As previously mentioned, a task may only alter its own credentials, and may not
+alter those of another task. This means that it doesn't need to use any
+locking to alter its own credentials.
+
+To alter the current process's credentials, a function should first prepare a
+new set of credentials by calling:
+
+ struct cred *prepare_creds(void);
+
+this locks current->cred_replace_mutex and then allocates and constructs a
+duplicate of the current process's credentials, returning with the mutex still
+held if successful. It returns NULL if not successful (out of memory).
+
+The mutex prevents ptrace() from altering the ptrace state of a process whilst
+security checks on credentials construction and changing is taking place as
+the ptrace state may alter the outcome, particularly in the case of execve().
+
+The new credentials set should be altered appropriately, and any security
+checks and hooks done. Both the current and the proposed sets of credentials
+are available for this purpose as current_cred() will return the current set
+still at this point.
+
+
+When the credential set is ready, it should be committed to the current process
+by calling:
+
+ int commit_creds(struct cred *new);
+
+This will alter various aspects of the credentials and the process, giving the
+LSM a chance to do likewise, then it will use rcu_assign_pointer() to actually
+commit the new credentials to current->cred, it will release
+current->cred_replace_mutex to allow ptrace() to take place, and it will notify
+the scheduler and others of the changes.
+
+This function is guaranteed to return 0, so that it can be tail-called at the
+end of such functions as sys_setresuid().
+
+Note that this function consumes the caller's reference to the new credentials.
+The caller should _not_ call put_cred() on the new credentials afterwards.
+
+Furthermore, once this function has been called on a new set of credentials,
+those credentials may _not_ be changed further.
+
+
+Should the security checks fail or some other error occur after prepare_creds()
+has been called, then the following function should be invoked:
+
+ void abort_creds(struct cred *new);
+
+This releases the lock on current->cred_replace_mutex that prepare_creds() got
+and then releases the new credentials.
+
+
+A typical credentials alteration function would look something like this:
+
+ int alter_suid(uid_t suid)
+ {
+ struct cred *new;
+ int ret;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->suid = suid;
+ ret = security_alter_suid(new);
+ if (ret < 0) {
+ abort_creds(new);
+ return ret;
+ }
+
+ return commit_creds(new);
+ }
+
+
+MANAGING CREDENTIALS
+--------------------
+
+There are some functions to help manage credentials:
+
+ (*) void put_cred(const struct cred *cred);
+
+ This releases a reference to the given set of credentials. If the
+ reference count reaches zero, the credentials will be scheduled for
+ destruction by the RCU system.
+
+ (*) const struct cred *get_cred(const struct cred *cred);
+
+ This gets a reference on a live set of credentials, returning a pointer to
+ that set of credentials.
+
+ (*) struct cred *get_new_cred(struct cred *cred);
+
+ This gets a reference on a set of credentials that is under construction
+ and is thus still mutable, returning a pointer to that set of credentials.
+
+
+=====================
+OPEN FILE CREDENTIALS
+=====================
+
+When a new file is opened, a reference is obtained on the opening task's
+credentials and this is attached to the file struct as 'f_cred' in place of
+'f_uid' and 'f_gid'. Code that used to access file->f_uid and file->f_gid
+should now access file->f_cred->fsuid and file->f_cred->fsgid.
+
+It is safe to access f_cred without the use of RCU or locking because the
+pointer will not change over the lifetime of the file struct, and nor will the
+contents of the cred struct pointed to, barring the exceptions listed above
+(see the Task Credentials section).
+
+
+=======================================
+OVERRIDING THE VFS'S USE OF CREDENTIALS
+=======================================
+
+Under some circumstances it is desirable to override the credentials used by
+the VFS, and that can be done by calling into such as vfs_mkdir() with a
+different set of credentials. This is done in the following places:
+
+ (*) sys_faccessat().
+
+ (*) do_coredump().
+
+ (*) nfs4recover.c.

2008-08-06 15:43:43

by David Howells

[permalink] [raw]
Subject: [PATCH 18/24] CRED: Make execve() take advantage of copy-on-write credentials [ver #7]

Make execve() take advantage of copy-on-write credentials, allowing it to set
up the credentials in advance, and then commit the whole lot after the point
of no return.

This patch and the preceding patches have been tested with the LTP SELinux
testsuite.

This patch makes several logical sets of alteration:

(1) execve().

The credential bits from struct linux_binprm are, for the most part,
replaced with a single credentials pointer (bprm->cred). This means that
all the creds can be calculated in advance and then applied at the point
of no return with no possibility of failure.

I would like to replace bprm->cap_effective with:

cap_isclear(bprm->cap_effective)

but this seems impossible due to special behaviour for processes of pid 1
(they always retain their parent's capability masks where normally they'd
be changed - see cap_bprm_set_creds()).

The following sequence of events now happens:

(a) At the start of do_execve, the current task's cred_exec_mutex is
locked to prevent PTRACE_ATTACH from obsoleting the calculation of
creds that we make.

(a) prepare_exec_creds() is then called to make a copy of the current
task's credentials and prepare it. This copy is then assigned to
bprm->cred.

This renders security_bprm_alloc() and security_bprm_free()
unnecessary, and so they've been removed.

(b) The determination of unsafe execution is now performed immediately
after (a) rather than later on in the code. The result is stored in
bprm->unsafe for future reference.

(c) prepare_binprm() is called, possibly multiple times.

(i) This applies the result of set[ug]id binaries to the new creds
attached to bprm->cred. Personality bit clearance is recorded,
but now deferred on the basis that the exec procedure may yet
fail.

(ii) This then calls the new security_bprm_set_creds(). This should
calculate the new LSM and capability credentials into *bprm->cred.

This folds together security_bprm_set() and parts of
security_bprm_apply_creds() (these two have been removed).
Anything that might fail must be done at this point.

(iii) bprm->cred_prepared is set to 1.

bprm->cred_prepared is 0 on the first pass of the security
calculations, and 1 on all subsequent passes. This allows SELinux
in (ii) to base its calculations only on the initial script and
not on the interpreter.

(d) flush_old_exec() is called to commit the task to execution. This
performs the following steps with regard to credentials:

(i) Clear pdeath_signal and set dumpable on certain circumstances that
may not be covered by commit_creds().

(ii) Clear any bits in current->personality that were deferred from
(c.i).

(e) install_exec_creds() [compute_creds() as was] is called to install the
new credentials. This performs the following steps with regard to
credentials:

(i) Calls security_bprm_committing_creds() to apply any security
requirements, such as flushing unauthorised files in SELinux, that
must be done before the credentials are changed.

This is made up of bits of security_bprm_apply_creds() and
security_bprm_post_apply_creds(), both of which have been removed.
This function is not allowed to fail; anything that might fail
must have been done in (c.ii).

(ii) Calls commit_creds() to apply the new credentials in a single
assignment (more or less). Possibly pdeath_signal and dumpable
should be part of struct creds.

(iii) Unlocks the task's cred_replace_mutex, thus allowing
PTRACE_ATTACH to take place.

(iv) Clears The bprm->cred pointer as the credentials it was holding
are now immutable.

(v) Calls security_bprm_committed_creds() to apply any security
alterations that must be done after the creds have been changed.
SELinux uses this to flush signals and signal handlers.

(f) If an error occurs before (d.i), bprm_free() will call abort_creds()
to destroy the proposed new credentials and will then unlock
cred_replace_mutex. No changes to the credentials will have been
made.

(2) LSM interface.

A number of functions have been changed, added or removed:

(*) security_bprm_alloc(), ->bprm_alloc_security()
(*) security_bprm_free(), ->bprm_free_security()

Removed in favour of preparing new credentials and modifying those.

(*) security_bprm_apply_creds(), ->bprm_apply_creds()
(*) security_bprm_post_apply_creds(), ->bprm_post_apply_creds()

Removed; split between security_bprm_set_creds(),
security_bprm_committing_creds() and security_bprm_committed_creds().

(*) security_bprm_set(), ->bprm_set_security()

Removed; folded into security_bprm_set_creds().

(*) security_bprm_set_creds(), ->bprm_set_creds()

New. The new credentials in bprm->creds should be checked and set up
as appropriate. bprm->cred_prepared is 0 on the first call, 1 on the
second and subsequent calls.

(*) security_bprm_committing_creds(), ->bprm_committing_creds()
(*) security_bprm_committed_creds(), ->bprm_committed_creds()

New. Apply the security effects of the new credentials. This
includes closing unauthorised files in SELinux. This function may not
fail. When the former is called, the creds haven't yet been applied
to the process; when the latter is called, they have.

The former may access bprm->cred, the latter may not.

(3) SELinux.

SELinux has a number of changes, in addition to those to support the LSM
interface changes mentioned above:

(a) The bprm_security_struct struct has been removed in favour of using
the credentials-under-construction approach.

(c) flush_unauthorized_files() now takes a cred pointer and passes it on
to inode_has_perm(), file_has_perm() and dentry_open().

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

arch/x86/ia32/ia32_aout.c | 2
fs/binfmt_aout.c | 2
fs/binfmt_elf.c | 2
fs/binfmt_elf_fdpic.c | 2
fs/binfmt_flat.c | 2
fs/binfmt_som.c | 2
fs/compat.c | 20 +--
fs/exec.c | 124 +++++++++-------
fs/internal.h | 6 +
include/linux/binfmts.h | 16 +-
include/linux/cred.h | 3
include/linux/key.h | 2
include/linux/security.h | 103 +++++--------
kernel/cred.c | 44 ++++++
security/capability.c | 19 +-
security/commoncap.c | 133 ++++++++---------
security/keys/process_keys.c | 42 -----
security/root_plug.c | 13 +-
security/security.c | 26 +--
security/selinux/hooks.c | 290 ++++++++++++++++---------------------
security/selinux/include/objsec.h | 11 -
security/smack/smack_lsm.c | 3
22 files changed, 390 insertions(+), 477 deletions(-)


diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index a0e1dbe..57b2ade 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -325,7 +325,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
current->mm->cached_hole_size = 0;

current->mm->mmap = NULL;
- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;

if (N_MAGIC(ex) == OMAGIC) {
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 204cfd1..f1f3f41 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -320,7 +320,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;

- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
#ifdef __sparc__
if (N_MAGIC(ex) == NMAGIC) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 8761e97..fc98651 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -956,7 +956,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
}
#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */

- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
retval = create_elf_tables(bprm, &loc->elf_ex,
load_addr, interp_load_addr);
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 5625b23..83a55ef 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -403,7 +403,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
current->mm->start_stack = current->mm->start_brk + stack_size;
#endif

- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
if (create_elf_fdpic_tables(bprm, current->mm,
&exec_params, &interp_params) < 0)
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 56372ec..ae8554d 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -880,7 +880,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(libinfo.lib_list[j].loaded)?
libinfo.lib_list[j].start_data:UNLOADED_LIB;

- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;

set_binfmt(&flat_format);
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 68be580..bd87ae3 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -255,7 +255,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
kfree(hpuxhdr);

set_binfmt(&som_format);
- compute_creds(bprm);
+ install_exec_creds(bprm);
setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);

create_som_tables(bprm);
diff --git a/fs/compat.c b/fs/compat.c
index c9d1472..b8069c3 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1356,10 +1356,15 @@ int compat_do_execve(char * filename,
if (!bprm)
goto out_ret;

+ bprm->cred = prepare_exec_creds();
+ if (!bprm->cred)
+ goto out_free;
+ check_unsafe_exec(bprm);
+
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
- goto out_kfree;
+ goto out_free;

sched_exec();

@@ -1373,14 +1378,10 @@ int compat_do_execve(char * filename,

bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
- goto out_mm;
+ goto out;

bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(bprm);
- if (retval)
goto out;

retval = prepare_binprm(bprm);
@@ -1403,17 +1404,12 @@ int compat_do_execve(char * filename,
retval = search_binary_handler(bprm, regs);
if (retval >= 0) {
/* execve success */
- security_bprm_free(bprm);
acct_update_integrals(current);
free_bprm(bprm);
return retval;
}

out:
- if (bprm->security)
- security_bprm_free(bprm);
-
-out_mm:
if (bprm->mm)
mmput(bprm->mm);

@@ -1423,7 +1419,7 @@ out_file:
fput(bprm->file);
}

-out_kfree:
+out_free:
free_bprm(bprm);

out_ret:
diff --git a/fs/exec.c b/fs/exec.c
index fb7ace1..a7633e5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -54,6 +54,7 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
+#include "internal.h"

#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -1012,15 +1013,17 @@ int flush_old_exec(struct linux_binprm * bprm)
*/
current->mm->task_size = TASK_SIZE;

- if (bprm->e_uid != current_euid() ||
- bprm->e_gid != current_egid()) {
- set_dumpable(current->mm, suid_dumpable);
+ /* install the new credentials */
+ if (bprm->cred->uid != current_euid() ||
+ bprm->cred->gid != current_egid()) {
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
- (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
+ bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
set_dumpable(current->mm, suid_dumpable);
}

+ current->personality &= ~bprm->per_clear;
+
/* An exec changes our domain. We are no longer part of the thread
group */

@@ -1037,13 +1040,49 @@ out:

EXPORT_SYMBOL(flush_old_exec);

+/*
+ * install the new credentials for this executable
+ */
+void install_exec_creds(struct linux_binprm *bprm)
+{
+ security_bprm_committing_creds(bprm);
+
+ /* we hold cred_exec_mutex this far to prevent ptrace_attach() from
+ * altering our determination of the task's credentials */
+ commit_creds(bprm->cred);
+ bprm->cred = NULL;
+ mutex_unlock(&current->cred_exec_mutex);
+
+ security_bprm_committed_creds(bprm);
+}
+EXPORT_SYMBOL(install_exec_creds);
+
+/*
+ * determine how safe it is to execute the proposed program
+ * - the caller must hold current->cred_exec_mutex to protect against
+ * PTRACE_ATTACH
+ */
+void check_unsafe_exec(struct linux_binprm *bprm)
+{
+ struct task_struct *p = current;
+
+ bprm->unsafe = tracehook_unsafe_exec(p);
+
+ if (atomic_read(&p->fs->count) > 1 ||
+ atomic_read(&p->files->count) > 1 ||
+ atomic_read(&p->sighand->count) > 1)
+ bprm->unsafe |= LSM_UNSAFE_SHARE;
+}
+
/*
* Fill the binprm structure from the inode.
* Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
+ *
+ * This may be called multiple times for binary chains (scripts for example).
*/
int prepare_binprm(struct linux_binprm *bprm)
{
- int mode;
+ umode_t mode;
struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;

@@ -1051,14 +1090,15 @@ int prepare_binprm(struct linux_binprm *bprm)
if (bprm->file->f_op == NULL)
return -EACCES;

- bprm->e_uid = current_euid();
- bprm->e_gid = current_egid();
+ /* clear any previous set[ug]id data from a previous binary */
+ bprm->cred->euid = current_euid();
+ bprm->cred->egid = current_egid();

- if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+ if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
- current->personality &= ~PER_CLEAR_ON_SETID;
- bprm->e_uid = inode->i_uid;
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->cred->euid = inode->i_uid;
}

/* Set-gid? */
@@ -1068,50 +1108,23 @@ int prepare_binprm(struct linux_binprm *bprm)
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
- current->personality &= ~PER_CLEAR_ON_SETID;
- bprm->e_gid = inode->i_gid;
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->cred->egid = inode->i_gid;
}
}

/* fill in binprm security blob */
- retval = security_bprm_set(bprm);
+ retval = security_bprm_set_creds(bprm);
if (retval)
return retval;
+ bprm->cred_prepared = 1;

- memset(bprm->buf,0,BINPRM_BUF_SIZE);
- return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
+ memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+ return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
}

EXPORT_SYMBOL(prepare_binprm);

-static int unsafe_exec(struct task_struct *p)
-{
- int unsafe = tracehook_unsafe_exec(p);
-
- if (atomic_read(&p->fs->count) > 1 ||
- atomic_read(&p->files->count) > 1 ||
- atomic_read(&p->sighand->count) > 1)
- unsafe |= LSM_UNSAFE_SHARE;
-
- return unsafe;
-}
-
-void compute_creds(struct linux_binprm *bprm)
-{
- int unsafe;
-
- if (bprm->e_uid != current_uid())
- current->pdeath_signal = 0;
- exec_keys(current);
-
- task_lock(current);
- unsafe = unsafe_exec(current);
- security_bprm_apply_creds(bprm, unsafe);
- task_unlock(current);
- security_bprm_post_apply_creds(bprm);
-}
-EXPORT_SYMBOL(compute_creds);
-
/*
* Arguments are '\0' separated strings found at the location bprm->p
* points to; chop off the first by relocating brpm->p to right after
@@ -1264,6 +1277,10 @@ EXPORT_SYMBOL(search_binary_handler);
void free_bprm(struct linux_binprm *bprm)
{
free_arg_pages(bprm);
+ if (bprm->cred) {
+ mutex_unlock(&current->cred_exec_mutex);
+ abort_creds(bprm->cred);
+ }
kfree(bprm);
}

@@ -1289,6 +1306,16 @@ int do_execve(char * filename,
if (!bprm)
goto out_files;

+ retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+ if (retval < 0)
+ goto out_kfree;
+
+ retval = -ENOMEM;
+ bprm->cred = prepare_exec_creds();
+ if (!bprm->cred)
+ goto out_kfree;
+ check_unsafe_exec(bprm);
+
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
@@ -1306,14 +1333,10 @@ int do_execve(char * filename,

bprm->argc = count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
- goto out_mm;
+ goto out;

bprm->envc = count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(bprm);
- if (retval)
goto out;

retval = prepare_binprm(bprm);
@@ -1337,7 +1360,6 @@ int do_execve(char * filename,
retval = search_binary_handler(bprm,regs);
if (retval >= 0) {
/* execve success */
- security_bprm_free(bprm);
acct_update_integrals(current);
free_bprm(bprm);
if (displaced)
@@ -1346,10 +1368,6 @@ int do_execve(char * filename,
}

out:
- if (bprm->security)
- security_bprm_free(bprm);
-
-out_mm:
if (bprm->mm)
mmput (bprm->mm);

diff --git a/fs/internal.h b/fs/internal.h
index 80aa9a0..53af885 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -10,6 +10,7 @@
*/

struct super_block;
+struct linux_binprm;

/*
* block_dev.c
@@ -40,6 +41,11 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
extern void __init chrdev_init(void);

/*
+ * exec.c
+ */
+extern void check_unsafe_exec(struct linux_binprm *);
+
+/*
* namespace.c
*/
extern int copy_mount_options(const void __user *, unsigned long *);
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 826f623..26f9c1b 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -35,12 +35,16 @@ struct linux_binprm{
struct mm_struct *mm;
unsigned long p; /* current top of mem */
unsigned int sh_bang:1,
- misc_bang:1;
+ misc_bang:1,
+ cred_prepared:1,/* true if creds already prepared (multiple
+ * preps happen for interpreters) */
+ cap_effective:1;/* true if has elevated effective capabilities,
+ * false if not; except for init which inherits
+ * its parent's caps anyway */
struct file * file;
- int e_uid, e_gid;
- kernel_cap_t cap_post_exec_permitted;
- bool cap_effective;
- void *security;
+ struct cred *cred; /* new credentials */
+ int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
+ unsigned int per_clear; /* bits to clear in current->personality */
int argc, envc;
char * filename; /* Name of binary as seen by procps */
char * interp; /* Name of the binary really executed. Most
@@ -96,7 +100,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
int executable_stack);
extern int bprm_mm_init(struct linux_binprm *bprm);
extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
-extern void compute_creds(struct linux_binprm *binprm);
+extern void install_exec_creds(struct linux_binprm *bprm);
extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
extern int set_binfmt(struct linux_binfmt *new);
extern void free_bprm(struct linux_binprm *);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 202a82c..c508f4d 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -84,8 +84,6 @@ struct thread_group_cred {
struct key *process_keyring; /* keyring private to this process */
struct rcu_head rcu; /* RCU deletion hook */
};
-
-extern void put_tgcred(struct thread_group_cred *tgcred);
#endif

/*
@@ -144,6 +142,7 @@ struct cred {
extern void __put_cred(struct cred *);
extern int copy_creds(struct task_struct *, unsigned long);
extern struct cred *prepare_creds(void);
+extern struct cred *prepare_exec_creds(void);
extern struct cred *prepare_usermodehelper_creds(void);
extern int commit_creds(struct cred *);
extern void abort_creds(struct cred *);
diff --git a/include/linux/key.h b/include/linux/key.h
index acd4b13..e3f026c 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -278,7 +278,6 @@ extern ctl_table key_sysctls[];
* the userspace interface
*/
extern int install_thread_keyring_to_cred(struct cred *cred);
-extern int exec_keys(struct task_struct *tsk);
extern void key_fsuid_changed(struct task_struct *tsk);
extern void key_fsgid_changed(struct task_struct *tsk);
extern void key_init(void);
@@ -295,7 +294,6 @@ extern void key_init(void);
#define is_key_possessed(k) 0
#define install_session_keyring(k) NULL
#define install_thread_keyring_to_cred(c) NULL
-#define exec_keys(t) do { } while(0)
#define key_fsuid_changed(t) do { } while(0)
#define key_fsgid_changed(t) do { } while(0)
#define key_init() do { } while(0)
diff --git a/include/linux/security.h b/include/linux/security.h
index fd66260..29a6a32 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -53,8 +53,7 @@ extern int cap_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
-extern int cap_bprm_set_security(struct linux_binprm *bprm);
-extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+extern int cap_bprm_set_creds(struct linux_binprm *bprm);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
@@ -106,7 +105,7 @@ extern unsigned long mmap_min_addr;
struct sched_param;
struct request_sock;

-/* bprm_apply_creds unsafe reasons */
+/* bprm->unsafe reasons */
#define LSM_UNSAFE_SHARE 1
#define LSM_UNSAFE_PTRACE 2
#define LSM_UNSAFE_PTRACE_CAP 4
@@ -150,36 +149,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
*
* Security hooks for program execution operations.
*
- * @bprm_alloc_security:
- * Allocate and attach a security structure to the @bprm->security field.
- * The security field is initialized to NULL when the bprm structure is
- * allocated.
- * @bprm contains the linux_binprm structure to be modified.
- * Return 0 if operation was successful.
- * @bprm_free_security:
- * @bprm contains the linux_binprm structure to be modified.
- * Deallocate and clear the @bprm->security field.
- * @bprm_apply_creds:
- * Compute and set the security attributes of a process being transformed
- * by an execve operation based on the old attributes (current->security)
- * and the information saved in @bprm->security by the set_security hook.
- * Since this function may return an error, in which case the process will
- * be killed. However, it can leave the security attributes of the
- * process unchanged if an access failure occurs at this point.
- * bprm_apply_creds is called under task_lock. @unsafe indicates various
- * reasons why it may be unsafe to change security state.
- * @bprm contains the linux_binprm structure.
- * @bprm_post_apply_creds:
- * Runs after bprm_apply_creds with the task_lock dropped, so that
- * functions which cannot be called safely under the task_lock can
- * be used. This hook is a good place to perform state changes on
- * the process such as closing open file descriptors to which access
- * is no longer granted if the attributes were changed.
- * Note that a security module might need to save state between
- * bprm_apply_creds and bprm_post_apply_creds to store the decision
- * on whether the process may proceed.
- * @bprm contains the linux_binprm structure.
- * @bprm_set_security:
+ * @bprm_set_creds:
* Save security information in the bprm->security field, typically based
* on information about the bprm->file, for later use by the apply_creds
* hook. This hook may also optionally check permissions (e.g. for
@@ -192,15 +162,30 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted.
* @bprm_check_security:
- * This hook mediates the point when a search for a binary handler will
- * begin. It allows a check the @bprm->security value which is set in
- * the preceding set_security call. The primary difference from
- * set_security is that the argv list and envp list are reliably
- * available in @bprm. This hook may be called multiple times
- * during a single execve; and in each pass set_security is called
- * first.
+ * This hook mediates the point when a search for a binary handler will
+ * begin. It allows a check the @bprm->security value which is set in the
+ * preceding set_creds call. The primary difference from set_creds is
+ * that the argv list and envp list are reliably available in @bprm. This
+ * hook may be called multiple times during a single execve; and in each
+ * pass set_creds is called first.
* @bprm contains the linux_binprm structure.
* Return 0 if the hook is successful and permission is granted.
+ * @bprm_committing_creds:
+ * Prepare to install the new security attributes of a process being
+ * transformed by an execve operation, based on the old credentials
+ * pointed to by @current->cred and the information set in @bprm->cred by
+ * the bprm_set_creds hook. @bprm points to the linux_binprm structure.
+ * This hook is a good place to perform state changes on the process such
+ * as closing open file descriptors to which access will no longer be
+ * granted when the attributes are changed. This is called immediately
+ * before commit_creds().
+ * @bprm_committed_creds:
+ * Tidy up after the installation of the new security attributes of a
+ * process being transformed by an execve operation. The new credentials
+ * have, by this point, been set to @current->cred. @bprm points to the
+ * linux_binprm structure. This hook is a good place to perform state
+ * changes on the process such as clearing out non-inheritable signal
+ * state. This is called immediately after commit_creds().
* @bprm_secureexec:
* Return a boolean value (0 or 1) indicating whether a "secure exec"
* is required. The flag is passed in the auxiliary table
@@ -1297,13 +1282,11 @@ struct security_operations {
int (*settime) (struct timespec *ts, struct timezone *tz);
int (*vm_enough_memory) (struct mm_struct *mm, long pages);

- int (*bprm_alloc_security) (struct linux_binprm *bprm);
- void (*bprm_free_security) (struct linux_binprm *bprm);
- int (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
- void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
- int (*bprm_set_security) (struct linux_binprm *bprm);
+ int (*bprm_set_creds) (struct linux_binprm *bprm);
int (*bprm_check_security) (struct linux_binprm *bprm);
int (*bprm_secureexec) (struct linux_binprm *bprm);
+ void (*bprm_committing_creds) (struct linux_binprm *bprm);
+ void (*bprm_committed_creds) (struct linux_binprm *bprm);

int (*sb_alloc_security) (struct super_block *sb);
void (*sb_free_security) (struct super_block *sb);
@@ -1568,12 +1551,10 @@ int security_syslog(int type);
int security_settime(struct timespec *ts, struct timezone *tz);
int security_vm_enough_memory(long pages);
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
-int security_bprm_alloc(struct linux_binprm *bprm);
-void security_bprm_free(struct linux_binprm *bprm);
-int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
-void security_bprm_post_apply_creds(struct linux_binprm *bprm);
-int security_bprm_set(struct linux_binprm *bprm);
+int security_bprm_set_creds(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm);
+void security_bprm_committing_creds(struct linux_binprm *bprm);
+void security_bprm_committed_creds(struct linux_binprm *bprm);
int security_bprm_secureexec(struct linux_binprm *bprm);
int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
@@ -1801,32 +1782,22 @@ static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
return cap_vm_enough_memory(mm, pages);
}

-static inline int security_bprm_alloc(struct linux_binprm *bprm)
-{
- return 0;
-}
-
-static inline void security_bprm_free(struct linux_binprm *bprm)
-{ }
-
-static inline int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+static inline int security_bprm_set_creds(struct linux_binprm *bprm)
{
- return cap_bprm_apply_creds(bprm, unsafe);
+ return cap_bprm_set_creds(bprm);
}

-static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm)
+static inline int security_bprm_check(struct linux_binprm *bprm)
{
- return;
+ return 0;
}

-static inline int security_bprm_set(struct linux_binprm *bprm)
+static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
{
- return cap_bprm_set_security(bprm);
}

-static inline int security_bprm_check(struct linux_binprm *bprm)
+static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
{
- return 0;
}

static inline int security_bprm_secureexec(struct linux_binprm *bprm)
diff --git a/kernel/cred.c b/kernel/cred.c
index 7a4d311..319614d 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -177,6 +177,50 @@ error:
EXPORT_SYMBOL(prepare_creds);

/*
+ * Prepare credentials for current to perform an execve()
+ * - The caller must hold current->cred_exec_mutex
+ */
+struct cred *prepare_exec_creds(void)
+{
+ struct thread_group_cred *tgcred = NULL;
+ struct cred *new;
+
+#ifdef CONFIG_KEYS
+ tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
+ if (!tgcred)
+ return NULL;
+#endif
+
+ new = prepare_creds();
+ if (!new) {
+ kfree(tgcred);
+ return new;
+ }
+
+#ifdef CONFIG_KEYS
+ /* newly exec'd tasks don't get a thread keyring */
+ key_put(new->thread_keyring);
+ new->thread_keyring = NULL;
+
+ /* create a new per-thread-group creds for all this set of threads to
+ * share */
+ memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
+
+ atomic_set(&tgcred->usage, 1);
+ spin_lock_init(&tgcred->lock);
+
+ /* inherit the session keyring; new process keyring */
+ key_get(tgcred->session_keyring);
+ tgcred->process_keyring = NULL;
+
+ put_tgcred(new->tgcred);
+ new->tgcred = tgcred;
+#endif
+
+ return new;
+}
+
+/*
* prepare new credentials for the usermode helper dispatcher
*/
struct cred *prepare_usermodehelper_creds(void)
diff --git a/security/capability.c b/security/capability.c
index efeb6d9..185804f 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -32,24 +32,19 @@ static int cap_quota_on(struct dentry *dentry)
return 0;
}

-static int cap_bprm_alloc_security(struct linux_binprm *bprm)
+static int cap_bprm_check_security (struct linux_binprm *bprm)
{
return 0;
}

-static void cap_bprm_free_security(struct linux_binprm *bprm)
+static void cap_bprm_committing_creds(struct linux_binprm *bprm)
{
}

-static void cap_bprm_post_apply_creds(struct linux_binprm *bprm)
+static void cap_bprm_committed_creds(struct linux_binprm *bprm)
{
}

-static int cap_bprm_check_security(struct linux_binprm *bprm)
-{
- return 0;
-}
-
static int cap_sb_alloc_security(struct super_block *sb)
{
return 0;
@@ -827,11 +822,9 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, syslog);
set_to_cap_if_null(ops, settime);
set_to_cap_if_null(ops, vm_enough_memory);
- set_to_cap_if_null(ops, bprm_alloc_security);
- set_to_cap_if_null(ops, bprm_free_security);
- set_to_cap_if_null(ops, bprm_apply_creds);
- set_to_cap_if_null(ops, bprm_post_apply_creds);
- set_to_cap_if_null(ops, bprm_set_security);
+ set_to_cap_if_null(ops, bprm_set_creds);
+ set_to_cap_if_null(ops, bprm_committing_creds);
+ set_to_cap_if_null(ops, bprm_committed_creds);
set_to_cap_if_null(ops, bprm_check_security);
set_to_cap_if_null(ops, bprm_secureexec);
set_to_cap_if_null(ops, sb_alloc_security);
diff --git a/security/commoncap.c b/security/commoncap.c
index 1ae99fa..3da0ada 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -166,7 +166,7 @@ int cap_capset(struct cred *new,

static inline void bprm_clear_caps(struct linux_binprm *bprm)
{
- cap_clear(bprm->cap_post_exec_permitted);
+ cap_clear(bprm->cred->cap_permitted);
bprm->cap_effective = false;
}

@@ -197,8 +197,10 @@ int cap_inode_killpriv(struct dentry *dentry)
}

static inline int cap_from_disk(struct vfs_cap_data *caps,
- struct linux_binprm *bprm, unsigned size)
+ struct linux_binprm *bprm, unsigned size,
+ bool *effective)
{
+ struct cred *new = bprm->cred;
__u32 magic_etc;
unsigned tocopy, i;
int ret;
@@ -208,7 +210,7 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,

magic_etc = le32_to_cpu(caps->magic_etc);

- switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
+ switch (magic_etc & VFS_CAP_REVISION_MASK) {
case VFS_CAP_REVISION_1:
if (size != XATTR_CAPS_SZ_1)
return -EINVAL;
@@ -223,11 +225,8 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
return -EINVAL;
}

- if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
- bprm->cap_effective = true;
- } else {
- bprm->cap_effective = false;
- }
+ if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
+ *effective = true;

ret = 0;

@@ -238,18 +237,18 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
/*
* Legacy capability sets have no upper bits
*/
- bprm->cap_post_exec_permitted.cap[i] = 0;
+ new->cap_permitted.cap[i] = 0;
continue;
}
/*
* pP' = (X & fP) | (pI & fI)
*/
value_cpu = le32_to_cpu(caps->data[i].permitted);
- bprm->cap_post_exec_permitted.cap[i] =
- (current->cred->cap_bset.cap[i] & value_cpu) |
- (current->cred->cap_inheritable.cap[i] &
- le32_to_cpu(caps->data[i].inheritable));
- if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
+ new->cap_permitted.cap[i] =
+ (new->cap_bset.cap[i] & value_cpu) |
+ (new->cap_inheritable.cap[i] &
+ le32_to_cpu(caps->data[i].inheritable));
+ if (value_cpu & ~new->cap_permitted.cap[i]) {
/*
* insufficient to execute correctly
*/
@@ -262,11 +261,11 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
* do not have enough capabilities, we return an error if they are
* missing some "forced" (aka file-permitted) capabilities.
*/
- return bprm->cap_effective ? ret : 0;
+ return *effective ? ret : 0;
}

/* Locate any VFS capabilities: */
-static int get_file_caps(struct linux_binprm *bprm)
+static int get_file_caps(struct linux_binprm *bprm, bool *effective)
{
struct dentry *dentry;
int rc = 0;
@@ -293,7 +292,7 @@ static int get_file_caps(struct linux_binprm *bprm)
if (rc < 0)
goto out;

- rc = cap_from_disk(&vcaps, bprm, rc);
+ rc = cap_from_disk(&vcaps, bprm, rc, effective);
if (rc == -EINVAL)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
__func__, rc, bprm->filename);
@@ -317,18 +316,27 @@ int cap_inode_killpriv(struct dentry *dentry)
return 0;
}

-static inline int get_file_caps(struct linux_binprm *bprm)
+static inline int get_file_caps(struct linux_binprm *bprm, bool *effective)
{
bprm_clear_caps(bprm);
return 0;
}
#endif

-int cap_bprm_set_security (struct linux_binprm *bprm)
+/*
+ * set up the new credentials for an exec'd task
+ */
+int cap_bprm_set_creds(struct linux_binprm *bprm)
{
+ const struct cred *old = current_cred();
+ struct cred *new = bprm->cred;
+ bool effective;
int ret;

- ret = get_file_caps(bprm);
+ effective = false;
+ ret = get_file_caps(bprm, &effective);
+ if (ret < 0)
+ return ret;

if (!issecure(SECURE_NOROOT)) {
/*
@@ -336,78 +344,67 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
* executables under compatibility mode, we override the
* capability sets for the file.
*
- * If only the real uid is 0, we do not set the effective
- * bit.
+ * If only the real uid is 0, we do not set the effective bit.
*/
- if (bprm->e_uid == 0 || current_uid() == 0) {
+ if (new->euid == 0 || new->uid == 0) {
/* pP' = (cap_bset & ~0) | (pI & ~0) */
- bprm->cap_post_exec_permitted = cap_combine(
- current->cred->cap_bset,
- current->cred->cap_inheritable);
- bprm->cap_effective = (bprm->e_uid == 0);
- ret = 0;
+ new->cap_permitted = cap_combine(old->cap_bset,
+ old->cap_inheritable);
}
+ if (new->euid == 0)
+ effective = true;
}

- return ret;
-}
-
-int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
-{
- const struct cred *old = current_cred();
- struct cred *new;
-
- new = prepare_creds();
- if (!new)
- return -ENOMEM;
-
- if (bprm->e_uid != old->uid || bprm->e_gid != old->gid ||
- !cap_issubset(bprm->cap_post_exec_permitted,
- old->cap_permitted)) {
- set_dumpable(current->mm, suid_dumpable);
- current->pdeath_signal = 0;
-
- if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
- if (!capable(CAP_SETUID)) {
- bprm->e_uid = old->uid;
- bprm->e_gid = old->gid;
- }
- if (cap_limit_ptraced_target()) {
- bprm->cap_post_exec_permitted = cap_intersect(
- bprm->cap_post_exec_permitted,
- new->cap_permitted);
- }
+ /* Don't let someone trace a set[ug]id/setpcap binary with the revised
+ * credentials unless they have the appropriate permit
+ */
+ if ((new->euid != old->uid ||
+ 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 */
+ if (!capable(CAP_SETUID)) {
+ new->euid = new->uid;
+ new->egid = new->gid;
}
+ if (cap_limit_ptraced_target())
+ new->cap_permitted = cap_intersect(new->cap_permitted,
+ old->cap_permitted);
}

- new->suid = new->euid = new->fsuid = bprm->e_uid;
- new->sgid = new->egid = new->fsgid = bprm->e_gid;
+ new->suid = new->fsuid = new->euid;
+ new->sgid = new->fsgid = new->egid;

- /* For init, we want to retain the capabilities set
- * in the init_task struct. Thus we skip the usual
- * capability rules */
+ /* For init, we want to retain the capabilities set in the initial
+ * task. Thus we skip the usual capability rules
+ */
if (!is_global_init(current)) {
- new->cap_permitted = bprm->cap_post_exec_permitted;
- if (bprm->cap_effective)
- new->cap_effective = bprm->cap_post_exec_permitted;
+ if (effective)
+ new->cap_effective = new->cap_permitted;
else
cap_clear(new->cap_effective);
}
+ bprm->cap_effective = effective;

- /* AUD: Audit candidate if cred->cap_effective is set */
+ /* AUD: Audit candidate if new->cap_effective is set */

new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
- return commit_creds(new);
+ return 0;
}

-int cap_bprm_secureexec (struct linux_binprm *bprm)
+/*
+ * determine whether a secure execution is required
+ * - the creds have been committed at this point, and are no longer available
+ * through bprm
+ */
+int cap_bprm_secureexec(struct linux_binprm *bprm)
{
const struct cred *cred = current_cred();

if (cred->uid != 0) {
if (bprm->cap_effective)
return 1;
- if (!cap_isclear(bprm->cap_post_exec_permitted))
+ if (!cap_isclear(cred->cap_permitted))
return 1;
}

diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index c8d8f3c..717c4f4 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -276,48 +276,6 @@ static int install_session_keyring(struct key *keyring)

/*****************************************************************************/
/*
- * deal with execve()
- */
-int exec_keys(struct task_struct *tsk)
-{
- struct thread_group_cred *tgcred = NULL;
- struct cred *new;
-
-#ifdef CONFIG_KEYS
- tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
- if (!tgcred)
- return -ENOMEM;
-#endif
-
- new = prepare_creds();
- if (new < 0)
- return -ENOMEM;
-
- /* newly exec'd tasks don't get a thread keyring */
- key_put(new->thread_keyring);
- new->thread_keyring = NULL;
-
- /* create a new per-thread-group creds for all this set of threads to
- * share */
- memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred));
-
- atomic_set(&tgcred->usage, 1);
- spin_lock_init(&tgcred->lock);
-
- /* inherit the session keyring; new process keyring */
- key_get(tgcred->session_keyring);
- tgcred->process_keyring = NULL;
-
- put_tgcred(new->tgcred);
- new->tgcred = tgcred;
-
- commit_creds(new);
- return 0;
-
-} /* end exec_keys() */
-
-/*****************************************************************************/
-/*
* the filesystem user ID changed
*/
void key_fsuid_changed(struct task_struct *tsk)
diff --git a/security/root_plug.c b/security/root_plug.c
index c3f68b5..40fb4f1 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -55,9 +55,9 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm)
struct usb_device *dev;

root_dbg("file %s, e_uid = %d, e_gid = %d\n",
- bprm->filename, bprm->e_uid, bprm->e_gid);
+ bprm->filename, bprm->cred->euid, bprm->cred->egid);

- if (bprm->e_gid == 0) {
+ if (bprm->cred->egid == 0) {
dev = usb_find_device(vendor_id, product_id);
if (!dev) {
root_dbg("e_gid = 0, and device not found, "
@@ -75,15 +75,12 @@ static struct security_operations rootplug_security_ops = {
.ptrace_may_access = cap_ptrace_may_access,
.ptrace_traceme = cap_ptrace_traceme,
.capget = cap_capget,
- .capset_check = cap_capset_check,
- .capset_set = cap_capset_set,
+ .capset = cap_capset,
.capable = cap_capable,

- .bprm_apply_creds = cap_bprm_apply_creds,
- .bprm_set_security = cap_bprm_set_security,
+ .bprm_set_creds = cap_bprm_set_creds,

- .task_post_setuid = cap_task_post_setuid,
- .task_reparent_to_init = cap_task_reparent_to_init,
+ .task_fix_setuid = cap_task_fix_setuid,
.task_prctl = cap_task_prctl,

.bprm_check_security = rootplug_bprm_check_security,
diff --git a/security/security.c b/security/security.c
index c60c334..3da7856 100644
--- a/security/security.c
+++ b/security/security.c
@@ -199,34 +199,24 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
return security_ops->vm_enough_memory(mm, pages);
}

-int security_bprm_alloc(struct linux_binprm *bprm)
+int security_bprm_set_creds(struct linux_binprm *bprm)
{
- return security_ops->bprm_alloc_security(bprm);
+ return security_ops->bprm_set_creds(bprm);
}

-void security_bprm_free(struct linux_binprm *bprm)
-{
- security_ops->bprm_free_security(bprm);
-}
-
-int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
-{
- return security_ops->bprm_apply_creds(bprm, unsafe);
-}
-
-void security_bprm_post_apply_creds(struct linux_binprm *bprm)
+int security_bprm_check(struct linux_binprm *bprm)
{
- security_ops->bprm_post_apply_creds(bprm);
+ return security_ops->bprm_check_security(bprm);
}

-int security_bprm_set(struct linux_binprm *bprm)
+void security_bprm_committing_creds(struct linux_binprm *bprm)
{
- return security_ops->bprm_set_security(bprm);
+ return security_ops->bprm_committing_creds(bprm);
}

-int security_bprm_check(struct linux_binprm *bprm)
+void security_bprm_committed_creds(struct linux_binprm *bprm)
{
- return security_ops->bprm_check_security(bprm);
+ return security_ops->bprm_committed_creds(bprm);
}

int security_bprm_secureexec(struct linux_binprm *bprm)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 27441e7..f934830 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2028,59 +2028,45 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)

/* binprm security operations */

-static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
+static int selinux_bprm_set_creds(struct linux_binprm *bprm)
{
- struct bprm_security_struct *bsec;
-
- bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
- if (!bsec)
- return -ENOMEM;
-
- bsec->sid = SECINITSID_UNLABELED;
- bsec->set = 0;
-
- bprm->security = bsec;
- return 0;
-}
-
-static int selinux_bprm_set_security(struct linux_binprm *bprm)
-{
- struct task_security_struct *tsec;
- struct inode *inode = bprm->file->f_path.dentry->d_inode;
+ const struct task_security_struct *old_tsec;
+ struct task_security_struct *new_tsec;
struct inode_security_struct *isec;
- struct bprm_security_struct *bsec;
- u32 newsid;
struct avc_audit_data ad;
+ struct inode *inode = bprm->file->f_path.dentry->d_inode;
int rc;

- rc = secondary_ops->bprm_set_security(bprm);
+ rc = secondary_ops->bprm_set_creds(bprm);
if (rc)
return rc;

- bsec = bprm->security;
-
- if (bsec->set)
+ /* SELinux context only depends on initial program or script and not
+ * the script interpreter */
+ if (bprm->cred_prepared)
return 0;

- tsec = current_security();
+ old_tsec = current_security();
+ new_tsec = bprm->cred->security;
isec = inode->i_security;

/* Default to the current task SID. */
- bsec->sid = tsec->sid;
+ new_tsec->sid = old_tsec->sid;
+ new_tsec->osid = old_tsec->sid;

/* Reset fs, key, and sock SIDs on execve. */
- tsec->create_sid = 0;
- tsec->keycreate_sid = 0;
- tsec->sockcreate_sid = 0;
+ new_tsec->create_sid = 0;
+ new_tsec->keycreate_sid = 0;
+ new_tsec->sockcreate_sid = 0;

- if (tsec->exec_sid) {
- newsid = tsec->exec_sid;
+ if (old_tsec->exec_sid) {
+ new_tsec->sid = old_tsec->exec_sid;
/* Reset exec SID on execve. */
- tsec->exec_sid = 0;
+ new_tsec->exec_sid = 0;
} else {
/* Check for a default transition on this program. */
- rc = security_transition_sid(tsec->sid, isec->sid,
- SECCLASS_PROCESS, &newsid);
+ rc = security_transition_sid(old_tsec->sid, isec->sid,
+ SECCLASS_PROCESS, &new_tsec->sid);
if (rc)
return rc;
}
@@ -2089,33 +2075,63 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
ad.u.fs.path = bprm->file->f_path;

if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
- newsid = tsec->sid;
+ new_tsec->sid = old_tsec->sid;

- if (tsec->sid == newsid) {
- rc = avc_has_perm(tsec->sid, isec->sid,
+ if (new_tsec->sid == old_tsec->sid) {
+ rc = avc_has_perm(old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
/* Check permissions for the transition. */
- rc = avc_has_perm(tsec->sid, newsid,
+ rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
if (rc)
return rc;

- rc = avc_has_perm(newsid, isec->sid,
+ rc = avc_has_perm(new_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
if (rc)
return rc;

- /* Clear any possibly unsafe personality bits on exec: */
- current->personality &= ~PER_CLEAR_ON_SETID;
+ /* Check for shared state */
+ if (bprm->unsafe & LSM_UNSAFE_SHARE) {
+ rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ SECCLASS_PROCESS, PROCESS__SHARE,
+ NULL);
+ if (rc)
+ return -EPERM;
+ }
+
+ /* Make sure that anyone attempting to ptrace over a task that
+ * changes its SID has the appropriate permit */
+ if (bprm->unsafe &
+ (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
+ struct task_struct *tracer;
+ struct task_security_struct *sec;
+ u32 ptsid = 0;
+
+ rcu_read_lock();
+ tracer = tracehook_tracer_task(current);
+ if (likely(tracer != NULL)) {
+ sec = __task_cred(tracer)->security;
+ ptsid = sec->sid;
+ }
+ rcu_read_unlock();

- /* Set the security field to the new SID. */
- bsec->sid = newsid;
+ if (ptsid != 0) {
+ rc = avc_has_perm(ptsid, new_tsec->sid,
+ SECCLASS_PROCESS,
+ PROCESS__PTRACE, NULL);
+ if (rc)
+ return -EPERM;
+ }
+ }
+
+ /* Clear any possibly unsafe personality bits on exec: */
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
}

- bsec->set = 1;
return 0;
}

@@ -2124,7 +2140,6 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm)
return secondary_ops->bprm_check_security(bprm);
}

-
static int selinux_bprm_secureexec(struct linux_binprm *bprm)
{
const struct cred *cred = current_cred();
@@ -2140,19 +2155,13 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
atsecure = avc_has_perm(osid, sid,
- SECCLASS_PROCESS,
- PROCESS__NOATSECURE, NULL);
+ SECCLASS_PROCESS,
+ PROCESS__NOATSECURE, NULL);
}

return (atsecure || secondary_ops->bprm_secureexec(bprm));
}

-static void selinux_bprm_free_security(struct linux_binprm *bprm)
-{
- kfree(bprm->security);
- bprm->security = NULL;
-}
-
extern struct vfsmount *selinuxfs_mount;
extern struct dentry *selinux_null;

@@ -2250,106 +2259,83 @@ static inline void flush_unauthorized_files(const struct cred *cred,
spin_unlock(&files->file_lock);
}

-static int selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+/*
+ * Prepare a process for imminent new credential changes due to exec
+ */
+static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
{
- struct task_security_struct *tsec;
- struct bprm_security_struct *bsec;
- struct cred *new;
- u32 sid;
- int rc;
-
- rc = secondary_ops->bprm_apply_creds(bprm, unsafe);
- if (rc < 0)
- return rc;
+ struct task_security_struct *new_tsec;
+ struct rlimit *rlim, *initrlim;
+ int rc, i;

- new = prepare_creds();
- if (!new)
- return -ENOMEM;
+ secondary_ops->bprm_committing_creds(bprm);

- tsec = new->security;
+ new_tsec = bprm->cred->security;
+ if (new_tsec->sid == new_tsec->osid)
+ return;

- bsec = bprm->security;
- sid = bsec->sid;
-
- tsec->osid = tsec->sid;
- bsec->unsafe = 0;
- if (tsec->sid != sid) {
- /* Check for shared state. If not ok, leave SID
- unchanged and kill. */
- if (unsafe & LSM_UNSAFE_SHARE) {
- rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
- PROCESS__SHARE, NULL);
- if (rc) {
- bsec->unsafe = 1;
- goto out;
- }
- }
+ /* Close files for which the new task SID is not authorized. */
+ flush_unauthorized_files(bprm->cred, current->files);

- /* Check for ptracing, and update the task SID if ok.
- Otherwise, leave SID unchanged and kill. */
- if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
- struct task_struct *tracer;
- struct task_security_struct *sec;
- u32 ptsid = 0;
+ /* Always clear parent death signal on SID transitions. */
+ current->pdeath_signal = 0;

- rcu_read_lock();
- tracer = tracehook_tracer_task(current);
- if (likely(tracer != NULL)) {
- sec = __task_cred(tracer)->security;
- ptsid = sec->sid;
- }
- rcu_read_unlock();
+ /* Check whether the new SID can inherit resource limits from the old
+ * SID. If not, reset all soft limits to the lower of the current
+ * task's hard limit and the init task's soft limit.
+ *
+ * Note that the setting of hard limits (even to lower them) can be
+ * controlled by the setrlimit check. The inclusion of the init task's
+ * soft limit into the computation is to avoid resetting soft limits
+ * higher than the default soft limit for cases where the default is
+ * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
+ */
+ rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
+ PROCESS__RLIMITINH, NULL);
+ if (rc) {
+ for (i = 0; i < RLIM_NLIMITS; i++) {
+ rlim = current->signal->rlim + i;
+ initrlim = init_task.signal->rlim+i;
+ rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
+ }

- if (ptsid != 0) {
- rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
- PROCESS__PTRACE, NULL);
- if (rc) {
- bsec->unsafe = 1;
- goto out;
- }
- }
+ if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
+ /*
+ * This will cause RLIMIT_CPU calculations to be
+ * refigured.
+ */
+ current->it_prof_expires = jiffies_to_cputime(1);
}
- tsec->sid = sid;
}
-
-out:
- commit_creds(new);
- return 0;
}

/*
- * called after apply_creds without the task lock held
+ * Clean up the process immediately after the installation of new credentials
+ * due to exec
*/
-static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
+static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
{
- const struct cred *cred = current_cred();
- struct task_security_struct *tsec;
- struct rlimit *rlim, *initrlim;
+ const struct task_security_struct *tsec = current_security();
struct itimerval itimer;
- struct bprm_security_struct *bsec;
+ u32 osid, sid;
int rc, i;

- tsec = current_security();
- bsec = bprm->security;
+ secondary_ops->bprm_committed_creds(bprm);

- if (bsec->unsafe) {
- force_sig_specific(SIGKILL, current);
- return;
- }
- if (tsec->osid == tsec->sid)
+ osid = tsec->osid;
+ sid = tsec->sid;
+
+ if (sid == osid)
return;

- /* Close files for which the new task SID is not authorized. */
- flush_unauthorized_files(cred, current->files);
-
- /* Check whether the new SID can inherit signal state
- from the old SID. If not, clear itimers to avoid
- subsequent signal generation and flush and unblock
- signals. This must occur _after_ the task SID has
- been updated so that any kill done after the flush
- will be checked against the new SID. */
- rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
- PROCESS__SIGINH, NULL);
+ /* Check whether the new SID can inherit signal state from the old SID.
+ * If not, clear itimers to avoid subsequent signal generation and
+ * flush and unblock signals.
+ *
+ * This must occur _after_ the task SID has been updated so that any
+ * kill done after the flush will be checked against the new SID.
+ */
+ rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) {
memset(&itimer, 0, sizeof itimer);
for (i = 0; i < 3; i++)
@@ -2362,36 +2348,6 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
spin_unlock_irq(&current->sighand->siglock);
}

- /* Always clear parent death signal on SID transitions. */
- current->pdeath_signal = 0;
-
- /* Check whether the new SID can inherit resource limits
- from the old SID. If not, reset all soft limits to
- the lower of the current task's hard limit and the init
- task's soft limit. Note that the setting of hard limits
- (even to lower them) can be controlled by the setrlimit
- check. The inclusion of the init task's soft limit into
- the computation is to avoid resetting soft limits higher
- than the default soft limit for cases where the default
- is lower than the hard limit, e.g. RLIMIT_CORE or
- RLIMIT_STACK.*/
- rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS,
- PROCESS__RLIMITINH, NULL);
- if (rc) {
- for (i = 0; i < RLIM_NLIMITS; i++) {
- rlim = current->signal->rlim + i;
- initrlim = init_task.signal->rlim+i;
- rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
- }
- if (current->signal->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
- /*
- * This will cause RLIMIT_CPU calculations
- * to be refigured.
- */
- current->it_prof_expires = jiffies_to_cputime(1);
- }
- }
-
/* Wake up the parent if it is waiting so that it can
recheck wait permission to the new task SID. */
wake_up_interruptible(&current->parent->signal->wait_chldexit);
@@ -5456,12 +5412,10 @@ static struct security_operations selinux_ops = {
.netlink_send = selinux_netlink_send,
.netlink_recv = selinux_netlink_recv,

- .bprm_alloc_security = selinux_bprm_alloc_security,
- .bprm_free_security = selinux_bprm_free_security,
- .bprm_apply_creds = selinux_bprm_apply_creds,
- .bprm_post_apply_creds = selinux_bprm_post_apply_creds,
- .bprm_set_security = selinux_bprm_set_security,
+ .bprm_set_creds = selinux_bprm_set_creds,
.bprm_check_security = selinux_bprm_check_security,
+ .bprm_committing_creds = selinux_bprm_committing_creds,
+ .bprm_committed_creds = selinux_bprm_committed_creds,
.bprm_secureexec = selinux_bprm_secureexec,

.sb_alloc_security = selinux_sb_alloc_security,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 91070ab..b831e17 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -77,17 +77,6 @@ struct ipc_security_struct {
u32 sid; /* SID of IPC resource */
};

-struct bprm_security_struct {
- u32 sid; /* SID for transformed process */
- unsigned char set;
-
- /*
- * unsafe is used to share failure information from bprm_apply_creds()
- * to bprm_post_apply_creds().
- */
- char unsafe;
-};
-
struct netif_security_struct {
int ifindex; /* device index */
u32 sid; /* SID for this interface */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 22e5271..3cf91f5 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2593,8 +2593,7 @@ struct security_operations smack_ops = {
.settime = cap_settime,
.vm_enough_memory = cap_vm_enough_memory,

- .bprm_apply_creds = cap_bprm_apply_creds,
- .bprm_set_security = cap_bprm_set_security,
+ .bprm_set_creds = cap_bprm_set_creds,
.bprm_secureexec = cap_bprm_secureexec,

.sb_alloc_security = smack_sb_alloc_security,

2008-08-06 15:44:48

by David Howells

[permalink] [raw]
Subject: [PATCH 23/24] CRED: Add a kernel_service object class to SELinux [ver #7]

Add a 'kernel_service' object class to SELinux and give this object class two
access vectors: 'use_as_override' and 'create_files_as'.

The first vector is used to grant a process the right to nominate an alternate
process security ID for the kernel to use as an override for the SELinux
subjective security when accessing stuff on behalf of another process.

For example, CacheFiles when accessing the cache on behalf on a process
accessing an NFS file needs to use a subjective security ID appropriate to the
cache rather then the one the calling process is using. The cachefilesd
daemon will nominate the security ID to be used.

The second vector is used to grant a process the right to nominate a file
creation label for a kernel service to use.

Signed-off-by: David Howells <[email protected]>
---

security/selinux/include/av_perm_to_string.h | 2 ++
security/selinux/include/av_permissions.h | 2 ++
security/selinux/include/class_to_string.h | 5 +++++
security/selinux/include/flask.h | 1 +
4 files changed, 10 insertions(+), 0 deletions(-)


diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 1223b4f..c0c8854 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -176,3 +176,5 @@
S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
S_(SECCLASS_PEER, PEER__RECV, "recv")
+ S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__USE_AS_OVERRIDE, "use_as_override")
+ S_(SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__CREATE_FILES_AS, "create_files_as")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index c4c5116..0ba79fe 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -841,3 +841,5 @@
#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL
#define MEMPROTECT__MMAP_ZERO 0x00000001UL
#define PEER__RECV 0x00000001UL
+#define KERNEL_SERVICE__USE_AS_OVERRIDE 0x00000001UL
+#define KERNEL_SERVICE__CREATE_FILES_AS 0x00000002UL
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index bd813c3..21ec786 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -72,3 +72,8 @@
S_(NULL)
S_("peer")
S_("capability2")
+ S_(NULL)
+ S_(NULL)
+ S_(NULL)
+ S_(NULL)
+ S_("kernel_service")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index febf886..882f27d 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -52,6 +52,7 @@
#define SECCLASS_MEMPROTECT 61
#define SECCLASS_PEER 68
#define SECCLASS_CAPABILITY2 69
+#define SECCLASS_KERNEL_SERVICE 74

/*
* Security identifier indices for initial entities

2008-08-06 15:45:20

by David Howells

[permalink] [raw]
Subject: [PATCH 22/24] CRED: Differentiate objective and effective subjective credentials on a task [ver #7]

Differentiate the objective and real subjective credentials from the effective
subjective credentials on a task by introducing a second credentials pointer
into the task_struct.

task_struct::real_cred then refers to the objective and apparent real
subjective credentials of a task, as perceived by the other tasks in the
system.

task_struct::cred then refers to the effective subjective credentials of a
task, as used by that task when it's actually running. These are not visible
to the other tasks in the system.

__task_cred(task) then refers to the objective/real credentials of the task in
question.

current_cred() refers to the effective subjective credentials of the current
task.

prepare_creds() uses the objective creds as a base and commit_creds() changes
both pointers in the task_struct (indeed commit_creds() requires them to be the
same).

override_creds() and revert_creds() change the subjective creds pointer only,
and the former returns the old subjective creds. These are used by NFSD,
faccessat() and do_coredump(), and will by used by CacheFiles.

In SELinux, current_has_perm() is provided as an alternative to
task_has_perm(). This uses the effective subjective context of current,
whereas task_has_perm() uses the objective/real context of the subject.

Signed-off-by: David Howells <[email protected]>
---

fs/nfsd/auth.c | 5 +++
include/linux/cred.h | 29 ++++++++++----------
include/linux/init_task.h | 1 +
include/linux/sched.h | 5 +++
kernel/cred.c | 38 ++++++++++++++++++--------
kernel/fork.c | 6 +++-
security/selinux/hooks.c | 65 ++++++++++++++++++++++++++++-----------------
7 files changed, 95 insertions(+), 54 deletions(-)


diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 836ffa1..0184fe9 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
int flags = nfsexp_flags(rqstp, exp);
int ret;

+ /* discard any old override before preparing the new set */
+ revert_creds(get_cred(current->real_cred));
new = prepare_creds();
if (!new)
return -ENOMEM;
@@ -82,7 +84,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
else
new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
new->cap_permitted);
- return commit_creds(new);
+ put_cred(override_creds(new));
+ return 0;

oom:
ret = -ENOMEM;
diff --git a/include/linux/cred.h b/include/linux/cred.h
index c508f4d..7efcecb 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -146,8 +146,8 @@ extern struct cred *prepare_exec_creds(void);
extern struct cred *prepare_usermodehelper_creds(void);
extern int commit_creds(struct cred *);
extern void abort_creds(struct cred *);
-extern const struct cred *override_creds(const struct cred *) __deprecated;
-extern void revert_creds(const struct cred *) __deprecated;
+extern const struct cred *override_creds(const struct cred *);
+extern void revert_creds(const struct cred *);
extern void __init cred_init(void);

/**
@@ -192,32 +192,32 @@ static inline void put_cred(const struct cred *_cred)
}

/**
- * current_cred - Access the current task's credentials
+ * current_cred - Access the current task's subjective credentials
*
- * Access the credentials of the current task.
+ * Access the subjective credentials of the current task.
*/
#define current_cred() \
(current->cred)

/**
- * __task_cred - Access another task's credentials
+ * __task_cred - Access a task's objective credentials
* @task: The task to query
*
- * Access the credentials of another task. The caller must hold the
- * RCU readlock.
+ * Access the objective credentials of a task. The caller must hold the RCU
+ * readlock.
*
* The caller must make sure task doesn't go away, either by holding a ref on
* task or by holding tasklist_lock to prevent it from being unlinked.
*/
#define __task_cred(task) \
- ((const struct cred *)(rcu_dereference((task)->cred)))
+ ((const struct cred *)(rcu_dereference((task)->real_cred)))

/**
- * get_task_cred - Get another task's credentials
+ * get_task_cred - Get another task's objective credentials
* @task: The task to query
*
- * Get the credentials of a task, pinning them so that they can't go away.
- * Accessing a task's credentials directly is not permitted.
+ * Get the objective credentials of a task, pinning them so that they can't go
+ * away. Accessing a task's credentials directly is not permitted.
*
* The caller must make sure task doesn't go away, either by holding a ref on
* task or by holding tasklist_lock to prevent it from being unlinked.
@@ -233,10 +233,11 @@ static inline void put_cred(const struct cred *_cred)
})

/**
- * get_current_cred - Get the current task's credentials
+ * get_current_cred - Get the current task's subjective credentials
*
- * Get the credentials of the current task, pinning them so that they can't go
- * away. Accessing the current task's credentials directly is not permitted.
+ * Get the subjective credentials of the current task, pinning them so that
+ * they can't go away. Accessing the current task's credentials directly is
+ * not permitted.
*/
#define get_current_cred() \
(get_cred(current_cred()))
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index e0cc816..edf0285 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -149,6 +149,7 @@ extern struct cred init_cred;
.children = LIST_HEAD_INIT(tsk.children), \
.sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \
+ .real_cred = &init_cred, \
.cred = &init_cred, \
.cred_exec_mutex = \
__MUTEX_INITIALIZER(tsk.cred_exec_mutex), \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index fd1126a..3b1001d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1103,7 +1103,10 @@ struct task_struct {
struct list_head cpu_timers[3];

/* process credentials */
- const struct cred *cred; /* actual/objective task credentials (COW) */
+ const struct cred *real_cred; /* objective and real subjective task
+ * credentials (COW) */
+ const struct cred *cred; /* effective (overridable) subjective task
+ * credentials (COW) */
struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */

char comm[TASK_COMM_LEN]; /* executable name excluding path
diff --git a/kernel/cred.c b/kernel/cred.c
index 319614d..eff48a4 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -35,7 +35,7 @@ static struct thread_group_cred init_tgcred = {
* The initial credentials for the initial task
*/
struct cred init_cred = {
- .usage = ATOMIC_INIT(3),
+ .usage = ATOMIC_INIT(4),
.securebits = SECUREBITS_DEFAULT,
.cap_inheritable = CAP_INIT_INH_SET,
.cap_permitted = CAP_FULL_SET,
@@ -133,6 +133,8 @@ struct cred *alloc_creds(const struct cred *old, gfp_t gfp)
* prepare a new copy, which the caller then modifies and then commits by
* calling commit_creds().
*
+ * Preparation involves making a copy of the objective creds for modification.
+ *
* Returns a pointer to the new creds-to-be if successful, NULL otherwise.
*
* Call commit_creds() or abort_creds() to clean up.
@@ -143,7 +145,7 @@ struct cred *prepare_creds(void)
const struct cred *old;
struct cred *new;

- BUG_ON(atomic_read(&task->cred->usage) < 1);
+ BUG_ON(atomic_read(&task->real_cred->usage) < 1);

new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
if (!new)
@@ -275,6 +277,9 @@ error:
*
* We share if we can, but under some circumstances we have to generate a new
* set.
+ *
+ * The new process gets the current process's subjective credentials as its
+ * objective and subjective credentials
*/
int copy_creds(struct task_struct *p, unsigned long clone_flags)
{
@@ -284,6 +289,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
mutex_init(&p->cred_exec_mutex);

if (!p->cred->thread_keyring && clone_flags & CLONE_THREAD) {
+ p->real_cred = get_cred(p->cred);
get_cred(p->cred);
return 0;
}
@@ -322,7 +328,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
#endif

atomic_inc(&new->user->processes);
- p->cred = new;
+ p->cred = p->real_cred = get_cred(new);
return 0;
}

@@ -331,7 +337,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
* @new: The credentials to be assigned
*
* Install a new set of credentials to the current task, using RCU to replace
- * the old set.
+ * the old set. Both the objective and the subjective credentials pointers are
+ * updated. This function may not be called if the subjective credentials are
+ * in an overridden state.
*
* This function eats the caller's reference to the new credentials.
*
@@ -343,12 +351,15 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old;

+ BUG_ON(task->cred != task->real_cred);
+ BUG_ON(atomic_read(&task->real_cred->usage) < 2);
BUG_ON(atomic_read(&new->usage) < 1);
- BUG_ON(atomic_read(&task->cred->usage) < 1);

- old = task->cred;
+ old = task->real_cred;
security_commit_creds(new, old);

+ get_cred(new); /* we will require a ref for the subj creds too */
+
/* dumpability changes */
if (old->euid != new->euid ||
old->egid != new->egid ||
@@ -374,6 +385,7 @@ int commit_creds(struct cred *new)
*/
if (new->user != old->user)
atomic_inc(&new->user->processes);
+ rcu_assign_pointer(task->real_cred, new);
rcu_assign_pointer(task->cred, new);
if (new->user != old->user)
atomic_dec(&old->user->processes);
@@ -393,6 +405,8 @@ int commit_creds(struct cred *new)
new->fsgid != old->fsgid)
proc_id_connector(task, PROC_EVENT_GID);

+ /* release the old obj and subj refs both */
+ put_cred(old);
put_cred(old);
return 0;
}
@@ -413,11 +427,11 @@ void abort_creds(struct cred *new)
EXPORT_SYMBOL(abort_creds);

/**
- * override_creds - Temporarily override the current process's credentials
+ * override_creds - Override the current process's subjective credentials
* @new: The credentials to be assigned
*
- * Install a set of temporary override credentials on the current process,
- * returning the old set for later reversion.
+ * Install a set of temporary override subjective credentials on the current
+ * process, returning the old set for later reversion.
*/
const struct cred *override_creds(const struct cred *new)
{
@@ -429,11 +443,11 @@ const struct cred *override_creds(const struct cred *new)
EXPORT_SYMBOL(override_creds);

/**
- * revert_creds - Revert a temporary credentials override
+ * revert_creds - Revert a temporary subjective credentials override
* @old: The credentials to be restored
*
- * Revert a temporary set of override credentials to an old set, discarding the
- * override set.
+ * Revert a temporary set of override subjective credentials to an old set,
+ * discarding the override set.
*/
extern void revert_creds(const struct cred *old)
{
diff --git a/kernel/fork.c b/kernel/fork.c
index a7cf83a..e65f424 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -145,6 +145,7 @@ void __put_task_struct(struct task_struct *tsk)
WARN_ON(atomic_read(&tsk->usage));
WARN_ON(tsk == current);

+ put_cred(tsk->real_cred);
put_cred(tsk->cred);
delayacct_tsk_free(tsk);

@@ -929,10 +930,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
retval = -EAGAIN;
- if (atomic_read(&p->cred->user->processes) >=
+ if (atomic_read(&p->real_cred->user->processes) >=
p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
- p->cred->user != current->nsproxy->user_ns->root_user)
+ p->real_cred->user != current->nsproxy->user_ns->root_user)
goto bad_fork_free;
}

@@ -1263,6 +1264,7 @@ bad_fork_cleanup_put_domain:
module_put(task_thread_info(p)->exec_domain->module);
bad_fork_cleanup_count:
atomic_dec(&p->cred->user->processes);
+ put_cred(p->real_cred);
put_cred(p->cred);
bad_fork_free:
free_task(p);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f934830..14067df 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -160,7 +160,7 @@ static int selinux_secmark_enabled(void)
*/
static void cred_init_security(void)
{
- struct cred *cred = (struct cred *) current->cred;
+ struct cred *cred = (struct cred *) current->real_cred;
struct task_security_struct *tsec;

tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
@@ -183,7 +183,7 @@ static inline u32 cred_sid(const struct cred *cred)
}

/*
- * get the security ID of a task
+ * get the objective security ID of a task
*/
static inline u32 task_sid(const struct task_struct *task)
{
@@ -196,7 +196,7 @@ static inline u32 task_sid(const struct task_struct *task)
}

/*
- * get the security ID of the current task
+ * get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
@@ -1393,6 +1393,7 @@ static int cred_has_perm(const struct cred *actor,
* Check permission between a pair of tasks, e.g. signal checks,
* fork check, ptrace check, etc.
* tsk1 is the actor and tsk2 is the target
+ * - this uses the default subjective creds of tsk1
*/
static int task_has_perm(const struct task_struct *tsk1,
const struct task_struct *tsk2,
@@ -1408,6 +1409,22 @@ static int task_has_perm(const struct task_struct *tsk1,
return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
}

+/*
+ * Check permission between current and another task, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * current is the actor and tsk2 is the target
+ * - this uses current's subjective creds
+ */
+static int current_has_perm(const struct task_struct *tsk,
+ u32 perms)
+{
+ u32 sid, tsid;
+
+ sid = current_sid();
+ tsid = task_sid(tsk);
+ return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
+}
+
#if CAP_LAST_CAP > 63
#error Fix SELinux to handle capabilities > 63.
#endif
@@ -1798,7 +1815,7 @@ static int selinux_ptrace_may_access(struct task_struct *child,
return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
}

- return task_has_perm(current, child, PROCESS__PTRACE);
+ return current_has_perm(child, PROCESS__PTRACE);
}

static int selinux_ptrace_traceme(struct task_struct *parent)
@@ -1817,7 +1834,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
{
int error;

- error = task_has_perm(current, target, PROCESS__GETCAP);
+ error = current_has_perm(target, PROCESS__GETCAP);
if (error)
return error;

@@ -3076,7 +3093,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
} else if (!vma->vm_file &&
vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack) {
- rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+ rc = current_has_perm(current, PROCESS__EXECSTACK);
} else if (vma->vm_file && vma->anon_vma) {
/*
* We are making executable a file mapping that has
@@ -3225,7 +3242,7 @@ static int selinux_task_create(unsigned long clone_flags)
if (rc)
return rc;

- return task_has_perm(current, current, PROCESS__FORK);
+ return current_has_perm(current, PROCESS__FORK);
}

/*
@@ -3290,17 +3307,17 @@ static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)

static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return task_has_perm(current, p, PROCESS__SETPGID);
+ return current_has_perm(p, PROCESS__SETPGID);
}

static int selinux_task_getpgid(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETPGID);
+ return current_has_perm(p, PROCESS__GETPGID);
}

static int selinux_task_getsid(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETSESSION);
+ return current_has_perm(p, PROCESS__GETSESSION);
}

static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
@@ -3322,7 +3339,7 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
if (rc)
return rc;

- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}

static int selinux_task_setioprio(struct task_struct *p, int ioprio)
@@ -3333,12 +3350,12 @@ static int selinux_task_setioprio(struct task_struct *p, int ioprio)
if (rc)
return rc;

- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}

static int selinux_task_getioprio(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETSCHED);
+ return current_has_perm(p, PROCESS__GETSCHED);
}

static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
@@ -3355,7 +3372,7 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return task_has_perm(current, current, PROCESS__SETRLIMIT);
+ return current_has_perm(current, PROCESS__SETRLIMIT);

return 0;
}
@@ -3368,17 +3385,17 @@ static int selinux_task_setscheduler(struct task_struct *p, int policy, struct s
if (rc)
return rc;

- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}

static int selinux_task_getscheduler(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETSCHED);
+ return current_has_perm(p, PROCESS__GETSCHED);
}

static int selinux_task_movememory(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}

static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
@@ -3399,7 +3416,7 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
rc = avc_has_perm(secid, task_sid(p),
SECCLASS_PROCESS, perm, NULL);
else
- rc = task_has_perm(current, p, perm);
+ rc = current_has_perm(p, perm);
return rc;
}

@@ -5154,7 +5171,7 @@ static int selinux_getprocattr(struct task_struct *p,
unsigned len;

if (current != p) {
- error = task_has_perm(current, p, PROCESS__GETATTR);
+ error = current_has_perm(p, PROCESS__GETATTR);
if (error)
return error;
}
@@ -5213,15 +5230,15 @@ static int selinux_setprocattr(struct task_struct *p,
* above restriction is ever removed.
*/
if (!strcmp(name, "exec"))
- error = task_has_perm(current, p, PROCESS__SETEXEC);
+ error = current_has_perm(p, PROCESS__SETEXEC);
else if (!strcmp(name, "fscreate"))
- error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+ error = current_has_perm(p, PROCESS__SETFSCREATE);
else if (!strcmp(name, "keycreate"))
- error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+ error = current_has_perm(p, PROCESS__SETKEYCREATE);
else if (!strcmp(name, "sockcreate"))
- error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
+ error = current_has_perm(p, PROCESS__SETSOCKCREATE);
else if (!strcmp(name, "current"))
- error = task_has_perm(current, p, PROCESS__SETCURRENT);
+ error = current_has_perm(p, PROCESS__SETCURRENT);
else
error = -EINVAL;
if (error)

2008-08-06 15:49:31

by David Howells

[permalink] [raw]
Subject: [PATCH 01/24] Fix setting of PF_SUPERPRIV by __capable() [ver #7]

Fix the setting of PF_SUPERPRIV by __capable() as it could corrupt the flags
the target process if that is not the current process and it is trying to
change its own flags in a different way at the same time.

__capable() is using neither atomic ops nor locking to protect t->flags. This
patch removes __capable() and introduces has_capability() that doesn't set
PF_SUPERPRIV on the process being queried.

This patch further splits security_ptrace() in two:

(1) security_ptrace_may_access(). This passes judgement on whether one
process may access another only (PTRACE_MODE_ATTACH for ptrace() and
PTRACE_MODE_READ for /proc), and takes a pointer to the child process.
current is the parent.

(2) security_ptrace_traceme(). This passes judgement on PTRACE_TRACEME only,
and takes only a pointer to the parent process. current is the child.

In Smack and commoncap, this uses has_capability() to determine whether
the parent will be permitted to use PTRACE_ATTACH if normal checks fail.
This does not set PF_SUPERPRIV.


Two of the instances of __capable() actually only act on current, and so have
been changed to calls to capable().

Of the places that were using __capable():

(1) The OOM killer calls __capable() thrice when weighing the killability of a
process. All of these now use has_capability().

(2) cap_ptrace() and smack_ptrace() were using __capable() to check to see
whether the parent was allowed to trace any process. As mentioned above,
these have been split. For PTRACE_ATTACH and /proc, capable() is now
used, and for PTRACE_TRACEME, has_capability() is used.

(3) cap_safe_nice() only ever saw current, so now uses capable().

(4) smack_setprocattr() rejected accesses to tasks other than current just
after calling __capable(), so the order of these two tests have been
switched and capable() is used instead.

(5) In smack_file_send_sigiotask(), we need to allow privileged processes to
receive SIGIO on files they're manipulating.

(6) In smack_task_wait(), we let a process wait for a privileged process,
whether or not the process doing the waiting is privileged.

I've tested this with the LTP SELinux and syscalls testscripts.

Signed-off-by: David Howells <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Acked-by: Casey Schaufler <[email protected]>
Acked-by: Andrew G. Morgan <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Al Viro <[email protected]>
---

include/linux/capability.h | 15 ++++++++++++-
include/linux/security.h | 39 ++++++++++++++++++++++-------------
kernel/capability.c | 21 ++++++++++++-------
kernel/ptrace.c | 5 ++--
mm/oom_kill.c | 6 ++++-
security/capability.c | 3 ++-
security/commoncap.c | 24 +++++++++++++++-------
security/root_plug.c | 3 ++-
security/security.c | 10 ++++++---
security/selinux/hooks.c | 25 ++++++++++++++++------
security/smack/smack_lsm.c | 49 +++++++++++++++++++++++++++++++-------------
11 files changed, 137 insertions(+), 63 deletions(-)


diff --git a/include/linux/capability.h b/include/linux/capability.h
index 0267384..9d1fe30 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -503,8 +503,19 @@ extern const kernel_cap_t __cap_init_eff_set;

kernel_cap_t cap_set_effective(const kernel_cap_t pE_new);

-int capable(int cap);
-int __capable(struct task_struct *t, int cap);
+/**
+ * has_capability - Determine if a task has a superior capability available
+ * @t: The task in question
+ * @cap: The capability to be tested for
+ *
+ * Return true if the specified task has the given superior capability
+ * currently in effect, false if not.
+ *
+ * Note that this does not set PF_SUPERPRIV on the task.
+ */
+#define has_capability(t, cap) (security_capable((t), (cap)) == 0)
+
+extern int capable(int cap);

#endif /* __KERNEL__ */

diff --git a/include/linux/security.h b/include/linux/security.h
index fd96e7f..80c4d00 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -46,8 +46,8 @@ struct audit_krule;
*/
extern int cap_capable(struct task_struct *tsk, int cap);
extern int cap_settime(struct timespec *ts, struct timezone *tz);
-extern int cap_ptrace(struct task_struct *parent, struct task_struct *child,
- unsigned int mode);
+extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
+extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@ -1157,17 +1157,24 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @alter contains the flag indicating whether changes are to be made.
* Return 0 if permission is granted.
*
- * @ptrace:
- * Check permission before allowing the @parent process to trace the
+ * @ptrace_may_access:
+ * Check permission before allowing the current process to trace the
* @child process.
* Security modules may also want to perform a process tracing check
* during an execve in the set_security or apply_creds hooks of
* binprm_security_ops if the process is being traced and its security
* attributes would be changed by the execve.
- * @parent contains the task_struct structure for parent process.
- * @child contains the task_struct structure for child process.
+ * @child contains the task_struct structure for the target process.
* @mode contains the PTRACE_MODE flags indicating the form of access.
* Return 0 if permission is granted.
+ * @ptrace_traceme:
+ * Check that the @parent process has sufficient permission to trace the
+ * current process before allowing the current process to present itself
+ * to the @parent process for tracing.
+ * The parent process will still have to undergo the ptrace_may_access
+ * checks before it is allowed to trace this one.
+ * @parent contains the task_struct structure for debugger process.
+ * Return 0 if permission is granted.
* @capget:
* Get the @effective, @inheritable, and @permitted capability sets for
* the @target process. The hook may also perform permission checking to
@@ -1287,8 +1294,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
struct security_operations {
char name[SECURITY_NAME_MAX + 1];

- int (*ptrace) (struct task_struct *parent, struct task_struct *child,
- unsigned int mode);
+ int (*ptrace_may_access) (struct task_struct *child, unsigned int mode);
+ int (*ptrace_traceme) (struct task_struct *parent);
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@ -1560,8 +1567,8 @@ extern struct dentry *securityfs_create_dir(const char *name, struct dentry *par
extern void securityfs_remove(struct dentry *dentry);

/* Security operations */
-int security_ptrace(struct task_struct *parent, struct task_struct *child,
- unsigned int mode);
+int security_ptrace_may_access(struct task_struct *child, unsigned int mode);
+int security_ptrace_traceme(struct task_struct *parent);
int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
@@ -1742,11 +1749,15 @@ static inline int security_init(void)
return 0;
}

-static inline int security_ptrace(struct task_struct *parent,
- struct task_struct *child,
- unsigned int mode)
+static inline int security_ptrace_may_access(struct task_struct *child,
+ unsigned int mode)
+{
+ return cap_ptrace_may_access(child, mode);
+}
+
+static inline int security_ptrace_traceme(struct task_struct *parent)
{
- return cap_ptrace(parent, child, mode);
+ return cap_ptrace_traceme(parent);
}

static inline int security_capget(struct task_struct *target,
diff --git a/kernel/capability.c b/kernel/capability.c
index 0101e84..33e51e7 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -486,17 +486,22 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
return ret;
}

-int __capable(struct task_struct *t, int cap)
+/**
+ * capable - Determine if the current task has a superior capability in effect
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+int capable(int cap)
{
- if (security_capable(t, cap) == 0) {
- t->flags |= PF_SUPERPRIV;
+ if (has_capability(current, cap)) {
+ current->flags |= PF_SUPERPRIV;
return 1;
}
return 0;
}
-
-int capable(int cap)
-{
- return __capable(current, cap);
-}
EXPORT_SYMBOL(capable);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 082b3fc..356699a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -140,7 +140,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;

- return security_ptrace(current, task, mode);
+ return security_ptrace_may_access(task, mode);
}

bool ptrace_may_access(struct task_struct *task, unsigned int mode)
@@ -499,8 +499,7 @@ repeat:
goto repeat;
}

- ret = security_ptrace(current->parent, current,
- PTRACE_MODE_ATTACH);
+ ret = security_ptrace_traceme(current->parent);

/*
* Set the ptrace bit in the process ptrace flags.
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 8a5467e..64e5b4b 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/memcontrol.h>
+#include <linux/security.h>

int sysctl_panic_on_oom;
int sysctl_oom_kill_allocating_task;
@@ -128,7 +129,8 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
* Superuser processes are usually more important, so we make it
* less likely that we kill those.
*/
- if (__capable(p, CAP_SYS_ADMIN) || __capable(p, CAP_SYS_RESOURCE))
+ if (has_capability(p, CAP_SYS_ADMIN) ||
+ has_capability(p, CAP_SYS_RESOURCE))
points /= 4;

/*
@@ -137,7 +139,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
* tend to only have this flag set on applications they think
* of as important.
*/
- if (__capable(p, CAP_SYS_RAWIO))
+ if (has_capability(p, CAP_SYS_RAWIO))
points /= 4;

/*
diff --git a/security/capability.c b/security/capability.c
index 63d10da..2458748 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -811,7 +811,8 @@ struct security_operations default_security_ops = {

void security_fixup_ops(struct security_operations *ops)
{
- set_to_cap_if_null(ops, ptrace);
+ set_to_cap_if_null(ops, ptrace_may_access);
+ set_to_cap_if_null(ops, ptrace_traceme);
set_to_cap_if_null(ops, capget);
set_to_cap_if_null(ops, capset_check);
set_to_cap_if_null(ops, capset_set);
diff --git a/security/commoncap.c b/security/commoncap.c
index 4afbece..e4c4b3f 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -63,14 +63,24 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
return 0;
}

-int cap_ptrace (struct task_struct *parent, struct task_struct *child,
- unsigned int mode)
+int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
{
/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
- if (!cap_issubset(child->cap_permitted, parent->cap_permitted) &&
- !__capable(parent, CAP_SYS_PTRACE))
- return -EPERM;
- return 0;
+ if (cap_issubset(child->cap_permitted, current->cap_permitted))
+ return 0;
+ if (capable(CAP_SYS_PTRACE))
+ return 0;
+ return -EPERM;
+}
+
+int cap_ptrace_traceme(struct task_struct *parent)
+{
+ /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
+ if (cap_issubset(current->cap_permitted, parent->cap_permitted))
+ return 0;
+ if (has_capability(parent, CAP_SYS_PTRACE))
+ return 0;
+ return -EPERM;
}

int cap_capget (struct task_struct *target, kernel_cap_t *effective,
@@ -534,7 +544,7 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
static inline int cap_safe_nice(struct task_struct *p)
{
if (!cap_issubset(p->cap_permitted, current->cap_permitted) &&
- !__capable(current, CAP_SYS_NICE))
+ !capable(CAP_SYS_NICE))
return -EPERM;
return 0;
}
diff --git a/security/root_plug.c b/security/root_plug.c
index be0ebec..c3f68b5 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -72,7 +72,8 @@ static int rootplug_bprm_check_security (struct linux_binprm *bprm)

static struct security_operations rootplug_security_ops = {
/* Use the capability functions for some of the hooks */
- .ptrace = cap_ptrace,
+ .ptrace_may_access = cap_ptrace_may_access,
+ .ptrace_traceme = cap_ptrace_traceme,
.capget = cap_capget,
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
diff --git a/security/security.c b/security/security.c
index ff70687..3a4b4f5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -127,10 +127,14 @@ int register_security(struct security_operations *ops)

/* Security operations */

-int security_ptrace(struct task_struct *parent, struct task_struct *child,
- unsigned int mode)
+int security_ptrace_may_access(struct task_struct *child, unsigned int mode)
{
- return security_ops->ptrace(parent, child, mode);
+ return security_ops->ptrace_may_access(child, mode);
+}
+
+int security_ptrace_traceme(struct task_struct *parent)
+{
+ return security_ops->ptrace_traceme(parent);
}

int security_capget(struct task_struct *target,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3eae306..6b5790b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1739,24 +1739,34 @@ static inline u32 file_to_av(struct file *file)

/* Hook functions begin here. */

-static int selinux_ptrace(struct task_struct *parent,
- struct task_struct *child,
- unsigned int mode)
+static int selinux_ptrace_may_access(struct task_struct *child,
+ unsigned int mode)
{
int rc;

- rc = secondary_ops->ptrace(parent, child, mode);
+ rc = secondary_ops->ptrace_may_access(child, mode);
if (rc)
return rc;

if (mode == PTRACE_MODE_READ) {
- struct task_security_struct *tsec = parent->security;
+ struct task_security_struct *tsec = current->security;
struct task_security_struct *csec = child->security;
return avc_has_perm(tsec->sid, csec->sid,
SECCLASS_FILE, FILE__READ, NULL);
}

- return task_has_perm(parent, child, PROCESS__PTRACE);
+ return task_has_perm(current, child, PROCESS__PTRACE);
+}
+
+static int selinux_ptrace_traceme(struct task_struct *parent)
+{
+ int rc;
+
+ rc = secondary_ops->ptrace_traceme(parent);
+ if (rc)
+ return rc;
+
+ return task_has_perm(parent, current, PROCESS__PTRACE);
}

static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
@@ -5353,7 +5363,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
static struct security_operations selinux_ops = {
.name = "selinux",

- .ptrace = selinux_ptrace,
+ .ptrace_may_access = selinux_ptrace_may_access,
+ .ptrace_traceme = selinux_ptrace_traceme,
.capget = selinux_capget,
.capset_check = selinux_capset_check,
.capset_set = selinux_capset_set,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 1b40e55..87d7541 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -87,27 +87,46 @@ struct inode_smack *new_inode_smack(char *smack)
*/

/**
- * smack_ptrace - Smack approval on ptrace
- * @ptp: parent task pointer
+ * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH
* @ctp: child task pointer
*
* Returns 0 if access is OK, an error code otherwise
*
* Do the capability checks, and require read and write.
*/
-static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp,
- unsigned int mode)
+static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
{
int rc;

- rc = cap_ptrace(ptp, ctp, mode);
+ rc = cap_ptrace_may_access(ctp, mode);
if (rc != 0)
return rc;

- rc = smk_access(ptp->security, ctp->security, MAY_READWRITE);
- if (rc != 0 && __capable(ptp, CAP_MAC_OVERRIDE))
+ rc = smk_access(current->security, ctp->security, MAY_READWRITE);
+ if (rc != 0 && capable(CAP_MAC_OVERRIDE))
return 0;
+ return rc;
+}
+
+/**
+ * smack_ptrace_traceme - Smack approval on PTRACE_TRACEME
+ * @ptp: parent task pointer
+ *
+ * Returns 0 if access is OK, an error code otherwise
+ *
+ * Do the capability checks, and require read and write.
+ */
+static int smack_ptrace_traceme(struct task_struct *ptp)
+{
+ int rc;
+
+ rc = cap_ptrace_traceme(ptp);
+ if (rc != 0)
+ return rc;

+ rc = smk_access(ptp->security, current->security, MAY_READWRITE);
+ if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
+ return 0;
return rc;
}

@@ -923,7 +942,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
*/
file = container_of(fown, struct file, f_owner);
rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
- if (rc != 0 && __capable(tsk, CAP_MAC_OVERRIDE))
+ if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
return 0;
return rc;
}
@@ -1164,12 +1183,12 @@ static int smack_task_wait(struct task_struct *p)
* account for the smack labels having gotten to
* be different in the first place.
*
- * This breaks the strict subjet/object access
+ * This breaks the strict subject/object access
* control ideal, taking the object's privilege
* state into account in the decision as well as
* the smack value.
*/
- if (capable(CAP_MAC_OVERRIDE) || __capable(p, CAP_MAC_OVERRIDE))
+ if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE))
return 0;

return rc;
@@ -2016,9 +2035,6 @@ static int smack_setprocattr(struct task_struct *p, char *name,
{
char *newsmack;

- if (!__capable(p, CAP_MAC_ADMIN))
- return -EPERM;
-
/*
* Changing another process' Smack value is too dangerous
* and supports no sane use case.
@@ -2026,6 +2042,9 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (p != current)
return -EPERM;

+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
if (value == NULL || size == 0 || size >= SMK_LABELLEN)
return -EINVAL;

@@ -2552,7 +2571,8 @@ static void smack_release_secctx(char *secdata, u32 seclen)
struct security_operations smack_ops = {
.name = "smack",

- .ptrace = smack_ptrace,
+ .ptrace_may_access = smack_ptrace_may_access,
+ .ptrace_traceme = smack_ptrace_traceme,
.capget = cap_capget,
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
@@ -2729,4 +2749,3 @@ static __init int smack_init(void)
* all processes and objects when they are created.
*/
security_initcall(smack_init);
-

2008-08-06 15:49:51

by David Howells

[permalink] [raw]
Subject: [PATCH 02/24] KEYS: Disperse linux/key_ui.h [ver #7]

Disperse the bits of linux/key_ui.h as the reason they were put here (keyfs)
didn't get in.

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
---

include/keys/keyring-type.h | 31 ++++++++++++++++++++
include/linux/key-ui.h | 66 -------------------------------------------
security/keys/internal.h | 31 ++++++++++++++++++++
security/keys/keyring.c | 1 +
security/keys/request_key.c | 2 +
5 files changed, 64 insertions(+), 67 deletions(-)
create mode 100644 include/keys/keyring-type.h
delete mode 100644 include/linux/key-ui.h


diff --git a/include/keys/keyring-type.h b/include/keys/keyring-type.h
new file mode 100644
index 0000000..843f872
--- /dev/null
+++ b/include/keys/keyring-type.h
@@ -0,0 +1,31 @@
+/* Keyring key type
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _KEYS_KEYRING_TYPE_H
+#define _KEYS_KEYRING_TYPE_H
+
+#include <linux/key.h>
+#include <linux/rcupdate.h>
+
+/*
+ * the keyring payload contains a list of the keys to which the keyring is
+ * subscribed
+ */
+struct keyring_list {
+ struct rcu_head rcu; /* RCU deletion hook */
+ unsigned short maxkeys; /* max keys this list can hold */
+ unsigned short nkeys; /* number of keys currently held */
+ unsigned short delkey; /* key to be unlinked by RCU */
+ struct key *keys[0];
+};
+
+
+#endif /* _KEYS_KEYRING_TYPE_H */
diff --git a/include/linux/key-ui.h b/include/linux/key-ui.h
deleted file mode 100644
index e8b8a7a..0000000
--- a/include/linux/key-ui.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* key-ui.h: key userspace interface stuff
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells ([email protected])
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_KEY_UI_H
-#define _LINUX_KEY_UI_H
-
-#include <linux/key.h>
-
-/* the key tree */
-extern struct rb_root key_serial_tree;
-extern spinlock_t key_serial_lock;
-
-/* required permissions */
-#define KEY_VIEW 0x01 /* require permission to view attributes */
-#define KEY_READ 0x02 /* require permission to read content */
-#define KEY_WRITE 0x04 /* require permission to update / modify */
-#define KEY_SEARCH 0x08 /* require permission to search (keyring) or find (key) */
-#define KEY_LINK 0x10 /* require permission to link */
-#define KEY_SETATTR 0x20 /* require permission to change attributes */
-#define KEY_ALL 0x3f /* all the above permissions */
-
-/*
- * the keyring payload contains a list of the keys to which the keyring is
- * subscribed
- */
-struct keyring_list {
- struct rcu_head rcu; /* RCU deletion hook */
- unsigned short maxkeys; /* max keys this list can hold */
- unsigned short nkeys; /* number of keys currently held */
- unsigned short delkey; /* key to be unlinked by RCU */
- struct key *keys[0];
-};
-
-/*
- * check to see whether permission is granted to use a key in the desired way
- */
-extern int key_task_permission(const key_ref_t key_ref,
- struct task_struct *context,
- key_perm_t perm);
-
-static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
-{
- return key_task_permission(key_ref, current, perm);
-}
-
-extern key_ref_t lookup_user_key(struct task_struct *context,
- key_serial_t id, int create, int partial,
- key_perm_t perm);
-
-extern long join_session_keyring(const char *name);
-
-extern struct key_type *key_type_lookup(const char *type);
-extern void key_type_put(struct key_type *ktype);
-
-#define key_negative_timeout 60 /* default timeout on a negative key's existence */
-
-
-#endif /* _LINUX_KEY_UI_H */
diff --git a/security/keys/internal.h b/security/keys/internal.h
index b39f5c2..a60c681 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -13,7 +13,6 @@
#define _INTERNAL_H

#include <linux/key-type.h>
-#include <linux/key-ui.h>

static inline __attribute__((format(printf, 1, 2)))
void no_printk(const char *fmt, ...)
@@ -82,6 +81,9 @@ extern struct mutex key_construction_mutex;
extern wait_queue_head_t request_key_conswq;


+extern struct key_type *key_type_lookup(const char *type);
+extern void key_type_put(struct key_type *ktype);
+
extern int __key_link(struct key *keyring, struct key *key);

extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
@@ -118,6 +120,33 @@ extern struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring,
unsigned long flags);

+extern key_ref_t lookup_user_key(struct task_struct *context,
+ key_serial_t id, int create, int partial,
+ key_perm_t perm);
+
+extern long join_session_keyring(const char *name);
+
+/*
+ * check to see whether permission is granted to use a key in the desired way
+ */
+extern int key_task_permission(const key_ref_t key_ref,
+ struct task_struct *context,
+ key_perm_t perm);
+
+static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
+{
+ return key_task_permission(key_ref, current, perm);
+}
+
+/* required permissions */
+#define KEY_VIEW 0x01 /* require permission to view attributes */
+#define KEY_READ 0x02 /* require permission to read content */
+#define KEY_WRITE 0x04 /* require permission to update / modify */
+#define KEY_SEARCH 0x08 /* require permission to search (keyring) or find (key) */
+#define KEY_LINK 0x10 /* require permission to link */
+#define KEY_SETATTR 0x20 /* require permission to change attributes */
+#define KEY_ALL 0x3f /* all the above permissions */
+
/*
* request_key authorisation
*/
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index a9ab8af..fdf75f9 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -16,6 +16,7 @@
#include <linux/security.h>
#include <linux/seq_file.h>
#include <linux/err.h>
+#include <keys/keyring-type.h>
#include <asm/uaccess.h>
#include "internal.h"

diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index ba32ca6..b9e50a9 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -19,6 +19,8 @@
#include <linux/slab.h>
#include "internal.h"

+#define key_negative_timeout 60 /* default timeout on a negative key's existence */
+
/*
* wait_on_bit() sleep function for uninterruptible waiting
*/

2008-08-06 15:50:22

by David Howells

[permalink] [raw]
Subject: [PATCH 05/24] CRED: Constify the kernel_cap_t arguments to the capset LSM hooks [ver #7]

Constify the kernel_cap_t arguments to the capset LSM hooks.

Signed-off-by: David Howells <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Acked-by: James Morris <[email protected]>
---

include/linux/security.h | 44 ++++++++++++++++++++++++--------------------
security/commoncap.c | 10 ++++++----
security/security.c | 12 ++++++------
security/selinux/hooks.c | 10 ++++++----
4 files changed, 42 insertions(+), 34 deletions(-)


diff --git a/include/linux/security.h b/include/linux/security.h
index dc23a3d..c3eed5a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -49,8 +49,12 @@ extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_capset_check(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern void cap_capset_set(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+extern int cap_capset_check(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
+extern void cap_capset_set(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
extern int cap_bprm_set_security(struct linux_binprm *bprm);
extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
@@ -1289,12 +1293,12 @@ struct security_operations {
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
- int (*capset_check) (kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted);
- void (*capset_set) (kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted);
+ int (*capset_check) (const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
+ void (*capset_set) (const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, int cap);
int (*acct) (struct file *file);
int (*sysctl) (struct ctl_table *table, int op);
@@ -1561,12 +1565,12 @@ int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
-int security_capset_check(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted);
-void security_capset_set(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted);
+int security_capset_check(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
+void security_capset_set(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
int security_capable(struct task_struct *tsk, int cap);
int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op);
@@ -1754,16 +1758,16 @@ static inline int security_capget(struct task_struct *target,
return cap_capget(target, effective, inheritable, permitted);
}

-static inline int security_capset_check(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+static inline int security_capset_check(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
return cap_capset_check(effective, inheritable, permitted);
}

-static inline void security_capset_set(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+static inline void security_capset_set(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
cap_capset_set(effective, inheritable, permitted);
}
diff --git a/security/commoncap.c b/security/commoncap.c
index 059a131..40e8b83 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -117,8 +117,9 @@ static inline int cap_limit_ptraced_target(void)

#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */

-int cap_capset_check (kernel_cap_t *effective,
- kernel_cap_t *inheritable, kernel_cap_t *permitted)
+int cap_capset_check(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
if (cap_inh_is_capped()
&& !cap_issubset(*inheritable,
@@ -149,8 +150,9 @@ int cap_capset_check (kernel_cap_t *effective,
return 0;
}

-void cap_capset_set (kernel_cap_t *effective,
- kernel_cap_t *inheritable, kernel_cap_t *permitted)
+void cap_capset_set(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
current->cap_effective = *effective;
current->cap_inheritable = *inheritable;
diff --git a/security/security.c b/security/security.c
index 78502ac..c2203f5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -145,16 +145,16 @@ int security_capget(struct task_struct *target,
return security_ops->capget(target, effective, inheritable, permitted);
}

-int security_capset_check(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+int security_capset_check(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
return security_ops->capset_check(effective, inheritable, permitted);
}

-void security_capset_set(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+void security_capset_set(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
security_ops->capset_set(effective, inheritable, permitted);
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b040887..9cc59f6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1781,8 +1781,9 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
return secondary_ops->capget(target, effective, inheritable, permitted);
}

-static int selinux_capset_check(kernel_cap_t *effective,
- kernel_cap_t *inheritable, kernel_cap_t *permitted)
+static int selinux_capset_check(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
int error;

@@ -1793,8 +1794,9 @@ static int selinux_capset_check(kernel_cap_t *effective,
return task_has_perm(current, current, PROCESS__SETCAP);
}

-static void selinux_capset_set(kernel_cap_t *effective,
- kernel_cap_t *inheritable, kernel_cap_t *permitted)
+static void selinux_capset_set(const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted)
{
secondary_ops->capset_set(effective, inheritable, permitted);
}

2008-08-06 15:50:45

by David Howells

[permalink] [raw]
Subject: [PATCH 04/24] CRED: Neuter sys_capset() [ver #7]

Take away the ability for sys_capset() to affect processes other than current.

This means that current will not need to lock its own credentials when reading
them against interference by other processes.

This has effectively been the case for a while anyway, since:

(1) Without LSM enabled, sys_capset() is disallowed.

(2) With file-based capabilities, sys_capset() is neutered.

Signed-off-by: David Howells <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Acked-by: Andrew G. Morgan <[email protected]>
Acked-by: James Morris <[email protected]>
---

fs/open.c | 12 ---
include/linux/security.h | 48 +++-------
kernel/capability.c | 215 +++-------------------------------------------
security/commoncap.c | 29 ++----
security/security.c | 18 ++--
security/selinux/hooks.c | 10 +-
6 files changed, 52 insertions(+), 280 deletions(-)


diff --git a/fs/open.c b/fs/open.c
index 07da935..0f410b1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -441,17 +441,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
current->fsgid = current->gid;

if (!issecure(SECURE_NO_SETUID_FIXUP)) {
- /*
- * Clear the capabilities if we switch to a non-root user
- */
-#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
- /*
- * FIXME: There is a race here against sys_capset. The
- * capabilities can change yet we will restore the old
- * value below. We should hold task_capabilities_lock,
- * but we cannot because user_path_at can sleep.
- */
-#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
+ /* Clear the capabilities if we switch to a non-root user */
if (current->uid)
old_cap = cap_set_effective(__cap_empty_set);
else
diff --git a/include/linux/security.h b/include/linux/security.h
index 80c4d00..dc23a3d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -49,8 +49,8 @@ extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+extern int cap_capset_check(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
+extern void cap_capset_set(kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_bprm_set_security(struct linux_binprm *bprm);
extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
@@ -1187,24 +1187,14 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return 0 if the capability sets were successfully obtained.
* @capset_check:
* Check permission before setting the @effective, @inheritable, and
- * @permitted capability sets for the @target process.
- * Caveat: @target is also set to current if a set of processes is
- * specified (i.e. all processes other than current and init or a
- * particular process group). Hence, the capset_set hook may need to
- * revalidate permission to the actual target process.
- * @target contains the task_struct structure for target process.
+ * @permitted capability sets for the current process.
* @effective contains the effective capability set.
* @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set.
* Return 0 if permission is granted.
* @capset_set:
* Set the @effective, @inheritable, and @permitted capability sets for
- * the @target process. Since capset_check cannot always check permission
- * to the real @target process, this hook may also perform permission
- * checking to determine if the current process is allowed to set the
- * capability sets of the @target process. However, this hook has no way
- * of returning an error due to the structure of the sys_capset code.
- * @target contains the task_struct structure for target process.
+ * the current process.
* @effective contains the effective capability set.
* @inheritable contains the inheritable capability set.
* @permitted contains the permitted capability set.
@@ -1299,12 +1289,10 @@ struct security_operations {
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
- int (*capset_check) (struct task_struct *target,
- kernel_cap_t *effective,
+ int (*capset_check) (kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
- void (*capset_set) (struct task_struct *target,
- kernel_cap_t *effective,
+ void (*capset_set) (kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
int (*capable) (struct task_struct *tsk, int cap);
@@ -1573,12 +1561,10 @@ int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
-int security_capset_check(struct task_struct *target,
- kernel_cap_t *effective,
+int security_capset_check(kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
-void security_capset_set(struct task_struct *target,
- kernel_cap_t *effective,
+void security_capset_set(kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
int security_capable(struct task_struct *tsk, int cap);
@@ -1768,20 +1754,18 @@ static inline int security_capget(struct task_struct *target,
return cap_capget(target, effective, inheritable, permitted);
}

-static inline int security_capset_check(struct task_struct *target,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+static inline int security_capset_check(kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted)
{
- return cap_capset_check(target, effective, inheritable, permitted);
+ return cap_capset_check(effective, inheritable, permitted);
}

-static inline void security_capset_set(struct task_struct *target,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+static inline void security_capset_set(kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted)
{
- cap_capset_set(target, effective, inheritable, permitted);
+ cap_capset_set(effective, inheritable, permitted);
}

static inline int security_capable(struct task_struct *tsk, int cap)
diff --git a/kernel/capability.c b/kernel/capability.c
index 33e51e7..bb96b53 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -115,160 +115,6 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
return 0;
}

-#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
-
-/*
- * Without filesystem capability support, we nominally support one process
- * setting the capabilities of another
- */
-static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
- kernel_cap_t *pIp, kernel_cap_t *pPp)
-{
- struct task_struct *target;
- int ret;
-
- spin_lock(&task_capability_lock);
- read_lock(&tasklist_lock);
-
- if (pid && pid != task_pid_vnr(current)) {
- target = find_task_by_vpid(pid);
- if (!target) {
- ret = -ESRCH;
- goto out;
- }
- } else
- target = current;
-
- ret = security_capget(target, pEp, pIp, pPp);
-
-out:
- read_unlock(&tasklist_lock);
- spin_unlock(&task_capability_lock);
-
- return ret;
-}
-
-/*
- * cap_set_pg - set capabilities for all processes in a given process
- * group. We call this holding task_capability_lock and tasklist_lock.
- */
-static inline int cap_set_pg(int pgrp_nr, kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
-{
- struct task_struct *g, *target;
- int ret = -EPERM;
- int found = 0;
- struct pid *pgrp;
-
- spin_lock(&task_capability_lock);
- read_lock(&tasklist_lock);
-
- pgrp = find_vpid(pgrp_nr);
- do_each_pid_task(pgrp, PIDTYPE_PGID, g) {
- target = g;
- while_each_thread(g, target) {
- if (!security_capset_check(target, effective,
- inheritable, permitted)) {
- security_capset_set(target, effective,
- inheritable, permitted);
- ret = 0;
- }
- found = 1;
- }
- } while_each_pid_task(pgrp, PIDTYPE_PGID, g);
-
- read_unlock(&tasklist_lock);
- spin_unlock(&task_capability_lock);
-
- if (!found)
- ret = 0;
- return ret;
-}
-
-/*
- * cap_set_all - set capabilities for all processes other than init
- * and self. We call this holding task_capability_lock and tasklist_lock.
- */
-static inline int cap_set_all(kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
-{
- struct task_struct *g, *target;
- int ret = -EPERM;
- int found = 0;
-
- spin_lock(&task_capability_lock);
- read_lock(&tasklist_lock);
-
- do_each_thread(g, target) {
- if (target == current
- || is_container_init(target->group_leader))
- continue;
- found = 1;
- if (security_capset_check(target, effective, inheritable,
- permitted))
- continue;
- ret = 0;
- security_capset_set(target, effective, inheritable, permitted);
- } while_each_thread(g, target);
-
- read_unlock(&tasklist_lock);
- spin_unlock(&task_capability_lock);
-
- if (!found)
- ret = 0;
-
- return ret;
-}
-
-/*
- * Given the target pid does not refer to the current process we
- * need more elaborate support... (This support is not present when
- * filesystem capabilities are configured.)
- */
-static inline int do_sys_capset_other_tasks(pid_t pid, kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
-{
- struct task_struct *target;
- int ret;
-
- if (!capable(CAP_SETPCAP))
- return -EPERM;
-
- if (pid == -1) /* all procs other than current and init */
- return cap_set_all(effective, inheritable, permitted);
-
- else if (pid < 0) /* all procs in process group */
- return cap_set_pg(-pid, effective, inheritable, permitted);
-
- /* target != current */
- spin_lock(&task_capability_lock);
- read_lock(&tasklist_lock);
-
- target = find_task_by_vpid(pid);
- if (!target)
- ret = -ESRCH;
- else {
- ret = security_capset_check(target, effective, inheritable,
- permitted);
-
- /* having verified that the proposed changes are legal,
- we now put them into effect. */
- if (!ret)
- security_capset_set(target, effective, inheritable,
- permitted);
- }
-
- read_unlock(&tasklist_lock);
- spin_unlock(&task_capability_lock);
-
- return ret;
-}
-
-#else /* ie., def CONFIG_SECURITY_FILE_CAPABILITIES */
-
/*
* If we have configured with filesystem capability support, then the
* only thing that can change the capabilities of the current process
@@ -303,22 +149,6 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
}

/*
- * With filesystem capability support configured, the kernel does not
- * permit the changing of capabilities in one process by another
- * process. (CAP_SETPCAP has much less broad semantics when configured
- * this way.)
- */
-static inline int do_sys_capset_other_tasks(pid_t pid,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
-{
- return -EPERM;
-}
-
-#endif /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */
-
-/*
* Atomically modify the effective capabilities returning the original
* value. No permission check is performed here - it is assumed that the
* caller is permitted to set the desired effective capabilities.
@@ -412,16 +242,14 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
* @data: pointer to struct that contains the effective, permitted,
* and inheritable capabilities
*
- * Set capabilities for a given process, all processes, or all
- * processes in a given process group.
+ * Set capabilities for the current process only. The ability to any other
+ * process(es) has been deprecated and removed.
*
* The restrictions on setting capabilities are specified as:
*
- * [pid is for the 'target' task. 'current' is the calling task.]
- *
- * I: any raised capabilities must be a subset of the (old current) permitted
- * P: any raised capabilities must be a subset of the (old current) permitted
- * E: must be set to a subset of (new target) permitted
+ * I: any raised capabilities must be a subset of the old permitted
+ * P: any raised capabilities must be a subset of the old permitted
+ * E: must be set to a subset of new permitted
*
* Returns 0 on success and < 0 on error.
*/
@@ -440,6 +268,10 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
if (get_user(pid, &header->pid))
return -EFAULT;

+ /* may only affect current now */
+ if (pid != 0 && pid != task_pid_vnr(current))
+ return -EPERM;
+
if (copy_from_user(&kdata, data, tocopy
* sizeof(struct __user_cap_data_struct))) {
return -EFAULT;
@@ -457,32 +289,13 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
i++;
}

- if (pid && (pid != task_pid_vnr(current)))
- ret = do_sys_capset_other_tasks(pid, &effective, &inheritable,
- &permitted);
- else {
- /*
- * This lock is required even when filesystem
- * capability support is configured - it protects the
- * sys_capget() call from returning incorrect data in
- * the case that the targeted process is not the
- * current one.
- */
- spin_lock(&task_capability_lock);
-
- ret = security_capset_check(current, &effective, &inheritable,
- &permitted);
- /*
- * Having verified that the proposed changes are
- * legal, we now put them into effect.
- */
- if (!ret)
- security_capset_set(current, &effective, &inheritable,
- &permitted);
- spin_unlock(&task_capability_lock);
- }
+ spin_lock(&task_capability_lock);

+ ret = security_capset_check(&effective, &inheritable, &permitted);
+ if (!ret)
+ security_capset_set(&effective, &inheritable, &permitted);

+ spin_unlock(&task_capability_lock);
return ret;
}

diff --git a/security/commoncap.c b/security/commoncap.c
index e4c4b3f..059a131 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -95,15 +95,6 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,

#ifdef CONFIG_SECURITY_FILE_CAPABILITIES

-static inline int cap_block_setpcap(struct task_struct *target)
-{
- /*
- * No support for remote process capability manipulation with
- * filesystem capability support.
- */
- return (target != current);
-}
-
static inline int cap_inh_is_capped(void)
{
/*
@@ -118,7 +109,6 @@ static inline int cap_limit_ptraced_target(void) { return 1; }

#else /* ie., ndef CONFIG_SECURITY_FILE_CAPABILITIES */

-static inline int cap_block_setpcap(struct task_struct *t) { return 0; }
static inline int cap_inh_is_capped(void) { return 1; }
static inline int cap_limit_ptraced_target(void)
{
@@ -127,21 +117,18 @@ static inline int cap_limit_ptraced_target(void)

#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */

-int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
+int cap_capset_check (kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- if (cap_block_setpcap(target)) {
- return -EPERM;
- }
if (cap_inh_is_capped()
&& !cap_issubset(*inheritable,
- cap_combine(target->cap_inheritable,
+ cap_combine(current->cap_inheritable,
current->cap_permitted))) {
/* incapable of using this inheritable set */
return -EPERM;
}
if (!cap_issubset(*inheritable,
- cap_combine(target->cap_inheritable,
+ cap_combine(current->cap_inheritable,
current->cap_bset))) {
/* no new pI capabilities outside bounding set */
return -EPERM;
@@ -149,7 +136,7 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,

/* verify restrictions on target's new Permitted set */
if (!cap_issubset (*permitted,
- cap_combine (target->cap_permitted,
+ cap_combine (current->cap_permitted,
current->cap_permitted))) {
return -EPERM;
}
@@ -162,12 +149,12 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
return 0;
}

-void cap_capset_set (struct task_struct *target, kernel_cap_t *effective,
+void cap_capset_set (kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- target->cap_effective = *effective;
- target->cap_inheritable = *inheritable;
- target->cap_permitted = *permitted;
+ current->cap_effective = *effective;
+ current->cap_inheritable = *inheritable;
+ current->cap_permitted = *permitted;
}

static inline void bprm_clear_caps(struct linux_binprm *bprm)
diff --git a/security/security.c b/security/security.c
index 3a4b4f5..78502ac 100644
--- a/security/security.c
+++ b/security/security.c
@@ -145,20 +145,18 @@ int security_capget(struct task_struct *target,
return security_ops->capget(target, effective, inheritable, permitted);
}

-int security_capset_check(struct task_struct *target,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+int security_capset_check(kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted)
{
- return security_ops->capset_check(target, effective, inheritable, permitted);
+ return security_ops->capset_check(effective, inheritable, permitted);
}

-void security_capset_set(struct task_struct *target,
- kernel_cap_t *effective,
- kernel_cap_t *inheritable,
- kernel_cap_t *permitted)
+void security_capset_set(kernel_cap_t *effective,
+ kernel_cap_t *inheritable,
+ kernel_cap_t *permitted)
{
- security_ops->capset_set(target, effective, inheritable, permitted);
+ security_ops->capset_set(effective, inheritable, permitted);
}

int security_capable(struct task_struct *tsk, int cap)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6b5790b..b040887 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1781,22 +1781,22 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
return secondary_ops->capget(target, effective, inheritable, permitted);
}

-static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective,
+static int selinux_capset_check(kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
int error;

- error = secondary_ops->capset_check(target, effective, inheritable, permitted);
+ error = secondary_ops->capset_check(effective, inheritable, permitted);
if (error)
return error;

- return task_has_perm(current, target, PROCESS__SETCAP);
+ return task_has_perm(current, current, PROCESS__SETCAP);
}

-static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
+static void selinux_capset_set(kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- secondary_ops->capset_set(target, effective, inheritable, permitted);
+ secondary_ops->capset_set(effective, inheritable, permitted);
}

static int selinux_capable(struct task_struct *tsk, int cap)

2008-08-06 15:51:16

by David Howells

[permalink] [raw]
Subject: [PATCH 06/24] CRED: Change current->fs[ug]id to current_fs[ug]id() [ver #7]

Change current->fs[ug]id to current_fs[ug]id() so that fsgid and fsuid can be
separated from the task_struct.

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

arch/ia64/kernel/perfmon.c | 4 ++--
arch/powerpc/platforms/cell/spufs/inode.c | 4 ++--
drivers/isdn/capi/capifs.c | 4 ++--
drivers/usb/core/inode.c | 4 ++--
fs/9p/fid.c | 2 +-
fs/9p/vfs_inode.c | 4 ++--
fs/9p/vfs_super.c | 4 ++--
fs/affs/inode.c | 4 ++--
fs/anon_inodes.c | 4 ++--
fs/attr.c | 4 ++--
fs/bfs/dir.c | 4 ++--
fs/cifs/cifsproto.h | 2 +-
fs/cifs/dir.c | 12 ++++++------
fs/cifs/inode.c | 8 ++++----
fs/cifs/misc.c | 4 ++--
fs/coda/cache.c | 6 +++---
fs/coda/upcall.c | 2 +-
fs/devpts/inode.c | 4 ++--
fs/dquot.c | 2 +-
fs/exec.c | 4 ++--
fs/ext2/balloc.c | 2 +-
fs/ext2/ialloc.c | 4 ++--
fs/ext3/balloc.c | 2 +-
fs/ext3/ialloc.c | 4 ++--
fs/ext4/balloc.c | 3 +--
fs/ext4/ialloc.c | 4 ++--
fs/fat/file.c | 2 +-
fs/fuse/dev.c | 4 ++--
fs/gfs2/inode.c | 10 +++++-----
fs/hfs/inode.c | 4 ++--
fs/hfsplus/inode.c | 4 ++--
fs/hpfs/namei.c | 24 ++++++++++++------------
fs/hugetlbfs/inode.c | 16 ++++++++--------
fs/jffs2/fs.c | 4 ++--
fs/jfs/jfs_inode.c | 4 ++--
fs/locks.c | 2 +-
fs/minix/bitmap.c | 4 ++--
fs/namei.c | 10 ++++++----
fs/nfsd/vfs.c | 6 +++---
fs/ocfs2/dlm/dlmfs.c | 8 ++++----
fs/ocfs2/namei.c | 4 ++--
fs/omfs/inode.c | 4 ++--
fs/pipe.c | 4 ++--
fs/posix_acl.c | 4 ++--
fs/ramfs/inode.c | 4 ++--
fs/reiserfs/namei.c | 4 ++--
fs/sysv/ialloc.c | 4 ++--
fs/ubifs/budget.c | 2 +-
fs/ubifs/dir.c | 4 ++--
fs/udf/ialloc.c | 4 ++--
fs/udf/namei.c | 2 +-
fs/ufs/ialloc.c | 4 ++--
fs/xfs/linux-2.6/xfs_linux.h | 4 ++--
fs/xfs/xfs_acl.c | 6 +++---
fs/xfs/xfs_inode.c | 4 ++--
fs/xfs/xfs_vnodeops.c | 8 ++++----
include/linux/cred.h | 25 +++++++++++++++++++++++++
include/linux/fs.h | 2 +-
include/linux/sched.h | 1 +
ipc/mqueue.c | 4 ++--
kernel/cgroup.c | 4 ++--
mm/shmem.c | 8 ++++----
net/9p/client.c | 2 +-
net/socket.c | 4 ++--
net/sunrpc/auth.c | 4 ++--
security/commoncap.c | 4 ++--
security/keys/key.c | 2 +-
security/keys/keyctl.c | 2 +-
security/keys/request_key.c | 10 +++++-----
security/keys/request_key_auth.c | 2 +-
70 files changed, 187 insertions(+), 160 deletions(-)
create mode 100644 include/linux/cred.h


diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index fc8f350..0cd24b2 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2224,8 +2224,8 @@ pfm_alloc_file(pfm_context_t *ctx)
DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));

inode->i_mode = S_IFCHR|S_IRUGO;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();

sprintf(name, "[%lu]", inode->i_ino);
this.name = name;
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 690ca7b..60bd5ed 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -95,8 +95,8 @@ spufs_new_inode(struct super_block *sb, int mode)
goto out;

inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
out:
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 550e80f..0aa66ec 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -156,8 +156,8 @@ void capifs_new_ncci(unsigned int number, dev_t device)
if (!inode)
return;
inode->i_ino = number+2;
- inode->i_uid = config.setuid ? config.uid : current->fsuid;
- inode->i_gid = config.setgid ? config.gid : current->fsgid;
+ inode->i_uid = config.setuid ? config.uid : current_fsuid();
+ inode->i_gid = config.setgid ? config.gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
//inode->i_op = &capifs_file_inode_operations;
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index db410e9..0f82019 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -275,8 +275,8 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de

if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 3031e32..a43e4ab 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -120,7 +120,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
switch (access) {
case V9FS_ACCESS_SINGLE:
case V9FS_ACCESS_USER:
- uid = current->fsuid;
+ uid = current_fsuid();
any = 0;
break;

diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index c95295c..517dd27 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -215,8 +215,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_rdev = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index bf59c39..f59ffcd 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -113,8 +113,8 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
struct v9fs_session_info *v9ses = NULL;
struct p9_stat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
- uid_t uid = current->fsuid;
- gid_t gid = current->fsgid;
+ uid_t uid = current_fsuid();
+ gid_t gid = current_fsgid();
struct p9_fid *fid;
int retval = 0;

diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index a13b334..415d9c6 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -293,8 +293,8 @@ affs_new_inode(struct inode *dir)
mark_buffer_dirty_inode(bh, inode);
affs_brelse(bh);

- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_ino = block;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 3662dd4..c16d9be 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -154,8 +154,8 @@ static struct inode *anon_inode_mkinode(void)
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
return inode;
}
diff --git a/fs/attr.c b/fs/attr.c
index 26c71ba..faa433a 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -29,13 +29,13 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)

/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
- (current->fsuid != inode->i_uid ||
+ (current_fsuid() != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
goto error;

/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
- (current->fsuid != inode->i_uid ||
+ (current_fsuid() != inode->i_uid ||
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
!capable(CAP_CHOWN))
goto error;
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 87ee5cc..e892a71 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -105,8 +105,8 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, int mode,
}
set_bit(ino, info->si_imap);
info->si_freei--;
- inode->i_uid = current->fsuid;
- inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = 0;
inode->i_op = &bfs_file_inops;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b9f5e93..8efbe47 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -39,7 +39,7 @@ extern int smb_send(struct socket *, struct smb_hdr *,
unsigned int /* length */ , struct sockaddr *);
extern unsigned int _GetXid(void);
extern void _FreeXid(unsigned int);
-#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
+#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
extern char *build_path_from_dentry(struct dentry *);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index fb69c1f..a2d4a2b 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -228,8 +228,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
- (__u64)current->fsuid,
- (__u64)current->fsgid,
+ (__u64)current_fsuid(),
+ (__u64)current_fsgid(),
0 /* dev */,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -266,8 +266,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if ((oplock & CIFS_CREATE_ACTION) &&
(cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID)) {
- newinode->i_uid = current->fsuid;
- newinode->i_gid = current->fsgid;
+ newinode->i_uid = current_fsuid();
+ newinode->i_gid = current_fsgid();
}
}
}
@@ -360,8 +360,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
- mode, (__u64)current->fsuid,
- (__u64)current->fsgid,
+ mode, (__u64)current_fsuid(),
+ (__u64)current_fsgid(),
device_number, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 46e54d3..4857f15 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -989,8 +989,8 @@ mkdir_get_info:
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode,
- (__u64)current->fsuid,
- (__u64)current->fsgid,
+ (__u64)current_fsuid(),
+ (__u64)current_fsgid(),
0 /* dev_t */,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -1023,9 +1023,9 @@ mkdir_get_info:
if (cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID) {
direntry->d_inode->i_uid =
- current->fsuid;
+ current_fsuid();
direntry->d_inode->i_gid =
- current->fsgid;
+ current_fsgid();
}
}
}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 4b17f8f..99f939e 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -351,13 +351,13 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* BB Add support for establishing new tCon and SMB Session */
/* with userid/password pairs found on the smb session */
/* for other target tcp/ip addresses BB */
- if (current->fsuid != treeCon->ses->linux_uid) {
+ if (current_fsuid() != treeCon->ses->linux_uid) {
cFYI(1, ("Multiuser mode and UID "
"did not match tcon uid"));
read_lock(&GlobalSMBSeslock);
list_for_each(temp_item, &GlobalSMBSessionList) {
ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
- if (ses->linux_uid == current->fsuid) {
+ if (ses->linux_uid == current_fsuid()) {
if (ses->server == treeCon->ses->server) {
cFYI(1, ("found matching uid substitute right smb_uid"));
buffer->Uid = ses->Suid;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 8a23703..a5bf577 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -32,8 +32,8 @@ void coda_cache_enter(struct inode *inode, int mask)
struct coda_inode_info *cii = ITOC(inode);

cii->c_cached_epoch = atomic_read(&permission_epoch);
- if (cii->c_uid != current->fsuid) {
- cii->c_uid = current->fsuid;
+ if (cii->c_uid != current_fsuid()) {
+ cii->c_uid = current_fsuid();
cii->c_cached_perm = mask;
} else
cii->c_cached_perm |= mask;
@@ -60,7 +60,7 @@ int coda_cache_check(struct inode *inode, int mask)
int hit;

hit = (mask & cii->c_cached_perm) == mask &&
- cii->c_uid == current->fsuid &&
+ cii->c_uid == current_fsuid() &&
cii->c_cached_epoch == atomic_read(&permission_epoch);

return hit;
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index ce432bc..c274d94 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -52,7 +52,7 @@ static void *alloc_upcall(int opcode, int size)
inp->ih.opcode = opcode;
inp->ih.pid = current->pid;
inp->ih.pgid = task_pgrp_nr(current);
- inp->ih.uid = current->fsuid;
+ inp->ih.uid = current_fsuid();

return (void*)inp;
}
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 488eb42..7d3ad2d 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -228,8 +228,8 @@ int devpts_pty_new(struct tty_struct *tty)
return -ENOMEM;

inode->i_ino = number+2;
- inode->i_uid = config.setuid ? config.uid : current->fsuid;
- inode->i_gid = config.setgid ? config.gid : current->fsgid;
+ inode->i_uid = config.setuid ? config.uid : current_fsuid();
+ inode->i_gid = config.setgid ? config.gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
inode->i_private = tty;
diff --git a/fs/dquot.c b/fs/dquot.c
index 8ec4d6c..7307324 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -876,7 +876,7 @@ static inline int need_print_warning(struct dquot *dquot)

switch (dquot->dq_type) {
case USRQUOTA:
- return current->fsuid == dquot->dq_id;
+ return current_fsuid() == dquot->dq_id;
case GRPQUOTA:
return in_group_p(dquot->dq_id);
}
diff --git a/fs/exec.c b/fs/exec.c
index 32993be..3b3231b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1715,7 +1715,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
struct inode * inode;
struct file * file;
int retval = 0;
- int fsuid = current->fsuid;
+ int fsuid = current_fsuid();
int flag = 0;
int ispipe = 0;
unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1821,7 +1821,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
* Dont allow local users get cute and trick others to coredump
* into their pre-created files:
*/
- if (inode->i_uid != current->fsuid)
+ if (inode->i_uid != current_fsuid())
goto close_fail;
if (!file->f_op)
goto close_fail;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 10bb02c..8c59a60 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1193,7 +1193,7 @@ static int ext2_has_free_blocks(struct ext2_sb_info *sbi)
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
- sbi->s_resuid != current->fsuid &&
+ sbi->s_resuid != current_fsuid() &&
(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
return 0;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index f597413..8d0add6 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -550,7 +550,7 @@ got:

sb->s_dirt = 1;
mark_buffer_dirty(bh2);
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
@@ -558,7 +558,7 @@ got:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;

inode->i_ino = ino;
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 92fd033..6f433f9 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1422,7 +1422,7 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
- sbi->s_resuid != current->fsuid &&
+ sbi->s_resuid != current_fsuid() &&
(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
return 0;
}
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 47b678d..490bd0e 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -539,7 +539,7 @@ got:
percpu_counter_inc(&sbi->s_dirs_counter);
sb->s_dirt = 1;

- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
@@ -547,7 +547,7 @@ got:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;

inode->i_ino = ino;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 495ab21..982042e 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -1615,7 +1615,7 @@ ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);

if (!capable(CAP_SYS_RESOURCE) &&
- sbi->s_resuid != current->fsuid &&
+ sbi->s_resuid != current_fsuid() &&
(sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid)))
root_blocks = ext4_r_blocks_count(sbi->s_es);
#ifdef CONFIG_SMP
@@ -1628,7 +1628,6 @@ ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi,
return nblocks;
}

-
/**
* ext4_should_retry_alloc()
* @sb: super block
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index a92eb30..58b285f 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -772,7 +772,7 @@ got:
spin_unlock(sb_bgl_lock(sbi, flex_group));
}

- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
@@ -780,7 +780,7 @@ got:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;

inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 8707a8c..a72aa05 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -302,7 +302,7 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
{
mode_t allow_utime = sbi->options.allow_utime;

- if (current->fsuid != inode->i_uid) {
+ if (current_fsuid() != inode->i_uid) {
if (in_group_p(inode->i_gid))
allow_utime >>= 3;
if (allow_utime & MAY_WRITE)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 87250b6..2d3ccbd 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -87,8 +87,8 @@ static void __fuse_put_request(struct fuse_req *req)

static void fuse_req_init_context(struct fuse_req *req)
{
- req->in.h.uid = current->fsuid;
- req->in.h.gid = current->fsgid;
+ req->in.h.uid = current_fsuid();
+ req->in.h.gid = current_fsgid();
req->in.h.pid = current->pid;
}

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 8b0806a..c1c36f3 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -701,18 +701,18 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode,
(dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) {
if (S_ISDIR(*mode))
*mode |= S_ISUID;
- else if (dip->i_inode.i_uid != current->fsuid)
+ else if (dip->i_inode.i_uid != current_fsuid())
*mode &= ~07111;
*uid = dip->i_inode.i_uid;
} else
- *uid = current->fsuid;
+ *uid = current_fsuid();

if (dip->i_inode.i_mode & S_ISGID) {
if (S_ISDIR(*mode))
*mode |= S_ISGID;
*gid = dip->i_inode.i_gid;
} else
- *gid = current->fsgid;
+ *gid = current_fsgid();
}

static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
@@ -1122,8 +1122,8 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
return -EPERM;

if ((dip->i_inode.i_mode & S_ISVTX) &&
- dip->i_inode.i_uid != current->fsuid &&
- ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER))
+ dip->i_inode.i_uid != current_fsuid() &&
+ ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
return -EPERM;

if (IS_APPEND(&dip->i_inode))
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 7e19835..d668267 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -155,8 +155,8 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
inode->i_ino = HFS_SB(sb)->next_id++;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
HFS_I(inode)->flags = 0;
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index b085d64..7c711ca 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -307,8 +307,8 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)

inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index d9c59a7..061db62 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -92,11 +92,11 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inc_nlink(dir);
insert_inode_hash(result);

- if (result->i_uid != current->fsuid ||
- result->i_gid != current->fsgid ||
+ if (result->i_uid != current_fsuid() ||
+ result->i_gid != current_fsgid() ||
result->i_mode != (mode | S_IFDIR)) {
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_mode = mode | S_IFDIR;
hpfs_write_inode_nolock(result);
}
@@ -184,11 +184,11 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc

insert_inode_hash(result);

- if (result->i_uid != current->fsuid ||
- result->i_gid != current->fsgid ||
+ if (result->i_uid != current_fsuid() ||
+ result->i_gid != current_fsgid() ||
result->i_mode != (mode | S_IFREG)) {
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_mode = mode | S_IFREG;
hpfs_write_inode_nolock(result);
}
@@ -247,8 +247,8 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_nlink = 1;
result->i_size = 0;
result->i_blocks = 1;
@@ -325,8 +325,8 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
result->i_mode = S_IFLNK | 0777;
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_blocks = 1;
result->i_nlink = 1;
result->i_size = strlen(symlink);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 3f58923..4c428f5 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -551,9 +551,9 @@ static int hugetlbfs_mknod(struct inode *dir,
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
- gid = current->fsgid;
+ gid = current_fsgid();
}
- inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, mode, dev);
+ inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(), gid, mode, dev);
if (inode) {
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d_instantiate(dentry, inode);
@@ -586,9 +586,9 @@ static int hugetlbfs_symlink(struct inode *dir,
if (dir->i_mode & S_ISGID)
gid = dir->i_gid;
else
- gid = current->fsgid;
+ gid = current_fsgid();

- inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid,
+ inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(),
gid, S_IFLNK|S_IRWXUGO, 0);
if (inode) {
int l = strlen(symname)+1;
@@ -854,8 +854,8 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)

config.nr_blocks = -1; /* No limit on size by default */
config.nr_inodes = -1; /* No limit on number of inodes by default */
- config.uid = current->fsuid;
- config.gid = current->fsgid;
+ config.uid = current_fsuid();
+ config.gid = current_fsgid();
config.mode = 0755;
config.hstate = &default_hstate;
ret = hugetlbfs_parse_options(data, &config);
@@ -970,8 +970,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
goto out_shm_unlock;

error = -ENOSPC;
- inode = hugetlbfs_get_inode(root->d_sb, current->fsuid,
- current->fsgid, S_IFREG | S_IRWXUGO, 0);
+ inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(),
+ current_fsgid(), S_IFREG | S_IRWXUGO, 0);
if (!inode)
goto out_dentry;

diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 086c438..df0cbdf 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -440,14 +440,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i

memset(ri, 0, sizeof(*ri));
/* Set OS-specific defaults for new inodes */
- ri->uid = cpu_to_je16(current->fsuid);
+ ri->uid = cpu_to_je16(current_fsuid());

if (dir_i->i_mode & S_ISGID) {
ri->gid = cpu_to_je16(dir_i->i_gid);
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
- ri->gid = cpu_to_je16(current->fsgid);
+ ri->gid = cpu_to_je16(current_fsgid());
}

/* POSIX ACLs have to be processed now, at least partly.
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index ed6574b..70022fd 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -93,13 +93,13 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
return ERR_PTR(rc);
}

- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (parent->i_mode & S_ISGID) {
inode->i_gid = parent->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();

/*
* New inodes need to save sane values on disk when
diff --git a/fs/locks.c b/fs/locks.c
index 5eb259e..ba4ff5a 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1349,7 +1349,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;

- if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
+ if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
return -EACCES;
if (!S_ISREG(inode->i_mode))
return -EINVAL;
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 703cc35..3aebe32 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -262,8 +262,8 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
iput(inode);
return NULL;
}
- inode->i_uid = current->fsuid;
- inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = 0;
diff --git a/fs/namei.c b/fs/namei.c
index 4ea63ed..6f95377 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -186,7 +186,7 @@ int generic_permission(struct inode *inode, int mask,

mask &= MAY_READ | MAY_WRITE | MAY_EXEC;

- if (current->fsuid == inode->i_uid)
+ if (current_fsuid() == inode->i_uid)
mode >>= 6;
else {
if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
@@ -454,7 +454,7 @@ static int exec_permission_lite(struct inode *inode)
if (inode->i_op && inode->i_op->permission)
return -EAGAIN;

- if (current->fsuid == inode->i_uid)
+ if (current_fsuid() == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
@@ -1363,11 +1363,13 @@ static int user_path_parent(int dfd, const char __user *path,
*/
static inline int check_sticky(struct inode *dir, struct inode *inode)
{
+ uid_t fsuid = current_fsuid();
+
if (!(dir->i_mode & S_ISVTX))
return 0;
- if (inode->i_uid == current->fsuid)
+ if (inode->i_uid == fsuid)
return 0;
- if (dir->i_uid == current->fsuid)
+ if (dir->i_uid == fsuid)
return 0;
return !capable(CAP_FOWNER);
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 18060be..a1b99c6 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1166,7 +1166,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
* send along the gid on create when it tries to implement
* setgid directories via NFS:
*/
- if (current->fsuid != 0)
+ if (current_fsuid() != 0)
iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
if (iap->ia_valid)
return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
@@ -1906,7 +1906,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
IS_APPEND(inode)? " append" : "",
__mnt_is_readonly(exp->ex_path.mnt)? " ro" : "");
dprintk(" owner %d/%d user %d/%d\n",
- inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
+ inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid());
#endif

/* Normally we reject any write/sattr etc access on a read-only file
@@ -1949,7 +1949,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
* with NFSv3.
*/
if ((acc & NFSD_MAY_OWNER_OVERRIDE) &&
- inode->i_uid == current->fsuid)
+ inode->i_uid == current_fsuid())
return 0;

/* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 533a789..3516d8a 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -339,8 +339,8 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
ip = DLMFS_I(inode);

inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -365,8 +365,8 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
return NULL;

inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index d5d808f..8dab41c 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -425,13 +425,13 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
fe->i_blkno = cpu_to_le64(fe_blkno);
fe->i_suballoc_bit = cpu_to_le16(suballoc_bit);
fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot);
- fe->i_uid = cpu_to_le32(current->fsuid);
+ fe->i_uid = cpu_to_le32(current_fsuid());
if (dir->i_mode & S_ISGID) {
fe->i_gid = cpu_to_le32(dir->i_gid);
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- fe->i_gid = cpu_to_le32(current->fsgid);
+ fe->i_gid = cpu_to_le32(current_fsgid());
fe->i_mode = cpu_to_le16(mode);
if (S_ISCHR(mode) || S_ISBLK(mode))
fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev));
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index d865f55..903f70f 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -37,8 +37,8 @@ struct inode *omfs_new_inode(struct inode *dir, int mode)

inode->i_ino = new_block;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->a_ops = &omfs_aops;

diff --git a/fs/pipe.c b/fs/pipe.c
index fcba654..8b4e3ed 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -902,8 +902,8 @@ static struct inode * get_pipe_inode(void)
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;

return inode;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index aec931e..39df95a 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -217,11 +217,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
switch(pa->e_tag) {
case ACL_USER_OBJ:
/* (May have been checked already) */
- if (inode->i_uid == current->fsuid)
+ if (inode->i_uid == current_fsuid())
goto check_perm;
break;
case ACL_USER:
- if (pa->e_id == current->fsuid)
+ if (pa->e_id == current_fsuid())
goto mask;
break;
case ACL_GROUP_OBJ:
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index b131234..08c755d 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -55,8 +55,8 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)

if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->a_ops = &ramfs_aops;
inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index c1add28..bd46f60 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -582,7 +582,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
/* the quota init calls have to know who to charge the quota to, so
** we have to set uid and gid here
*/
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
inode->i_mode = mode;
/* Make inode invalid - just in case we are going to drop it before
* the initialization happens */
@@ -593,7 +593,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
if (S_ISDIR(mode))
inode->i_mode |= S_ISGID;
} else {
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
}
DQUOT_INIT(inode);
return 0;
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 115ab0d..241e976 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -165,9 +165,9 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();

- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
inode->i_ino = fs16_to_cpu(sbi, ino);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = 0;
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index d81fb9e..1df3534 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -375,7 +375,7 @@ long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs)
*/
static int can_use_rp(struct ubifs_info *c)
{
- if (current->fsuid == c->rp_uid || capable(CAP_SYS_RESOURCE) ||
+ if (current_fsuid() == c->rp_uid || capable(CAP_SYS_RESOURCE) ||
(c->rp_gid != 0 && in_group_p(c->rp_gid)))
return 1;
return 0;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index e90374b..cd36ed5 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -104,13 +104,13 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
*/
inode->i_flags |= (S_NOCMTIME);

- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;
inode->i_mtime = inode->i_atime = inode->i_ctime =
ubifs_current_time(inode);
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index eb9cfa2..acfc807 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -112,13 +112,13 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
mark_buffer_dirty(sbi->s_lvid_bh);
}
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
}

iinfo->i_location.logicalBlockNum = block;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index d323194..09d5bfd 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -605,7 +605,7 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
goto out;

iinfo = UDF_I(inode);
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
init_special_inode(inode, mode, rdev);
fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
if (!fi) {
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index ac181f6..6f5dcf0 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -304,13 +304,13 @@ cg_found:

inode->i_ino = cg * uspi->s_ipg + bit;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
inode->i_mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();

inode->i_blocks = 0;
inode->i_generation = 0;
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index 4d45d93..bbc9b36 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -126,8 +126,8 @@

#define current_cpu() (raw_smp_processor_id())
#define current_pid() (current->pid)
-#define current_fsuid(cred) (current->fsuid)
-#define current_fsgid(cred) (current->fsgid)
+#define this_fsuid(cred) (current_fsuid())
+#define this_fsgid(cred) (current_fsgid())
#define current_test_flags(f) (current->flags & (f))
#define current_set_flags_nested(sp, f) \
(*(sp) = current->flags, current->flags |= (f))
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 3e4648a..f94e5a8 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -372,7 +372,7 @@ xfs_acl_allow_set(
return ENOTDIR;
if (vp->i_sb->s_flags & MS_RDONLY)
return EROFS;
- if (xfs_vtoi(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER))
+ if (xfs_vtoi(vp)->i_d.di_uid != current_fsuid() && !capable(CAP_FOWNER))
return EPERM;
return 0;
}
@@ -419,13 +419,13 @@ xfs_acl_access(
switch (fap->acl_entry[i].ae_tag) {
case ACL_USER_OBJ:
seen_userobj = 1;
- if (fuid != current->fsuid)
+ if (fuid != current_fsuid())
continue;
matched.ae_tag = ACL_USER_OBJ;
matched.ae_perm = allows;
break;
case ACL_USER:
- if (fap->acl_entry[i].ae_id != current->fsuid)
+ if (fap->acl_entry[i].ae_id != current_fsuid())
continue;
matched.ae_tag = ACL_USER;
matched.ae_perm = allows;
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index bedc661..5e481ae 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1082,8 +1082,8 @@ xfs_ialloc(
ip->i_d.di_onlink = 0;
ip->i_d.di_nlink = nlink;
ASSERT(ip->i_d.di_nlink == nlink);
- ip->i_d.di_uid = current_fsuid(cr);
- ip->i_d.di_gid = current_fsgid(cr);
+ ip->i_d.di_uid = this_fsuid(cr);
+ ip->i_d.di_gid = this_fsgid(cr);
ip->i_d.di_projid = prid;
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));

diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 76a1166..3dfe8a0 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -182,7 +182,7 @@ xfs_setattr(
xfs_ilock(ip, lock_flags);

/* boolean: are we the file owner? */
- file_owner = (current_fsuid(credp) == ip->i_d.di_uid);
+ file_owner = (this_fsuid(credp) == ip->i_d.di_uid);

/*
* Change various properties of a file.
@@ -1536,7 +1536,7 @@ xfs_create(
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp), prid,
+ this_fsuid(credp), this_fsgid(credp), prid,
XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
@@ -2352,7 +2352,7 @@ xfs_mkdir(
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp), prid,
+ this_fsuid(credp), this_fsgid(credp), prid,
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
@@ -2578,7 +2578,7 @@ xfs_symlink(
* Make sure that we have allocated dquot(s) on disk.
*/
error = XFS_QM_DQVOPALLOC(mp, dp,
- current_fsuid(credp), current_fsgid(credp), prid,
+ this_fsuid(credp), this_fsgid(credp), prid,
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp);
if (error)
goto std_return;
diff --git a/include/linux/cred.h b/include/linux/cred.h
new file mode 100644
index 0000000..9d56fbd
--- /dev/null
+++ b/include/linux/cred.h
@@ -0,0 +1,25 @@
+/* Credentials management
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_CRED_H
+#define _LINUX_CRED_H
+
+#define current_fsuid() (current->fsuid)
+#define current_fsgid() (current->fsgid)
+#define current_cap() (current->cap_effective)
+
+#define current_fsuid_fsgid(_uid, _gid) \
+do { \
+ *(_uid) = current->fsuid; \
+ *(_gid) = current->fsgid; \
+} while(0)
+
+#endif /* _LINUX_CRED_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 580b513..9a8397f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1149,7 +1149,7 @@ enum {
#define has_fs_excl() atomic_read(&current->fs_excl)

#define is_owner_or_cap(inode) \
- ((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER))
+ ((current_fsuid() == (inode)->i_uid) || capable(CAP_FOWNER))

/* not quite ready to be deprecated, but... */
extern void lock_super(struct super_block *);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5270d44..9fd5694 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -87,6 +87,7 @@ struct sched_param {
#include <linux/task_io_accounting.h>
#include <linux/kobject.h>
#include <linux/latencytop.h>
+#include <linux/cred.h>

#include <asm/processor.h>

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 96fb36c..c652c21 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -109,8 +109,8 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mtime = inode->i_ctime = inode->i_atime =
CURRENT_TIME;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 13932ab..f483904 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -573,8 +573,8 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)

if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->backing_dev_info = &cgroup_backing_dev_info;
diff --git a/mm/shmem.c b/mm/shmem.c
index c1e5a3b..ba957d4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1510,8 +1510,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -2275,8 +2275,8 @@ static int shmem_fill_super(struct super_block *sb,
sbinfo->max_blocks = 0;
sbinfo->max_inodes = 0;
sbinfo->mode = S_IRWXUGO | S_ISVTX;
- sbinfo->uid = current->fsuid;
- sbinfo->gid = current->fsgid;
+ sbinfo->uid = current_fsuid();
+ sbinfo->gid = current_fsgid();
sbinfo->mpol = NULL;
sb->s_fs_info = sbinfo;

diff --git a/net/9p/client.c b/net/9p/client.c
index 2ffe40c..a5dfc17 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1049,7 +1049,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
fid->rdir_fpos = 0;
fid->rdir_pos = 0;
fid->rdir_fcall = NULL;
- fid->uid = current->fsuid;
+ fid->uid = current_fsuid();
fid->clnt = clnt;
fid->aux = NULL;

diff --git a/net/socket.c b/net/socket.c
index 8ef8ba8..1080f7a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -491,8 +491,8 @@ static struct socket *sock_alloc(void)
sock = SOCKET_I(inode);

inode->i_mode = S_IFSOCK | S_IRWXUGO;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();

get_cpu_var(sockets_in_use)++;
put_cpu_var(sockets_in_use);
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 6bfea9e..9dd8062 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -351,8 +351,8 @@ struct rpc_cred *
rpcauth_lookupcred(struct rpc_auth *auth, int flags)
{
struct auth_cred acred = {
- .uid = current->fsuid,
- .gid = current->fsgid,
+ .uid = current_fsuid(),
+ .gid = current_fsgid(),
.group_info = current->group_info,
};
struct rpc_cred *ret;
diff --git a/security/commoncap.c b/security/commoncap.c
index 40e8b83..708aa05 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -498,12 +498,12 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
*/

if (!issecure (SECURE_NO_SETUID_FIXUP)) {
- if (old_fsuid == 0 && current->fsuid != 0) {
+ if (old_fsuid == 0 && current_fsuid() != 0) {
current->cap_effective =
cap_drop_fs_set(
current->cap_effective);
}
- if (old_fsuid != 0 && current->fsuid == 0) {
+ if (old_fsuid != 0 && current_fsuid() == 0) {
current->cap_effective =
cap_raise_fs_set(
current->cap_effective,
diff --git a/security/keys/key.c b/security/keys/key.c
index 14948cf..a6ca39e 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -802,7 +802,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
}

/* allocate a new key */
- key = key_alloc(ktype, description, current->fsuid, current->fsgid,
+ key = key_alloc(ktype, description, current_fsuid(), current_fsgid(),
current, perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_CAST(key);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index a738114..fcce331 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -817,7 +817,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
down_write(&key->sem);

/* if we're not the sysadmin, we can only change a key that we own */
- if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) {
+ if (capable(CAP_SYS_ADMIN) || key->uid == current_fsuid()) {
key->perm = perm;
ret = 0;
}
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 123edce..d7a4e25 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -79,7 +79,7 @@ static int call_sbin_request_key(struct key_construction *cons,
/* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial);

- keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+ keyring = keyring_alloc(desc, current_fsuid(), current_fsgid(), current,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
@@ -92,8 +92,8 @@ static int call_sbin_request_key(struct key_construction *cons,
goto error_link;

/* record the UID and GID */
- sprintf(uid_str, "%d", current->fsuid);
- sprintf(gid_str, "%d", current->fsgid);
+ sprintf(uid_str, "%d", current_fsuid());
+ sprintf(gid_str, "%d", current_fsgid());

/* we say which key is under construction */
sprintf(key_str, "%d", key->serial);
@@ -302,7 +302,7 @@ static int construct_alloc_key(struct key_type *type,
mutex_lock(&user->cons_lock);

key = key_alloc(type, description,
- current->fsuid, current->fsgid, current, KEY_POS_ALL,
+ current_fsuid(), current_fsgid(), current, KEY_POS_ALL,
flags);
if (IS_ERR(key))
goto alloc_failed;
@@ -362,7 +362,7 @@ static struct key *construct_key_and_link(struct key_type *type,
struct key *key;
int ret;

- user = key_user_lookup(current->fsuid);
+ user = key_user_lookup(current_fsuid());
if (!user)
return ERR_PTR(-ENOMEM);

diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index eccd2f2..1762d44 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -197,7 +197,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
sprintf(desc, "%x", target->serial);

authkey = key_alloc(&key_type_request_key_auth, desc,
- current->fsuid, current->fsgid, current,
+ current_fsuid(), current_fsgid(), current,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(authkey)) {

2008-08-06 15:51:38

by David Howells

[permalink] [raw]
Subject: [PATCH 09/24] CRED: Detach the credentials from task_struct [ver #7]

Detach the credentials from task_struct, duplicating them in copy_process()
and releasing them in __put_task_struct().

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

include/linux/cred.h | 29 ++++++++++++++
include/linux/init_task.h | 16 -------
include/linux/sched.h | 1
include/linux/security.h | 26 ++++++------
kernel/Makefile | 2 -
kernel/cred.c | 94 ++++++++++++++++++++++++++++++++++++++++++++
kernel/fork.c | 24 +++--------
security/capability.c | 8 ++--
security/security.c | 8 ++--
security/selinux/hooks.c | 32 +++++++--------
security/smack/smack_lsm.c | 20 +++++----
11 files changed, 177 insertions(+), 83 deletions(-)
create mode 100644 kernel/cred.c


diff --git a/include/linux/cred.h b/include/linux/cred.h
index 17ad725..a0fefc0 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -158,4 +158,33 @@ do { \
*(_gid) = current->cred->fsgid; \
} while(0)

+extern void __put_cred(struct cred *);
+extern int copy_creds(struct task_struct *, unsigned long);
+
+/**
+ * get_cred - Get a reference on a set of credentials
+ * @cred: The credentials to reference
+ *
+ * Get a reference on the specified set of credentials. The caller must
+ * release the reference.
+ */
+static inline struct cred *get_cred(struct cred *cred)
+{
+ atomic_inc(&cred->usage);
+ return cred;
+}
+
+/**
+ * put_cred - Release a reference to a set of credentials
+ * @cred: The credentials to release
+ *
+ * Release a reference to a set of credentials, deleting them when the last ref
+ * is released.
+ */
+static inline void put_cred(struct cred *cred)
+{
+ if (atomic_dec_and_test(&(cred)->usage))
+ __put_cred(cred);
+}
+
#endif /* _LINUX_CRED_H */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 0abd837..234c24a 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -115,19 +115,6 @@ extern struct group_info init_groups;

extern struct cred init_cred;

-#define INIT_CRED(p) \
-{ \
- .usage = ATOMIC_INIT(3), \
- .securebits = SECUREBITS_DEFAULT, \
- .cap_inheritable = CAP_INIT_INH_SET, \
- .cap_permitted = CAP_FULL_SET, \
- .cap_effective = CAP_INIT_EFF_SET, \
- .cap_bset = CAP_INIT_BSET, \
- .user = INIT_USER, \
- .group_info = &init_groups, \
- .lock = __SPIN_LOCK_UNLOCKED(p.lock), \
-}
-
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -162,8 +149,7 @@ extern struct cred init_cred;
.children = LIST_HEAD_INIT(tsk.children), \
.sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \
- .__temp_cred = INIT_CRED(tsk.__temp_cred), \
- .cred = &tsk.__temp_cred, \
+ .cred = &init_cred, \
.comm = "swapper", \
.thread = INIT_THREAD, \
.fs = &init_fs, \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 304ede6..041b153 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1109,7 +1109,6 @@ struct task_struct {
struct list_head cpu_timers[3];

/* process credentials */
- struct cred __temp_cred __deprecated; /* temporary credentials to be removed */
struct cred *cred; /* actual/objective task credentials */

char comm[TASK_COMM_LEN]; /* executable name excluding path
diff --git a/include/linux/security.h b/include/linux/security.h
index c3eed5a..a0f5886 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -589,15 +589,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* manual page for definitions of the @clone_flags.
* @clone_flags contains the flags indicating what should be shared.
* Return 0 if permission is granted.
- * @task_alloc_security:
- * @p contains the task_struct for child process.
- * Allocate and attach a security structure to the p->security field. The
- * security field is initialized to NULL when the task structure is
+ * @cred_alloc_security:
+ * @cred contains the cred struct for child process.
+ * Allocate and attach a security structure to the cred->security field.
+ * The security field is initialized to NULL when the task structure is
* allocated.
* Return 0 if operation was successful.
- * @task_free_security:
- * @p contains the task_struct for process.
- * Deallocate and clear the p->security field.
+ * @cred_free:
+ * @cred points to the credentials.
+ * Deallocate and clear the cred->security field in a set of credentials.
* @task_setuid:
* Check permission before setting one or more of the user identity
* attributes of the current process. The @flags parameter indicates
@@ -1401,8 +1401,8 @@ struct security_operations {
int (*dentry_open) (struct file *file);

int (*task_create) (unsigned long clone_flags);
- int (*task_alloc_security) (struct task_struct *p);
- void (*task_free_security) (struct task_struct *p);
+ int (*cred_alloc_security) (struct cred *cred);
+ void (*cred_free) (struct cred *cred);
int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ ,
uid_t old_euid, uid_t old_suid, int flags);
@@ -1659,8 +1659,8 @@ int security_file_send_sigiotask(struct task_struct *tsk,
int security_file_receive(struct file *file);
int security_dentry_open(struct file *file);
int security_task_create(unsigned long clone_flags);
-int security_task_alloc(struct task_struct *p);
-void security_task_free(struct task_struct *p);
+int security_cred_alloc(struct cred *cred);
+void security_cred_free(struct cred *cred);
int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
int security_task_post_setuid(uid_t old_ruid, uid_t old_euid,
uid_t old_suid, int flags);
@@ -2170,12 +2170,12 @@ static inline int security_task_create(unsigned long clone_flags)
return 0;
}

-static inline int security_task_alloc(struct task_struct *p)
+static inline int security_cred_alloc(struct cred *cred)
{
return 0;
}

-static inline void security_task_free(struct task_struct *p)
+static inline void security_cred_free(struct cred *cred)
{ }

static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
diff --git a/kernel/Makefile b/kernel/Makefile
index 4e1d7df..8e6ab9c 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
- notifier.o ksysfs.o pm_qos_params.o sched_clock.o
+ notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o

CFLAGS_REMOVE_sched.o = -mno-spe

diff --git a/kernel/cred.c b/kernel/cred.c
new file mode 100644
index 0000000..2195841
--- /dev/null
+++ b/kernel/cred.c
@@ -0,0 +1,94 @@
+/* Task credentials management
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/key.h>
+#include <linux/keyctl.h>
+#include <linux/init_task.h>
+#include <linux/security.h>
+
+/*
+ * The initial credentials for the initial task
+ */
+struct cred init_cred = {
+ .usage = ATOMIC_INIT(3),
+ .securebits = SECUREBITS_DEFAULT,
+ .cap_inheritable = CAP_INIT_INH_SET,
+ .cap_permitted = CAP_FULL_SET,
+ .cap_effective = CAP_INIT_EFF_SET,
+ .cap_bset = CAP_INIT_BSET,
+ .user = INIT_USER,
+ .group_info = &init_groups,
+};
+
+/*
+ * The RCU callback to actually dispose of a set of credentials
+ */
+static void put_cred_rcu(struct rcu_head *rcu)
+{
+ struct cred *cred = container_of(rcu, struct cred, rcu);
+
+ BUG_ON(atomic_read(&cred->usage) != 0);
+
+ key_put(cred->thread_keyring);
+ key_put(cred->request_key_auth);
+ put_group_info(cred->group_info);
+ free_uid(cred->user);
+ security_cred_free(cred);
+ kfree(cred);
+}
+
+/**
+ * __put_cred - Destroy a set of credentials
+ * @sec: The record to release
+ *
+ * Destroy a set of credentials on which no references remain.
+ */
+void __put_cred(struct cred *cred)
+{
+ call_rcu(&cred->rcu, put_cred_rcu);
+}
+EXPORT_SYMBOL(__put_cred);
+
+/*
+ * Copy credentials for the new process created by fork()
+ */
+int copy_creds(struct task_struct *p, unsigned long clone_flags)
+{
+ struct cred *pcred;
+ int ret;
+
+ pcred = kmemdup(p->cred, sizeof(*p->cred), GFP_KERNEL);
+ if (!pcred)
+ return -ENOMEM;
+
+#ifdef CONFIG_SECURITY
+ pcred->security = NULL;
+#endif
+
+ ret = security_cred_alloc(pcred);
+ if (ret < 0) {
+ kfree(pcred);
+ return ret;
+ }
+
+ atomic_set(&pcred->usage, 1);
+ get_group_info(pcred->group_info);
+ get_uid(pcred->user);
+ key_get(pcred->thread_keyring);
+ key_get(pcred->request_key_auth);
+
+ /* RCU assignment is unneeded here as no-one can have accessed this
+ * pointer yet, barring us */
+ p->cred = pcred;
+ return 0;
+}
diff --git a/kernel/fork.c b/kernel/fork.c
index be0c716..8993a45 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -145,9 +145,7 @@ void __put_task_struct(struct task_struct *tsk)
WARN_ON(atomic_read(&tsk->usage));
WARN_ON(tsk == current);

- security_task_free(tsk);
- free_uid(tsk->__temp_cred.user);
- put_group_info(tsk->__temp_cred.group_info);
+ put_cred(tsk->cred);
delayacct_tsk_free(tsk);

if (!profile_handoff_task(tsk))
@@ -938,7 +936,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
- p->cred = &p->__temp_cred;
retval = -EAGAIN;
if (atomic_read(&p->cred->user->processes) >=
p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
@@ -947,9 +944,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto bad_fork_free;
}

- atomic_inc(&p->cred->user->__count);
- atomic_inc(&p->cred->user->processes);
- get_group_info(p->cred->group_info);
+ retval = copy_creds(p, clone_flags);
+ if (retval < 0)
+ goto bad_fork_free;

/*
* If multiple threads are within copy_process(), then this check
@@ -1007,9 +1004,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
do_posix_clock_monotonic_gettime(&p->start_time);
p->real_start_time = p->start_time;
monotonic_to_bootbased(&p->real_start_time);
-#ifdef CONFIG_SECURITY
- p->cred->security = NULL;
-#endif
p->io_context = NULL;
p->audit_context = NULL;
cgroup_fork(p);
@@ -1054,10 +1048,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
/* Perform scheduler related setup. Assign this task to a CPU. */
sched_fork(p, clone_flags);

- if ((retval = security_task_alloc(p)))
- goto bad_fork_cleanup_policy;
if ((retval = audit_alloc(p)))
- goto bad_fork_cleanup_security;
+ goto bad_fork_cleanup_policy;
/* copy all the process information */
if ((retval = copy_semundo(clone_flags, p)))
goto bad_fork_cleanup_audit;
@@ -1270,8 +1262,6 @@ bad_fork_cleanup_semundo:
exit_sem(p);
bad_fork_cleanup_audit:
audit_free(p);
-bad_fork_cleanup_security:
- security_task_free(p);
bad_fork_cleanup_policy:
#ifdef CONFIG_NUMA
mpol_put(p->mempolicy);
@@ -1284,9 +1274,7 @@ bad_fork_cleanup_cgroup:
bad_fork_cleanup_put_domain:
module_put(task_thread_info(p)->exec_domain->module);
bad_fork_cleanup_count:
- put_group_info(p->cred->group_info);
- atomic_dec(&p->cred->user->processes);
- free_uid(p->cred->user);
+ put_cred(p->cred);
bad_fork_free:
free_task(p);
fork_out:
diff --git a/security/capability.c b/security/capability.c
index 2458748..6c4b513 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -340,12 +340,12 @@ static int cap_task_create(unsigned long clone_flags)
return 0;
}

-static int cap_task_alloc_security(struct task_struct *p)
+static int cap_cred_alloc_security(struct cred *cred)
{
return 0;
}

-static void cap_task_free_security(struct task_struct *p)
+static void cap_cred_free(struct cred *cred)
{
}

@@ -890,8 +890,8 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, file_receive);
set_to_cap_if_null(ops, dentry_open);
set_to_cap_if_null(ops, task_create);
- set_to_cap_if_null(ops, task_alloc_security);
- set_to_cap_if_null(ops, task_free_security);
+ set_to_cap_if_null(ops, cred_alloc_security);
+ set_to_cap_if_null(ops, cred_free);
set_to_cap_if_null(ops, task_setuid);
set_to_cap_if_null(ops, task_post_setuid);
set_to_cap_if_null(ops, task_setgid);
diff --git a/security/security.c b/security/security.c
index c2203f5..23c3c91 100644
--- a/security/security.c
+++ b/security/security.c
@@ -602,14 +602,14 @@ int security_task_create(unsigned long clone_flags)
return security_ops->task_create(clone_flags);
}

-int security_task_alloc(struct task_struct *p)
+int security_cred_alloc(struct cred *cred)
{
- return security_ops->task_alloc_security(p);
+ return security_ops->cred_alloc_security(cred);
}

-void security_task_free(struct task_struct *p)
+void security_cred_free(struct cred *cred)
{
- security_ops->task_free_security(p);
+ security_ops->cred_free(cred);
}

int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3e8900e..1efc990 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -157,7 +157,7 @@ static int selinux_secmark_enabled(void)

/* Allocate and free functions for each kind of security blob. */

-static int task_alloc_security(struct task_struct *task)
+static int cred_alloc_security(struct cred *cred)
{
struct task_security_struct *tsec;

@@ -166,18 +166,11 @@ static int task_alloc_security(struct task_struct *task)
return -ENOMEM;

tsec->osid = tsec->sid = SECINITSID_UNLABELED;
- task->cred->security = tsec;
+ cred->security = tsec;

return 0;
}

-static void task_free_security(struct task_struct *task)
-{
- struct task_security_struct *tsec = task->cred->security;
- task->cred->security = NULL;
- kfree(tsec);
-}
-
static int inode_alloc_security(struct inode *inode)
{
struct task_security_struct *tsec = current->cred->security;
@@ -3188,17 +3181,17 @@ static int selinux_task_create(unsigned long clone_flags)
return task_has_perm(current, current, PROCESS__FORK);
}

-static int selinux_task_alloc_security(struct task_struct *tsk)
+static int selinux_cred_alloc_security(struct cred *cred)
{
struct task_security_struct *tsec1, *tsec2;
int rc;

tsec1 = current->cred->security;

- rc = task_alloc_security(tsk);
+ rc = cred_alloc_security(cred);
if (rc)
return rc;
- tsec2 = tsk->cred->security;
+ tsec2 = cred->security;

tsec2->osid = tsec1->osid;
tsec2->sid = tsec1->sid;
@@ -3212,9 +3205,14 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
return 0;
}

-static void selinux_task_free_security(struct task_struct *tsk)
+/*
+ * detach and free the LSM part of a set of credentials
+ */
+static void selinux_cred_free(struct cred *cred)
{
- task_free_security(tsk);
+ struct task_security_struct *tsec = cred->security;
+ cred->security = NULL;
+ kfree(tsec);
}

static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
@@ -5446,8 +5444,8 @@ static struct security_operations selinux_ops = {
.dentry_open = selinux_dentry_open,

.task_create = selinux_task_create,
- .task_alloc_security = selinux_task_alloc_security,
- .task_free_security = selinux_task_free_security,
+ .cred_alloc_security = selinux_cred_alloc_security,
+ .cred_free = selinux_cred_free,
.task_setuid = selinux_task_setuid,
.task_post_setuid = selinux_task_post_setuid,
.task_setgid = selinux_task_setgid,
@@ -5577,7 +5575,7 @@ static __init int selinux_init(void)
printk(KERN_INFO "SELinux: Initializing.\n");

/* Set the security state for the initial task. */
- if (task_alloc_security(current))
+ if (cred_alloc_security(current->cred))
panic("SELinux: Failed to initialize initial task.\n");
tsec = current->cred->security;
tsec->osid = tsec->sid = SECINITSID_KERNEL;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ccded56..7da592f 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -975,8 +975,8 @@ static int smack_file_receive(struct file *file)
*/

/**
- * smack_task_alloc_security - "allocate" a task blob
- * @tsk: the task in need of a blob
+ * smack_cred_alloc_security - "allocate" a task cred blob
+ * @cred: the task creds in need of a blob
*
* Smack isn't using copies of blobs. Everyone
* points to an immutable list. No alloc required.
@@ -984,24 +984,24 @@ static int smack_file_receive(struct file *file)
*
* Always returns 0
*/
-static int smack_task_alloc_security(struct task_struct *tsk)
+static int smack_cred_alloc_security(struct cred *cred)
{
- tsk->cred->security = current->cred->security;
+ cred->security = current->cred->security;

return 0;
}

/**
- * smack_task_free_security - "free" a task blob
- * @task: the task with the blob
+ * smack_cred_free - "free" task-level security credentials
+ * @cred: the credentials in question
*
* Smack isn't using copies of blobs. Everyone
* points to an immutable list. The blobs never go away.
* There is no leak here.
*/
-static void smack_task_free_security(struct task_struct *task)
+static void smack_cred_free(struct cred *cred)
{
- task->cred->security = NULL;
+ cred->security = NULL;
}

/**
@@ -2627,8 +2627,8 @@ struct security_operations smack_ops = {
.file_send_sigiotask = smack_file_send_sigiotask,
.file_receive = smack_file_receive,

- .task_alloc_security = smack_task_alloc_security,
- .task_free_security = smack_task_free_security,
+ .cred_alloc_security = smack_cred_alloc_security,
+ .cred_free = smack_cred_free,
.task_post_setuid = cap_task_post_setuid,
.task_setpgid = smack_task_setpgid,
.task_getpgid = smack_task_getpgid,

2008-08-06 15:51:55

by David Howells

[permalink] [raw]
Subject: [PATCH 07/24] CRED: Wrap most current->e?[ug]id and some task->e?[ug]id [ver #7]

Change most current->e?[ug]id to current_e?[ug]id().

Change some task->e?[ug]id to task_e?[ug]id(). In some places it makes more
sense to use RCU directly rather than a convenient wrapper; these are addressed
by a later patch (see the patch entitled "CRED: Use RCU to access another
task's creds and to release a task's own creds").

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

arch/ia64/kernel/mca_drv.c | 2 -
arch/ia64/kernel/perfmon.c | 19 +++++---
arch/ia64/kernel/signal.c | 4 +-
arch/mips/kernel/mips-mt-fpaff.c | 5 +-
arch/parisc/kernel/signal.c | 2 -
arch/powerpc/mm/fault.c | 2 -
arch/s390/hypfs/inode.c | 4 +-
arch/x86/mm/fault.c | 2 -
drivers/block/loop.c | 6 ++-
drivers/char/tty_audit.c | 6 ++-
drivers/gpu/drm/drm_fops.c | 2 -
drivers/media/video/cpia.c | 2 -
drivers/net/tun.c | 4 +-
drivers/net/wan/sbni.c | 9 ++--
drivers/usb/core/devio.c | 8 ++-
fs/affs/super.c | 4 +-
fs/autofs/inode.c | 4 +-
fs/autofs4/inode.c | 4 +-
fs/autofs4/waitq.c | 4 +-
fs/binfmt_elf_fdpic.c | 8 ++-
fs/cifs/cifs_fs_sb.h | 2 -
fs/cifs/connect.c | 4 +-
fs/cifs/ioctl.c | 2 -
fs/dquot.c | 2 -
fs/ecryptfs/messaging.c | 18 ++++----
fs/ecryptfs/miscdev.c | 20 +++++---
fs/exec.c | 14 +++---
fs/fat/inode.c | 4 +-
fs/fcntl.c | 2 -
fs/hfs/super.c | 4 +-
fs/hfsplus/options.c | 4 +-
fs/hpfs/super.c | 4 +-
fs/inotify_user.c | 2 -
fs/ioprio.c | 4 +-
fs/namespace.c | 2 -
fs/ncpfs/ioctl.c | 91 ++++++++++++++++++--------------------
fs/omfs/inode.c | 4 +-
fs/quota.c | 4 +-
fs/smbfs/dir.c | 4 +-
fs/smbfs/inode.c | 2 -
fs/smbfs/proc.c | 2 -
fs/xfs/linux-2.6/xfs_cred.h | 2 -
include/linux/cred.h | 25 ++++++++++
include/net/scm.h | 4 +-
ipc/mqueue.c | 2 -
ipc/shm.c | 5 +-
ipc/util.c | 18 +++++---
kernel/acct.c | 7 +--
kernel/auditsc.c | 6 ++-
kernel/cgroup.c | 5 +-
kernel/futex.c | 8 ++-
kernel/futex_compat.c | 3 +
kernel/ptrace.c | 15 ++++--
kernel/sched.c | 11 +++--
kernel/signal.c | 15 ++++--
kernel/sys.c | 16 +++----
kernel/sysctl.c | 2 -
kernel/timer.c | 8 ++-
kernel/user_namespace.c | 2 -
mm/mempolicy.c | 7 ++-
mm/migrate.c | 7 ++-
net/ax25/af_ax25.c | 2 -
net/ax25/ax25_route.c | 2 -
net/core/dev.c | 8 +++
net/core/scm.c | 8 ++-
net/ipv6/ip6_flowlabel.c | 2 -
net/netrom/af_netrom.c | 4 +-
net/rose/af_rose.c | 4 +-
net/unix/af_unix.c | 11 ++---
security/commoncap.c | 27 +++++++----
70 files changed, 304 insertions(+), 228 deletions(-)


diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index fab1d21..f94aaa8 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -158,7 +158,7 @@ mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr)
ia64_mlogbuf_dump();
printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "
"iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",
- raw_smp_processor_id(), current->pid, current->uid,
+ raw_smp_processor_id(), current->pid, current_uid(),
iip, ipsr, paddr, current->comm);

spin_lock(&mca_bh_lock);
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 0cd24b2..ffe6de0 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2403,22 +2403,25 @@ error_kmem:
static int
pfm_bad_permissions(struct task_struct *task)
{
+ uid_t uid = current_uid();
+ gid_t gid = current_gid();
+
/* inspired by ptrace_attach() */
DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n",
- current->uid,
- current->gid,
+ uid,
+ gid,
task->euid,
task->suid,
task->uid,
task->egid,
task->sgid));

- return ((current->uid != task->euid)
- || (current->uid != task->suid)
- || (current->uid != task->uid)
- || (current->gid != task->egid)
- || (current->gid != task->sgid)
- || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE);
+ return (uid != task->euid)
+ || (uid != task->suid)
+ || (uid != task->uid)
+ || (gid != task->egid)
+ || (gid != task->sgid)
+ || (gid != task->gid)) && !capable(CAP_SYS_PTRACE);
}

static int
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 19c5a78..434e93e 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -228,7 +228,7 @@ ia64_rt_sigreturn (struct sigscratch *scr)
si.si_errno = 0;
si.si_code = SI_KERNEL;
si.si_pid = task_pid_vnr(current);
- si.si_uid = current->uid;
+ si.si_uid = current_uid();
si.si_addr = sc;
force_sig_info(SIGSEGV, &si, current);
return retval;
@@ -325,7 +325,7 @@ force_sigsegv_info (int sig, void __user *addr)
si.si_errno = 0;
si.si_code = SI_KERNEL;
si.si_pid = task_pid_vnr(current);
- si.si_uid = current->uid;
+ si.si_uid = current_uid();
si.si_addr = addr;
force_sig_info(SIGSEGV, &si, current);
return 0;
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c
index df4d3f2..928c72b 100644
--- a/arch/mips/kernel/mips-mt-fpaff.c
+++ b/arch/mips/kernel/mips-mt-fpaff.c
@@ -51,6 +51,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
int retval;
struct task_struct *p;
struct thread_info *ti;
+ uid_t euid;

if (len < sizeof(new_mask))
return -EINVAL;
@@ -76,9 +77,9 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
*/
get_task_struct(p);

+ euid = current_euid();
retval = -EPERM;
- if ((current->euid != p->euid) && (current->euid != p->uid) &&
- !capable(CAP_SYS_NICE)) {
+ if (euid != p->euid && euid != p->uid && !capable(CAP_SYS_NICE)) {
read_unlock(&tasklist_lock);
goto out_unlock;
}
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 06213d1..f825442 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -182,7 +182,7 @@ give_sigsegv:
si.si_errno = 0;
si.si_code = SI_KERNEL;
si.si_pid = task_pid_vnr(current);
- si.si_uid = current->uid;
+ si.si_uid = current_uid();
si.si_addr = &frame->uc;
force_sig_info(SIGSEGV, &si, current);
return;
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 565b7a2..8660986 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -339,7 +339,7 @@ bad_area_nosemaphore:
&& printk_ratelimit())
printk(KERN_CRIT "kernel tried to execute NX-protected"
" page (%lx) - exploit attempt? (uid: %d)\n",
- address, current->uid);
+ address, current_uid());

return SIGSEGV;

diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 7383781..5a11c77 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -280,8 +280,8 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
if (!sbi)
return -ENOMEM;
mutex_init(&sbi->lock);
- sbi->uid = current->uid;
- sbi->gid = current->gid;
+ sbi->uid = current_uid();
+ sbi->gid = current_gid();
sb->s_fs_info = sbi;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 455f3fe..5fc291c 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -394,7 +394,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code,
if (pte && pte_present(*pte) && !pte_exec(*pte))
printk(KERN_CRIT "kernel tried to execute "
"NX-protected page - exploit attempt? "
- "(uid: %d)\n", current->uid);
+ "(uid: %d)\n", current_uid());
}
#endif

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index d3a25b0..e96bc38 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -936,8 +936,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
{
int err;
struct loop_func_table *xfer;
+ uid_t uid = current_uid();

- if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid &&
+ if (lo->lo_encrypt_key_size &&
+ lo->lo_key_owner != uid &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
if (lo->lo_state != Lo_bound)
@@ -992,7 +994,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
if (info->lo_encrypt_key_size) {
memcpy(lo->lo_encrypt_key, info->lo_encrypt_key,
info->lo_encrypt_key_size);
- lo->lo_key_owner = current->uid;
+ lo->lo_key_owner = uid;
}

return 0;
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 3582f43..570d337 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -86,10 +86,12 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
if (ab) {
char name[sizeof(tsk->comm)];
+ uid_t uid = task_uid(tsk);

audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u "
- "major=%d minor=%d comm=", tsk->pid, tsk->uid,
- loginuid, sessionid, buf->major, buf->minor);
+ "major=%d minor=%d comm=",
+ tsk->pid, uid, loginuid, sessionid,
+ buf->major, buf->minor);
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 851a53f..dcf8b4d 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
memset(priv, 0, sizeof(*priv));
filp->private_data = priv;
priv->filp = filp;
- priv->uid = current->euid;
+ priv->uid = current_euid();
priv->pid = task_pid_nr(current);
priv->minor = idr_find(&drm_minors_idr, minor_id);
priv->ioctl_count = 0;
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index dc8cc61..824cb99 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3202,7 +3202,7 @@ static int cpia_open(struct inode *inode, struct file *file)

/* Set ownership of /proc/cpia/videoX to current user */
if(cam->proc_entry)
- cam->proc_entry->uid = current->uid;
+ cam->proc_entry->uid = current_uid();

/* set mark for loading first frame uncompressed */
cam->first_frame = 1;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e6bbc63..4174855 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -654,9 +654,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)

/* Check permissions */
if (((tun->owner != -1 &&
- current->euid != tun->owner) ||
+ current_euid() != tun->owner) ||
(tun->group != -1 &&
- current->egid != tun->group)) &&
+ current_egid() != tun->group)) &&
!capable(CAP_NET_ADMIN))
return -EPERM;
}
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index e59255a..1ae5bae 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -1302,6 +1302,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
{
struct net_local *nl = (struct net_local *) dev->priv;
struct sbni_flags flags;
+ uid_t euid = current_euid();
int error = 0;

#ifdef CONFIG_SBNI_MULTILINE
@@ -1317,7 +1318,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
break;

case SIOCDEVRESINSTATS :
- if( current->euid != 0 ) /* root only */
+ if (euid != 0) /* root only */
return -EPERM;
memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
break;
@@ -1334,7 +1335,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
break;

case SIOCDEVSHWSTATE :
- if( current->euid != 0 ) /* root only */
+ if (euid != 0) /* root only */
return -EPERM;

spin_lock( &nl->lock );
@@ -1355,7 +1356,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
#ifdef CONFIG_SBNI_MULTILINE

case SIOCDEVENSLAVE :
- if( current->euid != 0 ) /* root only */
+ if (euid != 0) /* root only */
return -EPERM;

if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name ))
@@ -1370,7 +1371,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
return enslave( dev, slave_dev );

case SIOCDEVEMANSIPATE :
- if( current->euid != 0 ) /* root only */
+ if (euid != 0) /* root only */
return -EPERM;

return emancipate( dev );
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 20290c5..6c7c115 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -616,8 +616,8 @@ static int usbdev_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
ps->disc_pid = get_pid(task_pid(current));
- ps->disc_uid = current->uid;
- ps->disc_euid = current->euid;
+ ps->disc_uid = current_uid();
+ ps->disc_euid = current_euid();
ps->disccontext = NULL;
ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid);
@@ -1171,8 +1171,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->signr = uurb->signr;
as->ifnum = ifnum;
as->pid = get_pid(task_pid(current));
- as->uid = current->uid;
- as->euid = current->euid;
+ as->uid = current_uid();
+ as->euid = current_euid();
security_task_getsecid(current, &as->secid);
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 3a89094..d5d9b10 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -163,8 +163,8 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s

/* Fill in defaults */

- *uid = current->uid;
- *gid = current->gid;
+ *uid = current_uid();
+ *gid = current_gid();
*reserved = 2;
*root = -1;
*blocksize = -1;
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index dda510d..61429c5 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -76,8 +76,8 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
substring_t args[MAX_OPT_ARGS];
int option;

- *uid = current->uid;
- *gid = current->gid;
+ *uid = current_uid();
+ *gid = current_gid();
*pgrp = task_pgrp_nr(current);

*minproto = *maxproto = AUTOFS_PROTO_VERSION;
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 7bb3e5b..8c9cf24 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -233,8 +233,8 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
substring_t args[MAX_OPT_ARGS];
int option;

- *uid = current->uid;
- *gid = current->gid;
+ *uid = current_uid();
+ *gid = current_gid();
*pgrp = task_pgrp_nr(current);

*minproto = AUTOFS_MIN_PROTO_VERSION;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 35216d1..dc1fa39 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -391,8 +391,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
memcpy(&wq->name, &qstr, sizeof(struct qstr));
wq->dev = autofs4_get_dev(sbi);
wq->ino = autofs4_get_ino(sbi);
- wq->uid = current->uid;
- wq->gid = current->gid;
+ wq->uid = current_uid();
+ wq->gid = current_gid();
wq->pid = current->pid;
wq->tgid = current->tgid;
wq->status = -EINTR; /* Status return if interrupted */
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 80c1f95..cee7ed4 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -586,10 +586,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr);
- NEW_AUX_ENT(AT_UID, (elf_addr_t) current->uid);
- NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid);
- NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid);
- NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid);
+ NEW_AUX_ENT(AT_UID, (elf_addr_t) current_uid());
+ NEW_AUX_ENT(AT_EUID, (elf_addr_t) current_euid());
+ NEW_AUX_ENT(AT_GID, (elf_addr_t) current_gid());
+ NEW_AUX_ENT(AT_EGID, (elf_addr_t) current_egid());

#ifdef ARCH_DLINFO
nr = 0;
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 877c854..1e7b874 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -19,7 +19,7 @@
#define _CIFS_FS_SB_H

#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
-#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */
+#define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index b51d577..ec56417 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -827,8 +827,8 @@ cifs_parse_mount_options(char *options, const char *devname,
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
vol->target_rfc1001_name[0] = 0;
- vol->linux_uid = current->uid; /* current->euid instead? */
- vol->linux_gid = current->gid;
+ vol->linux_uid = current_uid(); /* use current_euid() instead? */
+ vol->linux_gid = current_gid();
vol->dir_mode = S_IRWXUGO;
/* 2767 perms indicate mandatory locking support */
vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 0088a5b..f946506 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -65,7 +65,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
switch (command) {
case CIFS_IOC_CHECKUMOUNT:
cFYI(1, ("User unmount attempted"));
- if (cifs_sb->mnt_uid == current->uid)
+ if (cifs_sb->mnt_uid == current_uid())
rc = 0;
else {
rc = -EACCES;
diff --git a/fs/dquot.c b/fs/dquot.c
index 7307324..991d995 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -985,7 +985,7 @@ static void send_warning(const struct dquot *dquot, const char warntype)
MINOR(dquot->dq_sb->s_dev));
if (ret)
goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current->user->uid);
+ ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
if (ret)
goto attr_err_out;
genlmsg_end(skb, msg_head);
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index 1b5c200..92bf606 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -377,6 +377,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
size_t msg_size;
struct nsproxy *nsproxy;
struct user_namespace *current_user_ns;
+ uid_t ctx_euid;
int rc;

if (msg->index >= ecryptfs_message_buf_len) {
@@ -401,8 +402,8 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
goto wake_up;
}
current_user_ns = nsproxy->user_ns;
- rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid,
- current_user_ns);
+ ctx_euid = task_euid(msg_ctx->task);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, current_user_ns);
rcu_read_unlock();
mutex_unlock(&ecryptfs_daemon_hash_mux);
if (rc) {
@@ -410,14 +411,14 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
printk(KERN_WARNING "%s: User [%d] received a "
"message response from process [0x%p] but does "
"not have a registered daemon\n", __func__,
- msg_ctx->task->euid, pid);
+ ctx_euid, pid);
goto wake_up;
}
- if (msg_ctx->task->euid != euid) {
+ if (ctx_euid != euid) {
rc = -EBADMSG;
printk(KERN_WARNING "%s: Received message from user "
"[%d]; expected message from user [%d]\n", __func__,
- euid, msg_ctx->task->euid);
+ euid, ctx_euid);
goto unlock;
}
if (current_user_ns != user_ns) {
@@ -431,7 +432,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
rc = -EBADMSG;
printk(KERN_ERR "%s: User [%d] sent a message response "
"from an unrecognized process [0x%p]\n",
- __func__, msg_ctx->task->euid, pid);
+ __func__, ctx_euid, pid);
goto unlock;
}
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
@@ -482,14 +483,15 @@ ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
{
struct ecryptfs_daemon *daemon;
+ uid_t euid = current_euid();
int rc;

- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
current->nsproxy->user_ns);
if (rc || !daemon) {
rc = -ENOTCONN;
printk(KERN_ERR "%s: User [%d] does not have a daemon "
- "registered\n", __func__, current->euid);
+ "registered\n", __func__, euid);
goto out;
}
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index b484792..047ac60 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -42,11 +42,12 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
{
struct ecryptfs_daemon *daemon;
unsigned int mask = 0;
+ uid_t euid = current_euid();
int rc;

mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
current->nsproxy->user_ns);
BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux);
@@ -83,6 +84,7 @@ static int
ecryptfs_miscdev_open(struct inode *inode, struct file *file)
{
struct ecryptfs_daemon *daemon = NULL;
+ uid_t euid = current_euid();
int rc;

mutex_lock(&ecryptfs_daemon_hash_mux);
@@ -93,10 +95,10 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
"count; rc = [%d]\n", __func__, rc);
goto out_unlock_daemon_list;
}
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
current->nsproxy->user_ns);
if (rc || !daemon) {
- rc = ecryptfs_spawn_daemon(&daemon, current->euid,
+ rc = ecryptfs_spawn_daemon(&daemon, euid,
current->nsproxy->user_ns,
task_pid(current));
if (rc) {
@@ -147,10 +149,11 @@ static int
ecryptfs_miscdev_release(struct inode *inode, struct file *file)
{
struct ecryptfs_daemon *daemon = NULL;
+ uid_t euid = current_euid();
int rc;

mutex_lock(&ecryptfs_daemon_hash_mux);
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
current->nsproxy->user_ns);
BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux);
@@ -246,11 +249,12 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
char packet_length[3];
size_t i;
size_t total_length;
+ uid_t euid = current_euid();
int rc;

mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
current->nsproxy->user_ns);
BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux);
@@ -290,7 +294,7 @@ check_list:
* message from the queue; try again */
goto check_list;
}
- BUG_ON(current->euid != daemon->euid);
+ BUG_ON(euid != daemon->euid);
BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
BUG_ON(task_pid(current) != daemon->pid);
msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
@@ -414,6 +418,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
size_t packet_size, packet_size_length, i;
ssize_t sz = 0;
char *data;
+ uid_t euid = current_euid();
int rc;

if (count == 0)
@@ -463,8 +468,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
goto out_free;
}
rc = ecryptfs_miscdev_response(&data[i], packet_size,
- current->euid,
- current->nsproxy->user_ns,
+ euid, current->nsproxy->user_ns,
task_pid(current), seq);
if (rc)
printk(KERN_WARNING "%s: Failed to deliver miscdev "
diff --git a/fs/exec.c b/fs/exec.c
index 3b3231b..08c884c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -985,7 +985,7 @@ int flush_old_exec(struct linux_binprm * bprm)
/* This is the point of no return */
current->sas_ss_sp = current->sas_ss_size = 0;

- if (current->euid == current->uid && current->egid == current->gid)
+ if (current_euid() == current_uid() && current_egid() == current_gid())
set_dumpable(current->mm, 1);
else
set_dumpable(current->mm, suid_dumpable);
@@ -1012,7 +1012,7 @@ int flush_old_exec(struct linux_binprm * bprm)
*/
current->mm->task_size = TASK_SIZE;

- if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) {
+ if (bprm->e_uid != current_euid() || bprm->e_gid != current_egid()) {
suid_keys(current);
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;
@@ -1052,8 +1052,8 @@ int prepare_binprm(struct linux_binprm *bprm)
if (bprm->file->f_op == NULL)
return -EACCES;

- bprm->e_uid = current->euid;
- bprm->e_gid = current->egid;
+ bprm->e_uid = current_euid();
+ bprm->e_gid = current_egid();

if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
@@ -1101,7 +1101,7 @@ void compute_creds(struct linux_binprm *bprm)
{
int unsafe;

- if (bprm->e_uid != current->uid) {
+ if (bprm->e_uid != current_uid()) {
suid_keys(current);
current->pdeath_signal = 0;
}
@@ -1429,7 +1429,7 @@ static int format_corename(char *corename, int nr_threads, long signr)
/* uid */
case 'u':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->uid);
+ "%d", current_uid());
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
@@ -1437,7 +1437,7 @@ static int format_corename(char *corename, int nr_threads, long signr)
/* gid */
case 'g':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->gid);
+ "%d", current_gid());
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 6d266d7..52925a8 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -941,8 +941,8 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,

opts->isvfat = is_vfat;

- opts->fs_uid = current->uid;
- opts->fs_gid = current->gid;
+ opts->fs_uid = current_uid();
+ opts->fs_gid = current_gid();
opts->fs_fmask = opts->fs_dmask = current->fs->umask;
opts->allow_utime = -1;
opts->codepage = fat_default_codepage;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index ac4f7db..bf049a8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -211,7 +211,7 @@ int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
if (err)
return err;

- f_modown(filp, pid, type, current->uid, current->euid, force);
+ f_modown(filp, pid, type, current_uid(), current_euid(), force);
return 0;
}
EXPORT_SYMBOL(__f_setown);
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 4abb104..2d5df7d 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -210,8 +210,8 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
int tmp, token;

/* initialize the sb with defaults */
- hsb->s_uid = current->uid;
- hsb->s_gid = current->gid;
+ hsb->s_uid = current_uid();
+ hsb->s_gid = current_gid();
hsb->s_file_umask = 0133;
hsb->s_dir_umask = 0022;
hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f); /* == '????' */
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 9997cbf..4cfe720 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -49,8 +49,8 @@ void hfsplus_fill_defaults(struct hfsplus_sb_info *opts)
opts->creator = HFSPLUS_DEF_CR_TYPE;
opts->type = HFSPLUS_DEF_CR_TYPE;
opts->umask = current->fs->umask;
- opts->uid = current->uid;
- opts->gid = current->gid;
+ opts->uid = current_uid();
+ opts->gid = current_gid();
opts->part = -1;
opts->session = -1;
}
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index b8ae9c9..5e109f9 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -475,8 +475,8 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)

init_MUTEX(&sbi->hpfs_creation_de);

- uid = current->uid;
- gid = current->gid;
+ uid = current_uid();
+ gid = current_gid();
umask = current->fs->umask;
lowercase = 0;
conv = CONV_BINARY;
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 6024942..90eed91 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -591,7 +591,7 @@ asmlinkage long sys_inotify_init1(int flags)
goto out_put_fd;
}

- user = get_uid(current->user);
+ user = get_current_user();
if (unlikely(atomic_read(&user->inotify_devs) >=
inotify_max_user_instances)) {
ret = -EMFILE;
diff --git a/fs/ioprio.c b/fs/ioprio.c
index c4a1c3c..b1214b9 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -32,8 +32,8 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
int err;
struct io_context *ioc;

- if (task->uid != current->euid &&
- task->uid != current->uid && !capable(CAP_SYS_NICE))
+ if (task->uid != current_euid() &&
+ task->uid != current_uid() && !capable(CAP_SYS_NICE))
return -EPERM;

err = security_task_setioprio(task, ioprio);
diff --git a/fs/namespace.c b/fs/namespace.c
index 6e283c9..2c11cf3 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1176,7 +1176,7 @@ static int mount_is_safe(struct nameidata *nd)
if (S_ISLNK(nd->path.dentry->d_inode->i_mode))
return -EPERM;
if (nd->path.dentry->d_inode->i_mode & S_ISVTX) {
- if (current->uid != nd->path.dentry->d_inode->i_uid)
+ if (current_uid() != nd->path.dentry->d_inode->i_uid)
return -EPERM;
}
if (vfs_permission(nd, MAY_WRITE))
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 3a97c95..6d04e05 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -40,10 +40,10 @@ ncp_get_fs_info(struct ncp_server * server, struct file *file,
struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info info;

- if ((file_permission(file, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(file, MAY_WRITE) != 0
+ && current_uid() != server->m.mounted_uid)
return -EACCES;
- }
+
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;

@@ -70,10 +70,10 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info_v2 info2;

- if ((file_permission(file, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(file, MAY_WRITE) != 0
+ && current_uid() != server->m.mounted_uid)
return -EACCES;
- }
+
if (copy_from_user(&info2, arg, sizeof(info2)))
return -EFAULT;

@@ -141,10 +141,10 @@ ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
struct inode *inode = file->f_path.dentry->d_inode;
struct compat_ncp_fs_info_v2 info2;

- if ((file_permission(file, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(file, MAY_WRITE) != 0
+ && current_uid() != server->m.mounted_uid)
return -EACCES;
- }
+
if (copy_from_user(&info2, arg, sizeof(info2)))
return -EFAULT;

@@ -270,16 +270,17 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
struct ncp_ioctl_request request;
char* bouncebuffer;
void __user *argp = (void __user *)arg;
+ uid_t uid = current_uid();

switch (cmd) {
#ifdef CONFIG_COMPAT
case NCP_IOC_NCPREQUEST_32:
#endif
case NCP_IOC_NCPREQUEST:
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
#ifdef CONFIG_COMPAT
if (cmd == NCP_IOC_NCPREQUEST_32) {
struct compat_ncp_ioctl_request request32;
@@ -356,10 +357,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_GETMOUNTUID16:
case NCP_IOC_GETMOUNTUID32:
case NCP_IOC_GETMOUNTUID64:
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(filp, MAY_READ) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
if (cmd == NCP_IOC_GETMOUNTUID16) {
u16 uid;
SET_UID(uid, server->m.mounted_uid);
@@ -380,11 +381,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
{
struct ncp_setroot_ioctl sr;

- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_READ) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
if (server->m.mounted_vol[0]) {
struct dentry* dentry = inode->i_sb->s_root;

@@ -408,6 +408,7 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
return -EFAULT;
return 0;
}
+
case NCP_IOC_SETROOT:
{
struct ncp_setroot_ioctl sr;
@@ -455,11 +456,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,

#ifdef CONFIG_NCPFS_PACKET_SIGNING
case NCP_IOC_SIGN_INIT:
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
if (argp) {
if (server->sign_wanted)
{
@@ -478,24 +478,22 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
return 0;

case NCP_IOC_SIGN_WANTED:
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_READ) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }

if (put_user(server->sign_wanted, (int __user *)argp))
return -EFAULT;
return 0;
+
case NCP_IOC_SET_SIGN_WANTED:
{
int newstate;

- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
/* get only low 8 bits... */
if (get_user(newstate, (unsigned char __user *)argp))
return -EFAULT;
@@ -512,11 +510,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,

#ifdef CONFIG_NCPFS_IOCTL_LOCKING
case NCP_IOC_LOCKUNLOCK:
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
{
struct ncp_lock_ioctl rqdata;

@@ -585,9 +582,8 @@ outrel:

#ifdef CONFIG_COMPAT
case NCP_IOC_GETOBJECTNAME_32:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct compat_ncp_objectname_ioctl user;
size_t outl;
@@ -609,10 +605,10 @@ outrel:
return 0;
}
#endif
+
case NCP_IOC_GETOBJECTNAME:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_objectname_ioctl user;
size_t outl;
@@ -633,13 +629,13 @@ outrel:
return -EFAULT;
return 0;
}
+
#ifdef CONFIG_COMPAT
case NCP_IOC_SETOBJECTNAME_32:
#endif
case NCP_IOC_SETOBJECTNAME:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_objectname_ioctl user;
void* newname;
@@ -691,13 +687,13 @@ outrel:
kfree(oldname);
return 0;
}
+
#ifdef CONFIG_COMPAT
case NCP_IOC_GETPRIVATEDATA_32:
#endif
case NCP_IOC_GETPRIVATEDATA:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_privatedata_ioctl user;
size_t outl;
@@ -736,13 +732,13 @@ outrel:

return 0;
}
+
#ifdef CONFIG_COMPAT
case NCP_IOC_SETPRIVATEDATA_32:
#endif
case NCP_IOC_SETPRIVATEDATA:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_privatedata_ioctl user;
void* new;
@@ -794,9 +790,10 @@ outrel:
#endif /* CONFIG_NCPFS_NLS */

case NCP_IOC_SETDENTRYTTL:
- if ((file_permission(filp, MAY_WRITE) != 0) &&
- (current->uid != server->m.mounted_uid))
+ if (file_permission(filp, MAY_WRITE) != 0 &&
+ uid != server->m.mounted_uid)
return -EACCES;
+
{
u_int32_t user;

diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index 903f70f..9fc94de 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -421,8 +421,8 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)

sb->s_fs_info = sbi;

- sbi->s_uid = current->uid;
- sbi->s_gid = current->gid;
+ sbi->s_uid = current_uid();
+ sbi->s_gid = current_gid();
sbi->s_dmask = sbi->s_fmask = current->fs->umask;

if (!parse_options((char *) data, sbi))
diff --git a/fs/quota.c b/fs/quota.c
index 7f4386e..b7fe44e 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -79,7 +79,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid

/* Check privileges */
if (cmd == Q_GETQUOTA) {
- if (((type == USRQUOTA && current->euid != id) ||
+ if (((type == USRQUOTA && current_euid() != id) ||
(type == GRPQUOTA && !in_egroup_p(id))) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -130,7 +130,7 @@ static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t i

/* Check privileges */
if (cmd == Q_XGETQUOTA) {
- if (((type == XQM_USRQUOTA && current->euid != id) ||
+ if (((type == XQM_USRQUOTA && current_euid() != id) ||
(type == XQM_GRPQUOTA && !in_egroup_p(id))) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 48da4fa..9e9bb0d 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -667,8 +667,8 @@ smb_make_node(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)

attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
attr.ia_mode = mode;
- attr.ia_uid = current->euid;
- attr.ia_gid = current->egid;
+ attr.ia_uid = current_euid();
+ attr.ia_gid = current_egid();

if (!new_valid_dev(dev))
return -EINVAL;
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 3528f40..fc27fbf 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -586,7 +586,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
if (parse_options(mnt, raw_data))
goto out_bad_option;
}
- mnt->mounted_uid = current->uid;
+ mnt->mounted_uid = current_uid();
smb_setcodepage(server, &mnt->codepage);

/*
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index ee536e8..9468168 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -864,7 +864,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
goto out;

error = -EACCES;
- if (current->uid != server->mnt->mounted_uid &&
+ if (current_uid() != server->mnt->mounted_uid &&
!capable(CAP_SYS_ADMIN))
goto out;

diff --git a/fs/xfs/linux-2.6/xfs_cred.h b/fs/xfs/linux-2.6/xfs_cred.h
index 652721c..293043a 100644
--- a/fs/xfs/linux-2.6/xfs_cred.h
+++ b/fs/xfs/linux-2.6/xfs_cred.h
@@ -24,7 +24,7 @@
* Credentials
*/
typedef struct cred {
- /* EMPTY */
+ /* EMPTY */
} cred_t;

extern struct cred *sys_cred;
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 9d56fbd..b69222c 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -12,10 +12,35 @@
#ifndef _LINUX_CRED_H
#define _LINUX_CRED_H

+#define get_current_user() (get_uid(current->user))
+
+#define task_uid(task) ((task)->uid)
+#define task_gid(task) ((task)->gid)
+#define task_euid(task) ((task)->euid)
+#define task_egid(task) ((task)->egid)
+
+#define current_uid() (current->uid)
+#define current_gid() (current->gid)
+#define current_euid() (current->euid)
+#define current_egid() (current->egid)
+#define current_suid() (current->suid)
+#define current_sgid() (current->sgid)
#define current_fsuid() (current->fsuid)
#define current_fsgid() (current->fsgid)
#define current_cap() (current->cap_effective)

+#define current_uid_gid(_uid, _gid) \
+do { \
+ *(_uid) = current->uid; \
+ *(_gid) = current->gid; \
+} while(0)
+
+#define current_euid_egid(_uid, _gid) \
+do { \
+ *(_uid) = current->euid; \
+ *(_gid) = current->egid; \
+} while(0)
+
#define current_fsuid_fsgid(_uid, _gid) \
do { \
*(_uid) = current->fsuid; \
diff --git a/include/net/scm.h b/include/net/scm.h
index 06df126..f160116 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -54,8 +54,8 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm)
{
struct task_struct *p = current;
- scm->creds.uid = p->uid;
- scm->creds.gid = p->gid;
+ scm->creds.uid = current_uid();
+ scm->creds.gid = current_gid();
scm->creds.pid = task_tgid_vnr(p);
scm->fp = NULL;
scm->seq = 0;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c652c21..51d9588 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -499,7 +499,7 @@ static void __do_notify(struct mqueue_inode_info *info)
sig_i.si_code = SI_MESGQ;
sig_i.si_value = info->notify.sigev_value;
sig_i.si_pid = task_tgid_vnr(current);
- sig_i.si_uid = current->uid;
+ sig_i.si_uid = current_uid();

kill_pid_info(info->notify.sigev_signo,
&sig_i, info->notify_owner);
diff --git a/ipc/shm.c b/ipc/shm.c
index e77ec69..c46a7e6 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -748,9 +748,10 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
goto out_unlock;

if (!capable(CAP_IPC_LOCK)) {
+ uid_t euid = current_euid();
err = -EPERM;
- if (current->euid != shp->shm_perm.uid &&
- current->euid != shp->shm_perm.cuid)
+ if (euid != shp->shm_perm.uid &&
+ euid != shp->shm_perm.cuid)
goto out_unlock;
if (cmd == SHM_LOCK &&
!current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
diff --git a/ipc/util.c b/ipc/util.c
index 49b3ea6..c8a7670 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -258,6 +258,8 @@ int ipc_get_maxid(struct ipc_ids *ids)

int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
{
+ uid_t euid;
+ gid_t egid;
int id, err;

if (size > IPCMNI)
@@ -272,8 +274,9 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)

ids->in_use++;

- new->cuid = new->uid = current->euid;
- new->gid = new->cgid = current->egid;
+ current_euid_egid(&euid, &egid);
+ new->cuid = new->uid = euid;
+ new->gid = new->cgid = egid;

new->seq = ids->seq++;
if(ids->seq > ids->seq_max)
@@ -616,13 +619,15 @@ void ipc_rcu_putref(void *ptr)

int ipcperms (struct kern_ipc_perm *ipcp, short flag)
{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
+ uid_t euid = current_euid();
int requested_mode, granted_mode, err;

if (unlikely((err = audit_ipc_obj(ipcp))))
return err;
requested_mode = (flag >> 6) | (flag >> 3) | flag;
granted_mode = ipcp->mode;
- if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
+ if (euid == ipcp->cuid ||
+ euid == ipcp->uid)
granted_mode >>= 6;
else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
granted_mode >>= 3;
@@ -784,6 +789,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
struct ipc64_perm *perm, int extra_perm)
{
struct kern_ipc_perm *ipcp;
+ uid_t euid;
int err;

down_write(&ids->rw_mutex);
@@ -803,8 +809,10 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
if (err)
goto out_unlock;
}
- if (current->euid == ipcp->cuid ||
- current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
+
+ euid = current_euid();
+ if (euid == ipcp->cuid ||
+ euid == ipcp->uid || capable(CAP_SYS_ADMIN))
return ipcp;

err = -EPERM;
diff --git a/kernel/acct.c b/kernel/acct.c
index dd68b90..f7f06ce 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -530,15 +530,14 @@ static void do_acct_process(struct bsd_acct_struct *acct,
do_div(elapsed, AHZ);
ac.ac_btime = get_seconds() - elapsed;
/* we really need to bite the bullet and change layout */
- ac.ac_uid = current->uid;
- ac.ac_gid = current->gid;
+ current_uid_gid(&ac.ac_uid, &ac.ac_gid);
#if ACCT_VERSION==2
ac.ac_ahz = AHZ;
#endif
#if ACCT_VERSION==1 || ACCT_VERSION==2
/* backward-compatible 16 bit fields */
- ac.ac_uid16 = current->uid;
- ac.ac_gid16 = current->gid;
+ ac.ac_uid16 = ac.ac_uid;
+ ac.ac_gid16 = ac.ac_gid;
#endif
#if ACCT_VERSION==3
ac.ac_pid = task_tgid_nr_ns(current, ns);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 496c3dd..af446be 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2433,7 +2433,8 @@ void audit_core_dumps(long signr)
{
struct audit_buffer *ab;
u32 sid;
- uid_t auid = audit_get_loginuid(current);
+ uid_t auid = audit_get_loginuid(current), uid;
+ gid_t gid;
unsigned int sessionid = audit_get_sessionid(current);

if (!audit_enabled)
@@ -2443,8 +2444,9 @@ void audit_core_dumps(long signr)
return;

ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+ current_uid_gid(&uid, &gid);
audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
- auid, current->uid, current->gid, sessionid);
+ auid, uid, gid, sessionid);
security_task_getsecid(current, &sid);
if (sid) {
char *ctx = NULL;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f483904..9f5a62a 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1276,6 +1276,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
{
struct task_struct *tsk;
+ uid_t euid;
int ret;

if (pid) {
@@ -1288,8 +1289,8 @@ static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
get_task_struct(tsk);
rcu_read_unlock();

- if ((current->euid) && (current->euid != tsk->uid)
- && (current->euid != tsk->suid)) {
+ euid = current_euid();
+ if (euid && euid != tsk->uid && euid != tsk->suid) {
put_task_struct(tsk);
return -EACCES;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index 7d1136e..a28b82b 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -439,10 +439,11 @@ static void free_pi_state(struct futex_pi_state *pi_state)
static struct task_struct * futex_find_get_task(pid_t pid)
{
struct task_struct *p;
+ uid_t euid = current_euid();

rcu_read_lock();
p = find_task_by_vpid(pid);
- if (!p || ((current->euid != p->euid) && (current->euid != p->uid)))
+ if (!p || (euid != p->euid && euid != p->uid))
p = ERR_PTR(-ESRCH);
else
get_task_struct(p);
@@ -1826,6 +1827,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
{
struct robust_list_head __user *head;
unsigned long ret;
+ uid_t euid = current_euid();

if (!futex_cmpxchg_enabled)
return -ENOSYS;
@@ -1841,8 +1843,8 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
if (!p)
goto err_unlock;
ret = -EPERM;
- if ((current->euid != p->euid) && (current->euid != p->uid) &&
- !capable(CAP_SYS_PTRACE))
+ if (euid != p->euid && euid != p->uid &&
+ !capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->robust_list;
rcu_read_unlock();
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 04ac3a9..3254d4e 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -135,6 +135,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
{
struct compat_robust_list_head __user *head;
unsigned long ret;
+ uid_t euid = current_euid();

if (!futex_cmpxchg_enabled)
return -ENOSYS;
@@ -150,7 +151,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
if (!p)
goto err_unlock;
ret = -EPERM;
- if ((current->euid != p->euid) && (current->euid != p->uid) &&
+ if (euid != p->euid && euid != p->uid &&
!capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->compat_robust_list;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 356699a..0dafab1 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -123,16 +123,19 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
* because setting up the necessary parent/child relationship
* or halting the specified task is impossible.
*/
+ uid_t uid;
+ gid_t gid;
int dumpable = 0;
/* Don't let security modules deny introspection */
if (task == current)
return 0;
- if (((current->uid != task->euid) ||
- (current->uid != task->suid) ||
- (current->uid != task->uid) ||
- (current->gid != task->egid) ||
- (current->gid != task->sgid) ||
- (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+ current_uid_gid(&uid, &gid);
+ if ((uid != task->euid ||
+ uid != task->suid ||
+ uid != task->uid ||
+ gid != task->egid ||
+ gid != task->sgid ||
+ gid != task->gid) && !capable(CAP_SYS_PTRACE))
return -EPERM;
smp_rmb();
if (task->mm)
diff --git a/kernel/sched.c b/kernel/sched.c
index 21f7da9..4a97b29 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4947,6 +4947,7 @@ static int __sched_setscheduler(struct task_struct *p, int policy,
unsigned long flags;
const struct sched_class *prev_class = p->sched_class;
struct rq *rq;
+ uid_t euid;

/* may grab non-irq protected spin_locks */
BUG_ON(in_interrupt());
@@ -4999,8 +5000,9 @@ recheck:
return -EPERM;

/* can't change other user's priorities */
- if ((current->euid != p->euid) &&
- (current->euid != p->uid))
+ euid = current_euid();
+ if (euid != p->euid &&
+ euid != p->uid)
return -EPERM;
}

@@ -5208,6 +5210,7 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask)
cpumask_t cpus_allowed;
cpumask_t new_mask = *in_mask;
struct task_struct *p;
+ uid_t euid;
int retval;

get_online_cpus();
@@ -5228,9 +5231,9 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask)
get_task_struct(p);
read_unlock(&tasklist_lock);

+ euid = current_euid();
retval = -EPERM;
- if ((current->euid != p->euid) && (current->euid != p->uid) &&
- !capable(CAP_SYS_NICE))
+ if (euid != p->euid && euid != p->uid && !capable(CAP_SYS_NICE))
goto out_unlock;

retval = security_task_setscheduler(p, 0, NULL);
diff --git a/kernel/signal.c b/kernel/signal.c
index 954f77d..9ad5b74 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -566,6 +566,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
struct task_struct *t)
{
struct pid *sid;
+ uid_t uid, euid;
int error;

if (!valid_signal(sig))
@@ -578,8 +579,10 @@ static int check_kill_permission(int sig, struct siginfo *info,
if (error)
return error;

- if ((current->euid ^ t->suid) && (current->euid ^ t->uid) &&
- (current->uid ^ t->suid) && (current->uid ^ t->uid) &&
+ uid = current_uid();
+ euid = current_euid();
+ if ((euid ^ t->suid) && (euid ^ t->uid) &&
+ (uid ^ t->suid) && (uid ^ t->uid) &&
!capable(CAP_KILL)) {
switch (sig) {
case SIGCONT:
@@ -841,7 +844,7 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
q->info.si_errno = 0;
q->info.si_code = SI_USER;
q->info.si_pid = task_pid_vnr(current);
- q->info.si_uid = current->uid;
+ q->info.si_uid = current_uid();
break;
case (unsigned long) SEND_SIG_PRIV:
q->info.si_signo = sig;
@@ -1592,7 +1595,7 @@ void ptrace_notify(int exit_code)
info.si_signo = SIGTRAP;
info.si_code = exit_code;
info.si_pid = task_pid_vnr(current);
- info.si_uid = current->uid;
+ info.si_uid = current_uid();

/* Let the debugger run. */
spin_lock_irq(&current->sighand->siglock);
@@ -2205,7 +2208,7 @@ sys_kill(pid_t pid, int sig)
info.si_errno = 0;
info.si_code = SI_USER;
info.si_pid = task_tgid_vnr(current);
- info.si_uid = current->uid;
+ info.si_uid = current_uid();

return kill_something_info(sig, &info, pid);
}
@@ -2222,7 +2225,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
info.si_errno = 0;
info.si_code = SI_TKILL;
info.si_pid = task_tgid_vnr(current);
- info.si_uid = current->uid;
+ info.si_uid = current_uid();

rcu_read_lock();
p = find_task_by_vpid(pid);
diff --git a/kernel/sys.c b/kernel/sys.c
index c018580..f498f30 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -114,10 +114,10 @@ void (*pm_power_off_prepare)(void);

static int set_one_prio(struct task_struct *p, int niceval, int error)
{
+ uid_t euid = current_euid();
int no_nice;

- if (p->uid != current->euid &&
- p->euid != current->euid && !capable(CAP_SYS_NICE)) {
+ if (p->uid != euid && p->euid != euid && !capable(CAP_SYS_NICE)) {
error = -EPERM;
goto out;
}
@@ -176,16 +176,16 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
case PRIO_USER:
user = current->user;
if (!who)
- who = current->uid;
+ who = current_uid();
else
- if ((who != current->uid) && !(user = find_user(who)))
+ if (who != current_uid() && !(user = find_user(who)))
goto out_unlock; /* No processes for this user */

do_each_thread(g, p)
if (p->uid == who)
error = set_one_prio(p, niceval, error);
while_each_thread(g, p);
- if (who != current->uid)
+ if (who != current_uid())
free_uid(user); /* For find_user() */
break;
}
@@ -238,9 +238,9 @@ asmlinkage long sys_getpriority(int which, int who)
case PRIO_USER:
user = current->user;
if (!who)
- who = current->uid;
+ who = current_uid();
else
- if ((who != current->uid) && !(user = find_user(who)))
+ if (who != current_uid() && !(user = find_user(who)))
goto out_unlock; /* No processes for this user */

do_each_thread(g, p)
@@ -250,7 +250,7 @@ asmlinkage long sys_getpriority(int which, int who)
retval = niceval;
}
while_each_thread(g, p);
- if (who != current->uid)
+ if (who != current_uid())
free_uid(user); /* for find_user() */
break;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index fe47133..df3bea1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1631,7 +1631,7 @@ out:

static int test_perm(int mode, int op)
{
- if (!current->euid)
+ if (!current_euid())
mode >>= 6;
else if (in_egroup_p(0))
mode >>= 3;
diff --git a/kernel/timer.c b/kernel/timer.c
index 03bc7f1..c6119bd 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1122,25 +1122,25 @@ asmlinkage long sys_getppid(void)
asmlinkage long sys_getuid(void)
{
/* Only we change this so SMP safe */
- return current->uid;
+ return current_uid();
}

asmlinkage long sys_geteuid(void)
{
/* Only we change this so SMP safe */
- return current->euid;
+ return current_euid();
}

asmlinkage long sys_getgid(void)
{
/* Only we change this so SMP safe */
- return current->gid;
+ return current_gid();
}

asmlinkage long sys_getegid(void)
{
/* Only we change this so SMP safe */
- return current->egid;
+ return current_egid();
}

#endif
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index a9ab059..edbe9f1 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -39,7 +39,7 @@ static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
}

/* Reset current->user with a new one */
- new_user = alloc_uid(ns, current->uid);
+ new_user = alloc_uid(ns, current_uid());
if (!new_user) {
free_uid(ns->root_user);
kfree(ns);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index e550bec..6419497 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1111,6 +1111,7 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
nodemask_t old;
nodemask_t new;
nodemask_t task_nodes;
+ uid_t uid, euid;
int err;

err = get_nodes(&old, old_nodes, maxnode);
@@ -1140,8 +1141,10 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
* capabilities, superuser privileges or the same
* userid as the target process.
*/
- if ((current->euid != task->suid) && (current->euid != task->uid) &&
- (current->uid != task->suid) && (current->uid != task->uid) &&
+ uid = current_uid();
+ euid = current_euid();
+ if (euid != task->suid && euid != task->uid &&
+ uid != task->suid && uid != task->uid &&
!capable(CAP_SYS_NICE)) {
err = -EPERM;
goto out;
diff --git a/mm/migrate.c b/mm/migrate.c
index 153572f..efc200b 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -990,6 +990,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
nodemask_t task_nodes;
struct mm_struct *mm;
struct page_to_node *pm = NULL;
+ uid_t uid, euid;

/* Check flags */
if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL))
@@ -1017,8 +1018,10 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
* capabilities, superuser privileges or the same
* userid as the target process.
*/
- if ((current->euid != task->suid) && (current->euid != task->uid) &&
- (current->uid != task->suid) && (current->uid != task->uid) &&
+ uid = current_uid();
+ euid = current_euid();
+ if (euid != task->suid && euid != task->uid &&
+ uid != task->suid && uid != task->uid &&
!capable(CAP_SYS_NICE)) {
err = -EPERM;
goto out2;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 01c83e2..f3e5217 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1042,7 +1042,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (addr->fsa_ax25.sax25_family != AF_AX25)
return -EINVAL;

- user = ax25_findbyuid(current->euid);
+ user = ax25_findbyuid(current_euid());
if (user) {
call = user->call;
ax25_uid_put(user);
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 8672cd8..c833ba4 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -421,7 +421,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
goto put;
}

- user = ax25_findbyuid(current->euid);
+ user = ax25_findbyuid(current_euid());
if (user) {
ax25->source_addr = user->call;
ax25_uid_put(user);
diff --git a/net/core/dev.c b/net/core/dev.c
index 69320a5..5a32f11 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2906,6 +2906,8 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
static int __dev_set_promiscuity(struct net_device *dev, int inc)
{
unsigned short old_flags = dev->flags;
+ uid_t uid;
+ gid_t gid;

ASSERT_RTNL();

@@ -2930,15 +2932,17 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
printk(KERN_INFO "device %s %s promiscuous mode\n",
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
"left");
- if (audit_enabled)
+ if (audit_enabled) {
+ current_uid_gid(&uid, &gid);
audit_log(current->audit_context, GFP_ATOMIC,
AUDIT_ANOM_PROMISCUOUS,
"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
dev->name, (dev->flags & IFF_PROMISC),
(old_flags & IFF_PROMISC),
audit_get_loginuid(current),
- current->uid, current->gid,
+ uid, gid,
audit_get_sessionid(current));
+ }

if (dev->change_rx_flags)
dev->change_rx_flags(dev, IFF_PROMISC);
diff --git a/net/core/scm.c b/net/core/scm.c
index 10f5c65..4681d8f 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -45,10 +45,10 @@
static __inline__ int scm_check_creds(struct ucred *creds)
{
if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
- ((creds->uid == current->uid || creds->uid == current->euid ||
- creds->uid == current->suid) || capable(CAP_SETUID)) &&
- ((creds->gid == current->gid || creds->gid == current->egid ||
- creds->gid == current->sgid) || capable(CAP_SETGID))) {
+ ((creds->uid == current_uid() || creds->uid == current_euid() ||
+ creds->uid == current_suid()) || capable(CAP_SETUID)) &&
+ ((creds->gid == current_gid() || creds->gid == current_egid() ||
+ creds->gid == current_sgid()) || capable(CAP_SETGID))) {
return 0;
}
return -EPERM;
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 37a4e77..bd3c7b9 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -388,7 +388,7 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
fl->owner = current->pid;
break;
case IPV6_FL_S_USER:
- fl->owner = current->euid;
+ fl->owner = current_euid();
break;
default:
err = -EINVAL;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 532e4fa..a75e072 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -609,7 +609,7 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
} else {
source = &addr->fsa_ax25.sax25_call;

- user = ax25_findbyuid(current->euid);
+ user = ax25_findbyuid(current_euid());
if (user) {
nr->user_addr = user->call;
ax25_uid_put(user);
@@ -683,7 +683,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
}
source = (ax25_address *)dev->dev_addr;

- user = ax25_findbyuid(current->euid);
+ user = ax25_findbyuid(current_euid());
if (user) {
nr->user_addr = user->call;
ax25_uid_put(user);
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index a7f1ce1..d902e2d 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -690,7 +690,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)

source = &addr->srose_call;

- user = ax25_findbyuid(current->euid);
+ user = ax25_findbyuid(current_euid());
if (user) {
rose->source_call = user->call;
ax25_uid_put(user);
@@ -791,7 +791,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
goto out_release;
}

- user = ax25_findbyuid(current->euid);
+ user = ax25_findbyuid(current_euid());
if (!user) {
err = -EINVAL;
goto out_release;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 015606b..6322122 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -467,8 +467,7 @@ static int unix_listen(struct socket *sock, int backlog)
sk->sk_state = TCP_LISTEN;
/* set credentials so connect can copy them */
sk->sk_peercred.pid = task_tgid_vnr(current);
- sk->sk_peercred.uid = current->euid;
- sk->sk_peercred.gid = current->egid;
+ current_euid_egid(&sk->sk_peercred.uid, &sk->sk_peercred.gid);
err = 0;

out_unlock:
@@ -1124,8 +1123,7 @@ restart:
newsk->sk_state = TCP_ESTABLISHED;
newsk->sk_type = sk->sk_type;
newsk->sk_peercred.pid = task_tgid_vnr(current);
- newsk->sk_peercred.uid = current->euid;
- newsk->sk_peercred.gid = current->egid;
+ current_euid_egid(&newsk->sk_peercred.uid, &newsk->sk_peercred.gid);
newu = unix_sk(newsk);
newsk->sk_sleep = &newu->peer_wait;
otheru = unix_sk(other);
@@ -1185,8 +1183,9 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
unix_peer(ska)=skb;
unix_peer(skb)=ska;
ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current);
- ska->sk_peercred.uid = skb->sk_peercred.uid = current->euid;
- ska->sk_peercred.gid = skb->sk_peercred.gid = current->egid;
+ current_euid_egid(&skb->sk_peercred.uid, &skb->sk_peercred.gid);
+ ska->sk_peercred.uid = skb->sk_peercred.uid;
+ ska->sk_peercred.gid = skb->sk_peercred.gid;

if (ska->sk_type != SOCK_DGRAM) {
ska->sk_state = TCP_ESTABLISHED;
diff --git a/security/commoncap.c b/security/commoncap.c
index 708aa05..570fd75 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -334,7 +334,7 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
* If only the real uid is 0, we do not set the effective
* bit.
*/
- if (bprm->e_uid == 0 || current->uid == 0) {
+ if (bprm->e_uid == 0 || current_uid() == 0) {
/* pP' = (cap_bset & ~0) | (pI & ~0) */
bprm->cap_post_exec_permitted = cap_combine(
current->cap_bset, current->cap_inheritable
@@ -349,7 +349,12 @@ int cap_bprm_set_security (struct linux_binprm *bprm)

void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
+ uid_t uid;
+ gid_t gid;
+
+ current_uid_gid(&uid, &gid);
+
+ if (bprm->e_uid != uid || bprm->e_gid != gid ||
!cap_issubset(bprm->cap_post_exec_permitted,
current->cap_permitted)) {
set_dumpable(current->mm, suid_dumpable);
@@ -357,8 +362,8 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)

if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
if (!capable(CAP_SETUID)) {
- bprm->e_uid = current->uid;
- bprm->e_gid = current->gid;
+ bprm->e_uid = uid;
+ bprm->e_gid = gid;
}
if (cap_limit_ptraced_target()) {
bprm->cap_post_exec_permitted = cap_intersect(
@@ -389,15 +394,15 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)

int cap_bprm_secureexec (struct linux_binprm *bprm)
{
- if (current->uid != 0) {
+ if (current_uid() != 0) {
if (bprm->cap_effective)
return 1;
if (!cap_isclear(bprm->cap_post_exec_permitted))
return 1;
}

- return (current->euid != current->uid ||
- current->egid != current->gid);
+ return (current_euid() != current_uid() ||
+ current_egid() != current_gid());
}

int cap_inode_setxattr(struct dentry *dentry, const char *name,
@@ -460,16 +465,18 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
int old_suid)
{
+ uid_t euid = current_euid();
+
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
- (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
+ (current_uid() != 0 && euid != 0 && current_suid() != 0) &&
!issecure(SECURE_KEEP_CAPS)) {
cap_clear (current->cap_permitted);
cap_clear (current->cap_effective);
}
- if (old_euid == 0 && current->euid != 0) {
+ if (old_euid == 0 && euid != 0) {
cap_clear (current->cap_effective);
}
- if (old_euid != 0 && current->euid == 0) {
+ if (old_euid != 0 && euid == 0) {
current->cap_effective = current->cap_permitted;
}
}

2008-08-06 15:52:21

by David Howells

[permalink] [raw]
Subject: [PATCH 10/24] CRED: Wrap current->cred and a few other accessors [ver #7]

Wrap current->cred and a few other accessors to hide their actual
implementation.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

drivers/net/tun.c | 8 +-
drivers/usb/core/devio.c | 10 +-
fs/binfmt_elf.c | 10 +-
fs/binfmt_elf_fdpic.c | 9 +-
fs/exec.c | 5 +
fs/fcntl.c | 3 -
fs/file_table.c | 7 +-
fs/hugetlbfs/inode.c | 5 +
fs/ioprio.c | 4 -
fs/smbfs/dir.c | 3 -
include/linux/cred.h | 187 +++++++++++++++++++++++++++++++----------
include/linux/securebits.h | 2
ipc/mqueue.c | 2
ipc/shm.c | 4 -
kernel/sys.c | 59 ++++++-------
kernel/uid16.c | 31 ++++---
net/core/scm.c | 2
net/sunrpc/auth.c | 14 ++-
security/commoncap.c | 2
security/keys/process_keys.c | 4 -
security/keys/request_key.c | 11 +-
security/selinux/exports.c | 8 +-
security/selinux/xfrm.c | 6 +
security/smack/smack_access.c | 2
security/smack/smack_lsm.c | 26 +++---
security/smack/smackfs.c | 4 -
26 files changed, 269 insertions(+), 159 deletions(-)


diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 4174855..0b618bb 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -644,6 +644,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
struct tun_net *tn;
struct tun_struct *tun;
struct net_device *dev;
+ const struct cred *cred = current_cred();
int err;

tn = net_generic(net, tun_net_id);
@@ -654,11 +655,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)

/* Check permissions */
if (((tun->owner != -1 &&
- current_euid() != tun->owner) ||
+ cred->euid != tun->owner) ||
(tun->group != -1 &&
- current_egid() != tun->group)) &&
- !capable(CAP_NET_ADMIN))
+ cred->egid != tun->group)) &&
+ !capable(CAP_NET_ADMIN)) {
return -EPERM;
+ }
}
else if (__dev_get_by_name(net, ifr->ifr_name))
return -EINVAL;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 6c7c115..70829cd 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -573,6 +573,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
{
struct usb_device *dev = NULL;
struct dev_state *ps;
+ const struct cred *cred = current_cred();
int ret;

lock_kernel();
@@ -616,8 +617,8 @@ static int usbdev_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
ps->disc_pid = get_pid(task_pid(current));
- ps->disc_uid = current_uid();
- ps->disc_euid = current_euid();
+ ps->disc_uid = cred->uid;
+ ps->disc_euid = cred->euid;
ps->disccontext = NULL;
ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid);
@@ -964,6 +965,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_host_endpoint *ep;
struct async *as;
struct usb_ctrlrequest *dr = NULL;
+ const struct cred *cred = current_cred();
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
int is_in;
@@ -1171,8 +1173,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->signr = uurb->signr;
as->ifnum = ifnum;
as->pid = get_pid(task_pid(current));
- as->uid = current_uid();
- as->euid = current_euid();
+ as->uid = cred->uid;
+ as->euid = cred->euid;
security_task_getsecid(current, &as->secid);
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 0bf141e..8692d4a 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -157,7 +157,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
int items;
elf_addr_t *elf_info;
int ei_index = 0;
- struct task_struct *tsk = current;
+ const struct cred *cred = current_cred();
struct vm_area_struct *vma;

/*
@@ -223,10 +223,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
- NEW_AUX_ENT(AT_UID, tsk->cred->uid);
- NEW_AUX_ENT(AT_EUID, tsk->cred->euid);
- NEW_AUX_ENT(AT_GID, tsk->cred->gid);
- NEW_AUX_ENT(AT_EGID, tsk->cred->egid);
+ NEW_AUX_ENT(AT_UID, cred->uid);
+ NEW_AUX_ENT(AT_EUID, cred->euid);
+ NEW_AUX_ENT(AT_GID, cred->gid);
+ NEW_AUX_ENT(AT_EGID, cred->egid);
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
if (k_platform) {
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 779423e..6232e55 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -465,6 +465,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
{
unsigned long sp, csp, nitems;
elf_caddr_t __user *argv, *envp;
+ const struct cred *cred = current_cred();
size_t platform_len = 0, len;
char *k_platform;
char __user *u_platform, *p;
@@ -586,10 +587,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr);
- NEW_AUX_ENT(AT_UID, (elf_addr_t) current->cred->uid);
- NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->cred->euid);
- NEW_AUX_ENT(AT_GID, (elf_addr_t) current->cred->gid);
- NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->cred->egid);
+ NEW_AUX_ENT(AT_UID, (elf_addr_t) cred->uid);
+ NEW_AUX_ENT(AT_EUID, (elf_addr_t) cred->euid);
+ NEW_AUX_ENT(AT_GID, (elf_addr_t) cred->gid);
+ NEW_AUX_ENT(AT_EGID, (elf_addr_t) cred->egid);

#ifdef ARCH_DLINFO
nr = 0;
diff --git a/fs/exec.c b/fs/exec.c
index 93e9b1c..4867ee1 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1393,6 +1393,7 @@ EXPORT_SYMBOL(set_binfmt);
*/
static int format_corename(char *corename, int nr_threads, long signr)
{
+ const struct cred *cred = current_cred();
const char *pat_ptr = core_pattern;
int ispipe = (*pat_ptr == '|');
char *out_ptr = corename;
@@ -1429,7 +1430,7 @@ static int format_corename(char *corename, int nr_threads, long signr)
/* uid */
case 'u':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current_uid());
+ "%d", cred->uid);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
@@ -1437,7 +1438,7 @@ static int format_corename(char *corename, int nr_threads, long signr)
/* gid */
case 'g':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current_gid());
+ "%d", cred->gid);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 63964d8..c594cc0 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -205,13 +205,14 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
int force)
{
+ const struct cred *cred = current_cred();
int err;

err = security_file_set_fowner(filp);
if (err)
return err;

- f_modown(filp, pid, type, current_uid(), current_euid(), force);
+ f_modown(filp, pid, type, cred->uid, cred->euid, force);
return 0;
}
EXPORT_SYMBOL(__f_setown);
diff --git a/fs/file_table.c b/fs/file_table.c
index a807eb0..4183190 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -94,7 +94,7 @@ int proc_nr_files(ctl_table *table, int write, struct file *filp,
*/
struct file *get_empty_filp(void)
{
- struct task_struct *tsk;
+ const struct cred *cred = current_cred();
static int old_max;
struct file * f;

@@ -118,12 +118,11 @@ struct file *get_empty_filp(void)
if (security_file_alloc(f))
goto fail_sec;

- tsk = current;
INIT_LIST_HEAD(&f->f_u.fu_list);
atomic_long_set(&f->f_count, 1);
rwlock_init(&f->f_owner.lock);
- f->f_uid = tsk->cred->fsuid;
- f->f_gid = tsk->cred->fsgid;
+ f->f_uid = cred->fsuid;
+ f->f_gid = cred->fsgid;
eventpoll_init_file(f);
/* f->f_version: 0 */
return f;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 0cecb9e..9f32c1d 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -951,6 +951,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
struct inode *inode;
struct dentry *dentry, *root;
struct qstr quick_string;
+ struct user_struct *user = current_user();

if (!hugetlbfs_vfsmount)
return ERR_PTR(-ENOENT);
@@ -958,7 +959,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
if (!can_do_hugetlb_shm())
return ERR_PTR(-EPERM);

- if (!user_shm_lock(size, current->cred->user))
+ if (!user_shm_lock(size, user))
return ERR_PTR(-ENOMEM);

root = hugetlbfs_vfsmount->mnt_root;
@@ -998,7 +999,7 @@ out_inode:
out_dentry:
dput(dentry);
out_shm_unlock:
- user_shm_unlock(size, current->cred->user);
+ user_shm_unlock(size, user);
return ERR_PTR(error);
}

diff --git a/fs/ioprio.c b/fs/ioprio.c
index fa55afc..6d96eac 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -123,7 +123,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
break;
case IOPRIO_WHO_USER:
if (!who)
- user = current->cred->user;
+ user = current_user();
else
user = find_user(who);

@@ -216,7 +216,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
break;
case IOPRIO_WHO_USER:
if (!who)
- user = current->cred->user;
+ user = current_user();
else
user = find_user(who);

diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 9e9bb0d..e7ddd03 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -667,8 +667,7 @@ smb_make_node(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)

attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
attr.ia_mode = mode;
- attr.ia_uid = current_euid();
- attr.ia_gid = current_egid();
+ current_euid_egid(&attr.ia_uid, &attr.ia_gid);

if (!new_valid_dev(dev))
return -EINVAL;
diff --git a/include/linux/cred.h b/include/linux/cred.h
index a0fefc0..45e954d 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -37,15 +37,16 @@ struct group_info {
* get_group_info - Get a reference to a group info structure
* @group_info: The group info to reference
*
- * This must be called with the owning task locked (via task_lock()) when task
- * != current. The reason being that the vast majority of callers are looking
- * at current->group_info, which can not be changed except by the current task.
- * Changing current->group_info requires the task lock, too.
+ * This gets a reference to a set of supplementary groups.
+ *
+ * If the caller is accessing a task's credentials, they must hold the RCU read
+ * lock when reading.
*/
-#define get_group_info(group_info) \
-do { \
- atomic_inc(&(group_info)->usage); \
-} while (0)
+static inline struct group_info *get_group_info(struct group_info *gi)
+{
+ atomic_inc(&gi->usage);
+ return gi;
+}

/**
* put_group_info - Release a reference to a group info structure
@@ -61,7 +62,7 @@ extern struct group_info *groups_alloc(int);
extern void groups_free(struct group_info *);
extern int set_current_groups(struct group_info *);
extern int set_groups(struct cred *, struct group_info *);
-extern int groups_search(struct group_info *, gid_t);
+extern int groups_search(const struct group_info *, gid_t);

/* access the groups "array" with this macro */
#define GROUP_AT(gi, i) \
@@ -123,41 +124,6 @@ struct cred {
spinlock_t lock; /* lock for pointer changes */
};

-#define get_current_user() (get_uid(current->cred->user))
-
-#define task_uid(task) ((task)->cred->uid)
-#define task_gid(task) ((task)->cred->gid)
-#define task_euid(task) ((task)->cred->euid)
-#define task_egid(task) ((task)->cred->egid)
-
-#define current_uid() (current->cred->uid)
-#define current_gid() (current->cred->gid)
-#define current_euid() (current->cred->euid)
-#define current_egid() (current->cred->egid)
-#define current_suid() (current->cred->suid)
-#define current_sgid() (current->cred->sgid)
-#define current_fsuid() (current->cred->fsuid)
-#define current_fsgid() (current->cred->fsgid)
-#define current_cap() (current->cred->cap_effective)
-
-#define current_uid_gid(_uid, _gid) \
-do { \
- *(_uid) = current->cred->uid; \
- *(_gid) = current->cred->gid; \
-} while(0)
-
-#define current_euid_egid(_uid, _gid) \
-do { \
- *(_uid) = current->cred->euid; \
- *(_gid) = current->cred->egid; \
-} while(0)
-
-#define current_fsuid_fsgid(_uid, _gid) \
-do { \
- *(_uid) = current->cred->fsuid; \
- *(_gid) = current->cred->fsgid; \
-} while(0)
-
extern void __put_cred(struct cred *);
extern int copy_creds(struct task_struct *, unsigned long);

@@ -187,4 +153,137 @@ static inline void put_cred(struct cred *cred)
__put_cred(cred);
}

+/**
+ * current_cred - Access the current task's credentials
+ *
+ * Access the credentials of the current task.
+ */
+#define current_cred() \
+ (current->cred)
+
+/**
+ * __task_cred - Access another task's credentials
+ * @task: The task to query
+ *
+ * Access the credentials of another task. The caller must hold the
+ * RCU readlock.
+ *
+ * The caller must make sure task doesn't go away, either by holding a ref on
+ * task or by holding tasklist_lock to prevent it from being unlinked.
+ */
+#define __task_cred(task) \
+ ((const struct cred *)(rcu_dereference((task)->cred)))
+
+/**
+ * get_task_cred - Get another task's credentials
+ * @task: The task to query
+ *
+ * Get the credentials of a task, pinning them so that they can't go away.
+ * Accessing a task's credentials directly is not permitted.
+ *
+ * The caller must make sure task doesn't go away, either by holding a ref on
+ * task or by holding tasklist_lock to prevent it from being unlinked.
+ */
+#define get_task_cred(task) \
+({ \
+ struct cred *__cred; \
+ rcu_read_lock(); \
+ __cred = (struct cred *) __task_cred((task)); \
+ get_cred(__cred); \
+ rcu_read_unlock(); \
+ __cred; \
+})
+
+/**
+ * get_current_cred - Get the current task's credentials
+ *
+ * Get the credentials of the current task, pinning them so that they can't go
+ * away. Accessing the current task's credentials directly is not permitted.
+ */
+#define get_current_cred() \
+ (get_cred(current_cred()))
+
+/**
+ * get_current_user - Get the current task's user_struct
+ *
+ * Get the user record of the current task, pinning it so that it can't go
+ * away.
+ */
+#define get_current_user() \
+({ \
+ struct user_struct *__u; \
+ struct cred *__cred; \
+ __cred = (struct cred *) current_cred(); \
+ __u = get_uid(__cred->user); \
+ __u; \
+})
+
+/**
+ * get_current_groups - Get the current task's supplementary group list
+ *
+ * Get the supplementary group list of the current task, pinning it so that it
+ * can't go away.
+ */
+#define get_current_groups() \
+({ \
+ struct group_info *__groups; \
+ struct cred *__cred; \
+ __cred = (struct cred *) current_cred(); \
+ __groups = get_group_info(__cred->group_info); \
+ __groups; \
+})
+
+#define task_cred_xxx(task, xxx) \
+({ \
+ __typeof__(task->cred->xxx) ___val; \
+ rcu_read_lock(); \
+ ___val = __task_cred((task))->xxx; \
+ rcu_read_unlock(); \
+ ___val; \
+})
+
+#define task_uid(task) (task_cred_xxx((task), uid))
+#define task_euid(task) (task_cred_xxx((task), euid))
+
+#define current_cred_xxx(xxx) \
+({ \
+ current->cred->xxx; \
+})
+
+#define current_uid() (current_cred_xxx(uid))
+#define current_gid() (current_cred_xxx(gid))
+#define current_euid() (current_cred_xxx(euid))
+#define current_egid() (current_cred_xxx(egid))
+#define current_suid() (current_cred_xxx(suid))
+#define current_sgid() (current_cred_xxx(sgid))
+#define current_fsuid() (current_cred_xxx(fsuid))
+#define current_fsgid() (current_cred_xxx(fsgid))
+#define current_cap() (current_cred_xxx(cap_effective))
+#define current_user() (current_cred_xxx(user))
+#define current_security() (current_cred_xxx(security))
+
+#define current_uid_gid(_uid, _gid) \
+do { \
+ const struct cred *__cred; \
+ __cred = current_cred(); \
+ *(_uid) = __cred->uid; \
+ *(_gid) = __cred->gid; \
+} while(0)
+
+#define current_euid_egid(_euid, _egid) \
+do { \
+ const struct cred *__cred; \
+ __cred = current_cred(); \
+ *(_euid) = __cred->euid; \
+ *(_egid) = __cred->egid; \
+} while(0)
+
+#define current_fsuid_fsgid(_fsuid, _fsgid) \
+do { \
+ const struct cred *__cred; \
+ __cred = current_cred(); \
+ *(_fsuid) = __cred->fsuid; \
+ *(_fsgid) = __cred->fsgid; \
+} while(0)
+
#endif /* _LINUX_CRED_H */
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 6d38949..d2c5ed8 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -32,7 +32,7 @@
setting is locked or not. A setting which is locked cannot be
changed from user-level. */
#define issecure_mask(X) (1 << (X))
-#define issecure(X) (issecure_mask(X) & current->cred->securebits)
+#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits))

#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
issecure_mask(SECURE_NO_SETUID_FIXUP) | \
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4d5c116..f020a77 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -104,6 +104,7 @@ static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
struct mq_attr *attr)
{
+ struct user_struct *u = current_user();
struct inode *inode;

inode = new_inode(sb);
@@ -118,7 +119,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
if (S_ISREG(mode)) {
struct mqueue_inode_info *info;
struct task_struct *p = current;
- struct user_struct *u = p->cred->user;
unsigned long mq_bytes, mq_msg_tblsz;

inode->i_fop = &mqueue_file_operations;
diff --git a/ipc/shm.c b/ipc/shm.c
index da04353..327347b 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -366,7 +366,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
if (shmflg & SHM_HUGETLB) {
/* hugetlb_file_setup takes care of mlock user accounting */
file = hugetlb_file_setup(name, size);
- shp->mlock_user = current->cred->user;
+ shp->mlock_user = current_user();
} else {
int acctflag = VM_ACCOUNT;
/*
@@ -763,7 +763,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
goto out_unlock;

if(cmd==SHM_LOCK) {
- struct user_struct *user = current->cred->user;
+ struct user_struct *user = current_user();
if (!is_file_hugepages(shp->shm_file)) {
err = shmem_lock(shp->shm_file, 1, user);
if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
diff --git a/kernel/sys.c b/kernel/sys.c
index 48cbb5b..e2a16eb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -143,6 +143,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
{
struct task_struct *g, *p;
struct user_struct *user;
+ const struct cred *cred = current_cred();
int error = -EINVAL;
struct pid *pgrp;

@@ -176,18 +177,18 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = current->cred->user;
+ user = cred->user;
if (!who)
- who = current_uid();
- else
- if (who != current_uid() && !(user = find_user(who)))
- goto out_unlock; /* No processes for this user */
+ who = cred->uid;
+ else if ((who != cred->uid) &&
+ !(user = find_user(who)))
+ goto out_unlock; /* No processes for this user */

do_each_thread(g, p)
- if (p->cred->uid == who)
+ if (__task_cred(p)->uid == who)
error = set_one_prio(p, niceval, error);
while_each_thread(g, p);
- if (who != current_uid())
+ if (who != cred->uid)
free_uid(user); /* For find_user() */
break;
}
@@ -207,6 +208,7 @@ asmlinkage long sys_getpriority(int which, int who)
{
struct task_struct *g, *p;
struct user_struct *user;
+ const struct cred *cred = current_cred();
long niceval, retval = -ESRCH;
struct pid *pgrp;

@@ -238,21 +240,21 @@ asmlinkage long sys_getpriority(int which, int who)
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = current->cred->user;
+ user = (struct user_struct *) cred->user;
if (!who)
- who = current_uid();
- else
- if (who != current_uid() && !(user = find_user(who)))
- goto out_unlock; /* No processes for this user */
+ who = cred->uid;
+ else if ((who != cred->uid) &&
+ !(user = find_user(who)))
+ goto out_unlock; /* No processes for this user */

do_each_thread(g, p)
- if (p->cred->uid == who) {
+ if (__task_cred(p)->uid == who) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
}
while_each_thread(g, p);
- if (who != current_uid())
+ if (who != cred->uid)
free_uid(user); /* for find_user() */
break;
}
@@ -743,11 +745,11 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)

asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
{
- struct cred *cred = current->cred;
+ const struct cred *cred = current_cred();
int retval;

- if (!(retval = put_user(cred->uid, ruid)) &&
- !(retval = put_user(cred->euid, euid)))
+ if (!(retval = put_user(cred->uid, ruid)) &&
+ !(retval = put_user(cred->euid, euid)))
retval = put_user(cred->suid, suid);

return retval;
@@ -796,11 +798,11 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)

asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid)
{
- struct cred *cred = current->cred;
+ const struct cred *cred = current_cred();
int retval;

- if (!(retval = put_user(cred->gid, rgid)) &&
- !(retval = put_user(cred->egid, egid)))
+ if (!(retval = put_user(cred->gid, rgid)) &&
+ !(retval = put_user(cred->egid, egid)))
retval = put_user(cred->sgid, sgid);

return retval;
@@ -1211,7 +1213,7 @@ static void groups_sort(struct group_info *group_info)
}

/* a simple bsearch */
-int groups_search(struct group_info *group_info, gid_t grp)
+int groups_search(const struct group_info *group_info, gid_t grp)
{
unsigned int left, right;

@@ -1280,13 +1282,8 @@ EXPORT_SYMBOL(set_current_groups);

asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
{
- struct cred *cred = current->cred;
- int i = 0;
-
- /*
- * SMP: Nobody else can change our grouplist. Thus we are
- * safe.
- */
+ const struct cred *cred = current_cred();
+ int i;

if (gidsetsize < 0)
return -EINVAL;
@@ -1342,8 +1339,9 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
*/
int in_group_p(gid_t grp)
{
- struct cred *cred = current->cred;
+ const struct cred *cred = current_cred();
int retval = 1;
+
if (grp != cred->fsgid)
retval = groups_search(cred->group_info, grp);
return retval;
@@ -1353,8 +1351,9 @@ EXPORT_SYMBOL(in_group_p);

int in_egroup_p(gid_t grp)
{
- struct cred *cred = current->cred;
+ const struct cred *cred = current_cred();
int retval = 1;
+
if (grp != cred->egid)
retval = groups_search(cred->group_info, grp);
return retval;
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 71f07fc..2460c31 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -84,11 +84,12 @@ asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)

asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid)
{
+ const struct cred *cred = current_cred();
int retval;

- if (!(retval = put_user(high2lowuid(current->cred->uid), ruid)) &&
- !(retval = put_user(high2lowuid(current->cred->euid), euid)))
- retval = put_user(high2lowuid(current->cred->suid), suid);
+ if (!(retval = put_user(high2lowuid(cred->uid), ruid)) &&
+ !(retval = put_user(high2lowuid(cred->euid), euid)))
+ retval = put_user(high2lowuid(cred->suid), suid);

return retval;
}
@@ -104,11 +105,12 @@ asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid)

asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid)
{
+ const struct cred *cred = current_cred();
int retval;

- if (!(retval = put_user(high2lowgid(current->cred->gid), rgid)) &&
- !(retval = put_user(high2lowgid(current->cred->egid), egid)))
- retval = put_user(high2lowgid(current->cred->sgid), sgid);
+ if (!(retval = put_user(high2lowgid(cred->gid), rgid)) &&
+ !(retval = put_user(high2lowgid(cred->egid), egid)))
+ retval = put_user(high2lowgid(cred->sgid), sgid);

return retval;
}
@@ -161,25 +163,24 @@ static int groups16_from_user(struct group_info *group_info,

asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist)
{
- int i = 0;
+ const struct cred *cred = current_cred();
+ int i;

if (gidsetsize < 0)
return -EINVAL;

- get_group_info(current->cred->group_info);
- i = current->cred->group_info->ngroups;
+ i = cred->group_info->ngroups;
if (gidsetsize) {
if (i > gidsetsize) {
i = -EINVAL;
goto out;
}
- if (groups16_to_user(grouplist, current->cred->group_info)) {
+ if (groups16_to_user(grouplist, cred->group_info)) {
i = -EFAULT;
goto out;
}
}
out:
- put_group_info(current->cred->group_info);
return i;
}

@@ -210,20 +211,20 @@ asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist)

asmlinkage long sys_getuid16(void)
{
- return high2lowuid(current->cred->uid);
+ return high2lowuid(current_uid());
}

asmlinkage long sys_geteuid16(void)
{
- return high2lowuid(current->cred->euid);
+ return high2lowuid(current_euid());
}

asmlinkage long sys_getgid16(void)
{
- return high2lowgid(current->cred->gid);
+ return high2lowgid(current_gid());
}

asmlinkage long sys_getegid16(void)
{
- return high2lowgid(current->cred->egid);
+ return high2lowgid(current_egid());
}
diff --git a/net/core/scm.c b/net/core/scm.c
index c28ca32..f73c44b 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -44,7 +44,7 @@

static __inline__ int scm_check_creds(struct ucred *creds)
{
- struct cred *cred = current->cred;
+ const struct cred *cred = current_cred();

if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
((creds->uid == cred->uid || creds->uid == cred->euid ||
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 9515fef..d218553 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -350,16 +350,18 @@ EXPORT_SYMBOL_GPL(rpcauth_lookup_credcache);
struct rpc_cred *
rpcauth_lookupcred(struct rpc_auth *auth, int flags)
{
- struct auth_cred acred = {
- .uid = current_fsuid(),
- .gid = current_fsgid(),
- .group_info = current->cred->group_info,
- };
+ struct auth_cred acred;
struct rpc_cred *ret;
+ const struct cred *cred = current_cred();

dprintk("RPC: looking up %s cred\n",
auth->au_ops->au_name);
- get_group_info(acred.group_info);
+
+ memset(&acred, 0, sizeof(acred));
+ acred.uid = cred->fsuid;
+ acred.gid = cred->fsgid;
+ acred.group_info = get_group_info(((struct cred *)cred)->group_info);
+
ret = auth->au_ops->lookup_cred(auth, &acred, flags);
put_group_info(acred.group_info);
return ret;
diff --git a/security/commoncap.c b/security/commoncap.c
index cb4da7d..2de5cbe 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -606,7 +606,7 @@ int cap_task_setnice (struct task_struct *p, int nice)
int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5, long *rc_p)
{
- struct cred *cred = current->cred;
+ struct cred *cred = current_cred();
long error = 0;

switch (option) {
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 248ad13..c9ccbdb 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -42,7 +42,7 @@ struct key_user root_key_user = {
*/
static int install_user_keyrings(void)
{
- struct user_struct *user = current->cred->user;
+ struct user_struct *user = current_user();
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;
@@ -582,7 +582,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
{
struct request_key_auth *rka;
struct task_struct *t = current;
- struct cred *cred = t->cred;
+ struct cred *cred = current_cred();
struct key *key;
key_ref_t key_ref, skey_ref;
int ret;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 8ffd86e..650cc3e 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -67,6 +67,7 @@ static int call_sbin_request_key(struct key_construction *cons,
void *aux)
{
struct task_struct *tsk = current;
+ const struct cred *cred = current_cred();
key_serial_t prkey, sskey;
struct key *key = cons->key, *authkey = cons->authkey, *keyring;
char *argv[9], *envp[3], uid_str[12], gid_str[12];
@@ -92,16 +93,16 @@ static int call_sbin_request_key(struct key_construction *cons,
goto error_link;

/* record the UID and GID */
- sprintf(uid_str, "%d", current_fsuid());
- sprintf(gid_str, "%d", current_fsgid());
+ sprintf(uid_str, "%d", cred->fsuid);
+ sprintf(gid_str, "%d", cred->fsgid);

/* we say which key is under construction */
sprintf(key_str, "%d", key->serial);

/* we specify the process's default keyrings */
sprintf(keyring_str[0], "%d",
- tsk->cred->thread_keyring ?
- tsk->cred->thread_keyring->serial : 0);
+ cred->thread_keyring ?
+ cred->thread_keyring->serial : 0);

prkey = 0;
if (tsk->signal->process_keyring)
@@ -114,7 +115,7 @@ static int call_sbin_request_key(struct key_construction *cons,
sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
rcu_read_unlock();
} else {
- sskey = tsk->cred->user->session_keyring->serial;
+ sskey = cred->user->session_keyring->serial;
}

sprintf(keyring_str[2], "%d", sskey);
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index cf02490..c73aeaa 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -39,9 +39,13 @@ EXPORT_SYMBOL_GPL(selinux_string_to_sid);
int selinux_secmark_relabel_packet_permission(u32 sid)
{
if (selinux_enabled) {
- struct task_security_struct *tsec = current->cred->security;
+ const struct task_security_struct *__tsec;
+ u32 tsid;

- return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET,
+ __tsec = current_security();
+ tsid = __tsec->sid;
+
+ return avc_has_perm(tsid, sid, SECCLASS_PACKET,
PACKET__RELABELTO, NULL);
}
return 0;
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index d7db766..c0eb720 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -197,7 +197,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx, u32 sid)
{
int rc = 0;
- struct task_security_struct *tsec = current->cred->security;
+ const struct task_security_struct *tsec = current_security();
struct xfrm_sec_ctx *ctx = NULL;
char *ctx_str = NULL;
u32 str_len;
@@ -333,7 +333,7 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
*/
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
{
- struct task_security_struct *tsec = current->cred->security;
+ const struct task_security_struct *tsec = current_security();
int rc = 0;

if (ctx) {
@@ -378,7 +378,7 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
*/
int selinux_xfrm_state_delete(struct xfrm_state *x)
{
- struct task_security_struct *tsec = current->cred->security;
+ const struct task_security_struct *tsec = current_security();
struct xfrm_sec_ctx *ctx = x->security;
int rc = 0;

diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index b6dd4fc..247cec3 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -164,7 +164,7 @@ int smk_curacc(char *obj_label, u32 mode)
{
int rc;

- rc = smk_access(current->cred->security, obj_label, mode);
+ rc = smk_access(current_security(), obj_label, mode);
if (rc == 0)
return 0;

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7da592f..9d2e227 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -143,7 +143,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
static int smack_syslog(int type)
{
int rc;
- char *sp = current->cred->security;
+ char *sp = current_security();

rc = cap_syslog(type);
if (rc != 0)
@@ -375,7 +375,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
*/
static int smack_inode_alloc_security(struct inode *inode)
{
- inode->i_security = new_inode_smack(current->cred->security);
+ inode->i_security = new_inode_smack(current_security());
if (inode->i_security == NULL)
return -ENOMEM;
return 0;
@@ -820,7 +820,7 @@ static int smack_file_permission(struct file *file, int mask)
*/
static int smack_file_alloc_security(struct file *file)
{
- file->f_security = current->cred->security;
+ file->f_security = current_security();
return 0;
}

@@ -918,7 +918,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
*/
static int smack_file_set_fowner(struct file *file)
{
- file->f_security = current->cred->security;
+ file->f_security = current_security();
return 0;
}

@@ -986,8 +986,7 @@ static int smack_file_receive(struct file *file)
*/
static int smack_cred_alloc_security(struct cred *cred)
{
- cred->security = current->cred->security;
-
+ cred->security = current_security();
return 0;
}

@@ -1225,7 +1224,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
*/
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
{
- char *csp = current->cred->security;
+ char *csp = current_security();
struct socket_smack *ssp;

ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
@@ -1450,7 +1449,7 @@ static int smack_flags_to_may(int flags)
*/
static int smack_msg_msg_alloc_security(struct msg_msg *msg)
{
- msg->security = current->cred->security;
+ msg->security = current_security();
return 0;
}

@@ -1486,7 +1485,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
{
struct kern_ipc_perm *isp = &shp->shm_perm;

- isp->security = current->cred->security;
+ isp->security = current_security();
return 0;
}

@@ -1595,7 +1594,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
{
struct kern_ipc_perm *isp = &sma->sem_perm;

- isp->security = current->cred->security;
+ isp->security = current_security();
return 0;
}

@@ -1699,7 +1698,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
{
struct kern_ipc_perm *kisp = &msq->q_perm;

- kisp->security = current->cred->security;
+ kisp->security = current_security();
return 0;
}

@@ -1854,7 +1853,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
struct super_block *sbp;
struct superblock_smack *sbsp;
struct inode_smack *isp;
- char *csp = current->cred->security;
+ char *csp = current_security();
char *fetched;
char *final;
struct dentry *dp;
@@ -2287,8 +2286,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
return;

ssp = sk->sk_security;
- ssp->smk_in = current->cred->security;
- ssp->smk_out = current->cred->security;
+ ssp->smk_in = ssp->smk_out = current_security();
ssp->smk_packet[0] = '\0';

rc = smack_netlabel(sk);
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 7f84906..037236e 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -336,7 +336,7 @@ static void smk_cipso_doi(void)

audit_info.loginuid = audit_get_loginuid(current);
audit_info.sessionid = audit_get_sessionid(current);
- audit_info.secid = smack_to_secid(current->cred->security);
+ audit_info.secid = smack_to_secid(current_security());

rc = netlbl_cfg_map_del(NULL, &audit_info);
if (rc != 0)
@@ -369,7 +369,7 @@ static void smk_unlbl_ambient(char *oldambient)

audit_info.loginuid = audit_get_loginuid(current);
audit_info.sessionid = audit_get_sessionid(current);
- audit_info.secid = smack_to_secid(current->cred->security);
+ audit_info.secid = smack_to_secid(current_security());

if (oldambient != NULL) {
rc = netlbl_cfg_map_del(oldambient, &audit_info);

2008-08-06 15:52:41

by David Howells

[permalink] [raw]
Subject: [PATCH 08/24] CRED: Separate task security context from task_struct [ver #7]

Separate the task security context from task_struct. At this point, the
security data is temporarily embedded in the task_struct with two pointers
pointing to it.

Note that the Alpha arch is altered as it refers to (E)UID and (E)GID in
entry.S via asm-offsets.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

arch/alpha/kernel/asm-offsets.c | 11 +-
arch/alpha/kernel/entry.S | 10 +
arch/mips/kernel/kspd.c | 4 -
arch/s390/kernel/compat_linux.c | 28 ++--
arch/sparc64/kernel/sys_sparc32.c | 28 ++--
drivers/connector/cn_proc.c | 8 +
fs/binfmt_elf.c | 12 +-
fs/binfmt_elf_fdpic.c | 12 +-
fs/exec.c | 4 -
fs/fcntl.c | 4 -
fs/file_table.c | 4 -
fs/fuse/dir.c | 12 +-
fs/hugetlbfs/inode.c | 4 -
fs/ioprio.c | 12 +-
fs/nfsd/auth.c | 22 ++-
fs/nfsd/nfs4recover.c | 12 +-
fs/nfsd/nfsfh.c | 6 -
fs/open.c | 17 +-
fs/proc/array.c | 18 +--
fs/proc/base.c | 16 +-
fs/xfs/linux-2.6/xfs_cred.h | 6 -
fs/xfs/linux-2.6/xfs_globals.h | 2
fs/xfs/linux-2.6/xfs_ioctl.c | 2
fs/xfs/xfs_inode.h | 2
fs/xfs/xfs_vnodeops.h | 10 +
include/linux/cred.h | 155 +++++++++++++++++++---
include/linux/init_task.h | 24 ++-
include/linux/sched.h | 52 +------
include/linux/securebits.h | 2
ipc/mqueue.c | 2
ipc/shm.c | 4 -
kernel/auditsc.c | 44 +++---
kernel/capability.c | 4 -
kernel/cgroup.c | 4 -
kernel/exit.c | 10 +
kernel/fork.c | 24 ++-
kernel/futex.c | 6 +
kernel/futex_compat.c | 5 -
kernel/ptrace.c | 19 +--
kernel/sched.c | 10 +
kernel/signal.c | 16 +-
kernel/sys.c | 261 +++++++++++++++++++++----------------
kernel/trace/trace.c | 2
kernel/tsacct.c | 4 -
kernel/uid16.c | 28 ++--
kernel/user.c | 4 -
mm/mempolicy.c | 10 +
mm/migrate.c | 10 +
mm/oom_kill.c | 2
net/core/scm.c | 10 +
net/sunrpc/auth.c | 2
security/commoncap.c | 152 +++++++++++-----------
security/keys/keyctl.c | 25 ++--
security/keys/permission.c | 11 +-
security/keys/process_keys.c | 98 +++++++-------
security/keys/request_key.c | 18 +--
security/keys/request_key_auth.c | 12 +-
security/selinux/exports.c | 2
security/selinux/hooks.c | 120 +++++++++--------
security/selinux/selinuxfs.c | 2
security/selinux/xfrm.c | 6 -
security/smack/smack_access.c | 4 -
security/smack/smack_lsm.c | 77 ++++++-----
security/smack/smackfs.c | 6 -
64 files changed, 832 insertions(+), 681 deletions(-)


diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
index 4b18cd9..6ff8886 100644
--- a/arch/alpha/kernel/asm-offsets.c
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -19,15 +19,18 @@ void foo(void)
BLANK();

DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
- DEFINE(TASK_UID, offsetof(struct task_struct, uid));
- DEFINE(TASK_EUID, offsetof(struct task_struct, euid));
- DEFINE(TASK_GID, offsetof(struct task_struct, gid));
- DEFINE(TASK_EGID, offsetof(struct task_struct, egid));
+ DEFINE(TASK_CRED, offsetof(struct task_struct, cred));
DEFINE(TASK_REAL_PARENT, offsetof(struct task_struct, real_parent));
DEFINE(TASK_GROUP_LEADER, offsetof(struct task_struct, group_leader));
DEFINE(TASK_TGID, offsetof(struct task_struct, tgid));
BLANK();

+ DEFINE(CRED_UID, offsetof(struct cred, uid));
+ DEFINE(CRED_EUID, offsetof(struct cred, euid));
+ DEFINE(CRED_GID, offsetof(struct cred, gid));
+ DEFINE(CRED_EGID, offsetof(struct cred, egid));
+ BLANK();
+
DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs));
DEFINE(PT_PTRACED, PT_PTRACED);
DEFINE(CLONE_VM, CLONE_VM);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 5fc61e2..f77345b 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -850,8 +850,9 @@ osf_getpriority:
sys_getxuid:
.prologue 0
ldq $2, TI_TASK($8)
- ldl $0, TASK_UID($2)
- ldl $1, TASK_EUID($2)
+ ldq $3, TASK_CRED($2)
+ ldl $0, CRED_UID($3)
+ ldl $1, CRED_EUID($3)
stq $1, 80($sp)
ret
.end sys_getxuid
@@ -862,8 +863,9 @@ sys_getxuid:
sys_getxgid:
.prologue 0
ldq $2, TI_TASK($8)
- ldl $0, TASK_GID($2)
- ldl $1, TASK_EGID($2)
+ ldq $3, TASK_CRED($2)
+ ldl $0, CRED_GID($3)
+ ldl $1, CRED_EGID($3)
stq $1, 80($sp)
ret
.end sys_getxgid
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index b0591ae..fd6e512 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -174,8 +174,8 @@ static unsigned int translate_open_flags(int flags)

static void sp_setfsuidgid( uid_t uid, gid_t gid)
{
- current->fsuid = uid;
- current->fsgid = gid;
+ current->cred->fsuid = uid;
+ current->cred->fsgid = gid;

key_fsuid_changed(current);
key_fsgid_changed(current);
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index d7f2222..4ae7268 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -148,9 +148,9 @@ asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user
{
int retval;

- if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
- !(retval = put_user(high2lowuid(current->euid), euid)))
- retval = put_user(high2lowuid(current->suid), suid);
+ if (!(retval = put_user(high2lowuid(current->cred->uid), ruid)) &&
+ !(retval = put_user(high2lowuid(current->cred->euid), euid)))
+ retval = put_user(high2lowuid(current->cred->suid), suid);

return retval;
}
@@ -165,9 +165,9 @@ asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user
{
int retval;

- if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
- !(retval = put_user(high2lowgid(current->egid), egid)))
- retval = put_user(high2lowgid(current->sgid), sgid);
+ if (!(retval = put_user(high2lowgid(current->cred->gid), rgid)) &&
+ !(retval = put_user(high2lowgid(current->cred->egid), egid)))
+ retval = put_user(high2lowgid(current->cred->sgid), sgid);

return retval;
}
@@ -217,20 +217,20 @@ asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
if (gidsetsize < 0)
return -EINVAL;

- get_group_info(current->group_info);
- i = current->group_info->ngroups;
+ get_group_info(current->cred->group_info);
+ i = current->cred->group_info->ngroups;
if (gidsetsize) {
if (i > gidsetsize) {
i = -EINVAL;
goto out;
}
- if (groups16_to_user(grouplist, current->group_info)) {
+ if (groups16_to_user(grouplist, current->cred->group_info)) {
i = -EFAULT;
goto out;
}
}
out:
- put_group_info(current->group_info);
+ put_group_info(current->cred->group_info);
return i;
}

@@ -261,22 +261,22 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)

asmlinkage long sys32_getuid16(void)
{
- return high2lowuid(current->uid);
+ return high2lowuid(current->cred->uid);
}

asmlinkage long sys32_geteuid16(void)
{
- return high2lowuid(current->euid);
+ return high2lowuid(current->cred->euid);
}

asmlinkage long sys32_getgid16(void)
{
- return high2lowgid(current->gid);
+ return high2lowgid(current->cred->gid);
}

asmlinkage long sys32_getegid16(void)
{
- return high2lowgid(current->egid);
+ return high2lowgid(current->cred->egid);
}

/* 32-bit timeval and related flotsam. */
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 97b77fb..3546500 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -103,9 +103,9 @@ asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user
{
int retval;

- if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
- !(retval = put_user(high2lowuid(current->euid), euid)))
- retval = put_user(high2lowuid(current->suid), suid);
+ if (!(retval = put_user(high2lowuid(current->cred->uid), ruid)) &&
+ !(retval = put_user(high2lowuid(current->cred->euid), euid)))
+ retval = put_user(high2lowuid(current->cred->suid), suid);

return retval;
}
@@ -120,9 +120,9 @@ asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user
{
int retval;

- if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
- !(retval = put_user(high2lowgid(current->egid), egid)))
- retval = put_user(high2lowgid(current->sgid), sgid);
+ if (!(retval = put_user(high2lowgid(current->cred->gid), rgid)) &&
+ !(retval = put_user(high2lowgid(current->cred->egid), egid)))
+ retval = put_user(high2lowgid(current->cred->sgid), sgid);

return retval;
}
@@ -172,20 +172,20 @@ asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
if (gidsetsize < 0)
return -EINVAL;

- get_group_info(current->group_info);
- i = current->group_info->ngroups;
+ get_group_info(current->cred->group_info);
+ i = current->cred->group_info->ngroups;
if (gidsetsize) {
if (i > gidsetsize) {
i = -EINVAL;
goto out;
}
- if (groups16_to_user(grouplist, current->group_info)) {
+ if (groups16_to_user(grouplist, current->cred->group_info)) {
i = -EFAULT;
goto out;
}
}
out:
- put_group_info(current->group_info);
+ put_group_info(current->cred->group_info);
return i;
}

@@ -216,22 +216,22 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)

asmlinkage long sys32_getuid16(void)
{
- return high2lowuid(current->uid);
+ return high2lowuid(current->cred->uid);
}

asmlinkage long sys32_geteuid16(void)
{
- return high2lowuid(current->euid);
+ return high2lowuid(current->cred->euid);
}

asmlinkage long sys32_getgid16(void)
{
- return high2lowgid(current->gid);
+ return high2lowgid(current->cred->gid);
}

asmlinkage long sys32_getegid16(void)
{
- return high2lowgid(current->egid);
+ return high2lowgid(current->cred->egid);
}

/* 32-bit timeval and related flotsam. */
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 5c9f67f..354c1ff 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -116,11 +116,11 @@ void proc_id_connector(struct task_struct *task, int which_id)
ev->event_data.id.process_pid = task->pid;
ev->event_data.id.process_tgid = task->tgid;
if (which_id == PROC_EVENT_UID) {
- ev->event_data.id.r.ruid = task->uid;
- ev->event_data.id.e.euid = task->euid;
+ ev->event_data.id.r.ruid = task->cred->uid;
+ ev->event_data.id.e.euid = task->cred->euid;
} else if (which_id == PROC_EVENT_GID) {
- ev->event_data.id.r.rgid = task->gid;
- ev->event_data.id.e.egid = task->egid;
+ ev->event_data.id.r.rgid = task->cred->gid;
+ ev->event_data.id.e.egid = task->cred->egid;
} else
return;
get_seq(&msg->seq, &ev->cpu);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 655ed8d..0bf141e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -223,10 +223,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
- NEW_AUX_ENT(AT_UID, tsk->uid);
- NEW_AUX_ENT(AT_EUID, tsk->euid);
- NEW_AUX_ENT(AT_GID, tsk->gid);
- NEW_AUX_ENT(AT_EGID, tsk->egid);
+ NEW_AUX_ENT(AT_UID, tsk->cred->uid);
+ NEW_AUX_ENT(AT_EUID, tsk->cred->euid);
+ NEW_AUX_ENT(AT_GID, tsk->cred->gid);
+ NEW_AUX_ENT(AT_EGID, tsk->cred->egid);
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
if (k_platform) {
@@ -1385,8 +1385,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_zomb = psinfo->pr_sname == 'Z';
psinfo->pr_nice = task_nice(p);
psinfo->pr_flag = p->flags;
- SET_UID(psinfo->pr_uid, p->uid);
- SET_GID(psinfo->pr_gid, p->gid);
+ SET_UID(psinfo->pr_uid, p->cred->uid);
+ SET_GID(psinfo->pr_gid, p->cred->gid);
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));

return 0;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index cee7ed4..779423e 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -586,10 +586,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr);
- NEW_AUX_ENT(AT_UID, (elf_addr_t) current_uid());
- NEW_AUX_ENT(AT_EUID, (elf_addr_t) current_euid());
- NEW_AUX_ENT(AT_GID, (elf_addr_t) current_gid());
- NEW_AUX_ENT(AT_EGID, (elf_addr_t) current_egid());
+ NEW_AUX_ENT(AT_UID, (elf_addr_t) current->cred->uid);
+ NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->cred->euid);
+ NEW_AUX_ENT(AT_GID, (elf_addr_t) current->cred->gid);
+ NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->cred->egid);

#ifdef ARCH_DLINFO
nr = 0;
@@ -1406,8 +1406,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_zomb = psinfo->pr_sname == 'Z';
psinfo->pr_nice = task_nice(p);
psinfo->pr_flag = p->flags;
- SET_UID(psinfo->pr_uid, p->uid);
- SET_GID(psinfo->pr_gid, p->gid);
+ SET_UID(psinfo->pr_uid, p->cred->uid);
+ SET_GID(psinfo->pr_gid, p->cred->gid);
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));

return 0;
diff --git a/fs/exec.c b/fs/exec.c
index 08c884c..93e9b1c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1744,7 +1744,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
*/
if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
- current->fsuid = 0; /* Dump root private */
+ current->cred->fsuid = 0; /* Dump root private */
}

retval = coredump_wait(exit_code, &core_state);
@@ -1840,7 +1840,7 @@ fail_unlock:
if (helper_argv)
argv_free(helper_argv);

- current->fsuid = fsuid;
+ current->cred->fsuid = fsuid;
coredump_finish(mm);
fail:
return retval;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index bf049a8..63964d8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -401,8 +401,8 @@ static inline int sigio_perm(struct task_struct *p,
struct fown_struct *fown, int sig)
{
return (((fown->euid == 0) ||
- (fown->euid == p->suid) || (fown->euid == p->uid) ||
- (fown->uid == p->suid) || (fown->uid == p->uid)) &&
+ (fown->euid == p->cred->suid) || (fown->euid == p->cred->uid) ||
+ (fown->uid == p->cred->suid) || (fown->uid == p->cred->uid)) &&
!security_file_send_sigiotask(p, fown, sig));
}

diff --git a/fs/file_table.c b/fs/file_table.c
index f45a449..a807eb0 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -122,8 +122,8 @@ struct file *get_empty_filp(void)
INIT_LIST_HEAD(&f->f_u.fu_list);
atomic_long_set(&f->f_count, 1);
rwlock_init(&f->f_owner.lock);
- f->f_uid = tsk->fsuid;
- f->f_gid = tsk->fsgid;
+ f->f_uid = tsk->cred->fsuid;
+ f->f_gid = tsk->cred->fsgid;
eventpoll_init_file(f);
/* f->f_version: 0 */
return f;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index fd03330..e97a989 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -872,12 +872,12 @@ int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
if (fc->flags & FUSE_ALLOW_OTHER)
return 1;

- if (task->euid == fc->user_id &&
- task->suid == fc->user_id &&
- task->uid == fc->user_id &&
- task->egid == fc->group_id &&
- task->sgid == fc->group_id &&
- task->gid == fc->group_id)
+ if (task->cred->euid == fc->user_id &&
+ task->cred->suid == fc->user_id &&
+ task->cred->uid == fc->user_id &&
+ task->cred->egid == fc->group_id &&
+ task->cred->sgid == fc->group_id &&
+ task->cred->gid == fc->group_id)
return 1;

return 0;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 4c428f5..0cecb9e 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -958,7 +958,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
if (!can_do_hugetlb_shm())
return ERR_PTR(-EPERM);

- if (!user_shm_lock(size, current->user))
+ if (!user_shm_lock(size, current->cred->user))
return ERR_PTR(-ENOMEM);

root = hugetlbfs_vfsmount->mnt_root;
@@ -998,7 +998,7 @@ out_inode:
out_dentry:
dput(dentry);
out_shm_unlock:
- user_shm_unlock(size, current->user);
+ user_shm_unlock(size, current->cred->user);
return ERR_PTR(error);
}

diff --git a/fs/ioprio.c b/fs/ioprio.c
index b1214b9..fa55afc 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -32,8 +32,8 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
int err;
struct io_context *ioc;

- if (task->uid != current_euid() &&
- task->uid != current_uid() && !capable(CAP_SYS_NICE))
+ if (task->cred->uid != current_euid() &&
+ task->cred->uid != current_uid() && !capable(CAP_SYS_NICE))
return -EPERM;

err = security_task_setioprio(task, ioprio);
@@ -123,7 +123,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
break;
case IOPRIO_WHO_USER:
if (!who)
- user = current->user;
+ user = current->cred->user;
else
user = find_user(who);

@@ -131,7 +131,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
break;

do_each_thread(g, p) {
- if (p->uid != who)
+ if (p->cred->uid != who)
continue;
ret = set_task_ioprio(p, ioprio);
if (ret)
@@ -216,7 +216,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
break;
case IOPRIO_WHO_USER:
if (!who)
- user = current->user;
+ user = current->cred->user;
else
user = find_user(who);

@@ -224,7 +224,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
break;

do_each_thread(g, p) {
- if (p->uid != user->uid)
+ if (p->cred->uid != user->uid)
continue;
tmpio = get_task_ioprio(p);
if (tmpio < 0)
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 294992e..808fc03 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,6 +27,7 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)

int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
+ struct cred *act_as = current->cred ;
struct svc_cred cred = rqstp->rq_cred;
int i;
int flags = nfsexp_flags(rqstp, exp);
@@ -55,25 +56,26 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
get_group_info(cred.cr_group_info);

if (cred.cr_uid != (uid_t) -1)
- current->fsuid = cred.cr_uid;
+ act_as->fsuid = cred.cr_uid;
else
- current->fsuid = exp->ex_anon_uid;
+ act_as->fsuid = exp->ex_anon_uid;
if (cred.cr_gid != (gid_t) -1)
- current->fsgid = cred.cr_gid;
+ act_as->fsgid = cred.cr_gid;
else
- current->fsgid = exp->ex_anon_gid;
+ act_as->fsgid = exp->ex_anon_gid;

if (!cred.cr_group_info)
return -ENOMEM;
- ret = set_current_groups(cred.cr_group_info);
+ ret = set_groups(act_as, cred.cr_group_info);
put_group_info(cred.cr_group_info);
if ((cred.cr_uid)) {
- current->cap_effective =
- cap_drop_nfsd_set(current->cap_effective);
+ act_as->cap_effective =
+ cap_drop_nfsd_set(act_as->cap_effective);
} else {
- current->cap_effective =
- cap_raise_nfsd_set(current->cap_effective,
- current->cap_permitted);
+ act_as->cap_effective =
+ cap_raise_nfsd_set(act_as->cap_effective,
+ act_as->cap_permitted);
}
return ret;
}
+
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 145b3c8..6e751e7 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -57,17 +57,17 @@ static int rec_dir_init = 0;
static void
nfs4_save_user(uid_t *saveuid, gid_t *savegid)
{
- *saveuid = current->fsuid;
- *savegid = current->fsgid;
- current->fsuid = 0;
- current->fsgid = 0;
+ *saveuid = current->cred->fsuid;
+ *savegid = current->cred->fsgid;
+ current->cred->fsuid = 0;
+ current->cred->fsgid = 0;
}

static void
nfs4_reset_user(uid_t saveuid, gid_t savegid)
{
- current->fsuid = saveuid;
- current->fsgid = savegid;
+ current->cred->fsuid = saveuid;
+ current->cred->fsgid = savegid;
}

static void
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index ea37c96..54be127 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -186,9 +186,9 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
* access control settings being in effect, we cannot
* fix that case easily.
*/
- current->cap_effective =
- cap_raise_nfsd_set(current->cap_effective,
- current->cap_permitted);
+ current->cred->cap_effective =
+ cap_raise_nfsd_set(current->cred->cap_effective,
+ current->cred->cap_permitted);
} else {
error = nfsd_setuser_and_check_port(rqstp, exp);
if (error)
diff --git a/fs/open.c b/fs/open.c
index 0f410b1..a8ddf81 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -425,6 +425,7 @@ out:
*/
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
+ struct cred *cred = current->cred;
struct path path;
struct inode *inode;
int old_fsuid, old_fsgid;
@@ -434,18 +435,18 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;

- old_fsuid = current->fsuid;
- old_fsgid = current->fsgid;
+ old_fsuid = cred->fsuid;
+ old_fsgid = cred->fsgid;

- current->fsuid = current->uid;
- current->fsgid = current->gid;
+ cred->fsuid = cred->uid;
+ cred->fsgid = cred->gid;

if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/* Clear the capabilities if we switch to a non-root user */
- if (current->uid)
+ if (current->cred->uid)
old_cap = cap_set_effective(__cap_empty_set);
else
- old_cap = cap_set_effective(current->cap_permitted);
+ old_cap = cap_set_effective(cred->cap_permitted);
}

res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
@@ -484,8 +485,8 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
out_path_release:
path_put(&path);
out:
- current->fsuid = old_fsuid;
- current->fsgid = old_fsgid;
+ cred->fsuid = old_fsuid;
+ cred->fsgid = old_fsgid;

if (!issecure(SECURE_NO_SETUID_FIXUP))
cap_set_effective(old_cap);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 0d6eb33..af0962b 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -187,8 +187,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
task_tgid_nr_ns(p, ns),
pid_nr_ns(pid, ns),
ppid, tpid,
- p->uid, p->euid, p->suid, p->fsuid,
- p->gid, p->egid, p->sgid, p->fsgid);
+ p->cred->uid, p->cred->euid, p->cred->suid, p->cred->fsuid,
+ p->cred->gid, p->cred->egid, p->cred->sgid, p->cred->fsgid);

task_lock(p);
if (p->files)
@@ -199,7 +199,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
fdt ? fdt->max_fds : 0);
rcu_read_unlock();

- group_info = p->group_info;
+ group_info = p->cred->group_info;
get_group_info(group_info);
task_unlock(p);

@@ -268,7 +268,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
blocked = p->blocked;
collect_sigign_sigcatch(p, &ignored, &caught);
num_threads = atomic_read(&p->signal->count);
- qsize = atomic_read(&p->user->sigpending);
+ qsize = atomic_read(&p->cred->user->sigpending);
qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
unlock_task_sighand(p, &flags);
}
@@ -300,10 +300,12 @@ static void render_cap_t(struct seq_file *m, const char *header,

static inline void task_cap(struct seq_file *m, struct task_struct *p)
{
- render_cap_t(m, "CapInh:\t", &p->cap_inheritable);
- render_cap_t(m, "CapPrm:\t", &p->cap_permitted);
- render_cap_t(m, "CapEff:\t", &p->cap_effective);
- render_cap_t(m, "CapBnd:\t", &p->cap_bset);
+ struct cred *cred = p->cred;
+
+ render_cap_t(m, "CapInh:\t", &cred->cap_inheritable);
+ render_cap_t(m, "CapPrm:\t", &cred->cap_permitted);
+ render_cap_t(m, "CapEff:\t", &cred->cap_effective);
+ render_cap_t(m, "CapBnd:\t", &cred->cap_bset);
}

static inline void task_context_switch_counts(struct seq_file *m,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 01ed610..96fb315 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1436,8 +1436,8 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
inode->i_uid = 0;
inode->i_gid = 0;
if (task_dumpable(task)) {
- inode->i_uid = task->euid;
- inode->i_gid = task->egid;
+ inode->i_uid = task->cred->euid;
+ inode->i_gid = task->cred->egid;
}
security_task_to_inode(task, inode);

@@ -1462,8 +1462,8 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
if (task) {
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
task_dumpable(task)) {
- stat->uid = task->euid;
- stat->gid = task->egid;
+ stat->uid = task->cred->euid;
+ stat->gid = task->cred->egid;
}
}
rcu_read_unlock();
@@ -1494,8 +1494,8 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
if (task) {
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
task_dumpable(task)) {
- inode->i_uid = task->euid;
- inode->i_gid = task->egid;
+ inode->i_uid = task->cred->euid;
+ inode->i_gid = task->cred->egid;
} else {
inode->i_uid = 0;
inode->i_gid = 0;
@@ -1666,8 +1666,8 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
rcu_read_unlock();
put_files_struct(files);
if (task_dumpable(task)) {
- inode->i_uid = task->euid;
- inode->i_gid = task->egid;
+ inode->i_uid = task->cred->euid;
+ inode->i_gid = task->cred->egid;
} else {
inode->i_uid = 0;
inode->i_gid = 0;
diff --git a/fs/xfs/linux-2.6/xfs_cred.h b/fs/xfs/linux-2.6/xfs_cred.h
index 293043a..8c022cd 100644
--- a/fs/xfs/linux-2.6/xfs_cred.h
+++ b/fs/xfs/linux-2.6/xfs_cred.h
@@ -23,11 +23,9 @@
/*
* Credentials
*/
-typedef struct cred {
- /* EMPTY */
-} cred_t;
+typedef const struct cred cred_t;

-extern struct cred *sys_cred;
+extern cred_t *sys_cred;

/* this is a hack.. (assumes sys_cred is the only cred_t in the system) */
static inline int capable_cred(cred_t *cr, int cid)
diff --git a/fs/xfs/linux-2.6/xfs_globals.h b/fs/xfs/linux-2.6/xfs_globals.h
index 2770b00..6eda8a3 100644
--- a/fs/xfs/linux-2.6/xfs_globals.h
+++ b/fs/xfs/linux-2.6/xfs_globals.h
@@ -19,6 +19,6 @@
#define __XFS_GLOBALS_H__

extern uint64_t xfs_panic_mask; /* set to cause more panics */
-extern struct cred *sys_cred;
+extern cred_t *sys_cred;

#endif /* __XFS_GLOBALS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index acb978d..acc3fd9 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -1008,7 +1008,7 @@ xfs_ioctl_setattr(
* to the file owner ID, except in cases where the
* CAP_FSETID capability is applicable.
*/
- if (current->fsuid != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
+ if (current_fsuid() != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
code = XFS_ERROR(EPERM);
goto error_return;
}
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 17a04b6..171e939 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -492,7 +492,7 @@ int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
xfs_inode_t **, xfs_daddr_t, uint);
int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t,
- xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t,
+ xfs_nlink_t, xfs_dev_t, cred_t *, xfs_prid_t,
int, struct xfs_buf **, boolean_t *, xfs_inode_t **);
void xfs_dinode_from_disk(struct xfs_icdinode *,
struct xfs_dinode_core *);
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index e932a96..7b0c2ab 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -16,7 +16,7 @@ struct xfs_iomap;

int xfs_open(struct xfs_inode *ip);
int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags,
- struct cred *credp);
+ cred_t *credp);
#define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */
#define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */
#define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */
@@ -28,24 +28,24 @@ int xfs_inactive(struct xfs_inode *ip);
int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode **ipp, struct xfs_name *ci_name);
int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode,
- xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp);
+ xfs_dev_t rdev, struct xfs_inode **ipp, cred_t *credp);
int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode *ip);
int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
struct xfs_name *target_name);
int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name,
- mode_t mode, struct xfs_inode **ipp, struct cred *credp);
+ mode_t mode, struct xfs_inode **ipp, cred_t *credp);
int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize,
xfs_off_t *offset, filldir_t filldir);
int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
const char *target_path, mode_t mode, struct xfs_inode **ipp,
- struct cred *credp);
+ cred_t *credp);
int xfs_inode_flush(struct xfs_inode *ip, int flags);
int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
int xfs_reclaim(struct xfs_inode *ip);
int xfs_change_file_space(struct xfs_inode *ip, int cmd,
xfs_flock64_t *bf, xfs_off_t offset,
- struct cred *credp, int attr_flags);
+ cred_t *credp, int attr_flags);
int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
struct xfs_inode *src_ip, struct xfs_inode *target_dp,
struct xfs_name *target_name, struct xfs_inode *target_ip);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index b69222c..17ad725 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -12,39 +12,150 @@
#ifndef _LINUX_CRED_H
#define _LINUX_CRED_H

-#define get_current_user() (get_uid(current->user))
-
-#define task_uid(task) ((task)->uid)
-#define task_gid(task) ((task)->gid)
-#define task_euid(task) ((task)->euid)
-#define task_egid(task) ((task)->egid)
-
-#define current_uid() (current->uid)
-#define current_gid() (current->gid)
-#define current_euid() (current->euid)
-#define current_egid() (current->egid)
-#define current_suid() (current->suid)
-#define current_sgid() (current->sgid)
-#define current_fsuid() (current->fsuid)
-#define current_fsgid() (current->fsgid)
-#define current_cap() (current->cap_effective)
+#include <linux/capability.h>
+#include <linux/key.h>
+#include <asm/atomic.h>
+
+struct user_struct;
+struct cred;
+
+/*
+ * COW Supplementary groups list
+ */
+#define NGROUPS_SMALL 32
+#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
+
+struct group_info {
+ atomic_t usage;
+ int ngroups;
+ int nblocks;
+ gid_t small_block[NGROUPS_SMALL];
+ gid_t *blocks[0];
+};
+
+/**
+ * get_group_info - Get a reference to a group info structure
+ * @group_info: The group info to reference
+ *
+ * This must be called with the owning task locked (via task_lock()) when task
+ * != current. The reason being that the vast majority of callers are looking
+ * at current->group_info, which can not be changed except by the current task.
+ * Changing current->group_info requires the task lock, too.
+ */
+#define get_group_info(group_info) \
+do { \
+ atomic_inc(&(group_info)->usage); \
+} while (0)
+
+/**
+ * put_group_info - Release a reference to a group info structure
+ * @group_info: The group info to release
+ */
+#define put_group_info(group_info) \
+do { \
+ if (atomic_dec_and_test(&(group_info)->usage)) \
+ groups_free(group_info); \
+} while (0)
+
+extern struct group_info *groups_alloc(int);
+extern void groups_free(struct group_info *);
+extern int set_current_groups(struct group_info *);
+extern int set_groups(struct cred *, struct group_info *);
+extern int groups_search(struct group_info *, gid_t);
+
+/* access the groups "array" with this macro */
+#define GROUP_AT(gi, i) \
+ ((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK])
+
+extern int in_group_p(gid_t);
+extern int in_egroup_p(gid_t);
+
+/*
+ * The security context of a task
+ *
+ * The parts of the context break down into two categories:
+ *
+ * (1) The objective context of a task. These parts are used when some other
+ * task is attempting to affect this one.
+ *
+ * (2) The subjective context. These details are used when the task is acting
+ * upon another object, be that a file, a task, a key or whatever.
+ *
+ * Note that some members of this structure belong to both categories - the
+ * LSM security pointer for instance.
+ *
+ * A task has two security pointers. task->sec points to the objective context
+ * that defines that task's actual details. The objective part of this context
+ * is used whenever that task is acted upon.
+ *
+ * task->act_as points to the subjective context that defines the details of
+ * how that task is going to act upon another object. This may be overridden
+ * temporarily to point to another security context, but normally points to the
+ * same context as task->sec.
+ */
+struct cred {
+ atomic_t usage;
+ uid_t uid; /* real UID of the task */
+ gid_t gid; /* real GID of the task */
+ uid_t suid; /* saved UID of the task */
+ gid_t sgid; /* saved GID of the task */
+ uid_t euid; /* effective UID of the task */
+ gid_t egid; /* effective GID of the task */
+ uid_t fsuid; /* UID for VFS ops */
+ gid_t fsgid; /* GID for VFS ops */
+ unsigned securebits; /* SUID-less security management */
+ kernel_cap_t cap_inheritable; /* caps our children can inherit */
+ kernel_cap_t cap_permitted; /* caps we're permitted */
+ kernel_cap_t cap_effective; /* caps we can actually use */
+ kernel_cap_t cap_bset; /* capability bounding set */
+#ifdef CONFIG_KEYS
+ unsigned char jit_keyring; /* default keyring to attach requested
+ * keys to */
+ struct key *thread_keyring; /* keyring private to this thread */
+ struct key *request_key_auth; /* assumed request_key authority */
+#endif
+#ifdef CONFIG_SECURITY
+ void *security; /* subjective LSM security */
+#endif
+ struct user_struct *user; /* real user ID subscription */
+ struct group_info *group_info; /* supplementary groups for euid/fsgid */
+ struct rcu_head rcu; /* RCU deletion hook */
+ spinlock_t lock; /* lock for pointer changes */
+};
+
+#define get_current_user() (get_uid(current->cred->user))
+
+#define task_uid(task) ((task)->cred->uid)
+#define task_gid(task) ((task)->cred->gid)
+#define task_euid(task) ((task)->cred->euid)
+#define task_egid(task) ((task)->cred->egid)
+
+#define current_uid() (current->cred->uid)
+#define current_gid() (current->cred->gid)
+#define current_euid() (current->cred->euid)
+#define current_egid() (current->cred->egid)
+#define current_suid() (current->cred->suid)
+#define current_sgid() (current->cred->sgid)
+#define current_fsuid() (current->cred->fsuid)
+#define current_fsgid() (current->cred->fsgid)
+#define current_cap() (current->cred->cap_effective)

#define current_uid_gid(_uid, _gid) \
do { \
- *(_uid) = current->uid; \
- *(_gid) = current->gid; \
+ *(_uid) = current->cred->uid; \
+ *(_gid) = current->cred->gid; \
} while(0)

#define current_euid_egid(_uid, _gid) \
do { \
- *(_uid) = current->euid; \
- *(_gid) = current->egid; \
+ *(_uid) = current->cred->euid; \
+ *(_gid) = current->cred->egid; \
} while(0)

#define current_fsuid_fsgid(_uid, _gid) \
do { \
- *(_uid) = current->fsuid; \
- *(_gid) = current->fsgid; \
+ *(_uid) = current->cred->fsuid; \
+ *(_gid) = current->cred->fsgid; \
} while(0)

#endif /* _LINUX_CRED_H */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 021d8e7..0abd837 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -113,6 +113,21 @@ extern struct group_info init_groups;
# define CAP_INIT_BSET CAP_INIT_EFF_SET
#endif

+extern struct cred init_cred;
+
+#define INIT_CRED(p) \
+{ \
+ .usage = ATOMIC_INIT(3), \
+ .securebits = SECUREBITS_DEFAULT, \
+ .cap_inheritable = CAP_INIT_INH_SET, \
+ .cap_permitted = CAP_FULL_SET, \
+ .cap_effective = CAP_INIT_EFF_SET, \
+ .cap_bset = CAP_INIT_BSET, \
+ .user = INIT_USER, \
+ .group_info = &init_groups, \
+ .lock = __SPIN_LOCK_UNLOCKED(p.lock), \
+}
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -147,13 +162,8 @@ extern struct group_info init_groups;
.children = LIST_HEAD_INIT(tsk.children), \
.sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \
- .group_info = &init_groups, \
- .cap_effective = CAP_INIT_EFF_SET, \
- .cap_inheritable = CAP_INIT_INH_SET, \
- .cap_permitted = CAP_FULL_SET, \
- .cap_bset = CAP_INIT_BSET, \
- .securebits = SECUREBITS_DEFAULT, \
- .user = INIT_USER, \
+ .__temp_cred = INIT_CRED(tsk.__temp_cred), \
+ .cred = &tsk.__temp_cred, \
.comm = "swapper", \
.thread = INIT_THREAD, \
.fs = &init_fs, \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9fd5694..304ede6 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -618,6 +618,7 @@ extern struct user_struct *find_user(uid_t);
extern struct user_struct root_user;
#define INIT_USER (&root_user)

+
struct backing_dev_info;
struct reclaim_state;

@@ -842,38 +843,7 @@ partition_sched_domains(int ndoms_new, cpumask_t *doms_new,
#endif /* !CONFIG_SMP */

struct io_context; /* See blkdev.h */
-#define NGROUPS_SMALL 32
-#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
-struct group_info {
- int ngroups;
- atomic_t usage;
- gid_t small_block[NGROUPS_SMALL];
- int nblocks;
- gid_t *blocks[0];
-};
-
-/*
- * get_group_info() must be called with the owning task locked (via task_lock())
- * when task != current. The reason being that the vast majority of callers are
- * looking at current->group_info, which can not be changed except by the
- * current task. Changing current->group_info requires the task lock, too.
- */
-#define get_group_info(group_info) do { \
- atomic_inc(&(group_info)->usage); \
-} while (0)

-#define put_group_info(group_info) do { \
- if (atomic_dec_and_test(&(group_info)->usage)) \
- groups_free(group_info); \
-} while (0)
-
-extern struct group_info *groups_alloc(int gidsetsize);
-extern void groups_free(struct group_info *group_info);
-extern int set_current_groups(struct group_info *group_info);
-extern int groups_search(struct group_info *group_info, gid_t grp);
-/* access the groups "array" with this macro */
-#define GROUP_AT(gi, i) \
- ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])

#ifdef ARCH_HAS_PREFETCH_SWITCH_STACK
extern void prefetch_stack(struct task_struct *t);
@@ -1139,17 +1109,9 @@ struct task_struct {
struct list_head cpu_timers[3];

/* process credentials */
- uid_t uid,euid,suid,fsuid;
- gid_t gid,egid,sgid,fsgid;
- struct group_info *group_info;
- kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset;
- struct user_struct *user;
- unsigned securebits;
-#ifdef CONFIG_KEYS
- unsigned char jit_keyring; /* default keyring to attach requested keys to */
- struct key *request_key_auth; /* assumed request_key authority */
- struct key *thread_keyring; /* keyring private to this thread */
-#endif
+ struct cred __temp_cred __deprecated; /* temporary credentials to be removed */
+ struct cred *cred; /* actual/objective task credentials */
+
char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
it with task_lock())
@@ -1186,9 +1148,6 @@ struct task_struct {
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
-#ifdef CONFIG_SECURITY
- void *security;
-#endif
struct audit_context *audit_context;
#ifdef CONFIG_AUDITSYSCALL
uid_t loginuid;
@@ -1756,9 +1715,6 @@ extern void wake_up_new_task(struct task_struct *tsk,
extern void sched_fork(struct task_struct *p, int clone_flags);
extern void sched_dead(struct task_struct *p);

-extern int in_group_p(gid_t);
-extern int in_egroup_p(gid_t);
-
extern void proc_caches_init(void);
extern void flush_signals(struct task_struct *);
extern void ignore_signals(struct task_struct *);
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 92f09bd..6d38949 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -32,7 +32,7 @@
setting is locked or not. A setting which is locked cannot be
changed from user-level. */
#define issecure_mask(X) (1 << (X))
-#define issecure(X) (issecure_mask(X) & current->securebits)
+#define issecure(X) (issecure_mask(X) & current->cred->securebits)

#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
issecure_mask(SECURE_NO_SETUID_FIXUP) | \
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 51d9588..4d5c116 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -118,7 +118,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
if (S_ISREG(mode)) {
struct mqueue_inode_info *info;
struct task_struct *p = current;
- struct user_struct *u = p->user;
+ struct user_struct *u = p->cred->user;
unsigned long mq_bytes, mq_msg_tblsz;

inode->i_fop = &mqueue_file_operations;
diff --git a/ipc/shm.c b/ipc/shm.c
index c46a7e6..da04353 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -366,7 +366,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
if (shmflg & SHM_HUGETLB) {
/* hugetlb_file_setup takes care of mlock user accounting */
file = hugetlb_file_setup(name, size);
- shp->mlock_user = current->user;
+ shp->mlock_user = current->cred->user;
} else {
int acctflag = VM_ACCOUNT;
/*
@@ -763,7 +763,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
goto out_unlock;

if(cmd==SHM_LOCK) {
- struct user_struct * user = current->user;
+ struct user_struct *user = current->cred->user;
if (!is_file_hugepages(shp->shm_file)) {
err = shmem_lock(shp->shm_file, 1, user);
if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index af446be..9e817df 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -413,6 +413,7 @@ static int audit_filter_rules(struct task_struct *tsk,
struct audit_names *name,
enum audit_state *state)
{
+ struct cred *cred = tsk->cred;
int i, j, need_sid = 1;
u32 sid;

@@ -432,28 +433,28 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_UID:
- result = audit_comparator(tsk->uid, f->op, f->val);
+ result = audit_comparator(cred->uid, f->op, f->val);
break;
case AUDIT_EUID:
- result = audit_comparator(tsk->euid, f->op, f->val);
+ result = audit_comparator(cred->euid, f->op, f->val);
break;
case AUDIT_SUID:
- result = audit_comparator(tsk->suid, f->op, f->val);
+ result = audit_comparator(cred->suid, f->op, f->val);
break;
case AUDIT_FSUID:
- result = audit_comparator(tsk->fsuid, f->op, f->val);
+ result = audit_comparator(cred->fsuid, f->op, f->val);
break;
case AUDIT_GID:
- result = audit_comparator(tsk->gid, f->op, f->val);
+ result = audit_comparator(cred->gid, f->op, f->val);
break;
case AUDIT_EGID:
- result = audit_comparator(tsk->egid, f->op, f->val);
+ result = audit_comparator(cred->egid, f->op, f->val);
break;
case AUDIT_SGID:
- result = audit_comparator(tsk->sgid, f->op, f->val);
+ result = audit_comparator(cred->sgid, f->op, f->val);
break;
case AUDIT_FSGID:
- result = audit_comparator(tsk->fsgid, f->op, f->val);
+ result = audit_comparator(cred->fsgid, f->op, f->val);
break;
case AUDIT_PERS:
result = audit_comparator(tsk->personality, f->op, f->val);
@@ -1165,6 +1166,7 @@ static void audit_log_execve_info(struct audit_context *context,

static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
+ struct cred *cred = tsk->cred;
int i, call_panic = 0;
struct audit_buffer *ab;
struct audit_aux_data *aux;
@@ -1174,14 +1176,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->pid = tsk->pid;
if (!context->ppid)
context->ppid = sys_getppid();
- context->uid = tsk->uid;
- context->gid = tsk->gid;
- context->euid = tsk->euid;
- context->suid = tsk->suid;
- context->fsuid = tsk->fsuid;
- context->egid = tsk->egid;
- context->sgid = tsk->sgid;
- context->fsgid = tsk->fsgid;
+ context->uid = cred->uid;
+ context->gid = cred->gid;
+ context->euid = cred->euid;
+ context->suid = cred->suid;
+ context->fsuid = cred->fsuid;
+ context->egid = cred->egid;
+ context->sgid = cred->sgid;
+ context->fsgid = cred->fsgid;
context->personality = tsk->personality;

ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
@@ -1971,7 +1973,7 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
audit_log_format(ab, "login pid=%d uid=%u "
"old auid=%u new auid=%u"
" old ses=%u new ses=%u",
- task->pid, task->uid,
+ task->pid, task->cred->uid,
task->loginuid, loginuid,
task->sessionid, sessionid);
audit_log_end(ab);
@@ -2354,7 +2356,7 @@ void __audit_ptrace(struct task_struct *t)

context->target_pid = t->pid;
context->target_auid = audit_get_loginuid(t);
- context->target_uid = t->uid;
+ context->target_uid = t->cred->uid;
context->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &context->target_sid);
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
@@ -2380,7 +2382,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
if (tsk->loginuid != -1)
audit_sig_uid = tsk->loginuid;
else
- audit_sig_uid = tsk->uid;
+ audit_sig_uid = tsk->cred->uid;
security_task_getsecid(tsk, &audit_sig_sid);
}
if (!audit_signals || audit_dummy_context())
@@ -2392,7 +2394,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
if (!ctx->target_pid) {
ctx->target_pid = t->tgid;
ctx->target_auid = audit_get_loginuid(t);
- ctx->target_uid = t->uid;
+ ctx->target_uid = t->cred->uid;
ctx->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &ctx->target_sid);
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
@@ -2413,7 +2415,7 @@ int __audit_signal_info(int sig, struct task_struct *t)

axp->target_pid[axp->pid_count] = t->tgid;
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
- axp->target_uid[axp->pid_count] = t->uid;
+ axp->target_uid[axp->pid_count] = t->cred->uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
diff --git a/kernel/capability.c b/kernel/capability.c
index bb96b53..758bfe1 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -159,8 +159,8 @@ kernel_cap_t cap_set_effective(const kernel_cap_t pE_new)

spin_lock(&task_capability_lock);

- pE_old = current->cap_effective;
- current->cap_effective = pE_new;
+ pE_old = current->cred->cap_effective;
+ current->cred->cap_effective = pE_new;

spin_unlock(&task_capability_lock);

diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 9f5a62a..5658dc3 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1290,7 +1290,9 @@ static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
rcu_read_unlock();

euid = current_euid();
- if (euid && euid != tsk->uid && euid != tsk->suid) {
+ if (euid &&
+ euid != tsk->cred->uid &&
+ euid != tsk->cred->suid) {
put_task_struct(tsk);
return -EACCES;
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 38ec406..5ba3db3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -159,7 +159,7 @@ void release_task(struct task_struct * p)
int zap_leader;
repeat:
tracehook_prepare_release_task(p);
- atomic_dec(&p->user->processes);
+ atomic_dec(&p->cred->user->processes);
proc_flush_task(p);
write_lock_irq(&tasklist_lock);
tracehook_finish_release_task(p);
@@ -1272,7 +1272,7 @@ static int wait_task_zombie(struct task_struct *p, int options,
return 0;

if (unlikely(options & WNOWAIT)) {
- uid_t uid = p->uid;
+ uid_t uid = p->cred->uid;
int exit_code = p->exit_code;
int why, status;

@@ -1389,7 +1389,7 @@ static int wait_task_zombie(struct task_struct *p, int options,
if (!retval && infop)
retval = put_user(pid, &infop->si_pid);
if (!retval && infop)
- retval = put_user(p->uid, &infop->si_uid);
+ retval = put_user(p->cred->uid, &infop->si_uid);
if (!retval)
retval = pid;

@@ -1454,7 +1454,7 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
if (!unlikely(options & WNOWAIT))
p->exit_code = 0;

- uid = p->uid;
+ uid = p->cred->uid;
unlock_sig:
spin_unlock_irq(&p->sighand->siglock);
if (!exit_code)
@@ -1531,7 +1531,7 @@ static int wait_task_continued(struct task_struct *p, int options,
spin_unlock_irq(&p->sighand->siglock);

pid = task_pid_vnr(p);
- uid = p->uid;
+ uid = p->cred->uid;
get_task_struct(p);
read_unlock(&tasklist_lock);

diff --git a/kernel/fork.c b/kernel/fork.c
index 7ce2ebe..be0c716 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -146,8 +146,8 @@ void __put_task_struct(struct task_struct *tsk)
WARN_ON(tsk == current);

security_task_free(tsk);
- free_uid(tsk->user);
- put_group_info(tsk->group_info);
+ free_uid(tsk->__temp_cred.user);
+ put_group_info(tsk->__temp_cred.group_info);
delayacct_tsk_free(tsk);

if (!profile_handoff_task(tsk))
@@ -938,17 +938,18 @@ static struct task_struct *copy_process(unsigned long clone_flags,
DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
#endif
+ p->cred = &p->__temp_cred;
retval = -EAGAIN;
- if (atomic_read(&p->user->processes) >=
+ if (atomic_read(&p->cred->user->processes) >=
p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
- p->user != current->nsproxy->user_ns->root_user)
+ p->cred->user != current->nsproxy->user_ns->root_user)
goto bad_fork_free;
}

- atomic_inc(&p->user->__count);
- atomic_inc(&p->user->processes);
- get_group_info(p->group_info);
+ atomic_inc(&p->cred->user->__count);
+ atomic_inc(&p->cred->user->processes);
+ get_group_info(p->cred->group_info);

/*
* If multiple threads are within copy_process(), then this check
@@ -1007,9 +1008,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->real_start_time = p->start_time;
monotonic_to_bootbased(&p->real_start_time);
#ifdef CONFIG_SECURITY
- p->security = NULL;
+ p->cred->security = NULL;
#endif
- p->cap_bset = current->cap_bset;
p->io_context = NULL;
p->audit_context = NULL;
cgroup_fork(p);
@@ -1284,9 +1284,9 @@ bad_fork_cleanup_cgroup:
bad_fork_cleanup_put_domain:
module_put(task_thread_info(p)->exec_domain->module);
bad_fork_cleanup_count:
- put_group_info(p->group_info);
- atomic_dec(&p->user->processes);
- free_uid(p->user);
+ put_group_info(p->cred->group_info);
+ atomic_dec(&p->cred->user->processes);
+ free_uid(p->cred->user);
bad_fork_free:
free_task(p);
fork_out:
diff --git a/kernel/futex.c b/kernel/futex.c
index a28b82b..3f594ac 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -443,7 +443,8 @@ static struct task_struct * futex_find_get_task(pid_t pid)

rcu_read_lock();
p = find_task_by_vpid(pid);
- if (!p || (euid != p->euid && euid != p->uid))
+ if (!p || (euid != p->cred->euid &&
+ euid != p->cred->uid))
p = ERR_PTR(-ESRCH);
else
get_task_struct(p);
@@ -1843,7 +1844,8 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
if (!p)
goto err_unlock;
ret = -EPERM;
- if (euid != p->euid && euid != p->uid &&
+ if (euid != p->cred->euid &&
+ euid != p->cred->uid &&
!capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->robust_list;
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 3254d4e..2c3fd5e 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -151,8 +151,9 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
if (!p)
goto err_unlock;
ret = -EPERM;
- if (euid != p->euid && euid != p->uid &&
- !capable(CAP_SYS_PTRACE))
+ if (euid != p->cred->euid &&
+ euid != p->cred->uid &&
+ !capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->compat_robust_list;
read_unlock(&tasklist_lock);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 0dafab1..efa4556 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -115,6 +115,8 @@ int ptrace_check_attach(struct task_struct *child, int kill)

int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
+ struct cred *cred = current->cred, *tcred = task->cred;
+
/* May we inspect the given task?
* This check is used both for attaching with ptrace
* and for allowing access to sensitive information in /proc.
@@ -123,19 +125,18 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
* because setting up the necessary parent/child relationship
* or halting the specified task is impossible.
*/
- uid_t uid;
- gid_t gid;
+ uid_t uid = cred->uid;
+ gid_t gid = cred->gid;
int dumpable = 0;
/* Don't let security modules deny introspection */
if (task == current)
return 0;
- current_uid_gid(&uid, &gid);
- if ((uid != task->euid ||
- uid != task->suid ||
- uid != task->uid ||
- gid != task->egid ||
- gid != task->sgid ||
- gid != task->gid) && !capable(CAP_SYS_PTRACE))
+ if ((uid != tcred->euid ||
+ uid != tcred->suid ||
+ uid != tcred->uid ||
+ gid != tcred->egid ||
+ gid != tcred->sgid ||
+ gid != tcred->gid) && !capable(CAP_SYS_PTRACE))
return -EPERM;
smp_rmb();
if (task->mm)
diff --git a/kernel/sched.c b/kernel/sched.c
index 4a97b29..152ea80 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -339,7 +339,7 @@ static inline struct task_group *task_group(struct task_struct *p)
struct task_group *tg;

#ifdef CONFIG_USER_SCHED
- tg = p->user->tg;
+ tg = p->cred->user->tg;
#elif defined(CONFIG_CGROUP_SCHED)
tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id),
struct task_group, css);
@@ -5001,8 +5001,8 @@ recheck:

/* can't change other user's priorities */
euid = current_euid();
- if (euid != p->euid &&
- euid != p->uid)
+ if (euid != p->cred->euid &&
+ euid != p->cred->uid)
return -EPERM;
}

@@ -5233,7 +5233,9 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask)

euid = current_euid();
retval = -EPERM;
- if (euid != p->euid && euid != p->uid && !capable(CAP_SYS_NICE))
+ if (euid != p->cred->euid &&
+ euid != p->cred->uid &&
+ !capable(CAP_SYS_NICE))
goto out_unlock;

retval = security_task_setscheduler(p, 0, NULL);
diff --git a/kernel/signal.c b/kernel/signal.c
index 9ad5b74..dfdbaaf 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -186,7 +186,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
* In order to avoid problems with "switch_user()", we want to make
* sure that the compiler doesn't re-load "t->user"
*/
- user = t->user;
+ user = t->cred->user;
barrier();
atomic_inc(&user->sigpending);
if (override_rlimit ||
@@ -581,8 +581,8 @@ static int check_kill_permission(int sig, struct siginfo *info,

uid = current_uid();
euid = current_euid();
- if ((euid ^ t->suid) && (euid ^ t->uid) &&
- (uid ^ t->suid) && (uid ^ t->uid) &&
+ if ((euid ^ t->cred->suid) && (euid ^ t->cred->uid) &&
+ (uid ^ t->cred->suid) && (uid ^ t->cred->uid) &&
!capable(CAP_KILL)) {
switch (sig) {
case SIGCONT:
@@ -1097,8 +1097,8 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
goto out_unlock;
}
if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
- && (euid != p->suid) && (euid != p->uid)
- && (uid != p->suid) && (uid != p->uid)) {
+ && (euid != p->cred->suid) && (euid != p->cred->uid)
+ && (uid != p->cred->suid) && (uid != p->cred->uid)) {
ret = -EPERM;
goto out_unlock;
}
@@ -1367,7 +1367,7 @@ int do_notify_parent(struct task_struct *tsk, int sig)
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
rcu_read_unlock();

- info.si_uid = tsk->uid;
+ info.si_uid = tsk->cred->uid;

info.si_utime = cputime_to_clock_t(cputime_add(tsk->utime,
tsk->signal->utime));
@@ -1439,7 +1439,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
rcu_read_unlock();

- info.si_uid = tsk->uid;
+ info.si_uid = tsk->cred->uid;

info.si_utime = cputime_to_clock_t(tsk->utime);
info.si_stime = cputime_to_clock_t(tsk->stime);
@@ -1707,7 +1707,7 @@ static int ptrace_signal(int signr, siginfo_t *info,
info->si_errno = 0;
info->si_code = SI_USER;
info->si_pid = task_pid_vnr(current->parent);
- info->si_uid = current->parent->uid;
+ info->si_uid = current->parent->cred->uid;
}

/* If the (new) signal is now blocked, requeue it. */
diff --git a/kernel/sys.c b/kernel/sys.c
index f498f30..48cbb5b 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -117,7 +117,9 @@ static int set_one_prio(struct task_struct *p, int niceval, int error)
uid_t euid = current_euid();
int no_nice;

- if (p->uid != euid && p->euid != euid && !capable(CAP_SYS_NICE)) {
+ if (p->cred->uid != euid &&
+ p->cred->euid != euid &&
+ !capable(CAP_SYS_NICE)) {
error = -EPERM;
goto out;
}
@@ -174,7 +176,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = current->user;
+ user = current->cred->user;
if (!who)
who = current_uid();
else
@@ -182,7 +184,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
goto out_unlock; /* No processes for this user */

do_each_thread(g, p)
- if (p->uid == who)
+ if (p->cred->uid == who)
error = set_one_prio(p, niceval, error);
while_each_thread(g, p);
if (who != current_uid())
@@ -236,7 +238,7 @@ asmlinkage long sys_getpriority(int which, int who)
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = current->user;
+ user = current->cred->user;
if (!who)
who = current_uid();
else
@@ -244,7 +246,7 @@ asmlinkage long sys_getpriority(int which, int who)
goto out_unlock; /* No processes for this user */

do_each_thread(g, p)
- if (p->uid == who) {
+ if (p->cred->uid == who) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
@@ -472,8 +474,9 @@ void ctrl_alt_del(void)
*/
asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
{
- int old_rgid = current->gid;
- int old_egid = current->egid;
+ struct cred *cred = current->cred;
+ int old_rgid = cred->gid;
+ int old_egid = cred->egid;
int new_rgid = old_rgid;
int new_egid = old_egid;
int retval;
@@ -484,7 +487,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)

if (rgid != (gid_t) -1) {
if ((old_rgid == rgid) ||
- (current->egid==rgid) ||
+ (cred->egid == rgid) ||
capable(CAP_SETGID))
new_rgid = rgid;
else
@@ -492,8 +495,8 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
}
if (egid != (gid_t) -1) {
if ((old_rgid == egid) ||
- (current->egid == egid) ||
- (current->sgid == egid) ||
+ (cred->egid == egid) ||
+ (cred->sgid == egid) ||
capable(CAP_SETGID))
new_egid = egid;
else
@@ -505,10 +508,10 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
}
if (rgid != (gid_t) -1 ||
(egid != (gid_t) -1 && egid != old_rgid))
- current->sgid = new_egid;
- current->fsgid = new_egid;
- current->egid = new_egid;
- current->gid = new_rgid;
+ cred->sgid = new_egid;
+ cred->fsgid = new_egid;
+ cred->egid = new_egid;
+ cred->gid = new_rgid;
key_fsgid_changed(current);
proc_id_connector(current, PROC_EVENT_GID);
return 0;
@@ -521,7 +524,8 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
*/
asmlinkage long sys_setgid(gid_t gid)
{
- int old_egid = current->egid;
+ struct cred *cred = current->cred;
+ int old_egid = cred->egid;
int retval;

retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
@@ -533,13 +537,13 @@ asmlinkage long sys_setgid(gid_t gid)
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->gid = current->egid = current->sgid = current->fsgid = gid;
- } else if ((gid == current->gid) || (gid == current->sgid)) {
+ cred->gid = cred->egid = cred->sgid = cred->fsgid = gid;
+ } else if ((gid == cred->gid) || (gid == cred->sgid)) {
if (old_egid != gid) {
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->egid = current->fsgid = gid;
+ cred->egid = cred->fsgid = gid;
}
else
return -EPERM;
@@ -570,7 +574,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->uid = new_ruid;
+ current->cred->uid = new_ruid;
return 0;
}

@@ -591,6 +595,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
*/
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
{
+ struct cred *cred = current->cred;
int old_ruid, old_euid, old_suid, new_ruid, new_euid;
int retval;

@@ -598,14 +603,14 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
if (retval)
return retval;

- new_ruid = old_ruid = current->uid;
- new_euid = old_euid = current->euid;
- old_suid = current->suid;
+ new_ruid = old_ruid = cred->uid;
+ new_euid = old_euid = cred->euid;
+ old_suid = cred->suid;

if (ruid != (uid_t) -1) {
new_ruid = ruid;
if ((old_ruid != ruid) &&
- (current->euid != ruid) &&
+ (cred->euid != ruid) &&
!capable(CAP_SETUID))
return -EPERM;
}
@@ -613,8 +618,8 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
if (euid != (uid_t) -1) {
new_euid = euid;
if ((old_ruid != euid) &&
- (current->euid != euid) &&
- (current->suid != euid) &&
+ (cred->euid != euid) &&
+ (cred->suid != euid) &&
!capable(CAP_SETUID))
return -EPERM;
}
@@ -626,11 +631,11 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->fsuid = current->euid = new_euid;
+ cred->fsuid = cred->euid = new_euid;
if (ruid != (uid_t) -1 ||
(euid != (uid_t) -1 && euid != old_ruid))
- current->suid = current->euid;
- current->fsuid = current->euid;
+ cred->suid = cred->euid;
+ cred->fsuid = cred->euid;

key_fsuid_changed(current);
proc_id_connector(current, PROC_EVENT_UID);
@@ -653,7 +658,8 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
*/
asmlinkage long sys_setuid(uid_t uid)
{
- int old_euid = current->euid;
+ struct cred *cred = current->cred;
+ int old_euid = cred->euid;
int old_ruid, old_suid, new_suid;
int retval;

@@ -661,23 +667,23 @@ asmlinkage long sys_setuid(uid_t uid)
if (retval)
return retval;

- old_ruid = current->uid;
- old_suid = current->suid;
+ old_ruid = cred->uid;
+ old_suid = cred->suid;
new_suid = old_suid;

if (capable(CAP_SETUID)) {
if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
return -EAGAIN;
new_suid = uid;
- } else if ((uid != current->uid) && (uid != new_suid))
+ } else if ((uid != cred->uid) && (uid != new_suid))
return -EPERM;

if (old_euid != uid) {
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->fsuid = current->euid = uid;
- current->suid = new_suid;
+ cred->fsuid = cred->euid = uid;
+ cred->suid = new_suid;

key_fsuid_changed(current);
proc_id_connector(current, PROC_EVENT_UID);
@@ -692,9 +698,10 @@ asmlinkage long sys_setuid(uid_t uid)
*/
asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
{
- int old_ruid = current->uid;
- int old_euid = current->euid;
- int old_suid = current->suid;
+ struct cred *cred = current->cred;
+ int old_ruid = cred->uid;
+ int old_euid = cred->euid;
+ int old_suid = cred->suid;
int retval;

retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
@@ -702,30 +709,31 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
return retval;

if (!capable(CAP_SETUID)) {
- if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
- (ruid != current->euid) && (ruid != current->suid))
+ if ((ruid != (uid_t) -1) && (ruid != cred->uid) &&
+ (ruid != cred->euid) && (ruid != cred->suid))
return -EPERM;
- if ((euid != (uid_t) -1) && (euid != current->uid) &&
- (euid != current->euid) && (euid != current->suid))
+ if ((euid != (uid_t) -1) && (euid != cred->uid) &&
+ (euid != cred->euid) && (euid != cred->suid))
return -EPERM;
- if ((suid != (uid_t) -1) && (suid != current->uid) &&
- (suid != current->euid) && (suid != current->suid))
+ if ((suid != (uid_t) -1) && (suid != cred->uid) &&
+ (suid != cred->euid) && (suid != cred->suid))
return -EPERM;
}
if (ruid != (uid_t) -1) {
- if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
+ if (ruid != cred->uid &&
+ set_user(ruid, euid != cred->euid) < 0)
return -EAGAIN;
}
if (euid != (uid_t) -1) {
- if (euid != current->euid) {
+ if (euid != cred->euid) {
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->euid = euid;
+ cred->euid = euid;
}
- current->fsuid = current->euid;
+ cred->fsuid = cred->euid;
if (suid != (uid_t) -1)
- current->suid = suid;
+ cred->suid = suid;

key_fsuid_changed(current);
proc_id_connector(current, PROC_EVENT_UID);
@@ -735,11 +743,12 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)

asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
{
+ struct cred *cred = current->cred;
int retval;

- if (!(retval = put_user(current->uid, ruid)) &&
- !(retval = put_user(current->euid, euid)))
- retval = put_user(current->suid, suid);
+ if (!(retval = put_user(cred->uid, ruid)) &&
+ !(retval = put_user(cred->euid, euid)))
+ retval = put_user(cred->suid, suid);

return retval;
}
@@ -749,6 +758,7 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us
*/
asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{
+ struct cred *cred = current->cred;
int retval;

retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
@@ -756,28 +766,28 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
return retval;

if (!capable(CAP_SETGID)) {
- if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
- (rgid != current->egid) && (rgid != current->sgid))
+ if ((rgid != (gid_t) -1) && (rgid != cred->gid) &&
+ (rgid != cred->egid) && (rgid != cred->sgid))
return -EPERM;
- if ((egid != (gid_t) -1) && (egid != current->gid) &&
- (egid != current->egid) && (egid != current->sgid))
+ if ((egid != (gid_t) -1) && (egid != cred->gid) &&
+ (egid != cred->egid) && (egid != cred->sgid))
return -EPERM;
- if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
- (sgid != current->egid) && (sgid != current->sgid))
+ if ((sgid != (gid_t) -1) && (sgid != cred->gid) &&
+ (sgid != cred->egid) && (sgid != cred->sgid))
return -EPERM;
}
if (egid != (gid_t) -1) {
- if (egid != current->egid) {
+ if (egid != cred->egid) {
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->egid = egid;
+ cred->egid = egid;
}
- current->fsgid = current->egid;
+ cred->fsgid = cred->egid;
if (rgid != (gid_t) -1)
- current->gid = rgid;
+ cred->gid = rgid;
if (sgid != (gid_t) -1)
- current->sgid = sgid;
+ cred->sgid = sgid;

key_fsgid_changed(current);
proc_id_connector(current, PROC_EVENT_GID);
@@ -786,11 +796,12 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)

asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid)
{
+ struct cred *cred = current->cred;
int retval;

- if (!(retval = put_user(current->gid, rgid)) &&
- !(retval = put_user(current->egid, egid)))
- retval = put_user(current->sgid, sgid);
+ if (!(retval = put_user(cred->gid, rgid)) &&
+ !(retval = put_user(cred->egid, egid)))
+ retval = put_user(cred->sgid, sgid);

return retval;
}
@@ -804,20 +815,21 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us
*/
asmlinkage long sys_setfsuid(uid_t uid)
{
+ struct cred *cred = current->cred;
int old_fsuid;

- old_fsuid = current->fsuid;
+ old_fsuid = cred->fsuid;
if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
return old_fsuid;

- if (uid == current->uid || uid == current->euid ||
- uid == current->suid || uid == current->fsuid ||
+ if (uid == cred->uid || uid == cred->euid ||
+ uid == cred->suid || uid == cred->fsuid ||
capable(CAP_SETUID)) {
if (uid != old_fsuid) {
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->fsuid = uid;
+ cred->fsuid = uid;
}

key_fsuid_changed(current);
@@ -833,20 +845,21 @@ asmlinkage long sys_setfsuid(uid_t uid)
*/
asmlinkage long sys_setfsgid(gid_t gid)
{
+ struct cred *cred = current->cred;
int old_fsgid;

- old_fsgid = current->fsgid;
+ old_fsgid = cred->fsgid;
if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
return old_fsgid;

- if (gid == current->gid || gid == current->egid ||
- gid == current->sgid || gid == current->fsgid ||
+ if (gid == cred->gid || gid == cred->egid ||
+ gid == cred->sgid || gid == cred->fsgid ||
capable(CAP_SETGID)) {
if (gid != old_fsgid) {
set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
- current->fsgid = gid;
+ cred->fsgid = gid;
key_fsgid_changed(current);
proc_id_connector(current, PROC_EVENT_GID);
}
@@ -1220,8 +1233,15 @@ int groups_search(struct group_info *group_info, gid_t grp)
return 0;
}

-/* validate and set current->group_info */
-int set_current_groups(struct group_info *group_info)
+/**
+ * set_groups - Change a group subscription in a security record
+ * @sec: The security record to alter
+ * @group_info: The group list to impose
+ *
+ * Validate a group subscription and, if valid, impose it upon a task security
+ * record.
+ */
+int set_groups(struct cred *cred, struct group_info *group_info)
{
int retval;
struct group_info *old_info;
@@ -1233,20 +1253,34 @@ int set_current_groups(struct group_info *group_info)
groups_sort(group_info);
get_group_info(group_info);

- task_lock(current);
- old_info = current->group_info;
- current->group_info = group_info;
- task_unlock(current);
+ spin_lock(&cred->lock);
+ old_info = cred->group_info;
+ cred->group_info = group_info;
+ spin_unlock(&cred->lock);

put_group_info(old_info);
-
return 0;
}

+EXPORT_SYMBOL(set_groups);
+
+/**
+ * set_current_groups - Change current's group subscription
+ * @group_info: The group list to impose
+ *
+ * Validate a group subscription and, if valid, impose it upon current's task
+ * security record.
+ */
+int set_current_groups(struct group_info *group_info)
+{
+ return set_groups(current->cred, group_info);
+}
+
EXPORT_SYMBOL(set_current_groups);

asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
{
+ struct cred *cred = current->cred;
int i = 0;

/*
@@ -1258,13 +1292,13 @@ asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
return -EINVAL;

/* no need to grab task_lock here; it cannot change */
- i = current->group_info->ngroups;
+ i = cred->group_info->ngroups;
if (gidsetsize) {
if (i > gidsetsize) {
i = -EINVAL;
goto out;
}
- if (groups_to_user(grouplist, current->group_info)) {
+ if (groups_to_user(grouplist, cred->group_info)) {
i = -EFAULT;
goto out;
}
@@ -1308,9 +1342,10 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
*/
int in_group_p(gid_t grp)
{
+ struct cred *cred = current->cred;
int retval = 1;
- if (grp != current->fsgid)
- retval = groups_search(current->group_info, grp);
+ if (grp != cred->fsgid)
+ retval = groups_search(cred->group_info, grp);
return retval;
}

@@ -1318,9 +1353,10 @@ EXPORT_SYMBOL(in_group_p);

int in_egroup_p(gid_t grp)
{
+ struct cred *cred = current->cred;
int retval = 1;
- if (grp != current->egid)
- retval = groups_search(current->group_info, grp);
+ if (grp != cred->egid)
+ retval = groups_search(cred->group_info, grp);
return retval;
}

@@ -1635,7 +1671,9 @@ asmlinkage long sys_umask(int mask)
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
- long error = 0;
+ struct task_struct *me = current;
+ unsigned char comm[sizeof(me->comm)];
+ long uninitialized_var(error);

if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
return error;
@@ -1646,39 +1684,39 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = -EINVAL;
break;
}
- current->pdeath_signal = arg2;
+ me->pdeath_signal = arg2;
break;
case PR_GET_PDEATHSIG:
- error = put_user(current->pdeath_signal, (int __user *)arg2);
+ error = put_user(me->pdeath_signal, (int __user *)arg2);
break;
case PR_GET_DUMPABLE:
- error = get_dumpable(current->mm);
+ error = get_dumpable(me->mm);
break;
case PR_SET_DUMPABLE:
if (arg2 < 0 || arg2 > 1) {
error = -EINVAL;
break;
}
- set_dumpable(current->mm, arg2);
+ set_dumpable(me->mm, arg2);
break;

case PR_SET_UNALIGN:
- error = SET_UNALIGN_CTL(current, arg2);
+ error = SET_UNALIGN_CTL(me, arg2);
break;
case PR_GET_UNALIGN:
- error = GET_UNALIGN_CTL(current, arg2);
+ error = GET_UNALIGN_CTL(me, arg2);
break;
case PR_SET_FPEMU:
- error = SET_FPEMU_CTL(current, arg2);
+ error = SET_FPEMU_CTL(me, arg2);
break;
case PR_GET_FPEMU:
- error = GET_FPEMU_CTL(current, arg2);
+ error = GET_FPEMU_CTL(me, arg2);
break;
case PR_SET_FPEXC:
- error = SET_FPEXC_CTL(current, arg2);
+ error = SET_FPEXC_CTL(me, arg2);
break;
case PR_GET_FPEXC:
- error = GET_FPEXC_CTL(current, arg2);
+ error = GET_FPEXC_CTL(me, arg2);
break;
case PR_GET_TIMING:
error = PR_TIMING_STATISTICAL;
@@ -1688,31 +1726,24 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = -EINVAL;
break;

- case PR_SET_NAME: {
- struct task_struct *me = current;
- unsigned char ncomm[sizeof(me->comm)];
-
- ncomm[sizeof(me->comm)-1] = 0;
- if (strncpy_from_user(ncomm, (char __user *)arg2,
- sizeof(me->comm)-1) < 0)
+ case PR_SET_NAME:
+ comm[sizeof(me->comm)-1] = 0;
+ if (strncpy_from_user(comm, (char __user *)arg2,
+ sizeof(me->comm) - 1) < 0)
return -EFAULT;
- set_task_comm(me, ncomm);
+ set_task_comm(me, comm);
return 0;
- }
- case PR_GET_NAME: {
- struct task_struct *me = current;
- unsigned char tcomm[sizeof(me->comm)];
-
- get_task_comm(tcomm, me);
- if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm)))
+ case PR_GET_NAME:
+ get_task_comm(comm, me);
+ if (copy_to_user((char __user *)arg2, comm,
+ sizeof(comm)))
return -EFAULT;
return 0;
- }
case PR_GET_ENDIAN:
- error = GET_ENDIAN(current, arg2);
+ error = GET_ENDIAN(me, arg2);
break;
case PR_SET_ENDIAN:
- error = SET_ENDIAN(current, arg2);
+ error = SET_ENDIAN(me, arg2);
break;

case PR_GET_SECCOMP:
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8f3fb3d..c97b5bb 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -257,7 +257,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)

memcpy(data->comm, tsk->comm, TASK_COMM_LEN);
data->pid = tsk->pid;
- data->uid = tsk->uid;
+ data->uid = task_uid(tsk);
data->nice = tsk->static_prio - 20 - MAX_RT_PRIO;
data->policy = tsk->policy;
data->rt_priority = tsk->rt_priority;
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 8ebcd85..6d1ed07 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -53,8 +53,8 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
stats->ac_flag |= AXSIG;
stats->ac_nice = task_nice(tsk);
stats->ac_sched = tsk->policy;
- stats->ac_uid = tsk->uid;
- stats->ac_gid = tsk->gid;
+ stats->ac_uid = tsk->cred->uid;
+ stats->ac_gid = tsk->cred->gid;
stats->ac_pid = tsk->pid;
rcu_read_lock();
stats->ac_ppid = pid_alive(tsk) ?
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 3e41c16..71f07fc 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -86,9 +86,9 @@ asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid,
{
int retval;

- if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
- !(retval = put_user(high2lowuid(current->euid), euid)))
- retval = put_user(high2lowuid(current->suid), suid);
+ if (!(retval = put_user(high2lowuid(current->cred->uid), ruid)) &&
+ !(retval = put_user(high2lowuid(current->cred->euid), euid)))
+ retval = put_user(high2lowuid(current->cred->suid), suid);

return retval;
}
@@ -106,9 +106,9 @@ asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid,
{
int retval;

- if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
- !(retval = put_user(high2lowgid(current->egid), egid)))
- retval = put_user(high2lowgid(current->sgid), sgid);
+ if (!(retval = put_user(high2lowgid(current->cred->gid), rgid)) &&
+ !(retval = put_user(high2lowgid(current->cred->egid), egid)))
+ retval = put_user(high2lowgid(current->cred->sgid), sgid);

return retval;
}
@@ -166,20 +166,20 @@ asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist)
if (gidsetsize < 0)
return -EINVAL;

- get_group_info(current->group_info);
- i = current->group_info->ngroups;
+ get_group_info(current->cred->group_info);
+ i = current->cred->group_info->ngroups;
if (gidsetsize) {
if (i > gidsetsize) {
i = -EINVAL;
goto out;
}
- if (groups16_to_user(grouplist, current->group_info)) {
+ if (groups16_to_user(grouplist, current->cred->group_info)) {
i = -EFAULT;
goto out;
}
}
out:
- put_group_info(current->group_info);
+ put_group_info(current->cred->group_info);
return i;
}

@@ -210,20 +210,20 @@ asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist)

asmlinkage long sys_getuid16(void)
{
- return high2lowuid(current->uid);
+ return high2lowuid(current->cred->uid);
}

asmlinkage long sys_geteuid16(void)
{
- return high2lowuid(current->euid);
+ return high2lowuid(current->cred->euid);
}

asmlinkage long sys_getgid16(void)
{
- return high2lowgid(current->gid);
+ return high2lowgid(current->cred->gid);
}

asmlinkage long sys_getegid16(void)
{
- return high2lowgid(current->egid);
+ return high2lowgid(current->cred->egid);
}
diff --git a/kernel/user.c b/kernel/user.c
index 865ecf5..9c9e27b 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -457,11 +457,11 @@ void switch_uid(struct user_struct *new_user)
* cheaply with the new uid cache, so if it matters
* we should be checking for it. -DaveM
*/
- old_user = current->user;
+ old_user = current->cred->user;
atomic_inc(&new_user->processes);
atomic_dec(&old_user->processes);
switch_uid_keyring(new_user);
- current->user = new_user;
+ current->cred->user = new_user;
sched_switch_user(current);

/*
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 6419497..4374a83 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1106,12 +1106,12 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
const unsigned long __user *old_nodes,
const unsigned long __user *new_nodes)
{
+ struct cred *cred, *tcred;
struct mm_struct *mm;
struct task_struct *task;
nodemask_t old;
nodemask_t new;
nodemask_t task_nodes;
- uid_t uid, euid;
int err;

err = get_nodes(&old, old_nodes, maxnode);
@@ -1141,10 +1141,10 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
* capabilities, superuser privileges or the same
* userid as the target process.
*/
- uid = current_uid();
- euid = current_euid();
- if (euid != task->suid && euid != task->uid &&
- uid != task->suid && uid != task->uid &&
+ cred = current->cred;
+ tcred = task->cred;
+ if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
+ cred->uid != tcred->suid && cred->uid != tcred->uid &&
!capable(CAP_SYS_NICE)) {
err = -EPERM;
goto out;
diff --git a/mm/migrate.c b/mm/migrate.c
index efc200b..78af7fd 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -984,13 +984,13 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
const int __user *nodes,
int __user *status, int flags)
{
+ struct cred *cred, *tcred;
int err = 0;
int i;
struct task_struct *task;
nodemask_t task_nodes;
struct mm_struct *mm;
struct page_to_node *pm = NULL;
- uid_t uid, euid;

/* Check flags */
if (flags & ~(MPOL_MF_MOVE|MPOL_MF_MOVE_ALL))
@@ -1018,10 +1018,10 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
* capabilities, superuser privileges or the same
* userid as the target process.
*/
- uid = current_uid();
- euid = current_euid();
- if (euid != task->suid && euid != task->uid &&
- uid != task->suid && uid != task->uid &&
+ cred = current->cred;
+ tcred = task->cred;
+ if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
+ cred->uid != tcred->suid && cred->uid != tcred->uid &&
!capable(CAP_SYS_NICE)) {
err = -EPERM;
goto out2;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 64e5b4b..c156ffb 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -298,7 +298,7 @@ static void dump_tasks(const struct mem_cgroup *mem)

task_lock(p);
printk(KERN_INFO "[%5d] %5d %5d %8lu %8lu %3d %3d %s\n",
- p->pid, p->uid, p->tgid, p->mm->total_vm,
+ p->pid, p->cred->uid, p->tgid, p->mm->total_vm,
get_mm_rss(p->mm), (int)task_cpu(p), p->oomkilladj,
p->comm);
task_unlock(p);
diff --git a/net/core/scm.c b/net/core/scm.c
index 4681d8f..c28ca32 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -44,11 +44,13 @@

static __inline__ int scm_check_creds(struct ucred *creds)
{
+ struct cred *cred = current->cred;
+
if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
- ((creds->uid == current_uid() || creds->uid == current_euid() ||
- creds->uid == current_suid()) || capable(CAP_SETUID)) &&
- ((creds->gid == current_gid() || creds->gid == current_egid() ||
- creds->gid == current_sgid()) || capable(CAP_SETGID))) {
+ ((creds->uid == cred->uid || creds->uid == cred->euid ||
+ creds->uid == cred->suid) || capable(CAP_SETUID)) &&
+ ((creds->gid == cred->gid || creds->gid == cred->egid ||
+ creds->gid == cred->sgid) || capable(CAP_SETGID))) {
return 0;
}
return -EPERM;
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 9dd8062..9515fef 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -353,7 +353,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
struct auth_cred acred = {
.uid = current_fsuid(),
.gid = current_fsgid(),
- .group_info = current->group_info,
+ .group_info = current->cred->group_info,
};
struct rpc_cred *ret;

diff --git a/security/commoncap.c b/security/commoncap.c
index 570fd75..cb4da7d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -29,7 +29,7 @@

int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- NETLINK_CB(skb).eff_cap = current->cap_effective;
+ NETLINK_CB(skb).eff_cap = current_cap();
return 0;
}

@@ -51,7 +51,7 @@ EXPORT_SYMBOL(cap_netlink_recv);
int cap_capable (struct task_struct *tsk, int cap)
{
/* Derived from include/linux/sched.h:capable. */
- if (cap_raised(tsk->cap_effective, cap))
+ if (cap_raised(tsk->cred->cap_effective, cap))
return 0;
return -EPERM;
}
@@ -66,7 +66,8 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
{
/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
- if (cap_issubset(child->cap_permitted, current->cap_permitted))
+ if (cap_issubset(child->cred->cap_permitted,
+ current->cred->cap_permitted))
return 0;
if (capable(CAP_SYS_PTRACE))
return 0;
@@ -75,8 +76,8 @@ int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)

int cap_ptrace_traceme(struct task_struct *parent)
{
- /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
- if (cap_issubset(current->cap_permitted, parent->cap_permitted))
+ if (cap_issubset(current->cred->cap_permitted,
+ parent->cred->cap_permitted))
return 0;
if (has_capability(parent, CAP_SYS_PTRACE))
return 0;
@@ -86,10 +87,12 @@ int cap_ptrace_traceme(struct task_struct *parent)
int cap_capget (struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
+ struct cred *cred = target->cred;
+
/* Derived from kernel/capability.c:sys_capget. */
- *effective = target->cap_effective;
- *inheritable = target->cap_inheritable;
- *permitted = target->cap_permitted;
+ *effective = cred->cap_effective;
+ *inheritable = cred->cap_inheritable;
+ *permitted = cred->cap_permitted;
return 0;
}

@@ -121,24 +124,26 @@ int cap_capset_check(const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
+ const struct cred *cred = current->cred;
+
if (cap_inh_is_capped()
&& !cap_issubset(*inheritable,
- cap_combine(current->cap_inheritable,
- current->cap_permitted))) {
+ cap_combine(cred->cap_inheritable,
+ cred->cap_permitted))) {
/* incapable of using this inheritable set */
return -EPERM;
}
if (!cap_issubset(*inheritable,
- cap_combine(current->cap_inheritable,
- current->cap_bset))) {
+ cap_combine(cred->cap_inheritable,
+ cred->cap_bset))) {
/* no new pI capabilities outside bounding set */
return -EPERM;
}

/* verify restrictions on target's new Permitted set */
if (!cap_issubset (*permitted,
- cap_combine (current->cap_permitted,
- current->cap_permitted))) {
+ cap_combine (cred->cap_permitted,
+ cred->cap_permitted))) {
return -EPERM;
}

@@ -154,9 +159,11 @@ void cap_capset_set(const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- current->cap_effective = *effective;
- current->cap_inheritable = *inheritable;
- current->cap_permitted = *permitted;
+ struct cred *cred = current->cred;
+
+ cred->cap_effective = *effective;
+ cred->cap_inheritable = *inheritable;
+ cred->cap_permitted = *permitted;
}

static inline void bprm_clear_caps(struct linux_binprm *bprm)
@@ -241,8 +248,8 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
*/
value_cpu = le32_to_cpu(caps->data[i].permitted);
bprm->cap_post_exec_permitted.cap[i] =
- (current->cap_bset.cap[i] & value_cpu) |
- (current->cap_inheritable.cap[i] &
+ (current->cred->cap_bset.cap[i] & value_cpu) |
+ (current->cred->cap_inheritable.cap[i] &
le32_to_cpu(caps->data[i].inheritable));
if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
/*
@@ -337,8 +344,8 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
if (bprm->e_uid == 0 || current_uid() == 0) {
/* pP' = (cap_bset & ~0) | (pI & ~0) */
bprm->cap_post_exec_permitted = cap_combine(
- current->cap_bset, current->cap_inheritable
- );
+ current->cred->cap_bset,
+ current->cred->cap_inheritable);
bprm->cap_effective = (bprm->e_uid == 0);
ret = 0;
}
@@ -349,60 +356,59 @@ int cap_bprm_set_security (struct linux_binprm *bprm)

void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- uid_t uid;
- gid_t gid;
+ struct cred *cred = current->cred;

- current_uid_gid(&uid, &gid);
-
- if (bprm->e_uid != uid || bprm->e_gid != gid ||
+ if (bprm->e_uid != cred->uid || bprm->e_gid != cred->gid ||
!cap_issubset(bprm->cap_post_exec_permitted,
- current->cap_permitted)) {
+ cred->cap_permitted)) {
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;

if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
if (!capable(CAP_SETUID)) {
- bprm->e_uid = uid;
- bprm->e_gid = gid;
+ bprm->e_uid = cred->uid;
+ bprm->e_gid = cred->gid;
}
if (cap_limit_ptraced_target()) {
bprm->cap_post_exec_permitted = cap_intersect(
bprm->cap_post_exec_permitted,
- current->cap_permitted);
+ cred->cap_permitted);
}
}
}

- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ cred->suid = cred->euid = cred->fsuid = bprm->e_uid;
+ cred->sgid = cred->egid = cred->fsgid = bprm->e_gid;

/* For init, we want to retain the capabilities set
* in the init_task struct. Thus we skip the usual
* capability rules */
if (!is_global_init(current)) {
- current->cap_permitted = bprm->cap_post_exec_permitted;
+ cred->cap_permitted = bprm->cap_post_exec_permitted;
if (bprm->cap_effective)
- current->cap_effective = bprm->cap_post_exec_permitted;
+ cred->cap_effective = bprm->cap_post_exec_permitted;
else
- cap_clear(current->cap_effective);
+ cap_clear(cred->cap_effective);
}

- /* AUD: Audit candidate if current->cap_effective is set */
+ /* AUD: Audit candidate if cred->cap_effective is set */

- current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+ cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
}

int cap_bprm_secureexec (struct linux_binprm *bprm)
{
- if (current_uid() != 0) {
+ const struct cred *cred = current->cred;
+
+ if (cred->uid != 0) {
if (bprm->cap_effective)
return 1;
if (!cap_isclear(bprm->cap_post_exec_permitted))
return 1;
}

- return (current_euid() != current_uid() ||
- current_egid() != current_gid());
+ return (cred->euid != cred->uid ||
+ cred->egid != cred->gid);
}

int cap_inode_setxattr(struct dentry *dentry, const char *name,
@@ -465,25 +471,27 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
int old_suid)
{
- uid_t euid = current_euid();
+ struct cred *cred = current->cred;

if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
- (current_uid() != 0 && euid != 0 && current_suid() != 0) &&
+ (cred->uid != 0 && cred->euid != 0 && cred->suid != 0) &&
!issecure(SECURE_KEEP_CAPS)) {
- cap_clear (current->cap_permitted);
- cap_clear (current->cap_effective);
+ cap_clear (cred->cap_permitted);
+ cap_clear (cred->cap_effective);
}
- if (old_euid == 0 && euid != 0) {
- cap_clear (current->cap_effective);
+ if (old_euid == 0 && cred->euid != 0) {
+ cap_clear (cred->cap_effective);
}
- if (old_euid != 0 && euid == 0) {
- current->cap_effective = current->cap_permitted;
+ if (old_euid != 0 && cred->euid == 0) {
+ cred->cap_effective = cred->cap_permitted;
}
}

int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
int flags)
{
+ struct cred *cred = current->cred;
+
switch (flags) {
case LSM_SETID_RE:
case LSM_SETID_ID:
@@ -505,16 +513,16 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
*/

if (!issecure (SECURE_NO_SETUID_FIXUP)) {
- if (old_fsuid == 0 && current_fsuid() != 0) {
- current->cap_effective =
+ if (old_fsuid == 0 && cred->fsuid != 0) {
+ cred->cap_effective =
cap_drop_fs_set(
- current->cap_effective);
+ cred->cap_effective);
}
- if (old_fsuid != 0 && current_fsuid() == 0) {
- current->cap_effective =
+ if (old_fsuid != 0 && cred->fsuid == 0) {
+ cred->cap_effective =
cap_raise_fs_set(
- current->cap_effective,
- current->cap_permitted);
+ cred->cap_effective,
+ cred->cap_permitted);
}
}
break;
@@ -539,7 +547,8 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
*/
static inline int cap_safe_nice(struct task_struct *p)
{
- if (!cap_issubset(p->cap_permitted, current->cap_permitted) &&
+ if (!cap_issubset(p->cred->cap_permitted,
+ current->cred->cap_permitted) &&
!capable(CAP_SYS_NICE))
return -EPERM;
return 0;
@@ -574,7 +583,7 @@ static long cap_prctl_drop(unsigned long cap)
return -EPERM;
if (!cap_valid(cap))
return -EINVAL;
- cap_lower(current->cap_bset, cap);
+ cap_lower(current->cred->cap_bset, cap);
return 0;
}

@@ -597,6 +606,7 @@ int cap_task_setnice (struct task_struct *p, int nice)
int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5, long *rc_p)
{
+ struct cred *cred = current->cred;
long error = 0;

switch (option) {
@@ -604,7 +614,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
if (!cap_valid(arg2))
error = -EINVAL;
else
- error = !!cap_raised(current->cap_bset, arg2);
+ error = !!cap_raised(cred->cap_bset, arg2);
break;
#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
case PR_CAPBSET_DROP:
@@ -631,9 +641,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
* capability-based-privilege environment.
*/
case PR_SET_SECUREBITS:
- if ((((current->securebits & SECURE_ALL_LOCKS) >> 1)
- & (current->securebits ^ arg2)) /*[1]*/
- || ((current->securebits & SECURE_ALL_LOCKS
+ if ((((cred->securebits & SECURE_ALL_LOCKS) >> 1)
+ & (cred->securebits ^ arg2)) /*[1]*/
+ || ((cred->securebits & SECURE_ALL_LOCKS
& ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|| (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/
@@ -646,11 +656,11 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
*/
error = -EPERM; /* cannot change a locked bit */
} else {
- current->securebits = arg2;
+ cred->securebits = arg2;
}
break;
case PR_GET_SECUREBITS:
- error = current->securebits;
+ error = cred->securebits;
break;

#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
@@ -665,10 +675,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
else if (issecure(SECURE_KEEP_CAPS_LOCKED))
error = -EPERM;
else if (arg2)
- current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
+ cred->securebits |= issecure_mask(SECURE_KEEP_CAPS);
else
- current->securebits &=
- ~issecure_mask(SECURE_KEEP_CAPS);
+ cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
break;

default:
@@ -683,11 +692,12 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,

void cap_task_reparent_to_init (struct task_struct *p)
{
- cap_set_init_eff(p->cap_effective);
- cap_clear(p->cap_inheritable);
- cap_set_full(p->cap_permitted);
- p->securebits = SECUREBITS_DEFAULT;
- return;
+ struct cred *cred = p->cred;
+
+ cap_set_init_eff(cred->cap_effective);
+ cap_clear(cred->cap_inheritable);
+ cap_set_full(cred->cap_permitted);
+ p->cred->securebits = SECUREBITS_DEFAULT;
}

int cap_syslog (int type)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index fcce331..8833b44 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -889,7 +889,7 @@ long keyctl_instantiate_key(key_serial_t id,
/* the appropriate instantiation authorisation key must have been
* assumed before calling this */
ret = -EPERM;
- instkey = current->request_key_auth;
+ instkey = current->cred->request_key_auth;
if (!instkey)
goto error;

@@ -932,8 +932,8 @@ long keyctl_instantiate_key(key_serial_t id,
/* discard the assumed authority if it's just been disabled by
* instantiation of the key */
if (ret == 0) {
- key_put(current->request_key_auth);
- current->request_key_auth = NULL;
+ key_put(current->cred->request_key_auth);
+ current->cred->request_key_auth = NULL;
}

error2:
@@ -960,7 +960,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
/* the appropriate instantiation authorisation key must have been
* assumed before calling this */
ret = -EPERM;
- instkey = current->request_key_auth;
+ instkey = current->cred->request_key_auth;
if (!instkey)
goto error;

@@ -983,8 +983,8 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
/* discard the assumed authority if it's just been disabled by
* instantiation of the key */
if (ret == 0) {
- key_put(current->request_key_auth);
- current->request_key_auth = NULL;
+ key_put(current->cred->request_key_auth);
+ current->cred->request_key_auth = NULL;
}

error:
@@ -999,6 +999,7 @@ error:
*/
long keyctl_set_reqkey_keyring(int reqkey_defl)
{
+ struct cred *cred = current->cred;
int ret;

switch (reqkey_defl) {
@@ -1018,10 +1019,10 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
case KEY_REQKEY_DEFL_USER_KEYRING:
case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
set:
- current->jit_keyring = reqkey_defl;
+ cred->jit_keyring = reqkey_defl;

case KEY_REQKEY_DEFL_NO_CHANGE:
- return current->jit_keyring;
+ return cred->jit_keyring;

case KEY_REQKEY_DEFL_GROUP_KEYRING:
default:
@@ -1086,8 +1087,8 @@ long keyctl_assume_authority(key_serial_t id)

/* we divest ourselves of authority if given an ID of 0 */
if (id == 0) {
- key_put(current->request_key_auth);
- current->request_key_auth = NULL;
+ key_put(current->cred->request_key_auth);
+ current->cred->request_key_auth = NULL;
ret = 0;
goto error;
}
@@ -1103,8 +1104,8 @@ long keyctl_assume_authority(key_serial_t id)
goto error;
}

- key_put(current->request_key_auth);
- current->request_key_auth = authkey;
+ key_put(current->cred->request_key_auth);
+ current->cred->request_key_auth = authkey;
ret = authkey->serial;

error:
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 3b41f9b..baf3d5f 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -22,6 +22,7 @@ int key_task_permission(const key_ref_t key_ref,
struct task_struct *context,
key_perm_t perm)
{
+ struct cred *cred = context->cred;
struct key *key;
key_perm_t kperm;
int ret;
@@ -29,7 +30,7 @@ int key_task_permission(const key_ref_t key_ref,
key = key_ref_to_ptr(key_ref);

/* use the second 8-bits of permissions for keys the caller owns */
- if (key->uid == context->fsuid) {
+ if (key->uid == cred->fsuid) {
kperm = key->perm >> 16;
goto use_these_perms;
}
@@ -37,14 +38,14 @@ int key_task_permission(const key_ref_t key_ref,
/* use the third 8-bits of permissions for keys the caller has a group
* membership in common with */
if (key->gid != -1 && key->perm & KEY_GRP_ALL) {
- if (key->gid == context->fsgid) {
+ if (key->gid == cred->fsgid) {
kperm = key->perm >> 8;
goto use_these_perms;
}

- task_lock(context);
- ret = groups_search(context->group_info, key->gid);
- task_unlock(context);
+ spin_lock(&cred->lock);
+ ret = groups_search(cred->group_info, key->gid);
+ spin_unlock(&cred->lock);

if (ret) {
kperm = key->perm >> 8;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 324093d..248ad13 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -42,7 +42,7 @@ struct key_user root_key_user = {
*/
static int install_user_keyrings(void)
{
- struct user_struct *user = current->user;
+ struct user_struct *user = current->cred->user;
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;
@@ -156,7 +156,7 @@ int install_thread_keyring(void)

sprintf(buf, "_tid.%u", tsk->pid);

- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
@@ -164,8 +164,8 @@ int install_thread_keyring(void)
}

task_lock(tsk);
- old = tsk->thread_keyring;
- tsk->thread_keyring = keyring;
+ old = tsk->cred->thread_keyring;
+ tsk->cred->thread_keyring = keyring;
task_unlock(tsk);

ret = 0;
@@ -192,7 +192,7 @@ int install_process_keyring(void)
if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid);

- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
@@ -238,7 +238,7 @@ static int install_session_keyring(struct key *keyring)
if (tsk->signal->session_keyring)
flags = KEY_ALLOC_IN_QUOTA;

- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk,
flags, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
@@ -292,14 +292,14 @@ int copy_thread_group_keys(struct task_struct *tsk)
*/
int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
{
- key_check(tsk->thread_keyring);
- key_check(tsk->request_key_auth);
+ key_check(tsk->cred->thread_keyring);
+ key_check(tsk->cred->request_key_auth);

/* no thread keyring yet */
- tsk->thread_keyring = NULL;
+ tsk->cred->thread_keyring = NULL;

/* copy the request_key() authorisation for this thread */
- key_get(tsk->request_key_auth);
+ key_get(tsk->cred->request_key_auth);

return 0;

@@ -322,8 +322,8 @@ void exit_thread_group_keys(struct signal_struct *tg)
*/
void exit_keys(struct task_struct *tsk)
{
- key_put(tsk->thread_keyring);
- key_put(tsk->request_key_auth);
+ key_put(tsk->cred->thread_keyring);
+ key_put(tsk->cred->request_key_auth);

} /* end exit_keys() */

@@ -337,8 +337,8 @@ int exec_keys(struct task_struct *tsk)

/* newly exec'd tasks don't get a thread keyring */
task_lock(tsk);
- old = tsk->thread_keyring;
- tsk->thread_keyring = NULL;
+ old = tsk->cred->thread_keyring;
+ tsk->cred->thread_keyring = NULL;
task_unlock(tsk);

key_put(old);
@@ -373,10 +373,11 @@ int suid_keys(struct task_struct *tsk)
void key_fsuid_changed(struct task_struct *tsk)
{
/* update the ownership of the thread keyring */
- if (tsk->thread_keyring) {
- down_write(&tsk->thread_keyring->sem);
- tsk->thread_keyring->uid = tsk->fsuid;
- up_write(&tsk->thread_keyring->sem);
+ BUG_ON(!tsk->cred);
+ if (tsk->cred->thread_keyring) {
+ down_write(&tsk->cred->thread_keyring->sem);
+ tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
+ up_write(&tsk->cred->thread_keyring->sem);
}

} /* end key_fsuid_changed() */
@@ -388,10 +389,11 @@ void key_fsuid_changed(struct task_struct *tsk)
void key_fsgid_changed(struct task_struct *tsk)
{
/* update the ownership of the thread keyring */
- if (tsk->thread_keyring) {
- down_write(&tsk->thread_keyring->sem);
- tsk->thread_keyring->gid = tsk->fsgid;
- up_write(&tsk->thread_keyring->sem);
+ BUG_ON(!tsk->cred);
+ if (tsk->cred->thread_keyring) {
+ down_write(&tsk->cred->thread_keyring->sem);
+ tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
+ up_write(&tsk->cred->thread_keyring->sem);
}

} /* end key_fsgid_changed() */
@@ -426,9 +428,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
err = ERR_PTR(-EAGAIN);

/* search the thread keyring first */
- if (context->thread_keyring) {
+ if (context->cred->thread_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->thread_keyring, 1),
+ make_key_ref(context->cred->thread_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -493,9 +495,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
}
}
/* or search the user-session keyring */
- else if (context->user->session_keyring) {
+ else if (context->cred->user->session_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->user->session_keyring, 1),
+ make_key_ref(context->cred->user->session_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -517,20 +519,20 @@ key_ref_t search_process_keyrings(struct key_type *type,
* search the keyrings of the process mentioned there
* - we don't permit access to request_key auth keys via this method
*/
- if (context->request_key_auth &&
+ if (context->cred->request_key_auth &&
context == current &&
type != &key_type_request_key_auth
) {
/* defend against the auth key being revoked */
- down_read(&context->request_key_auth->sem);
+ down_read(&context->cred->request_key_auth->sem);

- if (key_validate(context->request_key_auth) == 0) {
- rka = context->request_key_auth->payload.data;
+ if (key_validate(context->cred->request_key_auth) == 0) {
+ rka = context->cred->request_key_auth->payload.data;

key_ref = search_process_keyrings(type, description,
match, rka->context);

- up_read(&context->request_key_auth->sem);
+ up_read(&context->cred->request_key_auth->sem);

if (!IS_ERR(key_ref))
goto found;
@@ -547,7 +549,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
break;
}
} else {
- up_read(&context->request_key_auth->sem);
+ up_read(&context->cred->request_key_auth->sem);
}
}

@@ -580,15 +582,16 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
{
struct request_key_auth *rka;
struct task_struct *t = current;
- key_ref_t key_ref, skey_ref;
+ struct cred *cred = t->cred;
struct key *key;
+ key_ref_t key_ref, skey_ref;
int ret;

key_ref = ERR_PTR(-ENOKEY);

switch (id) {
case KEY_SPEC_THREAD_KEYRING:
- if (!t->thread_keyring) {
+ if (!cred->thread_keyring) {
if (!create)
goto error;

@@ -599,7 +602,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
}
}

- key = t->thread_keyring;
+ key = cred->thread_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;
@@ -628,7 +631,8 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
ret = install_user_keyrings();
if (ret < 0)
goto error;
- ret = install_session_keyring(t->user->session_keyring);
+ ret = install_session_keyring(
+ cred->user->session_keyring);
if (ret < 0)
goto error;
}
@@ -641,25 +645,25 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
break;

case KEY_SPEC_USER_KEYRING:
- if (!t->user->uid_keyring) {
+ if (!cred->user->uid_keyring) {
ret = install_user_keyrings();
if (ret < 0)
goto error;
}

- key = t->user->uid_keyring;
+ key = cred->user->uid_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;

case KEY_SPEC_USER_SESSION_KEYRING:
- if (!t->user->session_keyring) {
+ if (!cred->user->session_keyring) {
ret = install_user_keyrings();
if (ret < 0)
goto error;
}

- key = t->user->session_keyring;
+ key = cred->user->session_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;
@@ -670,7 +674,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
goto error;

case KEY_SPEC_REQKEY_AUTH_KEY:
- key = t->request_key_auth;
+ key = cred->request_key_auth;
if (!key)
goto error;

@@ -679,19 +683,19 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
break;

case KEY_SPEC_REQUESTOR_KEYRING:
- if (!t->request_key_auth)
+ if (!cred->request_key_auth)
goto error;

- down_read(&t->request_key_auth->sem);
- if (t->request_key_auth->flags & KEY_FLAG_REVOKED) {
+ down_read(&cred->request_key_auth->sem);
+ if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) {
key_ref = ERR_PTR(-EKEYREVOKED);
key = NULL;
} else {
- rka = t->request_key_auth->payload.data;
+ rka = cred->request_key_auth->payload.data;
key = rka->dest_keyring;
atomic_inc(&key->usage);
}
- up_read(&t->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);
if (!key)
goto error;
key_ref = make_key_ref(key, 1);
@@ -791,7 +795,7 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, false);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
+ keyring = keyring_alloc(name, tsk->cred->uid, tsk->cred->gid, tsk,
KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index d7a4e25..8ffd86e 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -100,7 +100,8 @@ static int call_sbin_request_key(struct key_construction *cons,

/* we specify the process's default keyrings */
sprintf(keyring_str[0], "%d",
- tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
+ tsk->cred->thread_keyring ?
+ tsk->cred->thread_keyring->serial : 0);

prkey = 0;
if (tsk->signal->process_keyring)
@@ -113,7 +114,7 @@ static int call_sbin_request_key(struct key_construction *cons,
sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
rcu_read_unlock();
} else {
- sskey = tsk->user->session_keyring->serial;
+ sskey = tsk->cred->user->session_keyring->serial;
}

sprintf(keyring_str[2], "%d", sskey);
@@ -228,11 +229,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
} else {
/* use a default keyring; falling through the cases until we
* find one that we actually have */
- switch (tsk->jit_keyring) {
+ switch (tsk->cred->jit_keyring) {
case KEY_REQKEY_DEFL_DEFAULT:
case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
- if (tsk->request_key_auth) {
- authkey = tsk->request_key_auth;
+ if (tsk->cred->request_key_auth) {
+ authkey = tsk->cred->request_key_auth;
down_read(&authkey->sem);
rka = authkey->payload.data;
if (!test_bit(KEY_FLAG_REVOKED,
@@ -245,7 +246,7 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
}

case KEY_REQKEY_DEFL_THREAD_KEYRING:
- dest_keyring = key_get(tsk->thread_keyring);
+ dest_keyring = key_get(tsk->cred->thread_keyring);
if (dest_keyring)
break;

@@ -264,11 +265,12 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
break;

case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
- dest_keyring = key_get(tsk->user->session_keyring);
+ dest_keyring =
+ key_get(tsk->cred->user->session_keyring);
break;

case KEY_REQKEY_DEFL_USER_KEYRING:
- dest_keyring = key_get(tsk->user->uid_keyring);
+ dest_keyring = key_get(tsk->cred->user->uid_keyring);
break;

case KEY_REQKEY_DEFL_GROUP_KEYRING:
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 1762d44..2125579 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -164,22 +164,22 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,

/* see if the calling process is already servicing the key request of
* another process */
- if (current->request_key_auth) {
+ if (current->cred->request_key_auth) {
/* it is - use that instantiation context here too */
- down_read(&current->request_key_auth->sem);
+ down_read(&current->cred->request_key_auth->sem);

/* if the auth key has been revoked, then the key we're
* servicing is already instantiated */
if (test_bit(KEY_FLAG_REVOKED,
- &current->request_key_auth->flags))
+ &current->cred->request_key_auth->flags))
goto auth_key_revoked;

- irka = current->request_key_auth->payload.data;
+ irka = current->cred->request_key_auth->payload.data;
rka->context = irka->context;
rka->pid = irka->pid;
get_task_struct(rka->context);

- up_read(&current->request_key_auth->sem);
+ up_read(&current->cred->request_key_auth->sem);
}
else {
/* it isn't - use this process as the context */
@@ -214,7 +214,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
return authkey;

auth_key_revoked:
- up_read(&current->request_key_auth->sem);
+ up_read(&current->cred->request_key_auth->sem);
kfree(rka->callout_info);
kfree(rka);
kleave("= -EKEYREVOKED");
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index 64af2d3..cf02490 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -39,7 +39,7 @@ EXPORT_SYMBOL_GPL(selinux_string_to_sid);
int selinux_secmark_relabel_packet_permission(u32 sid)
{
if (selinux_enabled) {
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;

return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET,
PACKET__RELABELTO, NULL);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9cc59f6..3e8900e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -166,21 +166,21 @@ static int task_alloc_security(struct task_struct *task)
return -ENOMEM;

tsec->osid = tsec->sid = SECINITSID_UNLABELED;
- task->security = tsec;
+ task->cred->security = tsec;

return 0;
}

static void task_free_security(struct task_struct *task)
{
- struct task_security_struct *tsec = task->security;
- task->security = NULL;
+ struct task_security_struct *tsec = task->cred->security;
+ task->cred->security = NULL;
kfree(tsec);
}

static int inode_alloc_security(struct inode *inode)
{
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct inode_security_struct *isec;

isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
@@ -214,7 +214,7 @@ static void inode_free_security(struct inode *inode)

static int file_alloc_security(struct file *file)
{
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct file_security_struct *fsec;

fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
@@ -552,7 +552,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
int rc = 0, i;
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct superblock_security_struct *sbsec = sb->s_security;
const char *name = sb->s_type->name;
struct inode *inode = sbsec->sb->s_root->d_inode;
@@ -1351,8 +1351,8 @@ static int task_has_perm(struct task_struct *tsk1,
{
struct task_security_struct *tsec1, *tsec2;

- tsec1 = tsk1->security;
- tsec2 = tsk2->security;
+ tsec1 = tsk1->cred->security;
+ tsec2 = tsk2->cred->security;
return avc_has_perm(tsec1->sid, tsec2->sid,
SECCLASS_PROCESS, perms, NULL);
}
@@ -1370,7 +1370,7 @@ static int task_has_capability(struct task_struct *tsk,
u16 sclass;
u32 av = CAP_TO_MASK(cap);

- tsec = tsk->security;
+ tsec = tsk->cred->security;

AVC_AUDIT_DATA_INIT(&ad, CAP);
ad.tsk = tsk;
@@ -1397,7 +1397,7 @@ static int task_has_system(struct task_struct *tsk,
{
struct task_security_struct *tsec;

- tsec = tsk->security;
+ tsec = tsk->cred->security;

return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
SECCLASS_SYSTEM, perms, NULL);
@@ -1418,7 +1418,7 @@ static int inode_has_perm(struct task_struct *tsk,
if (unlikely(IS_PRIVATE(inode)))
return 0;

- tsec = tsk->security;
+ tsec = tsk->cred->security;
isec = inode->i_security;

if (!adp) {
@@ -1458,7 +1458,7 @@ static int file_has_perm(struct task_struct *tsk,
struct file *file,
u32 av)
{
- struct task_security_struct *tsec = tsk->security;
+ struct task_security_struct *tsec = tsk->cred->security;
struct file_security_struct *fsec = file->f_security;
struct inode *inode = file->f_path.dentry->d_inode;
struct avc_audit_data ad;
@@ -1495,7 +1495,7 @@ static int may_create(struct inode *dir,
struct avc_audit_data ad;
int rc;

- tsec = current->security;
+ tsec = current->cred->security;
dsec = dir->i_security;
sbsec = dir->i_sb->s_security;

@@ -1532,7 +1532,7 @@ static int may_create_key(u32 ksid,
{
struct task_security_struct *tsec;

- tsec = ctx->security;
+ tsec = ctx->cred->security;

return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
}
@@ -1553,7 +1553,7 @@ static int may_link(struct inode *dir,
u32 av;
int rc;

- tsec = current->security;
+ tsec = current->cred->security;
dsec = dir->i_security;
isec = dentry->d_inode->i_security;

@@ -1598,7 +1598,7 @@ static inline int may_rename(struct inode *old_dir,
int old_is_dir, new_is_dir;
int rc;

- tsec = current->security;
+ tsec = current->cred->security;
old_dsec = old_dir->i_security;
old_isec = old_dentry->d_inode->i_security;
old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
@@ -1651,7 +1651,7 @@ static int superblock_has_perm(struct task_struct *tsk,
struct task_security_struct *tsec;
struct superblock_security_struct *sbsec;

- tsec = tsk->security;
+ tsec = tsk->cred->security;
sbsec = sb->s_security;
return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
perms, ad);
@@ -1749,8 +1749,8 @@ static int selinux_ptrace_may_access(struct task_struct *child,
return rc;

if (mode == PTRACE_MODE_READ) {
- struct task_security_struct *tsec = current->security;
- struct task_security_struct *csec = child->security;
+ struct task_security_struct *tsec = current->cred->security;
+ struct task_security_struct *csec = child->cred->security;
return avc_has_perm(tsec->sid, csec->sid,
SECCLASS_FILE, FILE__READ, NULL);
}
@@ -1865,7 +1865,7 @@ static int selinux_sysctl(ctl_table *table, int op)
if (rc)
return rc;

- tsec = current->security;
+ tsec = current->cred->security;

rc = selinux_sysctl_get_sid(table, (op == 0001) ?
SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1972,7 +1972,7 @@ static int selinux_syslog(int type)
static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{
int rc, cap_sys_admin = 0;
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;

rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
if (rc == 0)
@@ -2024,7 +2024,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
if (bsec->set)
return 0;

- tsec = current->security;
+ tsec = current->cred->security;
isec = inode->i_security;

/* Default to the current task SID. */
@@ -2089,7 +2089,7 @@ static int selinux_bprm_check_security(struct linux_binprm *bprm)

static int selinux_bprm_secureexec(struct linux_binprm *bprm)
{
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
int atsecure = 0;

if (tsec->osid != tsec->sid) {
@@ -2212,7 +2212,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)

secondary_ops->bprm_apply_creds(bprm, unsafe);

- tsec = current->security;
+ tsec = current->cred->security;

bsec = bprm->security;
sid = bsec->sid;
@@ -2241,7 +2241,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
rcu_read_lock();
tracer = tracehook_tracer_task(current);
if (likely(tracer != NULL)) {
- sec = tracer->security;
+ sec = tracer->cred->security;
ptsid = sec->sid;
}
rcu_read_unlock();
@@ -2270,7 +2270,7 @@ static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm)
struct bprm_security_struct *bsec;
int rc, i;

- tsec = current->security;
+ tsec = current->cred->security;
bsec = bprm->security;

if (bsec->unsafe) {
@@ -2518,7 +2518,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
int rc;
char *namep = NULL, *context;

- tsec = current->security;
+ tsec = current->cred->security;
dsec = dir->i_security;
sbsec = dir->i_sb->s_security;

@@ -2703,7 +2703,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct inode *inode = dentry->d_inode;
struct inode_security_struct *isec = inode->i_security;
struct superblock_security_struct *sbsec;
@@ -2811,7 +2811,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
u32 size;
int error;
char *context = NULL;
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct inode_security_struct *isec = inode->i_security;

if (strcmp(name, XATTR_SELINUX_SUFFIX))
@@ -2922,7 +2922,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
static int selinux_file_permission(struct file *file, int mask)
{
struct inode *inode = file->f_path.dentry->d_inode;
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct file_security_struct *fsec = file->f_security;
struct inode_security_struct *isec = inode->i_security;

@@ -2999,7 +2999,8 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
unsigned long addr, unsigned long addr_only)
{
int rc = 0;
- u32 sid = ((struct task_security_struct *)(current->security))->sid;
+ u32 sid = ((struct task_security_struct *)
+ (current->cred->security))->sid;

if (addr < mmap_min_addr)
rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -3111,7 +3112,7 @@ static int selinux_file_set_fowner(struct file *file)
struct task_security_struct *tsec;
struct file_security_struct *fsec;

- tsec = current->security;
+ tsec = current->cred->security;
fsec = file->f_security;
fsec->fown_sid = tsec->sid;

@@ -3129,7 +3130,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
/* struct fown_struct is never outside the context of a struct file */
file = container_of(fown, struct file, f_owner);

- tsec = tsk->security;
+ tsec = tsk->cred->security;
fsec = file->f_security;

if (!signum)
@@ -3192,12 +3193,12 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
struct task_security_struct *tsec1, *tsec2;
int rc;

- tsec1 = current->security;
+ tsec1 = current->cred->security;

rc = task_alloc_security(tsk);
if (rc)
return rc;
- tsec2 = tsk->security;
+ tsec2 = tsk->cred->security;

tsec2->osid = tsec1->osid;
tsec2->sid = tsec1->sid;
@@ -3255,7 +3256,7 @@ static int selinux_task_getsid(struct task_struct *p)

static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
{
- struct task_security_struct *tsec = p->security;
+ struct task_security_struct *tsec = p->cred->security;
*secid = tsec->sid;
}

@@ -3347,7 +3348,7 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
perm = signal_to_av(sig);
- tsec = p->security;
+ tsec = p->cred->security;
if (secid)
rc = avc_has_perm(secid, tsec->sid, SECCLASS_PROCESS, perm, NULL);
else
@@ -3379,7 +3380,7 @@ static void selinux_task_reparent_to_init(struct task_struct *p)

secondary_ops->task_reparent_to_init(p);

- tsec = p->security;
+ tsec = p->cred->security;
tsec->osid = tsec->sid;
tsec->sid = SECINITSID_KERNEL;
return;
@@ -3388,7 +3389,7 @@ static void selinux_task_reparent_to_init(struct task_struct *p)
static void selinux_task_to_inode(struct task_struct *p,
struct inode *inode)
{
- struct task_security_struct *tsec = p->security;
+ struct task_security_struct *tsec = p->cred->security;
struct inode_security_struct *isec = inode->i_security;

isec->sid = tsec->sid;
@@ -3636,7 +3637,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
struct avc_audit_data ad;
int err = 0;

- tsec = task->security;
+ tsec = task->cred->security;
isec = SOCK_INODE(sock)->i_security;

if (isec->sid == SECINITSID_KERNEL)
@@ -3660,7 +3661,7 @@ static int selinux_socket_create(int family, int type,
if (kern)
goto out;

- tsec = current->security;
+ tsec = current->cred->security;
newsid = tsec->sockcreate_sid ? : tsec->sid;
err = avc_has_perm(tsec->sid, newsid,
socket_type_to_security_class(family, type,
@@ -3681,7 +3682,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,

isec = SOCK_INODE(sock)->i_security;

- tsec = current->security;
+ tsec = current->cred->security;
newsid = tsec->sockcreate_sid ? : tsec->sid;
isec->sclass = socket_type_to_security_class(family, type, protocol);
isec->sid = kern ? SECINITSID_KERNEL : newsid;
@@ -3727,7 +3728,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
struct sock *sk = sock->sk;
u32 sid, node_perm;

- tsec = current->security;
+ tsec = current->cred->security;
isec = SOCK_INODE(sock)->i_security;

if (family == PF_INET) {
@@ -4667,7 +4668,7 @@ static int ipc_alloc_security(struct task_struct *task,
struct kern_ipc_perm *perm,
u16 sclass)
{
- struct task_security_struct *tsec = task->security;
+ struct task_security_struct *tsec = task->cred->security;
struct ipc_security_struct *isec;

isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
@@ -4717,7 +4718,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
struct ipc_security_struct *isec;
struct avc_audit_data ad;

- tsec = current->security;
+ tsec = current->cred->security;
isec = ipc_perms->security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -4748,7 +4749,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
if (rc)
return rc;

- tsec = current->security;
+ tsec = current->cred->security;
isec = msq->q_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -4774,7 +4775,7 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
struct ipc_security_struct *isec;
struct avc_audit_data ad;

- tsec = current->security;
+ tsec = current->cred->security;
isec = msq->q_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -4820,7 +4821,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
struct avc_audit_data ad;
int rc;

- tsec = current->security;
+ tsec = current->cred->security;
isec = msq->q_perm.security;
msec = msg->security;

@@ -4868,7 +4869,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
struct avc_audit_data ad;
int rc;

- tsec = target->security;
+ tsec = target->cred->security;
isec = msq->q_perm.security;
msec = msg->security;

@@ -4895,7 +4896,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
if (rc)
return rc;

- tsec = current->security;
+ tsec = current->cred->security;
isec = shp->shm_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -4921,7 +4922,7 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
struct ipc_security_struct *isec;
struct avc_audit_data ad;

- tsec = current->security;
+ tsec = current->cred->security;
isec = shp->shm_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -4994,7 +4995,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
if (rc)
return rc;

- tsec = current->security;
+ tsec = current->cred->security;
isec = sma->sem_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -5020,7 +5021,7 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg)
struct ipc_security_struct *isec;
struct avc_audit_data ad;

- tsec = current->security;
+ tsec = current->cred->security;
isec = sma->sem_perm.security;

AVC_AUDIT_DATA_INIT(&ad, IPC);
@@ -5127,7 +5128,7 @@ static int selinux_getprocattr(struct task_struct *p,
return error;
}

- tsec = p->security;
+ tsec = p->cred->security;

if (!strcmp(name, "current"))
sid = tsec->sid;
@@ -5211,7 +5212,7 @@ static int selinux_setprocattr(struct task_struct *p,
operation. See selinux_bprm_set_security for the execve
checks and may_create for the file creation checks. The
operation will then fail if the context is not permitted. */
- tsec = p->security;
+ tsec = p->cred->security;
if (!strcmp(name, "exec"))
tsec->exec_sid = sid;
else if (!strcmp(name, "fscreate"))
@@ -5255,7 +5256,8 @@ static int selinux_setprocattr(struct task_struct *p,
rcu_read_lock();
tracer = tracehook_tracer_task(p);
if (tracer != NULL) {
- struct task_security_struct *ptsec = tracer->security;
+ struct task_security_struct *ptsec =
+ tracer->cred->security;
u32 ptsid = ptsec->sid;
rcu_read_unlock();
error = avc_has_perm_noaudit(ptsid, sid,
@@ -5299,7 +5301,7 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
unsigned long flags)
{
- struct task_security_struct *tsec = tsk->security;
+ struct task_security_struct *tsec = tsk->cred->security;
struct key_security_struct *ksec;

ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
@@ -5333,7 +5335,7 @@ static int selinux_key_permission(key_ref_t key_ref,

key = key_ref_to_ptr(key_ref);

- tsec = ctx->security;
+ tsec = ctx->cred->security;
ksec = key->security;

/* if no specific permissions are requested, we skip the
@@ -5577,7 +5579,7 @@ static __init int selinux_init(void)
/* Set the security state for the initial task. */
if (task_alloc_security(current))
panic("SELinux: Failed to initialize initial task.\n");
- tsec = current->security;
+ tsec = current->cred->security;
tsec->osid = tsec->sid = SECINITSID_KERNEL;

sel_inode_cache = kmem_cache_create("selinux_inode_security",
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 69c9dcc..10715d1 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -97,7 +97,7 @@ static int task_has_security(struct task_struct *tsk,
{
struct task_security_struct *tsec;

- tsec = tsk->security;
+ tsec = tsk->cred->security;
if (!tsec)
return -EACCES;

diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 8f17f54..d7db766 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -197,7 +197,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx, u32 sid)
{
int rc = 0;
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct xfrm_sec_ctx *ctx = NULL;
char *ctx_str = NULL;
u32 str_len;
@@ -333,7 +333,7 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
*/
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
{
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
int rc = 0;

if (ctx) {
@@ -378,7 +378,7 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
*/
int selinux_xfrm_state_delete(struct xfrm_state *x)
{
- struct task_security_struct *tsec = current->security;
+ struct task_security_struct *tsec = current->cred->security;
struct xfrm_sec_ctx *ctx = x->security;
int rc = 0;

diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 79ff21e..b6dd4fc 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -164,7 +164,7 @@ int smk_curacc(char *obj_label, u32 mode)
{
int rc;

- rc = smk_access(current->security, obj_label, mode);
+ rc = smk_access(current->cred->security, obj_label, mode);
if (rc == 0)
return 0;

@@ -173,7 +173,7 @@ int smk_curacc(char *obj_label, u32 mode)
* only one that gets privilege and current does not
* have that label.
*/
- if (smack_onlycap != NULL && smack_onlycap != current->security)
+ if (smack_onlycap != NULL && smack_onlycap != current->cred->security)
return rc;

if (capable(CAP_MAC_OVERRIDE))
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 87d7541..ccded56 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -102,7 +102,8 @@ static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
if (rc != 0)
return rc;

- rc = smk_access(current->security, ctp->security, MAY_READWRITE);
+ rc = smk_access(current->cred->security, ctp->cred->security,
+ MAY_READWRITE);
if (rc != 0 && capable(CAP_MAC_OVERRIDE))
return 0;
return rc;
@@ -124,7 +125,8 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
if (rc != 0)
return rc;

- rc = smk_access(ptp->security, current->security, MAY_READWRITE);
+ rc = smk_access(ptp->cred->security, current->cred->security,
+ MAY_READWRITE);
if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE))
return 0;
return rc;
@@ -141,7 +143,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
static int smack_syslog(int type)
{
int rc;
- char *sp = current->security;
+ char *sp = current->cred->security;

rc = cap_syslog(type);
if (rc != 0)
@@ -373,7 +375,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
*/
static int smack_inode_alloc_security(struct inode *inode)
{
- inode->i_security = new_inode_smack(current->security);
+ inode->i_security = new_inode_smack(current->cred->security);
if (inode->i_security == NULL)
return -ENOMEM;
return 0;
@@ -818,7 +820,7 @@ static int smack_file_permission(struct file *file, int mask)
*/
static int smack_file_alloc_security(struct file *file)
{
- file->f_security = current->security;
+ file->f_security = current->cred->security;
return 0;
}

@@ -916,7 +918,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
*/
static int smack_file_set_fowner(struct file *file)
{
- file->f_security = current->security;
+ file->f_security = current->cred->security;
return 0;
}

@@ -941,7 +943,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
* struct fown_struct is never outside the context of a struct file
*/
file = container_of(fown, struct file, f_owner);
- rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
+ rc = smk_access(file->f_security, tsk->cred->security, MAY_WRITE);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
return 0;
return rc;
@@ -984,7 +986,7 @@ static int smack_file_receive(struct file *file)
*/
static int smack_task_alloc_security(struct task_struct *tsk)
{
- tsk->security = current->security;
+ tsk->cred->security = current->cred->security;

return 0;
}
@@ -999,7 +1001,7 @@ static int smack_task_alloc_security(struct task_struct *tsk)
*/
static void smack_task_free_security(struct task_struct *task)
{
- task->security = NULL;
+ task->cred->security = NULL;
}

/**
@@ -1011,7 +1013,7 @@ static void smack_task_free_security(struct task_struct *task)
*/
static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return smk_curacc(p->security, MAY_WRITE);
+ return smk_curacc(p->cred->security, MAY_WRITE);
}

/**
@@ -1022,7 +1024,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
*/
static int smack_task_getpgid(struct task_struct *p)
{
- return smk_curacc(p->security, MAY_READ);
+ return smk_curacc(p->cred->security, MAY_READ);
}

/**
@@ -1033,7 +1035,7 @@ static int smack_task_getpgid(struct task_struct *p)
*/
static int smack_task_getsid(struct task_struct *p)
{
- return smk_curacc(p->security, MAY_READ);
+ return smk_curacc(p->cred->security, MAY_READ);
}

/**
@@ -1045,7 +1047,7 @@ static int smack_task_getsid(struct task_struct *p)
*/
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
{
- *secid = smack_to_secid(p->security);
+ *secid = smack_to_secid(p->cred->security);
}

/**
@@ -1061,7 +1063,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)

rc = cap_task_setnice(p, nice);
if (rc == 0)
- rc = smk_curacc(p->security, MAY_WRITE);
+ rc = smk_curacc(p->cred->security, MAY_WRITE);
return rc;
}

@@ -1078,7 +1080,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)

rc = cap_task_setioprio(p, ioprio);
if (rc == 0)
- rc = smk_curacc(p->security, MAY_WRITE);
+ rc = smk_curacc(p->cred->security, MAY_WRITE);
return rc;
}

@@ -1090,7 +1092,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
*/
static int smack_task_getioprio(struct task_struct *p)
{
- return smk_curacc(p->security, MAY_READ);
+ return smk_curacc(p->cred->security, MAY_READ);
}

/**
@@ -1108,7 +1110,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,

rc = cap_task_setscheduler(p, policy, lp);
if (rc == 0)
- rc = smk_curacc(p->security, MAY_WRITE);
+ rc = smk_curacc(p->cred->security, MAY_WRITE);
return rc;
}

@@ -1120,7 +1122,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
*/
static int smack_task_getscheduler(struct task_struct *p)
{
- return smk_curacc(p->security, MAY_READ);
+ return smk_curacc(p->cred->security, MAY_READ);
}

/**
@@ -1131,7 +1133,7 @@ static int smack_task_getscheduler(struct task_struct *p)
*/
static int smack_task_movememory(struct task_struct *p)
{
- return smk_curacc(p->security, MAY_WRITE);
+ return smk_curacc(p->cred->security, MAY_WRITE);
}

/**
@@ -1154,13 +1156,13 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver.
*/
if (secid == 0)
- return smk_curacc(p->security, MAY_WRITE);
+ return smk_curacc(p->cred->security, MAY_WRITE);
/*
* If the secid isn't 0 we're dealing with some USB IO
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
- return smk_access(smack_from_secid(secid), p->security, MAY_WRITE);
+ return smk_access(smack_from_secid(secid), p->cred->security, MAY_WRITE);
}

/**
@@ -1173,7 +1175,7 @@ static int smack_task_wait(struct task_struct *p)
{
int rc;

- rc = smk_access(current->security, p->security, MAY_WRITE);
+ rc = smk_access(current->cred->security, p->cred->security, MAY_WRITE);
if (rc == 0)
return 0;

@@ -1204,7 +1206,7 @@ static int smack_task_wait(struct task_struct *p)
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
struct inode_smack *isp = inode->i_security;
- isp->smk_inode = p->security;
+ isp->smk_inode = p->cred->security;
}

/*
@@ -1223,7 +1225,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
*/
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
{
- char *csp = current->security;
+ char *csp = current->cred->security;
struct socket_smack *ssp;

ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
@@ -1448,7 +1450,7 @@ static int smack_flags_to_may(int flags)
*/
static int smack_msg_msg_alloc_security(struct msg_msg *msg)
{
- msg->security = current->security;
+ msg->security = current->cred->security;
return 0;
}

@@ -1484,7 +1486,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
{
struct kern_ipc_perm *isp = &shp->shm_perm;

- isp->security = current->security;
+ isp->security = current->cred->security;
return 0;
}

@@ -1593,7 +1595,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
{
struct kern_ipc_perm *isp = &sma->sem_perm;

- isp->security = current->security;
+ isp->security = current->cred->security;
return 0;
}

@@ -1697,7 +1699,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
{
struct kern_ipc_perm *kisp = &msq->q_perm;

- kisp->security = current->security;
+ kisp->security = current->cred->security;
return 0;
}

@@ -1852,7 +1854,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
struct super_block *sbp;
struct superblock_smack *sbsp;
struct inode_smack *isp;
- char *csp = current->security;
+ char *csp = current->cred->security;
char *fetched;
char *final;
struct dentry *dp;
@@ -2009,7 +2011,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
if (strcmp(name, "current") != 0)
return -EINVAL;

- cp = kstrdup(p->security, GFP_KERNEL);
+ cp = kstrdup(p->cred->security, GFP_KERNEL);
if (cp == NULL)
return -ENOMEM;

@@ -2055,7 +2057,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (newsmack == NULL)
return -EINVAL;

- p->security = newsmack;
+ p->cred->security = newsmack;
return size;
}

@@ -2285,8 +2287,8 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
return;

ssp = sk->sk_security;
- ssp->smk_in = current->security;
- ssp->smk_out = current->security;
+ ssp->smk_in = current->cred->security;
+ ssp->smk_out = current->cred->security;
ssp->smk_packet[0] = '\0';

rc = smack_netlabel(sk);
@@ -2359,7 +2361,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
static int smack_key_alloc(struct key *key, struct task_struct *tsk,
unsigned long flags)
{
- key->security = tsk->security;
+ key->security = tsk->cred->security;
return 0;
}

@@ -2400,10 +2402,11 @@ static int smack_key_permission(key_ref_t key_ref,
/*
* This should not occur
*/
- if (context->security == NULL)
+ if (context->cred->security == NULL)
return -EACCES;

- return smk_access(context->security, keyp->security, MAY_READWRITE);
+ return smk_access(context->cred->security, keyp->security,
+ MAY_READWRITE);
}
#endif /* CONFIG_KEYS */

@@ -2723,7 +2726,7 @@ static __init int smack_init(void)
/*
* Set the security state for the initial task.
*/
- current->security = &smack_known_floor.smk_known;
+ current->cred->security = &smack_known_floor.smk_known;

/*
* Initialize locks
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index e7c6424..7f84906 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -336,7 +336,7 @@ static void smk_cipso_doi(void)

audit_info.loginuid = audit_get_loginuid(current);
audit_info.sessionid = audit_get_sessionid(current);
- audit_info.secid = smack_to_secid(current->security);
+ audit_info.secid = smack_to_secid(current->cred->security);

rc = netlbl_cfg_map_del(NULL, &audit_info);
if (rc != 0)
@@ -369,7 +369,7 @@ static void smk_unlbl_ambient(char *oldambient)

audit_info.loginuid = audit_get_loginuid(current);
audit_info.sessionid = audit_get_sessionid(current);
- audit_info.secid = smack_to_secid(current->security);
+ audit_info.secid = smack_to_secid(current->cred->security);

if (oldambient != NULL) {
rc = netlbl_cfg_map_del(oldambient, &audit_info);
@@ -841,7 +841,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char in[SMK_LABELLEN];
- char *sp = current->security;
+ char *sp = current->cred->security;

if (!capable(CAP_MAC_ADMIN))
return -EPERM;

2008-08-06 15:53:15

by David Howells

[permalink] [raw]
Subject: [PATCH 11/24] CRED: Use RCU to access another task's creds and to release a task's own creds [ver #7]

Use RCU to access another task's creds and to release a task's own creds.
This means that it will be possible for the credentials of a task to be
replaced without another task (a) requiring a full lock to read them, and (b)
seeing deallocated memory.

Signed-off-by: David Howells <[email protected]>
Acked-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
---

drivers/connector/cn_proc.c | 16 +++++++----
fs/binfmt_elf.c | 8 ++++-
fs/binfmt_elf_fdpic.c | 8 ++++-
fs/fcntl.c | 15 +++++++---
fs/fuse/dir.c | 23 ++++++++++-----
fs/ioprio.c | 14 +++++++--
fs/proc/array.c | 32 ++++++++++++++-------
fs/proc/base.c | 32 ++++++++++++++++-----
include/linux/cred.h | 3 +-
kernel/auditsc.c | 33 ++++++++++++----------
kernel/cgroup.c | 16 +++++------
kernel/exit.c | 14 ++++++---
kernel/futex.c | 22 +++++++++-----
kernel/futex_compat.c | 7 +++--
kernel/ptrace.c | 22 +++++++++-----
kernel/sched.c | 31 ++++++++++++++------
kernel/signal.c | 49 ++++++++++++++++++++------------
kernel/sys.c | 11 +++++--
kernel/tsacct.c | 6 +++-
mm/mempolicy.c | 8 +++--
mm/migrate.c | 8 +++--
mm/oom_kill.c | 6 ++--
security/commoncap.c | 64 ++++++++++++++++++++++++++----------------
security/keys/permission.c | 10 ++++---
security/keys/process_keys.c | 24 +++++++++-------
security/selinux/selinuxfs.c | 13 ++++++---
security/smack/smack_lsm.c | 32 +++++++++++----------
27 files changed, 335 insertions(+), 192 deletions(-)


diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 354c1ff..c5afc98 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -106,6 +106,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
struct timespec ts;
+ const struct cred *cred;

if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -115,14 +116,19 @@ void proc_id_connector(struct task_struct *task, int which_id)
ev->what = which_id;
ev->event_data.id.process_pid = task->pid;
ev->event_data.id.process_tgid = task->tgid;
+ rcu_read_lock();
+ cred = __task_cred(task);
if (which_id == PROC_EVENT_UID) {
- ev->event_data.id.r.ruid = task->cred->uid;
- ev->event_data.id.e.euid = task->cred->euid;
+ ev->event_data.id.r.ruid = cred->uid;
+ ev->event_data.id.e.euid = cred->euid;
} else if (which_id == PROC_EVENT_GID) {
- ev->event_data.id.r.rgid = task->cred->gid;
- ev->event_data.id.e.egid = task->cred->egid;
- } else
+ ev->event_data.id.r.rgid = cred->gid;
+ ev->event_data.id.e.egid = cred->egid;
+ } else {
+ rcu_read_unlock();
return;
+ }
+ rcu_read_unlock();
get_seq(&msg->seq, &ev->cpu);
ktime_get_ts(&ts); /* get high res monotonic timestamp */
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 8692d4a..8761e97 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1358,6 +1358,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
struct mm_struct *mm)
{
+ const struct cred *cred;
unsigned int i, len;

/* first copy the parameters from user space */
@@ -1385,8 +1386,11 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_zomb = psinfo->pr_sname == 'Z';
psinfo->pr_nice = task_nice(p);
psinfo->pr_flag = p->flags;
- SET_UID(psinfo->pr_uid, p->cred->uid);
- SET_GID(psinfo->pr_gid, p->cred->gid);
+ rcu_read_lock();
+ cred = __task_cred(p);
+ SET_UID(psinfo->pr_uid, cred->uid);
+ SET_GID(psinfo->pr_gid, cred->gid);
+ rcu_read_unlock();
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));

return 0;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 6232e55..5625b23 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1380,6 +1380,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
struct mm_struct *mm)
{
+ const struct cred *cred;
unsigned int i, len;

/* first copy the parameters from user space */
@@ -1407,8 +1408,11 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_zomb = psinfo->pr_sname == 'Z';
psinfo->pr_nice = task_nice(p);
psinfo->pr_flag = p->flags;
- SET_UID(psinfo->pr_uid, p->cred->uid);
- SET_GID(psinfo->pr_gid, p->cred->gid);
+ rcu_read_lock();
+ cred = __task_cred(p);
+ SET_UID(psinfo->pr_uid, cred->uid);
+ SET_GID(psinfo->pr_gid, cred->gid);
+ rcu_read_unlock();
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));

return 0;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index c594cc0..87c39f1 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -401,10 +401,17 @@ static const long band_table[NSIGPOLL] = {
static inline int sigio_perm(struct task_struct *p,
struct fown_struct *fown, int sig)
{
- return (((fown->euid == 0) ||
- (fown->euid == p->cred->suid) || (fown->euid == p->cred->uid) ||
- (fown->uid == p->cred->suid) || (fown->uid == p->cred->uid)) &&
- !security_file_send_sigiotask(p, fown, sig));
+ const struct cred *cred;
+ int ret;
+
+ rcu_read_lock();
+ cred = __task_cred(p);
+ ret = ((fown->euid == 0 ||
+ fown->euid == cred->suid || fown->euid == cred->uid ||
+ fown->uid == cred->suid || fown->uid == cred->uid) &&
+ !security_file_send_sigiotask(p, fown, sig));
+ rcu_read_unlock();
+ return ret;
}

static void send_sigio_to_task(struct task_struct *p,
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index e97a989..95bc22b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -869,18 +869,25 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
*/
int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
{
+ const struct cred *cred;
+ int ret;
+
if (fc->flags & FUSE_ALLOW_OTHER)
return 1;

- if (task->cred->euid == fc->user_id &&
- task->cred->suid == fc->user_id &&
- task->cred->uid == fc->user_id &&
- task->cred->egid == fc->group_id &&
- task->cred->sgid == fc->group_id &&
- task->cred->gid == fc->group_id)
- return 1;
+ rcu_read_lock();
+ ret = 0;
+ cred = __task_cred(task);
+ if (cred->euid == fc->user_id &&
+ cred->suid == fc->user_id &&
+ cred->uid == fc->user_id &&
+ cred->egid == fc->group_id &&
+ cred->sgid == fc->group_id &&
+ cred->gid == fc->group_id)
+ ret = 1;
+ rcu_read_unlock();

- return 0;
+ return ret;
}

static int fuse_access(struct inode *inode, int mask)
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 6d96eac..f716f8d 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -31,10 +31,16 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
{
int err;
struct io_context *ioc;
+ const struct cred *cred = current_cred(), *tcred;

- if (task->cred->uid != current_euid() &&
- task->cred->uid != current_uid() && !capable(CAP_SYS_NICE))
+ rcu_read_lock();
+ tcred = __task_cred(task);
+ if (tcred->uid != cred->euid &&
+ tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) {
+ rcu_read_unlock();
return -EPERM;
+ }
+ rcu_read_unlock();

err = security_task_setioprio(task, ioprio);
if (err)
@@ -131,7 +137,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
break;

do_each_thread(g, p) {
- if (p->cred->uid != who)
+ if (__task_cred(p)->uid != who)
continue;
ret = set_task_ioprio(p, ioprio);
if (ret)
@@ -224,7 +230,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
break;

do_each_thread(g, p) {
- if (p->cred->uid != user->uid)
+ if (__task_cred(p)->uid != user->uid)
continue;
tmpio = get_task_ioprio(p);
if (tmpio < 0)
diff --git a/fs/proc/array.c b/fs/proc/array.c
index af0962b..13944a3 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -164,6 +164,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
struct group_info *group_info;
int g;
struct fdtable *fdt = NULL;
+ const struct cred *cred;
pid_t ppid, tpid;

rcu_read_lock();
@@ -175,6 +176,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
if (tracer)
tpid = task_pid_nr_ns(tracer, ns);
}
+ cred = get_cred((struct cred *) __task_cred(p));
seq_printf(m,
"State:\t%s\n"
"Tgid:\t%d\n"
@@ -187,8 +189,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
task_tgid_nr_ns(p, ns),
pid_nr_ns(pid, ns),
ppid, tpid,
- p->cred->uid, p->cred->euid, p->cred->suid, p->cred->fsuid,
- p->cred->gid, p->cred->egid, p->cred->sgid, p->cred->fsgid);
+ cred->uid, cred->euid, cred->suid, cred->fsuid,
+ cred->gid, cred->egid, cred->sgid, cred->fsgid);

task_lock(p);
if (p->files)
@@ -199,13 +201,12 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
fdt ? fdt->max_fds : 0);
rcu_read_unlock();

- group_info = p->cred->group_info;
- get_group_info(group_info);
+ group_info = cred->group_info;
task_unlock(p);

for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
seq_printf(m, "%d ", GROUP_AT(group_info, g));
- put_group_info(group_info);
+ put_cred(cred);

seq_printf(m, "\n");
}
@@ -268,7 +269,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
blocked = p->blocked;
collect_sigign_sigcatch(p, &ignored, &caught);
num_threads = atomic_read(&p->signal->count);
- qsize = atomic_read(&p->cred->user->sigpending);
+ qsize = atomic_read(&__task_cred(p)->user->sigpending);
qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
unlock_task_sighand(p, &flags);
}
@@ -300,12 +301,21 @@ static void render_cap_t(struct seq_file *m, const char *header,

static inline void task_cap(struct seq_file *m, struct task_struct *p)
{
- struct cred *cred = p->cred;
+ const struct cred *cred;
+ kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset;

- render_cap_t(m, "CapInh:\t", &cred->cap_inheritable);
- render_cap_t(m, "CapPrm:\t", &cred->cap_permitted);
- render_cap_t(m, "CapEff:\t", &cred->cap_effective);
- render_cap_t(m, "CapBnd:\t", &cred->cap_bset);
+ rcu_read_lock();
+ cred = __task_cred(p);
+ cap_inheritable = cred->cap_inheritable;
+ cap_permitted = cred->cap_permitted;
+ cap_effective = cred->cap_effective;
+ cap_bset = cred->cap_bset;
+ rcu_read_unlock();
+
+ render_cap_t(m, "CapInh:\t", &cap_inheritable);
+ render_cap_t(m, "CapPrm:\t", &cap_permitted);
+ render_cap_t(m, "CapEff:\t", &cap_effective);
+ render_cap_t(m, "CapBnd:\t", &cap_bset);
}

static inline void task_context_switch_counts(struct seq_file *m,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 96fb315..74db376 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1414,6 +1414,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
{
struct inode * inode;
struct proc_inode *ei;
+ const struct cred *cred;

/* We need a new inode */

@@ -1436,8 +1437,11 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
inode->i_uid = 0;
inode->i_gid = 0;
if (task_dumpable(task)) {
- inode->i_uid = task->cred->euid;
- inode->i_gid = task->cred->egid;
+ rcu_read_lock();
+ cred = __task_cred(task);
+ inode->i_uid = cred->euid;
+ inode->i_gid = cred->egid;
+ rcu_read_unlock();
}
security_task_to_inode(task, inode);

@@ -1453,6 +1457,8 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
{
struct inode *inode = dentry->d_inode;
struct task_struct *task;
+ const struct cred *cred;
+
generic_fillattr(inode, stat);

rcu_read_lock();
@@ -1462,8 +1468,9 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
if (task) {
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
task_dumpable(task)) {
- stat->uid = task->cred->euid;
- stat->gid = task->cred->egid;
+ cred = __task_cred(task);
+ stat->uid = cred->euid;
+ stat->gid = cred->egid;
}
}
rcu_read_unlock();
@@ -1491,11 +1498,16 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
+ const struct cred *cred;
+
if (task) {
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
task_dumpable(task)) {
- inode->i_uid = task->cred->euid;
- inode->i_gid = task->cred->egid;
+ rcu_read_lock();
+ cred = __task_cred(task);
+ inode->i_uid = cred->euid;
+ inode->i_gid = cred->egid;
+ rcu_read_unlock();
} else {
inode->i_uid = 0;
inode->i_gid = 0;
@@ -1657,6 +1669,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
struct task_struct *task = get_proc_task(inode);
int fd = proc_fd(inode);
struct files_struct *files;
+ const struct cred *cred;

if (task) {
files = get_files_struct(task);
@@ -1666,8 +1679,11 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
rcu_read_unlock();
put_files_struct(files);
if (task_dumpable(task)) {
- inode->i_uid = task->cred->euid;
- inode->i_gid = task->cred->egid;
+ rcu_read_lock();
+ cred = __task_cred(task);
+ inode->i_uid = cred->euid;
+ inode->i_gid = cred->egid;
+ rcu_read_unlock();
} else {
inode->i_uid = 0;
inode->i_gid = 0;
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 45e954d..5c4e098 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -147,8 +147,9 @@ static inline struct cred *get_cred(struct cred *cred)
* Release a reference to a set of credentials, deleting them when the last ref
* is released.
*/
-static inline void put_cred(struct cred *cred)
+static inline void put_cred(const struct cred *_cred)
{
+ struct cred *cred = (struct cred *) _cred;
if (atomic_dec_and_test(&(cred)->usage))
__put_cred(cred);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 9e817df..58c3854 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -413,7 +413,7 @@ static int audit_filter_rules(struct task_struct *tsk,
struct audit_names *name,
enum audit_state *state)
{
- struct cred *cred = tsk->cred;
+ const struct cred *cred = get_task_cred(tsk);
int i, j, need_sid = 1;
u32 sid;

@@ -608,8 +608,10 @@ static int audit_filter_rules(struct task_struct *tsk,
break;
}

- if (!result)
+ if (!result) {
+ put_cred(cred);
return 0;
+ }
}
if (rule->filterkey && ctx)
ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
@@ -617,6 +619,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
}
+ put_cred(cred);
return 1;
}

@@ -1166,7 +1169,7 @@ static void audit_log_execve_info(struct audit_context *context,

static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
- struct cred *cred = tsk->cred;
+ const struct cred *cred;
int i, call_panic = 0;
struct audit_buffer *ab;
struct audit_aux_data *aux;
@@ -1176,13 +1179,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->pid = tsk->pid;
if (!context->ppid)
context->ppid = sys_getppid();
- context->uid = cred->uid;
- context->gid = cred->gid;
- context->euid = cred->euid;
- context->suid = cred->suid;
+ cred = current_cred();
+ context->uid = cred->uid;
+ context->gid = cred->gid;
+ context->euid = cred->euid;
+ context->suid = cred->suid;
context->fsuid = cred->fsuid;
- context->egid = cred->egid;
- context->sgid = cred->sgid;
+ context->egid = cred->egid;
+ context->sgid = cred->sgid;
context->fsgid = cred->fsgid;
context->personality = tsk->personality;

@@ -1973,7 +1977,7 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
audit_log_format(ab, "login pid=%d uid=%u "
"old auid=%u new auid=%u"
" old ses=%u new ses=%u",
- task->pid, task->cred->uid,
+ task->pid, task_uid(task),
task->loginuid, loginuid,
task->sessionid, sessionid);
audit_log_end(ab);
@@ -2356,7 +2360,7 @@ void __audit_ptrace(struct task_struct *t)

context->target_pid = t->pid;
context->target_auid = audit_get_loginuid(t);
- context->target_uid = t->cred->uid;
+ context->target_uid = task_uid(t);
context->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &context->target_sid);
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
@@ -2375,6 +2379,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
struct audit_aux_data_pids *axp;
struct task_struct *tsk = current;
struct audit_context *ctx = tsk->audit_context;
+ uid_t uid = current_uid(), t_uid = task_uid(t);

if (audit_pid && t->tgid == audit_pid) {
if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
@@ -2382,7 +2387,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
if (tsk->loginuid != -1)
audit_sig_uid = tsk->loginuid;
else
- audit_sig_uid = tsk->cred->uid;
+ audit_sig_uid = uid;
security_task_getsecid(tsk, &audit_sig_sid);
}
if (!audit_signals || audit_dummy_context())
@@ -2394,7 +2399,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
if (!ctx->target_pid) {
ctx->target_pid = t->tgid;
ctx->target_auid = audit_get_loginuid(t);
- ctx->target_uid = t->cred->uid;
+ ctx->target_uid = t_uid;
ctx->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &ctx->target_sid);
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
@@ -2415,7 +2420,7 @@ int __audit_signal_info(int sig, struct task_struct *t)

axp->target_pid[axp->pid_count] = t->tgid;
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
- axp->target_uid[axp->pid_count] = t->cred->uid;
+ axp->target_uid[axp->pid_count] = t_uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 5658dc3..3569fef 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -1276,7 +1276,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
{
struct task_struct *tsk;
- uid_t euid;
+ const struct cred *cred = current_cred(), *tcred;
int ret;

if (pid) {
@@ -1286,16 +1286,16 @@ static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
rcu_read_unlock();
return -ESRCH;
}
- get_task_struct(tsk);
- rcu_read_unlock();

- euid = current_euid();
- if (euid &&
- euid != tsk->cred->uid &&
- euid != tsk->cred->suid) {
- put_task_struct(tsk);
+ tcred = __task_cred(tsk);
+ if (cred->euid &&
+ cred->euid != tcred->uid &&
+ cred->euid != tcred->suid) {
+ rcu_read_unlock();
return -EACCES;
}
+ get_task_struct(tsk);
+ rcu_read_unlock();
} else {
tsk = current;
get_task_struct(tsk);
diff --git a/kernel/exit.c b/kernel/exit.c
index 5ba3db3..9bce79b 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -159,7 +159,10 @@ void release_task(struct task_struct * p)
int zap_leader;
repeat:
tracehook_prepare_release_task(p);
- atomic_dec(&p->cred->user->processes);
+ /* don't need to get the RCU readlock here - the process is dead and
+ * can't be modifying its own credentials */
+ atomic_dec(&__task_cred(p)->user->processes);
+
proc_flush_task(p);
write_lock_irq(&tasklist_lock);
tracehook_finish_release_task(p);
@@ -1267,12 +1270,12 @@ static int wait_task_zombie(struct task_struct *p, int options,
unsigned long state;
int retval, status, traced;
pid_t pid = task_pid_vnr(p);
+ uid_t uid = __task_cred(p)->uid;

if (!likely(options & WEXITED))
return 0;

if (unlikely(options & WNOWAIT)) {
- uid_t uid = p->cred->uid;
int exit_code = p->exit_code;
int why, status;

@@ -1389,7 +1392,7 @@ static int wait_task_zombie(struct task_struct *p, int options,
if (!retval && infop)
retval = put_user(pid, &infop->si_pid);
if (!retval && infop)
- retval = put_user(p->cred->uid, &infop->si_uid);
+ retval = put_user(uid, &infop->si_uid);
if (!retval)
retval = pid;

@@ -1454,7 +1457,8 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
if (!unlikely(options & WNOWAIT))
p->exit_code = 0;

- uid = p->cred->uid;
+ /* don't need the RCU readlock here as we're holding a spinlock */
+ uid = __task_cred(p)->uid;
unlock_sig:
spin_unlock_irq(&p->sighand->siglock);
if (!exit_code)
@@ -1528,10 +1532,10 @@ static int wait_task_continued(struct task_struct *p, int options,
}
if (!unlikely(options & WNOWAIT))
p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
+ uid = __task_cred(p)->uid;
spin_unlock_irq(&p->sighand->siglock);

pid = task_pid_vnr(p);
- uid = p->cred->uid;
get_task_struct(p);
read_unlock(&tasklist_lock);

diff --git a/kernel/futex.c b/kernel/futex.c
index 3f594ac..063795e 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -439,15 +439,20 @@ static void free_pi_state(struct futex_pi_state *pi_state)
static struct task_struct * futex_find_get_task(pid_t pid)
{
struct task_struct *p;
- uid_t euid = current_euid();
+ const struct cred *cred = current_cred(), *pcred;

rcu_read_lock();
p = find_task_by_vpid(pid);
- if (!p || (euid != p->cred->euid &&
- euid != p->cred->uid))
+ if (!p) {
p = ERR_PTR(-ESRCH);
- else
- get_task_struct(p);
+ } else {
+ pcred = __task_cred(p);
+ if (cred->euid != pcred->euid &&
+ cred->euid != pcred->uid)
+ p = ERR_PTR(-ESRCH);
+ else
+ get_task_struct(p);
+ }

rcu_read_unlock();

@@ -1828,7 +1833,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
{
struct robust_list_head __user *head;
unsigned long ret;
- uid_t euid = current_euid();
+ const struct cred *cred = current_cred(), *pcred;

if (!futex_cmpxchg_enabled)
return -ENOSYS;
@@ -1844,8 +1849,9 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
if (!p)
goto err_unlock;
ret = -EPERM;
- if (euid != p->cred->euid &&
- euid != p->cred->uid &&
+ pcred = __task_cred(p);
+ if (cred->euid != pcred->euid &&
+ cred->euid != pcred->uid &&
!capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->robust_list;
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 2c3fd5e..d607a5b 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -135,7 +135,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
{
struct compat_robust_list_head __user *head;
unsigned long ret;
- uid_t euid = current_euid();
+ const struct cred *cred = current_cred(), *pcred;

if (!futex_cmpxchg_enabled)
return -ENOSYS;
@@ -151,8 +151,9 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
if (!p)
goto err_unlock;
ret = -EPERM;
- if (euid != p->cred->euid &&
- euid != p->cred->uid &&
+ pcred = __task_cred(p);
+ if (cred->euid != pcred->euid &&
+ cred->euid != pcred->uid &&
!capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->compat_robust_list;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index efa4556..ed65d9f 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -115,7 +115,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)

int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
- struct cred *cred = current->cred, *tcred = task->cred;
+ const struct cred *cred = current_cred(), *tcred;

/* May we inspect the given task?
* This check is used both for attaching with ptrace
@@ -125,19 +125,23 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
* because setting up the necessary parent/child relationship
* or halting the specified task is impossible.
*/
- uid_t uid = cred->uid;
- gid_t gid = cred->gid;
int dumpable = 0;
/* Don't let security modules deny introspection */
if (task == current)
return 0;
- if ((uid != tcred->euid ||
- uid != tcred->suid ||
- uid != tcred->uid ||
- gid != tcred->egid ||
- gid != tcred->sgid ||
- gid != tcred->gid) && !capable(CAP_SYS_PTRACE))
+ rcu_read_lock();
+ tcred = __task_cred(task);
+ if ((cred->uid != tcred->euid ||
+ cred->uid != tcred->suid ||
+ cred->uid != tcred->uid ||
+ cred->gid != tcred->egid ||
+ cred->gid != tcred->sgid ||
+ cred->gid != tcred->gid) &&
+ !capable(CAP_SYS_PTRACE)) {
+ rcu_read_unlock();
return -EPERM;
+ }
+ rcu_read_unlock();
smp_rmb();
if (task->mm)
dumpable = get_dumpable(task->mm);
diff --git a/kernel/sched.c b/kernel/sched.c
index 152ea80..dd85fe0 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -339,7 +339,9 @@ static inline struct task_group *task_group(struct task_struct *p)
struct task_group *tg;

#ifdef CONFIG_USER_SCHED
- tg = p->cred->user->tg;
+ rcu_read_lock();
+ tg = __task_cred(p)->user->tg;
+ rcu_read_unlock();
#elif defined(CONFIG_CGROUP_SCHED)
tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id),
struct task_group, css);
@@ -4940,6 +4942,22 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
set_load_weight(p);
}

+/*
+ * check the target process has a UID that matches the current process's
+ */
+static bool check_same_owner(struct task_struct *p)
+{
+ const struct cred *cred = current_cred(), *pcred;
+ bool match;
+
+ rcu_read_lock();
+ pcred = __task_cred(p);
+ match = (cred->euid == pcred->euid ||
+ cred->euid == pcred->uid);
+ rcu_read_unlock();
+ return match;
+}
+
static int __sched_setscheduler(struct task_struct *p, int policy,
struct sched_param *param, bool user)
{
@@ -4947,7 +4965,6 @@ static int __sched_setscheduler(struct task_struct *p, int policy,
unsigned long flags;
const struct sched_class *prev_class = p->sched_class;
struct rq *rq;
- uid_t euid;

/* may grab non-irq protected spin_locks */
BUG_ON(in_interrupt());
@@ -5000,9 +5017,7 @@ recheck:
return -EPERM;

/* can't change other user's priorities */
- euid = current_euid();
- if (euid != p->cred->euid &&
- euid != p->cred->uid)
+ if (!check_same_owner(p))
return -EPERM;
}

@@ -5210,7 +5225,6 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask)
cpumask_t cpus_allowed;
cpumask_t new_mask = *in_mask;
struct task_struct *p;
- uid_t euid;
int retval;

get_online_cpus();
@@ -5231,11 +5245,8 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask)
get_task_struct(p);
read_unlock(&tasklist_lock);

- euid = current_euid();
retval = -EPERM;
- if (euid != p->cred->euid &&
- euid != p->cred->uid &&
- !capable(CAP_SYS_NICE))
+ if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
goto out_unlock;

retval = security_task_setscheduler(p, 0, NULL);
diff --git a/kernel/signal.c b/kernel/signal.c
index dfdbaaf..2632d94 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -176,6 +176,11 @@ int next_signal(struct sigpending *pending, sigset_t *mask)
return sig;
}

+/*
+ * allocate a new signal queue record
+ * - this may be called without locks if and only if t == current, otherwise an
+ * appopriate lock must be held to protect t's user_struct
+ */
static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
int override_rlimit)
{
@@ -183,11 +188,12 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
struct user_struct *user;

/*
- * In order to avoid problems with "switch_user()", we want to make
- * sure that the compiler doesn't re-load "t->user"
+ * We won't get problems with the target's UID changing under us
+ * because changing it requires RCU be used, and if t != current, the
+ * caller must be holding the RCU readlock (by way of a spinlock) and
+ * we use RCU protection here
*/
- user = t->cred->user;
- barrier();
+ user = __task_cred(t)->user;
atomic_inc(&user->sigpending);
if (override_rlimit ||
atomic_read(&user->sigpending) <=
@@ -561,12 +567,13 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s)

/*
* Bad permissions for sending the signal
+ * - the caller must hold at least the RCU read lock
*/
static int check_kill_permission(int sig, struct siginfo *info,
struct task_struct *t)
{
+ const struct cred *cred = current_cred(), *tcred;
struct pid *sid;
- uid_t uid, euid;
int error;

if (!valid_signal(sig))
@@ -579,10 +586,11 @@ static int check_kill_permission(int sig, struct siginfo *info,
if (error)
return error;

- uid = current_uid();
- euid = current_euid();
- if ((euid ^ t->cred->suid) && (euid ^ t->cred->uid) &&
- (uid ^ t->cred->suid) && (uid ^ t->cred->uid) &&
+ tcred = __task_cred(t);
+ if ((cred->euid ^ tcred->suid) &&
+ (cred->euid ^ tcred->uid) &&
+ (cred->uid ^ tcred->suid) &&
+ (cred->uid ^ tcred->uid) &&
!capable(CAP_KILL)) {
switch (sig) {
case SIGCONT:
@@ -1008,6 +1016,10 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long
return sighand;
}

+/*
+ * send signal info to all the members of a group
+ * - the caller must hold the RCU read lock at least
+ */
int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
{
unsigned long flags;
@@ -1029,8 +1041,8 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
/*
* __kill_pgrp_info() sends a signal to a process group: this is what the tty
* control characters do (^C, ^Z etc)
+ * - the caller must hold at least a readlock on tasklist_lock
*/
-
int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
{
struct task_struct *p = NULL;
@@ -1086,6 +1098,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
{
int ret = -EINVAL;
struct task_struct *p;
+ const struct cred *pcred;

if (!valid_signal(sig))
return ret;
@@ -1096,9 +1109,11 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
ret = -ESRCH;
goto out_unlock;
}
- if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
- && (euid != p->cred->suid) && (euid != p->cred->uid)
- && (uid != p->cred->suid) && (uid != p->cred->uid)) {
+ pcred = __task_cred(p);
+ if ((info == SEND_SIG_NOINFO ||
+ (!is_si_special(info) && SI_FROMUSER(info))) &&
+ euid != pcred->suid && euid != pcred->uid &&
+ uid != pcred->suid && uid != pcred->uid) {
ret = -EPERM;
goto out_unlock;
}
@@ -1365,10 +1380,9 @@ int do_notify_parent(struct task_struct *tsk, int sig)
*/
rcu_read_lock();
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
+ info.si_uid = __task_cred(tsk)->uid;
rcu_read_unlock();

- info.si_uid = tsk->cred->uid;
-
info.si_utime = cputime_to_clock_t(cputime_add(tsk->utime,
tsk->signal->utime));
info.si_stime = cputime_to_clock_t(cputime_add(tsk->stime,
@@ -1437,10 +1451,9 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
*/
rcu_read_lock();
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
+ info.si_uid = __task_cred(tsk)->uid;
rcu_read_unlock();

- info.si_uid = tsk->cred->uid;
-
info.si_utime = cputime_to_clock_t(tsk->utime);
info.si_stime = cputime_to_clock_t(tsk->stime);

@@ -1707,7 +1720,7 @@ static int ptrace_signal(int signr, siginfo_t *info,
info->si_errno = 0;
info->si_code = SI_USER;
info->si_pid = task_pid_vnr(current->parent);
- info->si_uid = current->parent->cred->uid;
+ info->si_uid = task_uid(current->parent);
}

/* If the (new) signal is now blocked, requeue it. */
diff --git a/kernel/sys.c b/kernel/sys.c
index e2a16eb..4c4ac7a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -112,14 +112,17 @@ EXPORT_SYMBOL(cad_pid);

void (*pm_power_off_prepare)(void);

+/*
+ * set the priority of a task
+ * - the caller must hold the RCU read lock
+ */
static int set_one_prio(struct task_struct *p, int niceval, int error)
{
- uid_t euid = current_euid();
+ const struct cred *cred = current_cred(), *pcred = __task_cred(p);
int no_nice;

- if (p->cred->uid != euid &&
- p->cred->euid != euid &&
- !capable(CAP_SYS_NICE)) {
+ if (pcred->uid != cred->euid &&
+ pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
error = -EPERM;
goto out;
}
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
index 6d1ed07..2dc06ab 100644
--- a/kernel/tsacct.c
+++ b/kernel/tsacct.c
@@ -27,6 +27,7 @@
*/
void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
{
+ const struct cred *tcred;
struct timespec uptime, ts;
u64 ac_etime;

@@ -53,10 +54,11 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
stats->ac_flag |= AXSIG;
stats->ac_nice = task_nice(tsk);
stats->ac_sched = tsk->policy;
- stats->ac_uid = tsk->cred->uid;
- stats->ac_gid = tsk->cred->gid;
stats->ac_pid = tsk->pid;
rcu_read_lock();
+ tcred = __task_cred(tsk);
+ stats->ac_uid = tcred->uid;
+ stats->ac_gid = tcred->gid;
stats->ac_ppid = pid_alive(tsk) ?
rcu_dereference(tsk->real_parent)->tgid : 0;
rcu_read_unlock();
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 4374a83..488d4f6 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1106,7 +1106,7 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
const unsigned long __user *old_nodes,
const unsigned long __user *new_nodes)
{
- struct cred *cred, *tcred;
+ const struct cred *cred = current_cred(), *tcred;
struct mm_struct *mm;
struct task_struct *task;
nodemask_t old;
@@ -1141,14 +1141,16 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
* capabilities, superuser privileges or the same
* userid as the target process.
*/
- cred = current->cred;
- tcred = task->cred;
+ rcu_read_lock();
+ tcred = __task_cred(task);
if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
cred->uid != tcred->suid && cred->uid != tcred->uid &&
!capable(CAP_SYS_NICE)) {
+ rcu_read_unlock();
err = -EPERM;
goto out;
}
+ rcu_read_unlock();

task_nodes = cpuset_mems_allowed(task);
/* Is the user allowed to access the target nodes? */
diff --git a/mm/migrate.c b/mm/migrate.c
index 78af7fd..32b352d 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -984,7 +984,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
const int __user *nodes,
int __user *status, int flags)
{
- struct cred *cred, *tcred;
+ const struct cred *cred = current_cred(), *tcred;
int err = 0;
int i;
struct task_struct *task;
@@ -1018,14 +1018,16 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
* capabilities, superuser privileges or the same
* userid as the target process.
*/
- cred = current->cred;
- tcred = task->cred;
+ rcu_read_lock();
+ tcred = __task_cred(task);
if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
cred->uid != tcred->suid && cred->uid != tcred->uid &&
!capable(CAP_SYS_NICE)) {
+ rcu_read_unlock();
err = -EPERM;
goto out2;
}
+ rcu_read_unlock();

err = security_task_movememory(task);
if (err)
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index c156ffb..235b7f7 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -298,9 +298,9 @@ static void dump_tasks(const struct mem_cgroup *mem)

task_lock(p);
printk(KERN_INFO "[%5d] %5d %5d %8lu %8lu %3d %3d %s\n",
- p->pid, p->cred->uid, p->tgid, p->mm->total_vm,
- get_mm_rss(p->mm), (int)task_cpu(p), p->oomkilladj,
- p->comm);
+ p->pid, __task_cred(p)->uid, p->tgid,
+ p->mm->total_vm, get_mm_rss(p->mm), (int)task_cpu(p),
+ p->oomkilladj, p->comm);
task_unlock(p);
} while_each_thread(g, p);
}
diff --git a/security/commoncap.c b/security/commoncap.c
index 2de5cbe..d6456b0 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -50,10 +50,13 @@ EXPORT_SYMBOL(cap_netlink_recv);
*/
int cap_capable (struct task_struct *tsk, int cap)
{
+ __u32 cap_raised;
+
/* Derived from include/linux/sched.h:capable. */
- if (cap_raised(tsk->cred->cap_effective, cap))
- return 0;
- return -EPERM;
+ rcu_read_lock();
+ cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
+ rcu_read_unlock();
+ return cap_raised ? 0 : -EPERM;
}

int cap_settime(struct timespec *ts, struct timezone *tz)
@@ -65,34 +68,42 @@ int cap_settime(struct timespec *ts, struct timezone *tz)

int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
{
- /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
- if (cap_issubset(child->cred->cap_permitted,
- current->cred->cap_permitted))
- return 0;
- if (capable(CAP_SYS_PTRACE))
- return 0;
- return -EPERM;
+ int ret = 0;
+
+ rcu_read_lock();
+ if (!cap_issubset(child->cred->cap_permitted,
+ current->cred->cap_permitted) &&
+ !capable(CAP_SYS_PTRACE))
+ ret = -EPERM;
+ rcu_read_unlock();
+ return ret;
}

int cap_ptrace_traceme(struct task_struct *parent)
{
- if (cap_issubset(current->cred->cap_permitted,
- parent->cred->cap_permitted))
- return 0;
- if (has_capability(parent, CAP_SYS_PTRACE))
- return 0;
- return -EPERM;
+ int ret = 0;
+
+ rcu_read_lock();
+ if (!cap_issubset(current->cred->cap_permitted,
+ parent->cred->cap_permitted) &&
+ !has_capability(parent, CAP_SYS_PTRACE))
+ ret = -EPERM;
+ rcu_read_unlock();
+ return ret;
}

int cap_capget (struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- struct cred *cred = target->cred;
+ const struct cred *cred;

/* Derived from kernel/capability.c:sys_capget. */
+ rcu_read_lock();
+ cred = __task_cred(target);
*effective = cred->cap_effective;
*inheritable = cred->cap_inheritable;
*permitted = cred->cap_permitted;
+ rcu_read_unlock();
return 0;
}

@@ -398,7 +409,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)

int cap_bprm_secureexec (struct linux_binprm *bprm)
{
- const struct cred *cred = current->cred;
+ const struct cred *cred = current_cred();

if (cred->uid != 0) {
if (bprm->cap_effective)
@@ -476,11 +487,11 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
(cred->uid != 0 && cred->euid != 0 && cred->suid != 0) &&
!issecure(SECURE_KEEP_CAPS)) {
- cap_clear (cred->cap_permitted);
- cap_clear (cred->cap_effective);
+ cap_clear(cred->cap_permitted);
+ cap_clear(cred->cap_effective);
}
if (old_euid == 0 && cred->euid != 0) {
- cap_clear (cred->cap_effective);
+ cap_clear(cred->cap_effective);
}
if (old_euid != 0 && cred->euid == 0) {
cred->cap_effective = cred->cap_permitted;
@@ -547,9 +558,14 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
*/
static inline int cap_safe_nice(struct task_struct *p)
{
- if (!cap_issubset(p->cred->cap_permitted,
- current->cred->cap_permitted) &&
- !capable(CAP_SYS_NICE))
+ int is_subset;
+
+ rcu_read_lock();
+ is_subset = cap_issubset(__task_cred(p)->cap_permitted,
+ current_cred()->cap_permitted);
+ rcu_read_unlock();
+
+ if (!is_subset && !capable(CAP_SYS_NICE))
return -EPERM;
return 0;
}
diff --git a/security/keys/permission.c b/security/keys/permission.c
index baf3d5f..13c3616 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -22,13 +22,16 @@ int key_task_permission(const key_ref_t key_ref,
struct task_struct *context,
key_perm_t perm)
{
- struct cred *cred = context->cred;
+ const struct cred *cred;
struct key *key;
key_perm_t kperm;
int ret;

key = key_ref_to_ptr(key_ref);

+ rcu_read_lock();
+ cred = __task_cred(context);
+
/* use the second 8-bits of permissions for keys the caller owns */
if (key->uid == cred->fsuid) {
kperm = key->perm >> 16;
@@ -43,10 +46,7 @@ int key_task_permission(const key_ref_t key_ref,
goto use_these_perms;
}

- spin_lock(&cred->lock);
ret = groups_search(cred->group_info, key->gid);
- spin_unlock(&cred->lock);
-
if (ret) {
kperm = key->perm >> 8;
goto use_these_perms;
@@ -57,6 +57,8 @@ int key_task_permission(const key_ref_t key_ref,
kperm = key->perm;

use_these_perms:
+ rcu_read_lock();
+
/* use the top 8-bits of permissions for keys the caller possesses
* - possessor permissions are additive with other permissions
*/
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index c9ccbdb..d3fa0ae 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -412,10 +412,13 @@ key_ref_t search_process_keyrings(struct key_type *type,
struct task_struct *context)
{
struct request_key_auth *rka;
+ struct cred *cred;
key_ref_t key_ref, ret, err;

might_sleep();

+ cred = get_task_cred(context);
+
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -428,9 +431,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
err = ERR_PTR(-EAGAIN);

/* search the thread keyring first */
- if (context->cred->thread_keyring) {
+ if (cred->thread_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->cred->thread_keyring, 1),
+ make_key_ref(cred->thread_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -495,9 +498,9 @@ key_ref_t search_process_keyrings(struct key_type *type,
}
}
/* or search the user-session keyring */
- else if (context->cred->user->session_keyring) {
+ else if (cred->user->session_keyring) {
key_ref = keyring_search_aux(
- make_key_ref(context->cred->user->session_keyring, 1),
+ make_key_ref(cred->user->session_keyring, 1),
context, type, description, match);
if (!IS_ERR(key_ref))
goto found;
@@ -519,20 +522,20 @@ key_ref_t search_process_keyrings(struct key_type *type,
* search the keyrings of the process mentioned there
* - we don't permit access to request_key auth keys via this method
*/
- if (context->cred->request_key_auth &&
+ if (cred->request_key_auth &&
context == current &&
type != &key_type_request_key_auth
) {
/* defend against the auth key being revoked */
- down_read(&context->cred->request_key_auth->sem);
+ down_read(&cred->request_key_auth->sem);

- if (key_validate(context->cred->request_key_auth) == 0) {
- rka = context->cred->request_key_auth->payload.data;
+ if (key_validate(cred->request_key_auth) == 0) {
+ rka = cred->request_key_auth->payload.data;

key_ref = search_process_keyrings(type, description,
match, rka->context);

- up_read(&context->cred->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);

if (!IS_ERR(key_ref))
goto found;
@@ -549,7 +552,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
break;
}
} else {
- up_read(&context->cred->request_key_auth->sem);
+ up_read(&cred->request_key_auth->sem);
}
}

@@ -557,6 +560,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
key_ref = ret ? ret : err;

found:
+ put_cred(cred);
return key_ref;

} /* end search_process_keyrings() */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 10715d1..c863036 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -95,13 +95,18 @@ extern void selnl_notify_setenforce(int val);
static int task_has_security(struct task_struct *tsk,
u32 perms)
{
- struct task_security_struct *tsec;
-
- tsec = tsk->cred->security;
+ const struct task_security_struct *tsec;
+ u32 sid = 0;
+
+ rcu_read_lock();
+ tsec = __task_cred(tsk)->security;
+ if (tsec)
+ sid = tsec->sid;
+ rcu_read_unlock();
if (!tsec)
return -EACCES;

- return avc_has_perm(tsec->sid, SECINITSID_SECURITY,
+ return avc_has_perm(sid, SECINITSID_SECURITY,
SECCLASS_SECURITY, perms, NULL);
}

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9d2e227..3e3dcbf 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -30,6 +30,8 @@

#include "smack.h"

+#define task_security(task) (task_cred_xxx((task), security))
+
/*
* I hope these are the hokeyist lines of code in the module. Casey.
*/
@@ -1012,7 +1014,7 @@ static void smack_cred_free(struct cred *cred)
*/
static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return smk_curacc(p->cred->security, MAY_WRITE);
+ return smk_curacc(task_security(p), MAY_WRITE);
}

/**
@@ -1023,7 +1025,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
*/
static int smack_task_getpgid(struct task_struct *p)
{
- return smk_curacc(p->cred->security, MAY_READ);
+ return smk_curacc(task_security(p), MAY_READ);
}

/**
@@ -1034,7 +1036,7 @@ static int smack_task_getpgid(struct task_struct *p)
*/
static int smack_task_getsid(struct task_struct *p)
{
- return smk_curacc(p->cred->security, MAY_READ);
+ return smk_curacc(task_security(p), MAY_READ);
}

/**
@@ -1046,7 +1048,7 @@ static int smack_task_getsid(struct task_struct *p)
*/
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
{
- *secid = smack_to_secid(p->cred->security);
+ *secid = smack_to_secid(task_security(p));
}

/**
@@ -1062,7 +1064,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)

rc = cap_task_setnice(p, nice);
if (rc == 0)
- rc = smk_curacc(p->cred->security, MAY_WRITE);
+ rc = smk_curacc(task_security(p), MAY_WRITE);
return rc;
}

@@ -1079,7 +1081,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)

rc = cap_task_setioprio(p, ioprio);
if (rc == 0)
- rc = smk_curacc(p->cred->security, MAY_WRITE);
+ rc = smk_curacc(task_security(p), MAY_WRITE);
return rc;
}

@@ -1091,7 +1093,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)
*/
static int smack_task_getioprio(struct task_struct *p)
{
- return smk_curacc(p->cred->security, MAY_READ);
+ return smk_curacc(task_security(p), MAY_READ);
}

/**
@@ -1109,7 +1111,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,

rc = cap_task_setscheduler(p, policy, lp);
if (rc == 0)
- rc = smk_curacc(p->cred->security, MAY_WRITE);
+ rc = smk_curacc(task_security(p), MAY_WRITE);
return rc;
}

@@ -1121,7 +1123,7 @@ static int smack_task_setscheduler(struct task_struct *p, int policy,
*/
static int smack_task_getscheduler(struct task_struct *p)
{
- return smk_curacc(p->cred->security, MAY_READ);
+ return smk_curacc(task_security(p), MAY_READ);
}

/**
@@ -1132,7 +1134,7 @@ static int smack_task_getscheduler(struct task_struct *p)
*/
static int smack_task_movememory(struct task_struct *p)
{
- return smk_curacc(p->cred->security, MAY_WRITE);
+ return smk_curacc(task_security(p), MAY_WRITE);
}

/**
@@ -1155,13 +1157,13 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver.
*/
if (secid == 0)
- return smk_curacc(p->cred->security, MAY_WRITE);
+ return smk_curacc(task_security(p), MAY_WRITE);
/*
* If the secid isn't 0 we're dealing with some USB IO
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
- return smk_access(smack_from_secid(secid), p->cred->security, MAY_WRITE);
+ return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE);
}

/**
@@ -1174,7 +1176,7 @@ static int smack_task_wait(struct task_struct *p)
{
int rc;

- rc = smk_access(current->cred->security, p->cred->security, MAY_WRITE);
+ rc = smk_access(current_security(), task_security(p), MAY_WRITE);
if (rc == 0)
return 0;

@@ -1205,7 +1207,7 @@ static int smack_task_wait(struct task_struct *p)
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
struct inode_smack *isp = inode->i_security;
- isp->smk_inode = p->cred->security;
+ isp->smk_inode = task_security(p);
}

/*
@@ -2010,7 +2012,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
if (strcmp(name, "current") != 0)
return -EINVAL;

- cp = kstrdup(p->cred->security, GFP_KERNEL);
+ cp = kstrdup(task_security(p), GFP_KERNEL);
if (cp == NULL)
return -ENOMEM;

2008-08-06 16:08:28

by David Howells

[permalink] [raw]
Subject: [PATCH 03/24] KEYS: Alter use of key instantiation link-to-keyring argument [ver #7]

Alter the use of the key instantiation and negation functions' link-to-keyring
arguments. Currently this specifies a keyring in the target process to link
the key into, creating the keyring if it doesn't exist. This, however, can be
a problem for copy-on-write credentials as it means that the instantiating
process can alter the credentials of the requesting process.

This patch alters the behaviour such that:

(1) If keyctl_instantiate_key() or keyctl_negate_key() are given a specific
keyring by ID (ringid >= 0), then that keyring will be used.

(2) If keyctl_instantiate_key() or keyctl_negate_key() are given one of the
special constants that refer to the requesting process's keyrings
(KEY_SPEC_*_KEYRING, all <= 0), then:

(a) If sys_request_key() was given a keyring to use (destringid) then the
key will be attached to that keyring.

(b) If sys_request_key() was given a NULL keyring, then the key being
instantiated will be attached to the default keyring as set by
keyctl_set_reqkey_keyring().

(3) No extra link will be made.

Decision point (1) follows current behaviour, and allows those instantiators
who've searched for a specifically named keyring in the requestor's keyring so
as to partition the keys by type to still have their named keyrings.

Decision point (2) allows the requestor to make sure that the key or keys that
get produced by request_key() go where they want, whilst allowing the
instantiator to request that the key is retained. This is mainly useful for
situations where the instantiator makes a secondary request, the key for which
should be retained by the initial requestor:

+-----------+ +--------------+ +--------------+
| | | | | |
| Requestor |------->| Instantiator |------->| Instantiator |
| | | | | |
+-----------+ +--------------+ +--------------+
request_key() request_key()

This might be useful, for example, in Kerberos, where the requestor requests a
ticket, and then the ticket instantiator requests the TGT, which someone else
then has to go and fetch. The TGT, however, should be retained in the
keyrings of the requestor, not the first instantiator. To make this explict
an extra special keyring constant is also added.

Signed-off-by: David Howells <[email protected]>
Reviewed-by: James Morris <[email protected]>
---

include/linux/key.h | 18 +++---
include/linux/keyctl.h | 4 +
kernel/kmod.c | 2 -
security/keys/internal.h | 11 ++--
security/keys/keyctl.c | 118 +++++++++++++++++++++++---------------
security/keys/process_keys.c | 88 +++++++++++++++++-----------
security/keys/request_key.c | 71 +++++++++++++++--------
security/keys/request_key_auth.c | 5 +-
8 files changed, 195 insertions(+), 122 deletions(-)


diff --git a/include/linux/key.h b/include/linux/key.h
index c45c962..599a37c 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -287,25 +287,25 @@ extern void key_fsuid_changed(struct task_struct *tsk);
extern void key_fsgid_changed(struct task_struct *tsk);
extern void key_init(void);

-#define __install_session_keyring(tsk, keyring) \
-({ \
- struct key *old_session = tsk->signal->session_keyring; \
- tsk->signal->session_keyring = keyring; \
- old_session; \
+#define __install_session_keyring(keyring) \
+({ \
+ struct key *old_session = current->signal->session_keyring; \
+ current->signal->session_keyring = keyring; \
+ old_session; \
})

#else /* CONFIG_KEYS */

#define key_validate(k) 0
#define key_serial(k) 0
-#define key_get(k) ({ NULL; })
+#define key_get(k) NULL
#define key_put(k) do { } while(0)
#define key_ref_put(k) do { } while(0)
-#define make_key_ref(k, p) ({ NULL; })
-#define key_ref_to_ptr(k) ({ NULL; })
+#define make_key_ref(k, p) NULL
+#define key_ref_to_ptr(k) NULL
#define is_key_possessed(k) 0
#define switch_uid_keyring(u) do { } while(0)
-#define __install_session_keyring(t, k) ({ NULL; })
+#define __install_session_keyring(k) NULL
#define copy_keys(f,t) 0
#define copy_thread_group_keys(t) 0
#define exit_keys(t) do { } while(0)
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h
index 656ee6b..c0688eb 100644
--- a/include/linux/keyctl.h
+++ b/include/linux/keyctl.h
@@ -1,6 +1,6 @@
/* keyctl.h: keyctl command IDs
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004, 2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells ([email protected])
*
* This program is free software; you can redistribute it and/or
@@ -20,6 +20,7 @@
#define KEY_SPEC_USER_SESSION_KEYRING -5 /* - key ID for UID-session keyring */
#define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */
#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */
+#define KEY_SPEC_REQUESTOR_KEYRING -8 /* - key ID for request_key() dest keyring */

/* request-key default keyrings */
#define KEY_REQKEY_DEFL_NO_CHANGE -1
@@ -30,6 +31,7 @@
#define KEY_REQKEY_DEFL_USER_KEYRING 4
#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5
#define KEY_REQKEY_DEFL_GROUP_KEYRING 6
+#define KEY_REQKEY_DEFL_REQUESTOR_KEYRING 7

/* keyctl commands */
#define KEYCTL_GET_KEYRING_ID 0 /* ask for a keyring's ID */
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 2456d1a..27e02e6 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -140,7 +140,7 @@ static int ____call_usermodehelper(void *data)
/* Unblock all signals and set the session keyring. */
new_session = key_get(sub_info->ring);
spin_lock_irq(&current->sighand->siglock);
- old_session = __install_session_keyring(current, new_session);
+ old_session = __install_session_keyring(new_session);
flush_signal_handlers(current, 1);
sigemptyset(&current->blocked);
recalc_sigpending();
diff --git a/security/keys/internal.h b/security/keys/internal.h
index a60c681..cb8c678 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -109,8 +109,8 @@ extern key_ref_t search_process_keyrings(struct key_type *type,

extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);

-extern int install_thread_keyring(struct task_struct *tsk);
-extern int install_process_keyring(struct task_struct *tsk);
+extern int install_thread_keyring(void);
+extern int install_process_keyring(void);

extern struct key *request_key_and_link(struct key_type *type,
const char *description,
@@ -120,8 +120,7 @@ extern struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring,
unsigned long flags);

-extern key_ref_t lookup_user_key(struct task_struct *context,
- key_serial_t id, int create, int partial,
+extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
key_perm_t perm);

extern long join_session_keyring(const char *name);
@@ -152,6 +151,7 @@ static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
*/
struct request_key_auth {
struct key *target_key;
+ struct key *dest_keyring;
struct task_struct *context;
void *callout_info;
size_t callout_len;
@@ -161,7 +161,8 @@ struct request_key_auth {
extern struct key_type key_type_request_key_auth;
extern struct key *request_key_auth_new(struct key *target,
const void *callout_info,
- size_t callout_len);
+ size_t callout_len,
+ struct key *dest_keyring);

extern struct key *key_get_instantiation_authkey(key_serial_t target_id);

diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index acc9c89..a738114 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -103,7 +103,7 @@ asmlinkage long sys_add_key(const char __user *_type,
}

/* find the target keyring (which must be writable) */
- keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring_ref);
goto error3;
@@ -185,7 +185,7 @@ asmlinkage long sys_request_key(const char __user *_type,
/* get the destination keyring if specified */
dest_ref = NULL;
if (destringid) {
- dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+ dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest_ref)) {
ret = PTR_ERR(dest_ref);
goto error3;
@@ -235,7 +235,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
key_ref_t key_ref;
long ret;

- key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
+ key_ref = lookup_user_key(id, create, 0, KEY_SEARCH);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -308,7 +308,7 @@ long keyctl_update_key(key_serial_t id,
}

/* find the target key (which must be writable) */
- key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+ key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error2;
@@ -336,7 +336,7 @@ long keyctl_revoke_key(key_serial_t id)
key_ref_t key_ref;
long ret;

- key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+ key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -362,7 +362,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
key_ref_t keyring_ref;
long ret;

- keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring_ref);
goto error;
@@ -388,13 +388,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
key_ref_t keyring_ref, key_ref;
long ret;

- keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+ keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring_ref);
goto error;
}

- key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
+ key_ref = lookup_user_key(id, 1, 0, KEY_LINK);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error2;
@@ -422,13 +422,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
key_ref_t keyring_ref, key_ref;
long ret;

- keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
+ keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE);
if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring_ref);
goto error;
}

- key_ref = lookup_user_key(NULL, id, 0, 0, 0);
+ key_ref = lookup_user_key(id, 0, 0, 0);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error2;
@@ -464,7 +464,7 @@ long keyctl_describe_key(key_serial_t keyid,
char *tmpbuf;
long ret;

- key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+ key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
if (IS_ERR(key_ref)) {
/* viewing a key under construction is permitted if we have the
* authorisation token handy */
@@ -472,7 +472,7 @@ long keyctl_describe_key(key_serial_t keyid,
instkey = key_get_instantiation_authkey(keyid);
if (!IS_ERR(instkey)) {
key_put(instkey);
- key_ref = lookup_user_key(NULL, keyid,
+ key_ref = lookup_user_key(keyid,
0, 1, 0);
if (!IS_ERR(key_ref))
goto okay;
@@ -557,7 +557,7 @@ long keyctl_keyring_search(key_serial_t ringid,
}

/* get the keyring at which to begin the search */
- keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
+ keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
if (IS_ERR(keyring_ref)) {
ret = PTR_ERR(keyring_ref);
goto error2;
@@ -566,7 +566,7 @@ long keyctl_keyring_search(key_serial_t ringid,
/* get the destination keyring if specified */
dest_ref = NULL;
if (destringid) {
- dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+ dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest_ref)) {
ret = PTR_ERR(dest_ref);
goto error3;
@@ -636,7 +636,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
long ret;

/* find the key first */
- key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+ key_ref = lookup_user_key(keyid, 0, 0, 0);
if (IS_ERR(key_ref)) {
ret = -ENOKEY;
goto error;
@@ -699,7 +699,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (uid == (uid_t) -1 && gid == (gid_t) -1)
goto error;

- key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+ key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -804,7 +804,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
goto error;

- key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+ key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -829,6 +829,43 @@ error:

} /* end keyctl_setperm_key() */

+/*
+ * get the destination keyring for instantiation
+ */
+static long get_instantiation_keyring(key_serial_t ringid,
+ struct request_key_auth *rka,
+ struct key **_dest_keyring)
+{
+ key_ref_t dkref;
+
+ /* just return a NULL pointer if we weren't asked to make a link */
+ if (ringid == 0) {
+ *_dest_keyring = NULL;
+ return 0;
+ }
+
+ /* if a specific keyring is nominated by ID, then use that */
+ if (ringid > 0) {
+ dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ if (IS_ERR(dkref))
+ return PTR_ERR(dkref);
+ *_dest_keyring = key_ref_to_ptr(dkref);
+ return 0;
+ }
+
+ if (ringid == KEY_SPEC_REQKEY_AUTH_KEY)
+ return -EINVAL;
+
+ /* otherwise specify the destination keyring recorded in the
+ * authorisation key (any KEY_SPEC_*_KEYRING) */
+ if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) {
+ *_dest_keyring = rka->dest_keyring;
+ return 0;
+ }
+
+ return -ENOKEY;
+}
+
/*****************************************************************************/
/*
* instantiate the key with the specified payload, and, if one is given, link
@@ -840,8 +877,7 @@ long keyctl_instantiate_key(key_serial_t id,
key_serial_t ringid)
{
struct request_key_auth *rka;
- struct key *instkey;
- key_ref_t keyring_ref;
+ struct key *instkey, *dest_keyring;
void *payload;
long ret;
bool vm = false;
@@ -883,21 +919,15 @@ long keyctl_instantiate_key(key_serial_t id,

/* find the destination keyring amongst those belonging to the
* requesting task */
- keyring_ref = NULL;
- if (ringid) {
- keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
- KEY_WRITE);
- if (IS_ERR(keyring_ref)) {
- ret = PTR_ERR(keyring_ref);
- goto error2;
- }
- }
+ ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
+ if (ret < 0)
+ goto error2;

/* instantiate the key and link it into a keyring */
ret = key_instantiate_and_link(rka->target_key, payload, plen,
- key_ref_to_ptr(keyring_ref), instkey);
+ dest_keyring, instkey);

- key_ref_put(keyring_ref);
+ key_put(dest_keyring);

/* discard the assumed authority if it's just been disabled by
* instantiation of the key */
@@ -924,8 +954,7 @@ error:
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
struct request_key_auth *rka;
- struct key *instkey;
- key_ref_t keyring_ref;
+ struct key *instkey, *dest_keyring;
long ret;

/* the appropriate instantiation authorisation key must have been
@@ -941,20 +970,15 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)

/* find the destination keyring if present (which must also be
* writable) */
- keyring_ref = NULL;
- if (ringid) {
- keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
- if (IS_ERR(keyring_ref)) {
- ret = PTR_ERR(keyring_ref);
- goto error;
- }
- }
+ ret = get_instantiation_keyring(ringid, rka, &dest_keyring);
+ if (ret < 0)
+ goto error;

/* instantiate the key and link it into a keyring */
ret = key_negate_and_link(rka->target_key, timeout,
- key_ref_to_ptr(keyring_ref), instkey);
+ dest_keyring, instkey);

- key_ref_put(keyring_ref);
+ key_put(dest_keyring);

/* discard the assumed authority if it's just been disabled by
* instantiation of the key */
@@ -979,13 +1003,13 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)

switch (reqkey_defl) {
case KEY_REQKEY_DEFL_THREAD_KEYRING:
- ret = install_thread_keyring(current);
+ ret = install_thread_keyring();
if (ret < 0)
return ret;
goto set;

case KEY_REQKEY_DEFL_PROCESS_KEYRING:
- ret = install_process_keyring(current);
+ ret = install_process_keyring();
if (ret < 0)
return ret;

@@ -1018,7 +1042,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
time_t expiry;
long ret;

- key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+ key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
goto error;
@@ -1105,7 +1129,7 @@ long keyctl_get_security(key_serial_t keyid,
char *context;
long ret;

- key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+ key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
if (IS_ERR(key_ref)) {
if (PTR_ERR(key_ref) != -EACCES)
return PTR_ERR(key_ref);
@@ -1117,7 +1141,7 @@ long keyctl_get_security(key_serial_t keyid,
return PTR_ERR(key_ref);
key_put(instkey);

- key_ref = lookup_user_key(NULL, keyid, 0, 1, 0);
+ key_ref = lookup_user_key(keyid, 0, 1, 0);
if (IS_ERR(key_ref))
return PTR_ERR(key_ref);
}
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 5be6d01..324093d 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -40,9 +40,9 @@ struct key_user root_key_user = {
/*
* install user and user session keyrings for a particular UID
*/
-static int install_user_keyrings(struct task_struct *tsk)
+static int install_user_keyrings(void)
{
- struct user_struct *user = tsk->user;
+ struct user_struct *user = current->user;
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;
@@ -67,7 +67,7 @@ static int install_user_keyrings(struct task_struct *tsk)
uid_keyring = find_keyring_by_name(buf, true);
if (IS_ERR(uid_keyring)) {
uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
- tsk, KEY_ALLOC_IN_QUOTA,
+ current, KEY_ALLOC_IN_QUOTA,
NULL);
if (IS_ERR(uid_keyring)) {
ret = PTR_ERR(uid_keyring);
@@ -83,7 +83,8 @@ static int install_user_keyrings(struct task_struct *tsk)
if (IS_ERR(session_keyring)) {
session_keyring =
keyring_alloc(buf, user->uid, (gid_t) -1,
- tsk, KEY_ALLOC_IN_QUOTA, NULL);
+ current, KEY_ALLOC_IN_QUOTA,
+ NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error_release;
@@ -146,8 +147,9 @@ void switch_uid_keyring(struct user_struct *new_user)
/*
* install a fresh thread keyring, discarding the old one
*/
-int install_thread_keyring(struct task_struct *tsk)
+int install_thread_keyring(void)
{
+ struct task_struct *tsk = current;
struct key *keyring, *old;
char buf[20];
int ret;
@@ -178,8 +180,9 @@ error:
/*
* make sure a process keyring is installed
*/
-int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(void)
{
+ struct task_struct *tsk = current;
struct key *keyring;
char buf[20];
int ret;
@@ -218,9 +221,9 @@ error:
* install a session keyring, discarding the old one
* - if a keyring is not supplied, an empty one is invented
*/
-static int install_session_keyring(struct task_struct *tsk,
- struct key *keyring)
+static int install_session_keyring(struct key *keyring)
{
+ struct task_struct *tsk = current;
unsigned long flags;
struct key *old;
char buf[20];
@@ -572,93 +575,91 @@ static int lookup_user_key_possessed(const struct key *key, const void *target)
* - don't create special keyrings unless so requested
* - partially constructed keys aren't found unless requested
*/
-key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
- int create, int partial, key_perm_t perm)
+key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+ key_perm_t perm)
{
+ struct request_key_auth *rka;
+ struct task_struct *t = current;
key_ref_t key_ref, skey_ref;
struct key *key;
int ret;

- if (!context)
- context = current;
-
key_ref = ERR_PTR(-ENOKEY);

switch (id) {
case KEY_SPEC_THREAD_KEYRING:
- if (!context->thread_keyring) {
+ if (!t->thread_keyring) {
if (!create)
goto error;

- ret = install_thread_keyring(context);
+ ret = install_thread_keyring();
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}

- key = context->thread_keyring;
+ key = t->thread_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;

case KEY_SPEC_PROCESS_KEYRING:
- if (!context->signal->process_keyring) {
+ if (!t->signal->process_keyring) {
if (!create)
goto error;

- ret = install_process_keyring(context);
+ ret = install_process_keyring();
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}

- key = context->signal->process_keyring;
+ key = t->signal->process_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;

case KEY_SPEC_SESSION_KEYRING:
- if (!context->signal->session_keyring) {
+ if (!t->signal->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
- ret = install_user_keyrings(context);
+ ret = install_user_keyrings();
if (ret < 0)
goto error;
- ret = install_session_keyring(
- context, context->user->session_keyring);
+ ret = install_session_keyring(t->user->session_keyring);
if (ret < 0)
goto error;
}

rcu_read_lock();
- key = rcu_dereference(context->signal->session_keyring);
+ key = rcu_dereference(t->signal->session_keyring);
atomic_inc(&key->usage);
rcu_read_unlock();
key_ref = make_key_ref(key, 1);
break;

case KEY_SPEC_USER_KEYRING:
- if (!context->user->uid_keyring) {
- ret = install_user_keyrings(context);
+ if (!t->user->uid_keyring) {
+ ret = install_user_keyrings();
if (ret < 0)
goto error;
}

- key = context->user->uid_keyring;
+ key = t->user->uid_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;

case KEY_SPEC_USER_SESSION_KEYRING:
- if (!context->user->session_keyring) {
- ret = install_user_keyrings(context);
+ if (!t->user->session_keyring) {
+ ret = install_user_keyrings();
if (ret < 0)
goto error;
}

- key = context->user->session_keyring;
+ key = t->user->session_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;
@@ -669,7 +670,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
goto error;

case KEY_SPEC_REQKEY_AUTH_KEY:
- key = context->request_key_auth;
+ key = t->request_key_auth;
if (!key)
goto error;

@@ -677,6 +678,25 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
key_ref = make_key_ref(key, 1);
break;

+ case KEY_SPEC_REQUESTOR_KEYRING:
+ if (!t->request_key_auth)
+ goto error;
+
+ down_read(&t->request_key_auth->sem);
+ if (t->request_key_auth->flags & KEY_FLAG_REVOKED) {
+ key_ref = ERR_PTR(-EKEYREVOKED);
+ key = NULL;
+ } else {
+ rka = t->request_key_auth->payload.data;
+ key = rka->dest_keyring;
+ atomic_inc(&key->usage);
+ }
+ up_read(&t->request_key_auth->sem);
+ if (!key)
+ goto error;
+ key_ref = make_key_ref(key, 1);
+ break;
+
default:
key_ref = ERR_PTR(-EINVAL);
if (id < 1)
@@ -725,7 +745,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
goto invalid_key;

/* check the permissions */
- ret = key_task_permission(key_ref, context, perm);
+ ret = key_task_permission(key_ref, t, perm);
if (ret < 0)
goto invalid_key;

@@ -754,7 +774,7 @@ long join_session_keyring(const char *name)

/* if no name is provided, install an anonymous keyring */
if (!name) {
- ret = install_session_keyring(tsk, NULL);
+ ret = install_session_keyring(NULL);
if (ret < 0)
goto error;

@@ -784,7 +804,7 @@ long join_session_keyring(const char *name)
}

/* we've got a keyring - now to install it */
- ret = install_session_keyring(tsk, keyring);
+ ret = install_session_keyring(keyring);
if (ret < 0)
goto error2;

diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index b9e50a9..123edce 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -165,7 +165,8 @@ error_alloc:
* - we ignore program failure and go on key status instead
*/
static int construct_key(struct key *key, const void *callout_info,
- size_t callout_len, void *aux)
+ size_t callout_len, void *aux,
+ struct key *dest_keyring)
{
struct key_construction *cons;
request_key_actor_t actor;
@@ -179,7 +180,8 @@ static int construct_key(struct key *key, const void *callout_info,
return -ENOMEM;

/* allocate an authorisation key */
- authkey = request_key_auth_new(key, callout_info, callout_len);
+ authkey = request_key_auth_new(key, callout_info, callout_len,
+ dest_keyring);
if (IS_ERR(authkey)) {
kfree(cons);
ret = PTR_ERR(authkey);
@@ -207,27 +209,48 @@ static int construct_key(struct key *key, const void *callout_info,
}

/*
- * link a key to the appropriate destination keyring
- * - the caller must hold a write lock on the destination keyring
+ * get the appropriate destination keyring for the request
+ * - we return whatever keyring we select with an extra reference upon it which
+ * the caller must release
*/
-static void construct_key_make_link(struct key *key, struct key *dest_keyring)
+static void construct_get_dest_keyring(struct key **_dest_keyring)
{
+ struct request_key_auth *rka;
struct task_struct *tsk = current;
- struct key *drop = NULL;
+ struct key *dest_keyring = *_dest_keyring, *authkey;

- kenter("{%d},%p", key->serial, dest_keyring);
+ kenter("%p", dest_keyring);

/* find the appropriate keyring */
- if (!dest_keyring) {
+ if (dest_keyring) {
+ /* the caller supplied one */
+ key_get(dest_keyring);
+ } else {
+ /* use a default keyring; falling through the cases until we
+ * find one that we actually have */
switch (tsk->jit_keyring) {
case KEY_REQKEY_DEFL_DEFAULT:
+ case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
+ if (tsk->request_key_auth) {
+ authkey = tsk->request_key_auth;
+ down_read(&authkey->sem);
+ rka = authkey->payload.data;
+ if (!test_bit(KEY_FLAG_REVOKED,
+ &authkey->flags))
+ dest_keyring =
+ key_get(rka->dest_keyring);
+ up_read(&authkey->sem);
+ if (dest_keyring)
+ break;
+ }
+
case KEY_REQKEY_DEFL_THREAD_KEYRING:
- dest_keyring = tsk->thread_keyring;
+ dest_keyring = key_get(tsk->thread_keyring);
if (dest_keyring)
break;

case KEY_REQKEY_DEFL_PROCESS_KEYRING:
- dest_keyring = tsk->signal->process_keyring;
+ dest_keyring = key_get(tsk->signal->process_keyring);
if (dest_keyring)
break;

@@ -236,17 +259,16 @@ static void construct_key_make_link(struct key *key, struct key *dest_keyring)
dest_keyring = key_get(
rcu_dereference(tsk->signal->session_keyring));
rcu_read_unlock();
- drop = dest_keyring;

if (dest_keyring)
break;

case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
- dest_keyring = tsk->user->session_keyring;
+ dest_keyring = key_get(tsk->user->session_keyring);
break;

case KEY_REQKEY_DEFL_USER_KEYRING:
- dest_keyring = tsk->user->uid_keyring;
+ dest_keyring = key_get(tsk->user->uid_keyring);
break;

case KEY_REQKEY_DEFL_GROUP_KEYRING:
@@ -255,10 +277,9 @@ static void construct_key_make_link(struct key *key, struct key *dest_keyring)
}
}

- /* and attach the key to it */
- __key_link(dest_keyring, key);
- key_put(drop);
- kleave("");
+ *_dest_keyring = dest_keyring;
+ kleave(" [dk %d]", key_serial(dest_keyring));
+ return;
}

/*
@@ -288,8 +309,7 @@ static int construct_alloc_key(struct key_type *type,

set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);

- if (dest_keyring)
- down_write(&dest_keyring->sem);
+ down_write(&dest_keyring->sem);

/* attach the key to the destination keyring under lock, but we do need
* to do another check just in case someone beat us to it whilst we
@@ -301,12 +321,10 @@ static int construct_alloc_key(struct key_type *type,
if (!IS_ERR(key_ref))
goto key_already_present;

- if (dest_keyring)
- construct_key_make_link(key, dest_keyring);
+ __key_link(dest_keyring, key);

mutex_unlock(&key_construction_mutex);
- if (dest_keyring)
- up_write(&dest_keyring->sem);
+ up_write(&dest_keyring->sem);
mutex_unlock(&user->cons_lock);
*_key = key;
kleave(" = 0 [%d]", key_serial(key));
@@ -348,21 +366,26 @@ static struct key *construct_key_and_link(struct key_type *type,
if (!user)
return ERR_PTR(-ENOMEM);

+ construct_get_dest_keyring(&dest_keyring);
+
ret = construct_alloc_key(type, description, dest_keyring, flags, user,
&key);
key_user_put(user);

if (ret == 0) {
- ret = construct_key(key, callout_info, callout_len, aux);
+ ret = construct_key(key, callout_info, callout_len, aux,
+ dest_keyring);
if (ret < 0)
goto construction_failed;
}

+ key_put(dest_keyring);
return key;

construction_failed:
key_negate_and_link(key, key_negative_timeout, NULL, NULL);
key_put(key);
+ key_put(dest_keyring);
return ERR_PTR(ret);
}

diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index bd237b0..eccd2f2 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -128,6 +128,7 @@ static void request_key_auth_destroy(struct key *key)
}

key_put(rka->target_key);
+ key_put(rka->dest_keyring);
kfree(rka->callout_info);
kfree(rka);

@@ -139,7 +140,7 @@ static void request_key_auth_destroy(struct key *key)
* access to the caller's security data
*/
struct key *request_key_auth_new(struct key *target, const void *callout_info,
- size_t callout_len)
+ size_t callout_len, struct key *dest_keyring)
{
struct request_key_auth *rka, *irka;
struct key *authkey = NULL;
@@ -188,6 +189,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
}

rka->target_key = key_get(target);
+ rka->dest_keyring = key_get(dest_keyring);
memcpy(rka->callout_info, callout_info, callout_len);
rka->callout_len = callout_len;

@@ -223,6 +225,7 @@ error_inst:
key_put(authkey);
error_alloc:
key_put(rka->target_key);
+ key_put(rka->dest_keyring);
kfree(rka->callout_info);
kfree(rka);
kleave("= %d", ret);

2008-08-07 11:08:40

by James Morris

[permalink] [raw]
Subject: Re: [PATCH 00/24] Introduce credentials [ver #7]

On Wed, 6 Aug 2008, David Howells wrote:

>
>
> I've brought my patchset up to date with regards the recent merge melee and
> built the patches on top of the next branch of James's security testing tree as
> per his request.

These patches don't apply from here on:

Applying CRED: Detach the credentials from task_struct [ver #7]
error: patch failed: include/linux/cred.h:158
error: include/linux/cred.h: patch does not apply
error: patch failed: include/linux/init_task.h:115
error: include/linux/init_task.h: patch does not apply
error: patch failed: include/linux/sched.h:1109
error: include/linux/sched.h: patch does not apply
error: patch failed: kernel/fork.c:145
error: kernel/fork.c: patch does not apply
error: patch failed: security/selinux/hooks.c:166
error: security/selinux/hooks.c: patch does not apply
error: patch failed: security/smack/smack_lsm.c:984
error: security/smack/smack_lsm.c: patch does not apply
Patch failed at 0008.



- James
--
James Morris
<[email protected]>

2008-08-07 12:27:06

by James Morris

[permalink] [raw]
Subject: Re: [PATCH 00/24] Introduce credentials [ver #7]

On Wed, 6 Aug 2008, David Howells wrote:

> I've brought my patchset up to date with regards the recent merge melee and
> built the patches on top of the next branch of James's security testing tree as
> per his request.

These patches are now in
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next-creds

This is the 'next' branch + the credentials patches.

Stephen, could you add 'next-creds' to linux-next?


- James
--
James Morris
<[email protected]>

2008-08-07 12:27:30

by James Morris

[permalink] [raw]
Subject: Re: [PATCH 00/24] Introduce credentials [ver #7]

On Thu, 7 Aug 2008, David Howells wrote:

> James Morris <[email protected]> wrote:
>
> > These patches don't apply from here on:
>
> Hmmm... Applies for me on top of your next branch (commit ID
> 421fae06be9e0dac45747494756b3580643815f9).

Interesting, looks like git-am got confused when processing the patches as
a single mailbox, but worked ok when run on a per-patch basis.


- James
--
James Morris
<[email protected]>

2008-08-07 12:28:56

by David Howells

[permalink] [raw]
Subject: Re: [PATCH 00/24] Introduce credentials [ver #7]

James Morris <[email protected]> wrote:

> These patches don't apply from here on:

Hmmm... Applies for me on top of your next branch (commit ID
421fae06be9e0dac45747494756b3580643815f9).

David

2008-08-08 00:23:43

by Stephen Rothwell

[permalink] [raw]
Subject: Re: [PATCH 00/24] Introduce credentials [ver #7]

Hi James,

On Thu, 7 Aug 2008 22:03:57 +1000 (EST) James Morris <[email protected]> wrote:
>
> On Wed, 6 Aug 2008, David Howells wrote:
>
> > I've brought my patchset up to date with regards the recent merge melee and
> > built the patches on top of the next branch of James's security testing tree as
> > per his request.
>
> These patches are now in
> git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next-creds
>
> This is the 'next' branch + the credentials patches.
>
> Stephen, could you add 'next-creds' to linux-next?

OK, I have added it from today with you and David as contacts. It is
right at the end of the merge, so it will go away if it is too painful (I
don't expect it to be, just letting you know).

--
Cheers,
Stephen Rothwell [email protected]
http://www.canb.auug.org.au/~sfr/


Attachments:
(No filename) (853.00 B)
(No filename) (197.00 B)
Download all attachments