]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'master' into next
authorJames Morris <jmorris@namei.org>
Thu, 4 Dec 2008 06:16:36 +0000 (17:16 +1100)
committerJames Morris <jmorris@namei.org>
Thu, 4 Dec 2008 06:16:36 +0000 (17:16 +1100)
Conflicts:
fs/nfsd/nfs4recover.c

Manually fixed above to use new creds API functions, e.g.
nfs4_save_creds().

Signed-off-by: James Morris <jmorris@namei.org>
219 files changed:
Documentation/credentials.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
arch/alpha/kernel/asm-offsets.c
arch/alpha/kernel/entry.S
arch/ia64/ia32/sys_ia32.c
arch/ia64/kernel/mca_drv.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/signal.c
arch/mips/kernel/kspd.c
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/vpe.c
arch/parisc/kernel/signal.c
arch/powerpc/mm/fault.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/s390/hypfs/inode.c
arch/s390/kernel/compat_linux.c
arch/um/drivers/mconsole_kern.c
arch/x86/ia32/ia32_aout.c
arch/x86/mm/fault.c
drivers/block/loop.c
drivers/char/tty_audit.c
drivers/connector/cn_proc.c
drivers/isdn/capi/capifs.c
drivers/isdn/hysdn/hysdn_procconf.c
drivers/net/tun.c
drivers/usb/core/devio.c
drivers/usb/core/inode.c
fs/9p/fid.c
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/affs/inode.c
fs/affs/super.c
fs/anon_inodes.c
fs/attr.c
fs/autofs/inode.c
fs/autofs4/dev-ioctl.c
fs/autofs4/inode.c
fs/autofs4/waitq.c
fs/bfs/dir.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_flat.c
fs/binfmt_som.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/misc.c
fs/coda/cache.c
fs/coda/file.c
fs/coda/upcall.c
fs/compat.c
fs/devpts/inode.c
fs/dquot.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/kthread.c
fs/ecryptfs/main.c
fs/ecryptfs/messaging.c
fs/ecryptfs/miscdev.c
fs/exec.c
fs/exportfs/expfs.c
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext3/balloc.c
fs/ext3/ialloc.c
fs/ext4/balloc.c
fs/ext4/ialloc.c
fs/fat/file.c
fs/fat/inode.c
fs/fcntl.c
fs/file_table.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/gfs2/inode.c
fs/hfs/inode.c
fs/hfs/super.c
fs/hfsplus/inode.c
fs/hfsplus/options.c
fs/hpfs/namei.c
fs/hpfs/super.c
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/inotify_user.c
fs/internal.h
fs/ioprio.c
fs/jfs/jfs_inode.c
fs/locks.c
fs/minix/bitmap.c
fs/namei.c
fs/namespace.c
fs/ncpfs/ioctl.c
fs/nfsctl.c
fs/nfsd/auth.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfsfh.c
fs/nfsd/vfs.c
fs/ocfs2/dlm/dlmfs.c
fs/ocfs2/namei.c
fs/omfs/inode.c
fs/open.c
fs/pipe.c
fs/posix_acl.c
fs/proc/array.c
fs/proc/base.c
fs/quota.c
fs/ramfs/inode.c
fs/reiserfs/namei.c
fs/smbfs/dir.c
fs/smbfs/inode.c
fs/smbfs/proc.c
fs/sysv/ialloc.c
fs/ubifs/budget.c
fs/ubifs/dir.c
fs/udf/ialloc.c
fs/udf/namei.c
fs/ufs/ialloc.c
fs/xfs/linux-2.6/xfs_cred.h
fs/xfs/linux-2.6/xfs_globals.h
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_vnodeops.h
include/keys/keyring-type.h [new file with mode: 0644]
include/linux/audit.h
include/linux/binfmts.h
include/linux/capability.h
include/linux/cred.h
include/linux/fs.h
include/linux/init_task.h
include/linux/key-ui.h [deleted file]
include/linux/key.h
include/linux/keyctl.h
include/linux/nsproxy.h
include/linux/sched.h
include/linux/securebits.h
include/linux/security.h
include/linux/user_namespace.h
include/net/scm.h
init/main.c
ipc/mqueue.c
ipc/shm.c
ipc/util.c
kernel/Makefile
kernel/acct.c
kernel/auditsc.c
kernel/capability.c
kernel/cgroup.c
kernel/cred-internals.h [new file with mode: 0644]
kernel/cred.c [new file with mode: 0644]
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/futex_compat.c
kernel/kmod.c
kernel/nsproxy.c
kernel/ptrace.c
kernel/sched.c
kernel/signal.c
kernel/sys.c
kernel/sysctl.c
kernel/timer.c
kernel/trace/trace.c
kernel/tsacct.c
kernel/uid16.c
kernel/user.c
kernel/user_namespace.c
kernel/workqueue.c
lib/Makefile
lib/is_single_threaded.c [new file with mode: 0644]
mm/mempolicy.c
mm/migrate.c
mm/oom_kill.c
mm/shmem.c
net/9p/client.c
net/ax25/af_ax25.c
net/ax25/ax25_route.c
net/core/dev.c
net/core/scm.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv6/ip6_flowlabel.c
net/ipv6/netfilter/ip6t_LOG.c
net/netfilter/nfnetlink_log.c
net/netfilter/xt_owner.c
net/netrom/af_netrom.c
net/rose/af_rose.c
net/rxrpc/ar-key.c
net/sched/cls_flow.c
net/socket.c
net/sunrpc/auth.c
net/unix/af_unix.c
security/capability.c
security/commoncap.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/permission.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/root_plug.c
security/security.c
security/selinux/exports.c
security/selinux/hooks.c
security/selinux/include/av_perm_to_string.h
security/selinux/include/av_permissions.h
security/selinux/include/class_to_string.h
security/selinux/include/flask.h
security/selinux/include/objsec.h
security/selinux/nlmsgtab.c
security/selinux/selinuxfs.c
security/selinux/xfrm.c
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c

diff --git a/Documentation/credentials.txt b/Documentation/credentials.txt
new file mode 100644 (file)
index 0000000..df03169
--- /dev/null
@@ -0,0 +1,582 @@
+                            ====================
+                            CREDENTIALS IN LINUX
+                            ====================
+
+By: David Howells <dhowells@redhat.com>
+
+Contents:
+
+ (*) Overview.
+
+ (*) Types of credentials.
+
+ (*) File markings.
+
+ (*) Task credentials.
+
+     - Immutable 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.
+
+
+IMMUTABLE CREDENTIALS
+---------------------
+
+Once a set of credentials has been made public (by calling commit_creds() for
+example), it must be considered immutable, barring two exceptions:
+
+ (1) The reference count may be altered.
+
+ (2) Whilst the keyring subscriptions of a set of credentials may not be
+     changed, the keyrings subscribed to may have their contents altered.
+
+To catch accidental credential alteration at compile time, struct task_struct
+has _const_ pointers to its credential sets, as does struct file.  Furthermore,
+certain functions such as get_cred() and put_cred() operate on const pointers,
+thus rendering casts unnecessary, but require to temporarily ditch the const
+qualification to be able to alter the reference count.
+
+
+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.
index e0f346d201edb70fae654c55f6be842c4465a5ff..d8c4ceec37436a210c5a030c56c227f7253fe2c7 100644 (file)
@@ -1449,6 +1449,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        instruction doesn't work correctly and not to
                        use it.
 
+       no_file_caps    Tells the kernel not to honor file capabilities.  The
+                       only way then for a file to be executed with privilege
+                       is to be setuid root or executed by root.
+
        nohalt          [IA-64] Tells the kernel not to use the power saving
                        function PAL_HALT_LIGHT when idle. This increases
                        power-consumption. On the positive side, it reduces
index 4b18cd94d59d5060acfac02ad276101579ca481a..6ff8886e7e22b9c4af281abe417a99a88596a3d1 100644 (file)
@@ -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);
index 5fc61e281ac77724cbcf0270b4269dd4559a686b..f77345bc66a975ff244c2e4b83be931fbc50a096 100644 (file)
@@ -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
index 5e92ae00bdbba8403ee69ddd12d33ca44ce34699..16ef61a91d95810de82668fa23eefbd2d993a25c 100644 (file)
@@ -1767,25 +1767,24 @@ groups16_from_user(struct group_info *group_info, short __user *grouplist)
 asmlinkage long
 sys32_getgroups16 (int gidsetsize, short __user *grouplist)
 {
+       const struct cred *cred = current_cred();
        int i;
 
        if (gidsetsize < 0)
                return -EINVAL;
 
-       get_group_info(current->group_info);
-       i = current->group_info->ngroups;
+       i = 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, cred->group_info)) {
                        i = -EFAULT;
                        goto out;
                }
        }
 out:
-       put_group_info(current->group_info);
        return i;
 }
 
index fab1d21a4f2c1cfe4443aa8812518d4a6bfeaeb6..f94aaa86933fd81f0b347466907e16bdfcf10781 100644 (file)
@@ -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);
index 6543a5547c84669434e5d4dbc3d962400a714f57..0e499757309bfbdab35d1233126e4259d9f42bdd 100644 (file)
@@ -2220,8 +2220,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;
@@ -2399,22 +2399,33 @@ error_kmem:
 static int
 pfm_bad_permissions(struct task_struct *task)
 {
+       const struct cred *tcred;
+       uid_t uid = current_uid();
+       gid_t gid = current_gid();
+       int ret;
+
+       rcu_read_lock();
+       tcred = __task_cred(task);
+
        /* 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,
-               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);
+               uid,
+               gid,
+               tcred->euid,
+               tcred->suid,
+               tcred->uid,
+               tcred->egid,
+               tcred->sgid));
+
+       ret = ((uid != tcred->euid)
+              || (uid != tcred->suid)
+              || (uid != tcred->uid)
+              || (gid != tcred->egid)
+              || (gid != tcred->sgid)
+              || (gid != tcred->gid)) && !capable(CAP_SYS_PTRACE);
+
+       rcu_read_unlock();
+       return ret;
 }
 
 static int
index e12500a9c44390b025feeb0b670baac1c1ffd523..e1821ca4c7dfddea3827102e2bd63a016e1162f3 100644 (file)
@@ -229,7 +229,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;
@@ -326,7 +326,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;
index b0591ae0ce566456ed7c88eaa955d191a17bcaaa..fd6e512240347aac0a17b848cd9e1b42657badaf 100644 (file)
@@ -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);
index dc9eb72ed9de956164f557b0757496dae6638c2e..5e77a3a21f98e7926cc789915ad65bbe64911a1a 100644 (file)
@@ -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;
        }
index 972b2d2b8401b6dd7bd4922690205c6b8f3a5cdf..09786e496375267d1fafd9adffa7d1dd17c8928e 100644 (file)
@@ -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 */
index 06213d1d6d958f54d8a3139f9443aab13a5bbaed..f82544225e8e8b43b8ca76664101a849d1e8a7f7 100644 (file)
@@ -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;
index 565b7a237c847929e885eb5597fe4cdb14746cf3..866098686da8116c128ad02c2e1cc871acc6dfb2 100644 (file)
@@ -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;
 
index cb85d237e492b7156745acc396f308fd99068a34..6296bfd9cb0b5646ce7b1cd8d195041f8ed239bf 100644 (file)
@@ -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:
@@ -323,7 +323,7 @@ static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
                goto out;
        }
 
-       filp = dentry_open(dentry, mnt, O_RDONLY);
+       filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
        if (IS_ERR(filp)) {
                put_unused_fd(ret);
                ret = PTR_ERR(filp);
@@ -562,7 +562,7 @@ static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt)
                goto out;
        }
 
-       filp = dentry_open(dentry, mnt, O_RDONLY);
+       filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
        if (IS_ERR(filp)) {
                put_unused_fd(ret);
                ret = PTR_ERR(filp);
index 36313801cd5cf29e49d5c2c4d9c4e7a9cd12c104..8aadcd7a7cf86472d8e1957ef2eb4c9c66be9ac5 100644 (file)
@@ -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;
index 4646382af34f1260a547274d69c4341852fb55fb..6cc87d8c8682c356bcc95311f6a19f1c7504ba4b 100644 (file)
@@ -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);
 }
 
 /*
index 19d579d74d27f18ae67bb1b5c9adcf93f963a288..16d3b3789a50ad6dc37c758d78922e1d11fe147e 100644 (file)
@@ -159,7 +159,8 @@ void mconsole_proc(struct mc_request *req)
                goto out_kill;
        }
 
-       file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+       file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
+                          current_cred());
        if (IS_ERR(file)) {
                mconsole_reply(req, "Failed to open file", 1, 0);
                goto out_kill;
index 127ec3f072144b7976d19533989cd97cc41da327..2a4d073d2cf12124830ddcd2879485c5f61629b0 100644 (file)
@@ -327,7 +327,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) {
index 31e8730fa2463214f36c2f6b3df9d0f75f6be346..3a1b6ef4f05def923dc49ef49c9bc291ab8f5368 100644 (file)
@@ -393,7 +393,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
 
index 5c4ee70d5cf319311deab818996928af5f2736f6..fb06ed6592121fe8dbdfa79da727f2a6eac921f5 100644 (file)
@@ -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;
index 5787249934c8b01b1603b38677cf5f55ff5a4ed9..d961fa9612c4bf5ada684629fbd1cd755eba1176 100644 (file)
@@ -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=");
index 5c9f67f98d10b43e58b2736d07ca76b8f498faac..c5afc98e2675009ab703a3ae361956d3f284fdf2 100644 (file)
@@ -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->uid;
-               ev->event_data.id.e.euid = task->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->gid;
-               ev->event_data.id.e.egid = task->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);
index 550e80f390a63f87da84f84e9ec0290f75ca7151..0aa66ec4cbdd216789e11c30f8024a219b2e587c 100644 (file)
@@ -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;
index 484299b031f82d49b91dfeb303099a1920824933..8f9f4912de3243e4b118c09c4a346a006dc73981 100644 (file)
@@ -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 */
index 33b6d1b122fb59fdadfdd2f156a0596f37efcc25..55dc70c6b4db093cc5c021bdd722cf59b4873888 100644 (file)
@@ -702,6 +702,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);
@@ -712,11 +713,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;
index 2bccefebff1b4a05caf7f07961751c68e73cc462..aa79280df15dbe2419cadbaf234113f3d1a774a7 100644 (file)
@@ -574,6 +574,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();
@@ -617,8 +618,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);
@@ -967,6 +968,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;
@@ -1174,8 +1176,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,
index 94632264dccf253edf9a07e8278f4b33fa28eaad..185be760833e8b05a2940f13d90af0f9bdcec946 100644 (file)
@@ -277,8 +277,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) {
index 3031e3233dd625302715ff10c3e49ddc4b1aa7f7..a43e4ab7c6c3ebb4fbfed32bd76cc8733989f188 100644 (file)
@@ -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;
 
index 8314d3f43b716f41560e4517d42eaade5cfc1459..8fddfe86a0dcd27f7035426b0f27e9e41e53a4a8 100644 (file)
@@ -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;
index d6cb1a0ca724d772e2d8bec5093ea621bbe8d864..93212e40221ac10d39757a09cdacffb8fb922edb 100644 (file)
@@ -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_wstat *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;
 
index a13b334a391029a60de7426ae1f4684f1fd1f5a3..415d9c67ac1651b17449614221b81ecda5f431fc 100644 (file)
@@ -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;
index 8989c93193ed227e84c786e629f1fd4f1e81ce4c..a19d64b582aac0e2882610b3a5839d88e0bd329d 100644 (file)
@@ -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;
index 3662dd44896b71586e3a493193261d3a1adf92a6..c16d9be1b017c9ad8cdf6289fddad01df22732bd 100644 (file)
@@ -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;
 }
index 7a83819f6ba29144364f0f5769125d0ecb8f03f3..f4360192a9387614b090e4ee6b467c6ee9ae082d 100644 (file)
--- 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;
index b70eea1e8c59c586b89ee13d72cf641e76cabee4..c773680d5c605524b37481fdb4fb7fe83b2e7b7e 100644 (file)
@@ -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;
index 33bf8cbfd05172cc020200d4f4eec08d23eab420..63b7c7afe8df96172b1fe9a11bbf95e1c86c0e36 100644 (file)
@@ -308,7 +308,8 @@ static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid)
                        goto out;
                }
 
-               filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+               filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
+                                  current_cred());
                if (IS_ERR(filp)) {
                        err = PTR_ERR(filp);
                        goto out;
index c7e65bb30ba02b600e1b51d30e11ce78246ef983..7b19802cfef4b158cee241339c92c8f30ac88dd0 100644 (file)
@@ -235,8 +235,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;
index 4b67c2a2d77c51fcc93193dbdd6e31dea2defc14..e02cc8ae5eb326a9fcb05f1557a5d8cc64e7c005 100644 (file)
@@ -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 */
index daae463068e4e45615ba4c2ef03000f99fdfed96..4dd1b623f93748313be9cd4a2de3354bde9f8873 100644 (file)
@@ -106,8 +106,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;
index 204cfd1d76762e22cf2e62bd447fb6c7fd7da0d9..f1f3f4192a609fbbd4be4232b0e525697787be98 100644 (file)
@@ -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) {
index 8fcfa398d35075e1e149b70d62226a6095524ad3..f458c1217c5e8bcceb0065281730e73710c74aab 100644 (file)
@@ -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->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, 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) {
@@ -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);
@@ -1361,6 +1361,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 */
@@ -1388,8 +1389,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->uid);
-       SET_GID(psinfo->pr_gid, p->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;
index 5b5424cb339151db85754685f00e2c168ff37908..aa5b43205e3732a622e849d157b6227bb722ca81 100644 (file)
@@ -404,7 +404,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)
@@ -475,6 +475,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
                                   struct elf_fdpic_params *exec_params,
                                   struct elf_fdpic_params *interp_params)
 {
+       const struct cred *cred = current_cred();
        unsigned long sp, csp, nitems;
        elf_caddr_t __user *argv, *envp;
        size_t platform_len = 0, len;
@@ -623,10 +624,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) 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);
        NEW_AUX_ENT(AT_SECURE,  security_bprm_secureexec(bprm));
        NEW_AUX_ENT(AT_EXECFN,  bprm->exec);
 
@@ -1413,6 +1414,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 */
@@ -1440,8 +1442,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->uid);
-       SET_GID(psinfo->pr_gid, p->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;
index ccb781a6a804121e17e317372eb852243303d687..7bbd5c6b37257ad5beba8180f9249d6f4eb1a6f3 100644 (file)
@@ -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);
index 74e587a5279684f722b5b1733d1444ebf1ee1e35..08644a61616e1e7bb6cacb655de0ad06387d3ada 100644 (file)
@@ -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);
index 877c85409f1f90e8cbd0805bd2dda85359b0a68c..1e7b87497f2640d08fd02638369ba675db33cab6 100644 (file)
@@ -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       */
index 6f21ecb85ce517b07d36d973cfb030d478e08ebf..9d8b978137ad171e7a2db74c276d9fdeabacce04 100644 (file)
@@ -39,7 +39,7 @@ extern int smb_send(struct socket *, struct smb_hdr *,
                        unsigned int /* length */ , struct sockaddr *, bool);
 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);
index c7d341714586fdfc9086c381dc310fe81a371237..683dee4d2f766cc3f4d701998180cbbc12470658 100644 (file)
@@ -836,8 +836,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);
index e962e75e6f7b1e8f3d8011488f2d4c08c490a43e..2f02c52db666f59c8a6abe52a7cd818ea6f6bd03 100644 (file)
@@ -235,11 +235,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                        };
 
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                               args.uid = (__u64) current->fsuid;
+                               args.uid = (__u64) current_fsuid();
                                if (inode->i_mode & S_ISGID)
                                        args.gid = (__u64) inode->i_gid;
                                else
-                                       args.gid = (__u64) current->fsgid;
+                                       args.gid = (__u64) current_fsgid();
                        } else {
                                args.uid = NO_CHANGE_64;
                                args.gid = NO_CHANGE_64;
@@ -271,13 +271,13 @@ 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_uid = current_fsuid();
                                        if (inode->i_mode & S_ISGID)
                                                newinode->i_gid =
                                                        inode->i_gid;
                                        else
                                                newinode->i_gid =
-                                                       current->fsgid;
+                                                       current_fsgid();
                                }
                        }
                }
@@ -375,8 +375,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
                        .device = device_number,
                };
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                       args.uid = (__u64) current->fsuid;
-                       args.gid = (__u64) current->fsgid;
+                       args.uid = (__u64) current_fsuid();
+                       args.gid = (__u64) current_fsgid();
                } else {
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
index ff8c68de4a9205a9d0cd592d8a0c58872b0e8e65..8b7305e73d7eab00188b0aa50569fd05b5271d62 100644 (file)
@@ -1143,11 +1143,11 @@ mkdir_get_info:
                                .device = 0,
                        };
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                               args.uid = (__u64)current->fsuid;
+                               args.uid = (__u64)current_fsuid();
                                if (inode->i_mode & S_ISGID)
                                        args.gid = (__u64)inode->i_gid;
                                else
-                                       args.gid = (__u64)current->fsgid;
+                                       args.gid = (__u64)current_fsgid();
                        } else {
                                args.uid = NO_CHANGE_64;
                                args.gid = NO_CHANGE_64;
@@ -1184,13 +1184,13 @@ mkdir_get_info:
                                if (cifs_sb->mnt_cifs_flags &
                                     CIFS_MOUNT_SET_UID) {
                                        direntry->d_inode->i_uid =
-                                               current->fsuid;
+                                               current_fsuid();
                                        if (inode->i_mode & S_ISGID)
                                                direntry->d_inode->i_gid =
                                                        inode->i_gid;
                                        else
                                                direntry->d_inode->i_gid =
-                                                       current->fsgid;
+                                                       current_fsgid();
                                }
                        }
                }
index 0088a5b5256460cd73737ef12db8e718a0c6902f..f94650683a00355d48f6fa545e72baaf6721e95e 100644 (file)
@@ -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;
index 9ee3f689c2b0c0f78468082658d0aad8cf56791c..8a82d076450b052cb5a5ee628d3441675784362f 100644 (file)
@@ -338,13 +338,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(&cifs_tcp_ses_lock);
                                        list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
                                                ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
-                                               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;
index 8a2370341c7adef9188b23255261b5532ab1f22b..a5bf5771a22a5ad1a1fbee69f8e55aa5b8723094 100644 (file)
@@ -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;
index 29137ff3ca67c155ac2da3d9328258700369195e..466303db2df6acbd11e047338b00739408fa428d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
+#include <linux/cred.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/string.h>
@@ -174,7 +175,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);
index ce432bca95d1f875db17233560d7d7f8cf2dbbfa..c274d949179de383ea86f284e13fa5cd396e77db 100644 (file)
@@ -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;
 }
index e5f49f5385028b865aca64890a588eaa173db042..d1ece79b641144c8fb8697a31d8d2cc3ecac2c0a 100644 (file)
@@ -1393,10 +1393,20 @@ int compat_do_execve(char * filename,
        if (!bprm)
                goto out_ret;
 
+       retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+       if (retval < 0)
+               goto out_free;
+
+       retval = -ENOMEM;
+       bprm->cred = prepare_exec_creds();
+       if (!bprm->cred)
+               goto out_unlock;
+       check_unsafe_exec(bprm);
+
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_kfree;
+               goto out_unlock;
 
        sched_exec();
 
@@ -1410,14 +1420,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);
@@ -1438,19 +1444,16 @@ int compat_do_execve(char * filename,
                goto out;
 
        retval = search_binary_handler(bprm, regs);
-       if (retval >= 0) {
-               /* execve success */
-               security_bprm_free(bprm);
-               acct_update_integrals(current);
-               free_bprm(bprm);
-               return retval;
-       }
+       if (retval < 0)
+               goto out;
 
-out:
-       if (bprm->security)
-               security_bprm_free(bprm);
+       /* execve succeeded */
+       mutex_unlock(&current->cred_exec_mutex);
+       acct_update_integrals(current);
+       free_bprm(bprm);
+       return retval;
 
-out_mm:
+out:
        if (bprm->mm)
                mmput(bprm->mm);
 
@@ -1460,7 +1463,10 @@ out_file:
                fput(bprm->file);
        }
 
-out_kfree:
+out_unlock:
+       mutex_unlock(&current->cred_exec_mutex);
+
+out_free:
        free_bprm(bprm);
 
 out_ret:
index 4a714f6c1bede9c62ad9dc22433f7fda3b3a0396..5d61b7c06e134d3321d483793ac3973ce804de32 100644 (file)
@@ -222,8 +222,8 @@ int devpts_pty_new(struct inode *ptmx_inode, 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;
index 5e95261005b2ac68f2103ae7468f257c57ba89da..c237ccc8581c451e368e3f428278dff3378916aa 100644 (file)
@@ -874,7 +874,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);
        }
@@ -981,7 +981,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);
index 3504cf9df358076c840b2fe48f26000b965116e0..a75026d35d1620ba6986affb8149384d10c66f6c 100644 (file)
@@ -691,7 +691,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 */
index c440c6b58b2da5413ab431198304a5a2820e6891..c6d7a4d748a0b8f25308487fd6f52c6ec40505d1 100644 (file)
@@ -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;
index 64d2ba980df43b28d646fb18efc9842e9b380488..fd630713c5c7be966bb3038904407804e9bde25e 100644 (file)
@@ -115,6 +115,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;
@@ -127,7 +128,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]; "
index c6983978a31eda7218fa921b954848e2d4a5c42c..6913f727624d835870b860f5c3c0f6455eaa33d5 100644 (file)
@@ -360,7 +360,8 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
        struct ecryptfs_msg_ctx *msg_ctx;
        size_t msg_size;
        struct nsproxy *nsproxy;
-       struct user_namespace *current_user_ns;
+       struct user_namespace *tsk_user_ns;
+       uid_t ctx_euid;
        int rc;
 
        if (msg->index >= ecryptfs_message_buf_len) {
@@ -384,9 +385,9 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
                mutex_unlock(&ecryptfs_daemon_hash_mux);
                goto wake_up;
        }
-       current_user_ns = nsproxy->user_ns;
-       rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid,
-                                         current_user_ns);
+       tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
+       ctx_euid = task_euid(msg_ctx->task);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
        rcu_read_unlock();
        mutex_unlock(&ecryptfs_daemon_hash_mux);
        if (rc) {
@@ -394,28 +395,28 @@ 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) {
+       if (tsk_user_ns != user_ns) {
                rc = -EBADMSG;
                printk(KERN_WARNING "%s: Received message from user_ns "
                       "[0x%p]; expected message from user_ns [0x%p]\n",
-                      __func__, user_ns, nsproxy->user_ns);
+                      __func__, user_ns, tsk_user_ns);
                goto unlock;
        }
        if (daemon->pid != pid) {
                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) {
@@ -464,14 +465,14 @@ ecryptfs_send_message_locked(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,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_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);
index b484792a0996c0623b08f054f86c06214da47b3f..efd95a0ed1ea036459667628babd085f7803cd4f 100644 (file)
@@ -42,12 +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,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        BUG_ON(rc || !daemon);
        mutex_lock(&daemon->mux);
        mutex_unlock(&ecryptfs_daemon_hash_mux);
@@ -83,6 +83,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,11 +94,9 @@ 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,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        if (rc || !daemon) {
-               rc = ecryptfs_spawn_daemon(&daemon, current->euid,
-                                          current->nsproxy->user_ns,
+               rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
                                           task_pid(current));
                if (rc) {
                        printk(KERN_ERR "%s: Error attempting to spawn daemon; "
@@ -147,11 +146,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,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        BUG_ON(rc || !daemon);
        mutex_lock(&daemon->mux);
        BUG_ON(daemon->pid != task_pid(current));
@@ -246,12 +245,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,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        BUG_ON(rc || !daemon);
        mutex_lock(&daemon->mux);
        if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
@@ -290,8 +289,8 @@ check_list:
                 * message from the queue; try again */
                goto check_list;
        }
-       BUG_ON(current->euid != daemon->euid);
-       BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
+       BUG_ON(euid != daemon->euid);
+       BUG_ON(current_user_ns() != daemon->user_ns);
        BUG_ON(task_pid(current) != daemon->pid);
        msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
                                   struct ecryptfs_msg_ctx, daemon_out_list);
@@ -414,6 +413,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 +463,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_user_ns(),
                                               task_pid(current), seq);
                if (rc)
                        printk(KERN_WARNING "%s: Failed to deliver miscdev "
index 4e834f16d9da7d49c0f232b9fd46a7db2c680070..32f13e299417cbbc5ef22ada8169bb2807cb543f 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
+#include "internal.h"
 
 #ifdef __alpha__
 /* for /sbin/loader handling in search_binary_handler() */
@@ -980,7 +981,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);
@@ -1007,16 +1008,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) {
-               suid_keys(current);
-               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)) {
-               suid_keys(current);
+                  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 */
 
@@ -1033,13 +1035,50 @@ 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);
+
+       commit_creds(bprm->cred);
+       bprm->cred = NULL;
+
+       /* cred_exec_mutex must be held at least to this point to prevent
+        * ptrace_attach() from altering our determination of the task's
+        * credentials; any time after this it may be unlocked */
+
+       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;
 
@@ -1047,14 +1086,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? */
@@ -1064,52 +1104,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) {
-               suid_keys(current);
-               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
@@ -1262,6 +1273,8 @@ EXPORT_SYMBOL(search_binary_handler);
 void free_bprm(struct linux_binprm *bprm)
 {
        free_arg_pages(bprm);
+       if (bprm->cred)
+               abort_creds(bprm->cred);
        kfree(bprm);
 }
 
@@ -1287,10 +1300,20 @@ int do_execve(char * filename,
        if (!bprm)
                goto out_files;
 
+       retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+       if (retval < 0)
+               goto out_free;
+
+       retval = -ENOMEM;
+       bprm->cred = prepare_exec_creds();
+       if (!bprm->cred)
+               goto out_unlock;
+       check_unsafe_exec(bprm);
+
        file = open_exec(filename);
        retval = PTR_ERR(file);
        if (IS_ERR(file))
-               goto out_kfree;
+               goto out_unlock;
 
        sched_exec();
 
@@ -1304,14 +1327,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);
@@ -1333,21 +1352,18 @@ int do_execve(char * filename,
 
        current->flags &= ~PF_KTHREAD;
        retval = search_binary_handler(bprm,regs);
-       if (retval >= 0) {
-               /* execve success */
-               security_bprm_free(bprm);
-               acct_update_integrals(current);
-               free_bprm(bprm);
-               if (displaced)
-                       put_files_struct(displaced);
-               return retval;
-       }
+       if (retval < 0)
+               goto out;
 
-out:
-       if (bprm->security)
-               security_bprm_free(bprm);
+       /* execve succeeded */
+       mutex_unlock(&current->cred_exec_mutex);
+       acct_update_integrals(current);
+       free_bprm(bprm);
+       if (displaced)
+               put_files_struct(displaced);
+       return retval;
 
-out_mm:
+out:
        if (bprm->mm)
                mmput (bprm->mm);
 
@@ -1356,7 +1372,11 @@ out_file:
                allow_write_access(bprm->file);
                fput(bprm->file);
        }
-out_kfree:
+
+out_unlock:
+       mutex_unlock(&current->cred_exec_mutex);
+
+out_free:
        free_bprm(bprm);
 
 out_files:
@@ -1388,6 +1408,7 @@ EXPORT_SYMBOL(set_binfmt);
  */
 static int format_corename(char *corename, long signr)
 {
+       const struct cred *cred = current_cred();
        const char *pat_ptr = core_pattern;
        int ispipe = (*pat_ptr == '|');
        char *out_ptr = corename;
@@ -1424,7 +1445,7 @@ static int format_corename(char *corename, 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;
@@ -1432,7 +1453,7 @@ static int format_corename(char *corename, 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;
@@ -1708,8 +1729,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;
@@ -1722,12 +1744,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;
        }
 
@@ -1738,12 +1768,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->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
@@ -1815,7 +1849,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;
@@ -1834,7 +1868,8 @@ fail_unlock:
        if (helper_argv)
                argv_free(helper_argv);
 
-       current->fsuid = fsuid;
+       revert_creds(old_cred);
+       put_cred(cred);
        coredump_finish(mm);
 fail:
        return retval;
index 80246bad1b7fe513a7da15f4d6ac057cad3d7e54..ec1fb918200f7bc201c76e734cf12ed3ce250940 100644 (file)
@@ -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)
 
@@ -249,6 +250,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;
@@ -263,7 +265,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;
index 6dac7ba2d22d7ff41855b7866f757417612c09ea..4a29d6376081db526331f738b51dc6efe8f29e0b 100644 (file)
@@ -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;
        }
index f597413467605ab8f6c7a1cef2cc0e1d269c7b9d..8d0add62587020ab8299e33dd8a6b5ac4edae500 100644 (file)
@@ -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;
index f5b57a2ca35a5c4cb10a369933bec40291c78109..0dbf1c0484752f8108dc16b6530e60ae281c1648 100644 (file)
@@ -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;
        }
index 47b678d73e7a53d28ef1d0d35eae758bd87e54d7..490bd0ed789693dbb65ec6deb318541d06ed3911 100644 (file)
@@ -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;
index d2003cdc36aa687ab998a8c558144ddcc23ae6bb..a932b9a2924093a134b41c4a66bea413af4d7625 100644 (file)
@@ -624,7 +624,7 @@ int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
                return 1;
 
        /* Hm, nope.  Are (enough) root reserved blocks available? */
-       if (sbi->s_resuid == current->fsuid ||
+       if (sbi->s_resuid == current_fsuid() ||
            ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
            capable(CAP_SYS_RESOURCE)) {
                if (free_blocks >= (nblocks + dirty_blocks))
index 2a117e286e5420c6d5567961a14b340162b14a67..08cac9fcace287e9c9fbd29677a4ba8e84009290 100644 (file)
@@ -787,7 +787,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) {
@@ -795,7 +795,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);
index f06a4e525eceff2b758ba0ff62ebd6e6f2fca9bb..0a7f4a9918b346d117a814b1911f11e1b72b22c7 100644 (file)
@@ -304,7 +304,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)
index bdd8fb7be2ca48e5ac4e49b5b2dd147375f6c8b2..d937aaf77374f4b720aa85328da0779daad027ae 100644 (file)
@@ -926,8 +926,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;
index ac4f7db9f13452790e4d41daa8e6fc9633506259..87c39f1f0817c1d9b6c05f3da6f17730b2453941 100644 (file)
@@ -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);
@@ -400,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->suid) || (fown->euid == p->uid) ||
-                (fown->uid == p->suid) || (fown->uid == p->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,
index 5ad0eca6eea27b1ee33fcd8415c05edfeac97d82..0fbcacc3ea754a01e92e2529f7955ea1fcf08c13 100644 (file)
@@ -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);
 }
 
@@ -94,7 +96,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 +120,10 @@ 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->fsuid;
-       f->f_gid = tsk->fsgid;
+       f->f_cred = get_cred(cred);
        eventpoll_init_file(f);
        /* f->f_version: 0 */
        return f;
index b72361479be25789e8caa4e6be5febe1f276419e..fba571648a8e43efdbbb092a5f20a03a7e84f1e5 100644 (file)
@@ -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;
 }
 
index fd03330cadeb135979c5229eb861c89155df8de9..95bc22bdd0604e4562ec35b2ae286225530ad0bf 100644 (file)
@@ -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->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)
-               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)
index 7cee695fa44163f378293945514b1e4a9bbfd084..d57616840e893c729e7ce67948d30f69dac005f4 100644 (file)
@@ -705,18 +705,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)
@@ -1124,8 +1124,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))
index c69b7ac75bf7d16bb53f6f1603e9a47019a2071b..9435dda8f1e015c27d20f84c167917b064816316 100644 (file)
@@ -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;
index 3c7c7637719cfd6e83531402e0759f38c794e3a6..c8b5acf4b0b7c086953e5526677bf30c740272d4 100644 (file)
@@ -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); /* == '????' */
index b207f0e6fc22cec1feb87b127016f622b169656d..f105ee9e1cc4aad0e244e19c883e77c610954294 100644 (file)
@@ -296,8 +296,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);
index 9699c56d323f1d35a60f2beac0b31059a5207bac..bab7f8d1bdfa9f97ad8f3c85786daf9ecbc3c9df 100644 (file)
@@ -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;
 }
index 10783f3d265abd8876502fa63bebad1be2f3be35..b649232dde97baf4eac591548b7944c5aedcc666 100644 (file)
@@ -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);
index 29ad461d568f7f4b4241e3e0c4d2239bbe30a277..0d049b8919c42ed1c62871f26815994a5f00e254 100644 (file)
@@ -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;
index 2b3d1828db99a2a68a3e5fef961f0f6740cf04c8..b278f7f52024ba556d32604ac61cab01e114f39b 100644 (file)
@@ -426,6 +426,7 @@ static int file_mode(int fmode)
 
 static int hppfs_open(struct inode *inode, struct file *file)
 {
+       const struct cred *cred = file->f_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 = file->f_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;
index 61edc701b0e62eed87d702373e2c9a36d4b23581..7d479ce3aceb602c687a7f022a7d3d6c1284de0f 100644 (file)
@@ -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);
@@ -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->user))
+       if (!user_shm_lock(size, user))
                return ERR_PTR(-ENOMEM);
 
        root = hugetlbfs_vfsmount->mnt_root;
@@ -970,8 +971,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;
 
@@ -998,7 +999,7 @@ out_inode:
 out_dentry:
        dput(dentry);
 out_shm_unlock:
-       user_shm_unlock(size, current->user);
+       user_shm_unlock(size, user);
        return ERR_PTR(error);
 }
 
index d367e9b9286276db8c686c96485d29fefdbe876e..e2425bbd871f8bc5cd2fd80e962d5638f28e5832 100644 (file)
@@ -601,7 +601,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;
index 80aa9a023372d4356524824854fba73ac89dc4ec..53af885f173243df3a5bf0906b589edccece84db 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 struct super_block;
+struct linux_binprm;
 
 /*
  * block_dev.c
@@ -39,6 +40,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
  */
index da3cc460d4df4d16f3afb81fea786589948a2c18..3569e0ad86a2e0ccc96cef6862b93b1e19f7b14e 100644 (file)
@@ -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->uid != current->euid &&
-           task->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)
@@ -123,7 +129,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
                        break;
                case IOPRIO_WHO_USER:
                        if (!who)
-                               user = current->user;
+                               user = current_user();
                        else
                                user = find_user(who);
 
@@ -131,7 +137,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
                                break;
 
                        do_each_thread(g, p) {
-                               if (p->uid != who)
+                               if (__task_cred(p)->uid != who)
                                        continue;
                                ret = set_task_ioprio(p, ioprio);
                                if (ret)
@@ -216,7 +222,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
                        break;
                case IOPRIO_WHO_USER:
                        if (!who)
-                               user = current->user;
+                               user = current_user();
                        else
                                user = find_user(who);
 
@@ -224,7 +230,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
                                break;
 
                        do_each_thread(g, p) {
-                               if (p->uid != user->uid)
+                               if (__task_cred(p)->uid != user->uid)
                                        continue;
                                tmpio = get_task_ioprio(p);
                                if (tmpio < 0)
index ed6574bee51a211ea1c46f82e04d01625308577b..70022fd1c5399f0b6c85ec0d5ceee8e13269cb0d 100644 (file)
@@ -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
index 09062e3ff104d7222d4725d757c5493da3ad68fa..46a2e12f7d422992e5f6e48cbc6fb9f07b225e3b 100644 (file)
@@ -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;
index 703cc35e04b94ce6126ae390f03f066c0fb26618..3aebe322271a67cbe7abd5dd738f6ec9a88a981a 100644 (file)
@@ -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;
index d34e0f9681c6557d83852cf04646afbf9e670d98..af3783fff1de66ee922411dac7d5ad92811291d7 100644 (file)
@@ -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) {
@@ -441,7 +441,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;
@@ -1334,11 +1334,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);
 }
index 65b3dc844c879c059c004425487672eff21b5682..1c09cab8f7cf7c4faea9b1e0e4aa8fc6382824c4 100644 (file)
@@ -1176,7 +1176,7 @@ static int mount_is_safe(struct path *path)
        if (S_ISLNK(path->dentry->d_inode->i_mode))
                return -EPERM;
        if (path->dentry->d_inode->i_mode & S_ISVTX) {
-               if (current->uid != path->dentry->d_inode->i_uid)
+               if (current_uid() != path->dentry->d_inode->i_uid)
                        return -EPERM;
        }
        if (inode_permission(path->dentry->d_inode, MAY_WRITE))
index 3a97c95e1ca243111330fb82a69130c6353b7368..6d04e050c74ed89ab7f4bbb18c28d40e002bb904 100644 (file)
@@ -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;
 
index aed8145d9087e053a9349a46c07bd03ac6b02ed5..b1acbd6ab6fb07c857b910f518a53736d8bd3631 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/syscall.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
 #include <linux/linkage.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
@@ -41,7 +43,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);
index 294992e9bf69e18b17a52964dd0af23841894f26..0184fe9b514cc2dbdb1b50c15900f927272c5fd3 100644 (file)
@@ -27,53 +27,70 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
 
 int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 {
-       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;
 
+       /* discard any old override before preparing the new set */
+       revert_creds(get_cred(current->real_cred));
+       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)
-               current->fsuid = cred.cr_uid;
-       else
-               current->fsuid = exp->ex_anon_uid;
-       if (cred.cr_gid != (gid_t) -1)
-               current->fsgid = cred.cr_gid;
-       else
-               current->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_current_groups(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);
+               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 {
-               current->cap_effective =
-                       cap_raise_nfsd_set(current->cap_effective,
-                                          current->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);
+       put_cred(override_creds(new));
+       return 0;
+
+oom:
+       ret = -ENOMEM;
+error:
+       abort_creds(new);
        return ret;
 }
+
index b79ec930d9f1af003ddfb1fd9d130b12f6755f8b..0f9d6efaa62bb553bb95b3063516bcb793f52929 100644 (file)
 static struct path 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->fsuid;
-       *savegid = current->fsgid;
-       current->fsuid = 0;
-       current->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->fsuid = saveuid;
-       current->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.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,26 +218,29 @@ 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;
        INIT_LIST_HEAD(dentries);
 
-       filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY);
+       filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
+                          current_cred());
        status = PTR_ERR(filp);
        if (IS_ERR(filp))
                goto out;
+       INIT_LIST_HEAD(dentries);
        status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
        fput(filp);
        while (!list_empty(dentries)) {
@@ -249,7 +259,7 @@ out:
                dput(child->dentry);
                kfree(child);
        }
-       nfs4_reset_user(uid, gid);
+       nfs4_reset_creds(original_cred);
        return status;
 }
 
@@ -311,8 +321,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)
@@ -322,9 +331,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.mnt);
@@ -401,16 +414,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 = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
                        &rec_dir);
@@ -420,7 +438,7 @@ nfsd4_init_recdir(char *rec_dirname)
 
        if (!status)
                rec_dir_init = 1;
-       nfs4_reset_user(uid, gid);
+       nfs4_reset_creds(original_cred);
 }
 
 void
index cd25d91895a19fc0906b3e5b1891bed123cff15b..f0da7d9c3a92eabdc5e52850d8d918537ee8742c 100644 (file)
@@ -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->cap_effective =
-                       cap_raise_nfsd_set(current->cap_effective,
-                                          current->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)
index 4433c8f001635862419edb603ecf5725462f3222..d1c5f787b365dc727fb65b81ca33e3cfb0ca2555 100644 (file)
@@ -671,6 +671,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;
@@ -725,7 +726,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:
@@ -1169,7 +1170,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);
@@ -2001,7 +2002,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
@@ -2044,7 +2045,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} */
index ba962d71b34d15e7e089c741a9d6bd0d14559e79..6f7a77d5402001071f4f75a6f7ccbf5cf666a537 100644 (file)
@@ -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;
index f4967e634ffd01283e299bb6a7ee0d886048b813..2545e7402efed1453d69347c676beaf2231043e0 100644 (file)
@@ -421,13 +421,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));
index cbf047a847c5e3d6c3558d16cce217b475e9163c..6afe57c84f849f33560981ed87f9d5a3b2c96afd 100644 (file)
@@ -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;
 
@@ -420,8 +420,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))
index 83cdb9dee0c10ba29d3e2c793b2f4fffbc6522d9..c0a426d5766cfb451434b8555be388b9bddd8d47 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -425,39 +425,33 @@ out:
  */
 asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
 {
+       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 = current->fsuid;
-       old_fsgid = current->fsgid;
+       override_cred = prepare_creds();
+       if (!override_cred)
+               return -ENOMEM;
 
-       current->fsuid = current->uid;
-       current->fsgid = current->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
-                */
-#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 */
-               if (current->uid)
-                       old_cap = cap_set_effective(__cap_empty_set);
+               /* Clear the capabilities if we switch to a non-root user */
+               if (override_cred->uid)
+                       cap_clear(override_cred->cap_effective);
                else
-                       old_cap = cap_set_effective(current->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;
@@ -494,12 +488,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;
-
-       if (!issecure(SECURE_NO_SETUID_FIXUP))
-               cap_set_effective(old_cap);
-
+       revert_creds(old_cred);
+       put_cred(override_cred);
        return res;
 }
 
@@ -792,7 +782,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;
@@ -816,7 +807,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;
 
@@ -891,6 +882,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))
@@ -898,7 +891,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:
@@ -917,6 +910,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 */
@@ -924,7 +918,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;
@@ -934,7 +928,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;
@@ -959,7 +954,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);
 
index 7aea8b89baac9c8b550d17f8c14f592d63e08981..aaf797bd57b9f1a29d4fef90bcd2367dbe9cd32b 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -899,8 +899,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;
index aec931e09973716240bf55441622dccf95cf3c74..39df95a0ec25edc87e7c3e29aef2b9a707f95f9f 100644 (file)
@@ -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:
index 6af7fba7abb1832d66c5ae15b5dafa12a0f819c6..7e4877d9dcb58b71720cb6cd79a690b3149d44bb 100644 (file)
@@ -159,6 +159,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();
@@ -170,6 +171,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"
@@ -182,8 +184,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);
+               cred->uid, cred->euid, cred->suid, cred->fsuid,
+               cred->gid, cred->egid, cred->sgid, cred->fsgid);
 
        task_lock(p);
        if (p->files)
@@ -194,13 +196,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->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");
 }
@@ -262,7 +263,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(&__task_cred(p)->user->sigpending);
                qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
                unlock_task_sighand(p, &flags);
        }
@@ -293,10 +294,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)
 {
-       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);
+       const struct cred *cred;
+       kernel_cap_t cap_inheritable, cap_permitted, cap_effective, 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,
index 486cf3fe7139949a0911e0e33f9cb99a06bfb8fb..cf42c42cbfbbf5db12491dc769585f4a0c7f4229 100644 (file)
@@ -1406,6 +1406,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 */
 
@@ -1428,8 +1429,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->euid;
-               inode->i_gid = task->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);
 
@@ -1445,6 +1449,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();
@@ -1454,8 +1460,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->euid;
-                       stat->gid = task->egid;
+                       cred = __task_cred(task);
+                       stat->uid = cred->euid;
+                       stat->gid = cred->egid;
                }
        }
        rcu_read_unlock();
@@ -1483,11 +1490,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->euid;
-                       inode->i_gid = task->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;
@@ -1649,6 +1661,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);
@@ -1658,8 +1671,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->euid;
-                                       inode->i_gid = task->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;
index 7f4386ebc23a26b98f97d5088ecff7c79369fe17..b7fe44e01618ed8b67dbae7814bc3a5ee8927b26 100644 (file)
@@ -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;
index f031d1c925f0b72ff562a5b839674eb94b4ecf94..a83a3518ae331134458a72df0208249a90b8ee09 100644 (file)
@@ -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;
index f89ebb943f3f1f6a2f219db1a9ec9fd2275e5f0e..4f322e5ed8405f63e3f980256de23b9acc2c9849 100644 (file)
@@ -573,7 +573,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 */
@@ -584,7 +584,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;
index 48da4fa6b7d4847f67a54627a2d59f053857dcf3..e7ddd0328ddc79ce22f95896ba3dd063d275b73e 100644 (file)
@@ -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;
index 3528f40ffb0f0c137dfcd32b6e69a928dee5e400..fc27fbfc5397cb4777ce833a229e5cc9f9c13c5d 100644 (file)
@@ -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);
 
        /*
index ee536e8a649a28710fe89417265fc5bce0a1119d..9468168b9af5e6f22bdbcfb178d91d98d15a75d0 100644 (file)
@@ -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;
 
index 115ab0d6f4bcab86b06243cd107f92c082285c00..241e9765cfadfd9f2f9bd1f68fd355e8c5358959 100644 (file)
@@ -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;
index 1a4973e106643dd2badce2eaeb805f82be0744a4..4a18f084cc427a7df83214055d9efa023a549444 100644 (file)
@@ -363,7 +363,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;
index 0422c98e17932e41ecca3f25c6dea8aedb10e133..f448ab1f9c38eb7861ec62ad998fdebce72e1aa9 100644 (file)
@@ -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);
index a4f2b3ce45b053ca76168a01d93b38974d34a949..31fc84297ddb545809e2033a2b5d6c4bf427716a 100644 (file)
@@ -126,13 +126,13 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
        }
        mutex_unlock(&sbi->s_alloc_mutex);
        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;
index 082409cd4b8aec78918c697cc4666fe937cb26be..f84bfaa8d941bf2ba6b60793ea34d081c9c2fb2d 100644 (file)
@@ -604,7 +604,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) {
index ac181f6806a3f253e1fe70afe67f1a88da34018d..6f5dcf0060960c9999397fe64820a8db86c31c6d 100644 (file)
@@ -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;
index 652721ce0ea5ecd0bb19d53c519facf9a62026a6..8c022cd0ad672dc9f68687c54cb305dc5f846a19 100644 (file)
 /*
  * 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)
index 2770b0085ee869bedac0def84d8cdf3e37964c6f..6eda8a3eb6f18f87bb2b87fa94933fc42a4f9c49 100644 (file)
@@ -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__ */
index d3438c72dcaf555b8d18174a00d1b6eab264615f..281cbd5a25cfd1550645370cf339e0e251d1f721 100644 (file)
@@ -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;
@@ -321,7 +322,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));
@@ -1007,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;
        }
index b2f639a1416f0ecd1c0b91e4958584de823c3a46..91d69338d3b214c9ff8339217cf4834c842d6045 100644 (file)
@@ -366,7 +366,7 @@ xfs_acl_allow_set(
                return ENOTDIR;
        if (vp->i_sb->s_flags & MS_RDONLY)
                return EROFS;
-       if (XFS_I(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER))
+       if (XFS_I(vp)->i_d.di_uid != current_fsuid() && !capable(CAP_FOWNER))
                return EPERM;
        return 0;
 }
@@ -413,13 +413,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;
index 1420c49674d7451f196fabbd1df76b731dfc7703..6be310d41daf105556239a2f338dafaeb940e35f 100644 (file)
@@ -497,7 +497,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 *);
index e932a96bec54994615819245a277fb7ca4cfe8fb..7b0c2ab88333885b5f9075b1b99c2d14b71b4578 100644 (file)
@@ -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/keys/keyring-type.h b/include/keys/keyring-type.h
new file mode 100644 (file)
index 0000000..843f872
--- /dev/null
@@ -0,0 +1,31 @@
+/* Keyring key type
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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 */
index 6272a395d43c0b73a6ef4fd5d0a19062d6154a38..e8ce2c4c7ac7e3a8782a230930774175ce17a37d 100644 (file)
@@ -99,6 +99,8 @@
 #define AUDIT_OBJ_PID          1318    /* ptrace target */
 #define AUDIT_TTY              1319    /* Input on an administrative TTY */
 #define AUDIT_EOE              1320    /* End of multi-record event */
+#define AUDIT_BPRM_FCAPS       1321    /* Information about fcaps increasing perms */
+#define AUDIT_CAPSET           1322    /* Record showing argument to sys_capset */
 
 #define AUDIT_AVC              1400    /* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR      1401    /* Internal SE Linux Errors */
@@ -452,6 +454,10 @@ extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_pr
 extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
 extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
 extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
+extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
+                                 const struct cred *new,
+                                 const struct cred *old);
+extern int __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old);
 
 static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
@@ -501,6 +507,24 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
                return __audit_mq_getsetattr(mqdes, mqstat);
        return 0;
 }
+
+static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
+                                      const struct cred *new,
+                                      const struct cred *old)
+{
+       if (unlikely(!audit_dummy_context()))
+               return __audit_log_bprm_fcaps(bprm, new, old);
+       return 0;
+}
+
+static inline int audit_log_capset(pid_t pid, const struct cred *new,
+                                  const struct cred *old)
+{
+       if (unlikely(!audit_dummy_context()))
+               return __audit_log_capset(pid, new, old);
+       return 0;
+}
+
 extern int audit_n_rules;
 extern int audit_signals;
 #else
@@ -532,6 +556,8 @@ extern int audit_signals;
 #define audit_mq_timedreceive(d,l,p,t) ({ 0; })
 #define audit_mq_notify(d,n) ({ 0; })
 #define audit_mq_getsetattr(d,s) ({ 0; })
+#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; })
+#define audit_log_capset(pid, ncr, ocr) ({ 0; })
 #define audit_ptrace(t) ((void)0)
 #define audit_n_rules 0
 #define audit_signals 0
index 7394b5b349ffc82c2ea42e51188dc3839229fed1..6cbfbe297180595911709bccd3976aa97cbf1014 100644 (file)
@@ -35,16 +35,20 @@ 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 */
 #ifdef __alpha__
        unsigned int taso:1;
 #endif
        unsigned int recursion_depth;
        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
@@ -101,7 +105,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 *);
index 9d1fe30b6f6c1226b7fe6e6d37937c2d50be70ac..e22f48c2a46f78d2d40932afaaefb9afae2d3602 100644 (file)
@@ -53,6 +53,7 @@ typedef struct __user_cap_data_struct {
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
 #define VFS_CAP_REVISION_MASK  0xFF000000
+#define VFS_CAP_REVISION_SHIFT 24
 #define VFS_CAP_FLAGS_MASK     ~VFS_CAP_REVISION_MASK
 #define VFS_CAP_FLAGS_EFFECTIVE        0x000001
 
@@ -68,6 +69,9 @@ typedef struct __user_cap_data_struct {
 #define VFS_CAP_U32             VFS_CAP_U32_2
 #define VFS_CAP_REVISION       VFS_CAP_REVISION_2
 
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+extern int file_caps_enabled;
+#endif
 
 struct vfs_cap_data {
        __le32 magic_etc;            /* Little endian */
@@ -96,6 +100,13 @@ typedef struct kernel_cap_struct {
        __u32 cap[_KERNEL_CAPABILITY_U32S];
 } kernel_cap_t;
 
+/* exact same as vfs_cap_data but in cpu endian and always filled completely */
+struct cpu_vfs_cap_data {
+       __u32 magic_etc;
+       kernel_cap_t permitted;
+       kernel_cap_t inheritable;
+};
+
 #define _USER_CAP_HEADER_SIZE  (sizeof(struct __user_cap_header_struct))
 #define _KERNEL_CAP_T_SIZE     (sizeof(kernel_cap_t))
 
@@ -454,6 +465,13 @@ static inline int cap_isclear(const kernel_cap_t a)
        return 1;
 }
 
+/*
+ * Check if "a" is a subset of "set".
+ * return 1 if ALL of the capabilities in "a" are also in "set"
+ *     cap_issubset(0101, 1111) will return 1
+ * return 0 if ANY of the capabilities in "a" are not in "set"
+ *     cap_issubset(1111, 0101) will return 0
+ */
 static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
 {
        kernel_cap_t dest;
@@ -501,8 +519,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
@@ -514,9 +530,14 @@ kernel_cap_t cap_set_effective(const kernel_cap_t pE_new);
  * Note that this does not set PF_SUPERPRIV on the task.
  */
 #define has_capability(t, cap) (security_capable((t), (cap)) == 0)
+#define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0)
 
 extern int capable(int cap);
 
+/* audit system wants to get cap info from files as well */
+struct dentry;
+extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
+
 #endif /* __KERNEL__ */
 
 #endif /* !_LINUX_CAPABILITY_H */
index b69222cc1fd27c1811ae473f1eccc4e5f69dd07c..3282ee4318e7b98791fae49bac5510114d8f1420 100644 (file)
@@ -1,4 +1,4 @@
-/* Credentials management
+/* Credentials management - see Documentation/credentials.txt
  *
  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
 #ifndef _LINUX_CRED_H
 #define _LINUX_CRED_H
 
-#define get_current_user()     (get_uid(current->user))
+#include <linux/capability.h>
+#include <linux/key.h>
+#include <asm/atomic.h>
 
-#define task_uid(task)         ((task)->uid)
-#define task_gid(task)         ((task)->gid)
-#define task_euid(task)                ((task)->euid)
-#define task_egid(task)                ((task)->egid)
+struct user_struct;
+struct cred;
+struct inode;
 
-#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)
+/*
+ * 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 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.
+ */
+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
+ * @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 struct group_info init_groups;
+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(const 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 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:
+ *
+ *  (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->real_cred 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->cred 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->real_cred.
+ */
+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 */
+       struct thread_group_cred *tgcred; /* thread-group shared credentials */
+#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 */
+};
+
+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 *);
+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);
+
+/**
+ * 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
+ * @cred: The credentials to reference
+ *
+ * Get a reference on the specified set of credentials.  The caller must
+ * release the reference.
+ *
+ * This is used to deal with a committed set of credentials.  Although the
+ * pointer is const, this will temporarily discard the const and increment the
+ * usage count.  The purpose of this is to attempt to catch at compile time the
+ * accidental alteration of a set of credentials that should be considered
+ * immutable.
+ */
+static inline const struct cred *get_cred(const struct cred *cred)
+{
+       return get_new_cred((struct cred *) 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.
+ *
+ * This takes a const pointer to a set of credentials because the credentials
+ * on task_struct are attached by const pointers to prevent accidental
+ * alteration of otherwise immutable credential sets.
+ */
+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);
+}
+
+/**
+ * current_cred - Access the current task's subjective credentials
+ *
+ * Access the subjective credentials of the current task.
+ */
+#define current_cred() \
+       (current->cred)
+
+/**
+ * __task_cred - Access a task's objective credentials
+ * @task: The task to query
+ *
+ * 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)->real_cred)))
+
+/**
+ * get_task_cred - Get another task's objective credentials
+ * @task: The task to query
+ *
+ * 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.
+ */
+#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 subjective credentials
+ *
+ * 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()))
+
+/**
+ * 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__(((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))
+#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_user_ns()      (current_cred_xxx(user)->user_ns)
+#define current_security()     (current_cred_xxx(security))
 
 #define current_uid_gid(_uid, _gid)            \
 do {                                           \
-       *(_uid) = current->uid;                 \
-       *(_gid) = current->gid;                 \
+       const struct cred *__cred;              \
+       __cred = current_cred();                \
+       *(_uid) = __cred->uid;                  \
+       *(_gid) = __cred->gid;                  \
 } while(0)
 
-#define current_euid_egid(_uid, _gid)          \
+#define current_euid_egid(_euid, _egid)                \
 do {                                           \
-       *(_uid) = current->euid;                \
-       *(_gid) = current->egid;                \
+       const struct cred *__cred;              \
+       __cred = current_cred();                \
+       *(_euid) = __cred->euid;                \
+       *(_egid) = __cred->egid;                \
 } while(0)
 
-#define current_fsuid_fsgid(_uid, _gid)                \
+#define current_fsuid_fsgid(_fsuid, _fsgid)    \
 do {                                           \
-       *(_uid) = current->fsuid;               \
-       *(_gid) = current->fsgid;               \
+       const struct cred *__cred;              \
+       __cred = current_cred();                \
+       *(_fsuid) = __cred->fsuid;              \
+       *(_fsgid) = __cred->fsgid;              \
 } while(0)
 
 #endif /* _LINUX_CRED_H */
index 0dcdd9458f4bcce56d1a89c566892f5d5097e876..c0fb6d81d89b03b5126524e8222bec3fd325c320 100644 (file)
@@ -315,6 +315,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);
@@ -826,7 +827,7 @@ struct file {
        fmode_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;
@@ -1193,7 +1194,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 *);
@@ -1673,7 +1674,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 *);
 
index 23fd8909b9e52c143faf401030e8d282c559baeb..959f5522d10aab9cde46808f1449eeeed3c0fb4e 100644 (file)
@@ -57,7 +57,6 @@ extern struct nsproxy init_nsproxy;
        .mnt_ns         = NULL,                                         \
        INIT_NET_NS(net_ns)                                             \
        INIT_IPC_NS(ipc_ns)                                             \
-       .user_ns        = &init_user_ns,                                \
 }
 
 #define INIT_SIGHAND(sighand) {                                                \
@@ -113,6 +112,8 @@ extern struct group_info init_groups;
 # define CAP_INIT_BSET  CAP_INIT_EFF_SET
 #endif
 
+extern struct cred init_cred;
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -147,13 +148,10 @@ 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,                                    \
+       .real_cred      = &init_cred,                                   \
+       .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-ui.h b/include/linux/key-ui.h
deleted file mode 100644 (file)
index e8b8a7a..0000000
+++ /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 (dhowells@redhat.com)
- *
- * 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 */
index 1b70e35a71e378808454a60429c478c20200fe48..21d32a142c002b47da72abb18d9761a3e88aee11 100644 (file)
@@ -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,24 +277,11 @@ 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 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 int install_thread_keyring_to_cred(struct cred *cred);
 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;                                            \
-})
-
 #else /* CONFIG_KEYS */
 
 #define key_validate(k)                        0
@@ -302,17 +290,9 @@ extern void key_init(void);
 #define key_revoke(k)                  do { } while(0)
 #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 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)
 #define key_fsgid_changed(t)           do { } while(0)
 #define key_init()                     do { } while(0)
index 656ee6b77a4a337d2dcdd728e8a1d79af83ba5ad..c0688eb7209396bf8ca3d5ba3202f6b8033ef981 100644 (file)
@@ -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 (dhowells@redhat.com)
  *
  * 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 */
index c8a768e59640665af635cedb9c84745e421fdbab..afad7dec1b36fd2fee9e967c804f6b3f87a69bf8 100644 (file)
@@ -27,7 +27,6 @@ struct nsproxy {
        struct ipc_namespace *ipc_ns;
        struct mnt_namespace *mnt_ns;
        struct pid_namespace *pid_ns;
-       struct user_namespace *user_ns;
        struct net           *net_ns;
 };
 extern struct nsproxy init_nsproxy;
index 55e30d11447790dd433d0e874285ced3a5499328..9624e2cfc2dcdd36b193aed42befca13c35bb2fc 100644 (file)
@@ -572,12 +572,6 @@ struct signal_struct {
         */
        struct rlimit rlim[RLIM_NLIMITS];
 
-       /* 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
@@ -648,6 +642,7 @@ struct user_struct {
        /* Hash table maintenance information */
        struct hlist_node uidhash_node;
        uid_t uid;
+       struct user_namespace *user_ns;
 
 #ifdef CONFIG_USER_SCHED
        struct task_group *tg;
@@ -665,6 +660,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;
 
@@ -888,38 +884,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);
@@ -1186,17 +1151,12 @@ 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
+       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
                                     - access with [gs]et_task_comm (which lock
                                       it with task_lock())
@@ -1233,9 +1193,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;
@@ -1775,7 +1732,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>
@@ -1794,9 +1750,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 *);
@@ -1928,6 +1881,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.
index 92f09bdf11752dcbbe579f1e9f239dfb70036266..d2c5ed845bcc4a740b4e30b22bd0995f821a1ed9 100644 (file)
@@ -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_xxx(securebits))
 
 #define SECURE_ALL_BITS                (issecure_mask(SECURE_NOROOT) | \
                                 issecure_mask(SECURE_NO_SETUID_FIXUP) | \
index e3d4ecda267381d85da5697b2ad681c1da749fe3..6423abf1ac0faee1385d460bcd9951b1bd85a955 100644 (file)
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX      10
 
+/* If capable should audit the security request */
+#define SECURITY_CAP_NOAUDIT 0
+#define SECURITY_CAP_AUDIT 1
+
 struct ctl_table;
 struct audit_krule;
 
@@ -44,25 +48,25 @@ struct audit_krule;
  * These functions are in security/capability.c and are used
  * as the default capabilities functions
  */
-extern int cap_capable(struct task_struct *tsk, int cap);
+extern int cap_capable(struct task_struct *tsk, int cap, int audit);
 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_bprm_set_security(struct linux_binprm *bprm);
-extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+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_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);
 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);
@@ -105,7 +109,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
@@ -149,36 +153,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 hook function (and its caller) are void, this hook can not
- *     return an error.  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
@@ -191,15 +166,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
@@ -585,15 +575,31 @@ 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
- *     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.
+ * @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.
+ * @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
@@ -606,15 +612,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:
@@ -717,13 +721,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.
@@ -1000,7 +999,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
@@ -1162,6 +1161,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.
@@ -1185,29 +1185,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 @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.
- *     @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 @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.
+ *     @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.
@@ -1299,15 +1285,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) (struct task_struct *target,
-                            kernel_cap_t *effective,
-                            kernel_cap_t *inheritable,
-                            kernel_cap_t *permitted);
-       void (*capset_set) (struct task_struct *target,
-                           kernel_cap_t *effective,
-                           kernel_cap_t *inheritable,
-                           kernel_cap_t *permitted);
-       int (*capable) (struct task_struct *tsk, int cap);
+       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 audit);
        int (*acct) (struct file *file);
        int (*sysctl) (struct ctl_table *table, int op);
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
@@ -1316,13 +1299,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);
-       void (*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);
@@ -1406,14 +1387,18 @@ 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 (*task_alloc_security) (struct task_struct *p);
-       void (*task_free_security) (struct task_struct *p);
+       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 (*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_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);
@@ -1433,8 +1418,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);
@@ -1539,10 +1523,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 */
@@ -1568,15 +1552,12 @@ 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,
-                         kernel_cap_t *inheritable,
-                         kernel_cap_t *permitted);
-void security_capset_set(struct task_struct *target,
-                        kernel_cap_t *effective,
-                        kernel_cap_t *inheritable,
-                        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_capable_noaudit(struct task_struct *tsk, int cap);
 int security_acct(struct file *file);
 int security_sysctl(struct ctl_table *table, int op);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
@@ -1586,12 +1567,10 @@ 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_vm_enough_memory_kern(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);
-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);
@@ -1663,13 +1642,16 @@ 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_task_alloc(struct task_struct *p);
-void security_task_free(struct task_struct *p);
+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_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);
@@ -1688,8 +1670,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);
@@ -1764,25 +1745,23 @@ 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(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(target, effective, inheritable, permitted);
+       return cap_capset(new, old, 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 int security_capable(struct task_struct *tsk, int cap)
 {
-       cap_capset_set(target, effective, inheritable, permitted);
+       return cap_capable(tsk, cap, SECURITY_CAP_AUDIT);
 }
 
-static inline int security_capable(struct task_struct *tsk, int cap)
+static inline int security_capable_noaudit(struct task_struct *tsk, int cap)
 {
-       return cap_capable(tsk, cap);
+       return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT);
 }
 
 static inline int security_acct(struct file *file)
@@ -1835,32 +1814,22 @@ static inline int security_vm_enough_memory_kern(long pages)
        return cap_vm_enough_memory(current->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 void security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+static inline int security_bprm_set_creds(struct linux_binprm *bprm)
 {
-       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)
@@ -2177,7 +2146,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;
 }
@@ -2187,13 +2157,31 @@ static inline int security_task_create(unsigned long clone_flags)
        return 0;
 }
 
-static inline int security_task_alloc(struct task_struct *p)
+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_task_free(struct task_struct *p)
-{ }
+static inline void security_commit_creds(struct cred *new,
+                                        const struct cred *old)
+{
+}
+
+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)
@@ -2201,10 +2189,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,
@@ -2291,14 +2280,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)
@@ -2724,16 +2708,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;
@@ -2744,7 +2728,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;
index b5f41d4c2eec71a3d3c786128f0f980f0b41317d..315bcd375224869a0e54cbaab27274588452d4d3 100644 (file)
@@ -12,7 +12,7 @@
 struct user_namespace {
        struct kref             kref;
        struct hlist_head       uidhash_table[UIDHASH_SZ];
-       struct user_struct      *root_user;
+       struct user_struct      *creator;
 };
 
 extern struct user_namespace init_user_ns;
@@ -26,8 +26,7 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
        return ns;
 }
 
-extern struct user_namespace *copy_user_ns(int flags,
-                                          struct user_namespace *old_ns);
+extern int create_user_ns(struct cred *new);
 extern void free_user_ns(struct kref *kref);
 
 static inline void put_user_ns(struct user_namespace *ns)
@@ -43,13 +42,9 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
        return &init_user_ns;
 }
 
-static inline struct user_namespace *copy_user_ns(int flags,
-                                                 struct user_namespace *old_ns)
+static inline int create_user_ns(struct cred *new)
 {
-       if (flags & CLONE_NEWUSER)
-               return ERR_PTR(-EINVAL);
-
-       return old_ns;
+       return -EINVAL;
 }
 
 static inline void put_user_ns(struct user_namespace *ns)
index 33e9986beb86dd95d6f3f962ca8a89281c874a9d..f45bb6eca7d4263e179a203872c56c87f765ebe5 100644 (file)
@@ -55,8 +55,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;
index 7e117a231af10313f1b9bd963bf404eecaf94c9e..db843bff57325eb1375f9c9e3dd133ba60bc6f89 100644 (file)
@@ -669,6 +669,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();
index 68eb857cfdea2a1961760320a7e956608b8b432c..d9393f8e4c3ebb2ec4a63cd64290f237e45a4f83 100644 (file)
@@ -112,13 +112,14 @@ 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);
        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;
@@ -126,7 +127,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->user;
                        unsigned long mq_bytes, mq_msg_tblsz;
 
                        inode->i_fop = &mqueue_file_operations;
@@ -507,7 +507,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);
@@ -594,6 +594,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;
@@ -618,7 +619,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.
@@ -637,8 +638,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);
@@ -652,7 +655,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,
index 867e5d6a55c23ec64361db7e9eb2e1cf93b4f559..38a055758a9b212638775f19e60452350f62d482 100644 (file)
--- 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_user();
        } else {
                int acctflag = VM_ACCOUNT;
                /*
@@ -752,9 +752,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)
@@ -766,7 +767,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_user();
                        if (!is_file_hugepages(shp->shm_file)) {
                                err = shmem_lock(shp->shm_file, 1, user);
                                if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
index 361fd1c96fcf31b92475882803dc927f281a8718..5a1808c774a2f238746c9234ca40822eaff47fd9 100644 (file)
@@ -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)
@@ -280,8 +282,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)
@@ -620,13 +623,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;
@@ -788,6 +793,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);
@@ -807,8 +813,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;
index 19fad003b19d6ac0752597f5a23e18341d1d579a..b1e6b6625ea23ecbc048595ff52782775602ff02 100644 (file)
@@ -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
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
index f6006a60df5ddff73990656f73ea7fff55dcf9b8..d57b7cbb98b6db63e017045f9bb39ea6eb2bebf8 100644 (file)
@@ -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);
index cf5bc2f5f9c3e527ac2ea72ec019d156be72ecb6..bc1e2d854bf64c3bf25d41ca5a5fdad8e38812c5 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
 #include <linux/inotify.h>
+#include <linux/capability.h>
 
 #include "audit.h"
 
@@ -84,6 +85,15 @@ int audit_n_rules;
 /* determines whether we collect data for signals sent */
 int audit_signals;
 
+struct audit_cap_data {
+       kernel_cap_t            permitted;
+       kernel_cap_t            inheritable;
+       union {
+               unsigned int    fE;             /* effective bit of a file capability */
+               kernel_cap_t    effective;      /* effective set of a process */
+       };
+};
+
 /* When fs/namei.c:getname() is called, we store the pointer in name and
  * we don't let putname() free it (instead we free all of the saved
  * pointers at syscall exit time).
@@ -100,6 +110,8 @@ struct audit_names {
        gid_t           gid;
        dev_t           rdev;
        u32             osid;
+       struct audit_cap_data fcap;
+       unsigned int    fcap_ver;
 };
 
 struct audit_aux_data {
@@ -184,6 +196,20 @@ struct audit_aux_data_pids {
        int                     pid_count;
 };
 
+struct audit_aux_data_bprm_fcaps {
+       struct audit_aux_data   d;
+       struct audit_cap_data   fcap;
+       unsigned int            fcap_ver;
+       struct audit_cap_data   old_pcap;
+       struct audit_cap_data   new_pcap;
+};
+
+struct audit_aux_data_capset {
+       struct audit_aux_data   d;
+       pid_t                   pid;
+       struct audit_cap_data   cap;
+};
+
 struct audit_tree_refs {
        struct audit_tree_refs *next;
        struct audit_chunk *c[31];
@@ -421,6 +447,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                              struct audit_names *name,
                              enum audit_state *state)
 {
+       const struct cred *cred = get_task_cred(tsk);
        int i, j, need_sid = 1;
        u32 sid;
 
@@ -440,28 +467,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);
@@ -615,8 +642,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);
@@ -624,6 +653,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;
 }
 
@@ -1171,8 +1201,38 @@ static void audit_log_execve_info(struct audit_context *context,
        kfree(buf);
 }
 
+static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
+{
+       int i;
+
+       audit_log_format(ab, " %s=", prefix);
+       CAP_FOR_EACH_U32(i) {
+               audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+       }
+}
+
+static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
+{
+       kernel_cap_t *perm = &name->fcap.permitted;
+       kernel_cap_t *inh = &name->fcap.inheritable;
+       int log = 0;
+
+       if (!cap_isclear(*perm)) {
+               audit_log_cap(ab, "cap_fp", perm);
+               log = 1;
+       }
+       if (!cap_isclear(*inh)) {
+               audit_log_cap(ab, "cap_fi", inh);
+               log = 1;
+       }
+
+       if (log)
+               audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver);
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
+       const struct cred *cred;
        int i, call_panic = 0;
        struct audit_buffer *ab;
        struct audit_aux_data *aux;
@@ -1182,14 +1242,15 @@ 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;
+       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->fsgid = cred->fsgid;
        context->personality = tsk->personality;
 
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
@@ -1334,6 +1395,28 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
                        break; }
 
+               case AUDIT_BPRM_FCAPS: {
+                       struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
+                       audit_log_format(ab, "fver=%x", axs->fcap_ver);
+                       audit_log_cap(ab, "fp", &axs->fcap.permitted);
+                       audit_log_cap(ab, "fi", &axs->fcap.inheritable);
+                       audit_log_format(ab, " fe=%d", axs->fcap.fE);
+                       audit_log_cap(ab, "old_pp", &axs->old_pcap.permitted);
+                       audit_log_cap(ab, "old_pi", &axs->old_pcap.inheritable);
+                       audit_log_cap(ab, "old_pe", &axs->old_pcap.effective);
+                       audit_log_cap(ab, "new_pp", &axs->new_pcap.permitted);
+                       audit_log_cap(ab, "new_pi", &axs->new_pcap.inheritable);
+                       audit_log_cap(ab, "new_pe", &axs->new_pcap.effective);
+                       break; }
+
+               case AUDIT_CAPSET: {
+                       struct audit_aux_data_capset *axs = (void *)aux;
+                       audit_log_format(ab, "pid=%d", axs->pid);
+                       audit_log_cap(ab, "cap_pi", &axs->cap.inheritable);
+                       audit_log_cap(ab, "cap_pp", &axs->cap.permitted);
+                       audit_log_cap(ab, "cap_pe", &axs->cap.effective);
+                       break; }
+
                }
                audit_log_end(ab);
        }
@@ -1421,6 +1504,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        }
                }
 
+               audit_log_fcaps(ab, n);
+
                audit_log_end(ab);
        }
 
@@ -1787,8 +1872,36 @@ static int audit_inc_name_count(struct audit_context *context,
        return 0;
 }
 
+
+static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
+{
+       struct cpu_vfs_cap_data caps;
+       int rc;
+
+       memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t));
+       memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t));
+       name->fcap.fE = 0;
+       name->fcap_ver = 0;
+
+       if (!dentry)
+               return 0;
+
+       rc = get_vfs_caps_from_disk(dentry, &caps);
+       if (rc)
+               return rc;
+
+       name->fcap.permitted = caps.permitted;
+       name->fcap.inheritable = caps.inheritable;
+       name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+       name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
+
+       return 0;
+}
+
+
 /* Copy inode data into an audit_names. */
-static void audit_copy_inode(struct audit_names *name, const struct inode *inode)
+static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
+                            const struct inode *inode)
 {
        name->ino   = inode->i_ino;
        name->dev   = inode->i_sb->s_dev;
@@ -1797,6 +1910,7 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode
        name->gid   = inode->i_gid;
        name->rdev  = inode->i_rdev;
        security_inode_getsecid(inode, &name->osid);
+       audit_copy_fcaps(name, dentry);
 }
 
 /**
@@ -1831,7 +1945,7 @@ void __audit_inode(const char *name, const struct dentry *dentry)
                context->names[idx].name = NULL;
        }
        handle_path(dentry);
-       audit_copy_inode(&context->names[idx], inode);
+       audit_copy_inode(&context->names[idx], dentry, inode);
 }
 
 /**
@@ -1892,7 +2006,7 @@ void __audit_inode_child(const char *dname, const struct dentry *dentry,
                if (!strcmp(dname, n->name) ||
                     !audit_compare_dname_path(dname, n->name, &dirlen)) {
                        if (inode)
-                               audit_copy_inode(n, inode);
+                               audit_copy_inode(n, NULL, inode);
                        else
                                n->ino = (unsigned long)-1;
                        found_child = n->name;
@@ -1906,7 +2020,7 @@ add_names:
                        return;
                idx = context->name_count - 1;
                context->names[idx].name = NULL;
-               audit_copy_inode(&context->names[idx], parent);
+               audit_copy_inode(&context->names[idx], NULL, parent);
        }
 
        if (!found_child) {
@@ -1927,7 +2041,7 @@ add_names:
                }
 
                if (inode)
-                       audit_copy_inode(&context->names[idx], inode);
+                       audit_copy_inode(&context->names[idx], NULL, inode);
                else
                        context->names[idx].ino = (unsigned long)-1;
        }
@@ -1978,7 +2092,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_uid(task),
                                task->loginuid, loginuid,
                                task->sessionid, sessionid);
                        audit_log_end(ab);
@@ -2361,7 +2475,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 = 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);
@@ -2380,6 +2494,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) {
@@ -2387,7 +2502,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 = uid;
                        security_task_getsecid(tsk, &audit_sig_sid);
                }
                if (!audit_signals || audit_dummy_context())
@@ -2399,7 +2514,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_uid;
                ctx->target_sessionid = audit_get_sessionid(t);
                security_task_getsecid(t, &ctx->target_sid);
                memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
@@ -2420,7 +2535,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_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);
@@ -2429,6 +2544,86 @@ int __audit_signal_info(int sig, struct task_struct *t)
        return 0;
 }
 
+/**
+ * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps
+ * @bprm: pointer to the bprm being processed
+ * @new: the proposed new credentials
+ * @old: the old credentials
+ *
+ * Simply check if the proc already has the caps given by the file and if not
+ * store the priv escalation info for later auditing at the end of the syscall
+ *
+ * -Eric
+ */
+int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
+                          const struct cred *new, const struct cred *old)
+{
+       struct audit_aux_data_bprm_fcaps *ax;
+       struct audit_context *context = current->audit_context;
+       struct cpu_vfs_cap_data vcaps;
+       struct dentry *dentry;
+
+       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+       if (!ax)
+               return -ENOMEM;
+
+       ax->d.type = AUDIT_BPRM_FCAPS;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+
+       dentry = dget(bprm->file->f_dentry);
+       get_vfs_caps_from_disk(dentry, &vcaps);
+       dput(dentry);
+
+       ax->fcap.permitted = vcaps.permitted;
+       ax->fcap.inheritable = vcaps.inheritable;
+       ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+       ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
+
+       ax->old_pcap.permitted   = old->cap_permitted;
+       ax->old_pcap.inheritable = old->cap_inheritable;
+       ax->old_pcap.effective   = old->cap_effective;
+
+       ax->new_pcap.permitted   = new->cap_permitted;
+       ax->new_pcap.inheritable = new->cap_inheritable;
+       ax->new_pcap.effective   = new->cap_effective;
+       return 0;
+}
+
+/**
+ * __audit_log_capset - store information about the arguments to the capset syscall
+ * @pid: target pid of the capset call
+ * @new: the new credentials
+ * @old: the old (current) credentials
+ *
+ * Record the aguments userspace sent to sys_capset for later printing by the
+ * audit system if applicable
+ */
+int __audit_log_capset(pid_t pid,
+                      const struct cred *new, const struct cred *old)
+{
+       struct audit_aux_data_capset *ax;
+       struct audit_context *context = current->audit_context;
+
+       if (likely(!audit_enabled || !context || context->dummy))
+               return 0;
+
+       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+       if (!ax)
+               return -ENOMEM;
+
+       ax->d.type = AUDIT_CAPSET;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+
+       ax->pid = pid;
+       ax->cap.effective   = new->cap_effective;
+       ax->cap.inheritable = new->cap_effective;
+       ax->cap.permitted   = new->cap_permitted;
+
+       return 0;
+}
+
 /**
  * audit_core_dumps - record information about processes that end abnormally
  * @signr: signal value
@@ -2440,7 +2635,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)
@@ -2450,8 +2646,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;
index 33e51e78c2d8672559fa4aa6d5dcc4d38d113627..36b4b4daebec0a465fb8490c9531ed71d694ae59 100644 (file)
@@ -7,6 +7,7 @@
  * 30 May 2002:        Cleanup, Robert M. Love <rml@tech9.net>
  */
 
+#include <linux/audit.h>
 #include <linux/capability.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #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
@@ -33,6 +29,17 @@ EXPORT_SYMBOL(__cap_empty_set);
 EXPORT_SYMBOL(__cap_full_set);
 EXPORT_SYMBOL(__cap_init_eff_set);
 
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+int file_caps_enabled = 1;
+
+static int __init file_caps_disable(char *str)
+{
+       file_caps_enabled = 0;
+       return 1;
+}
+__setup("no_file_caps", file_caps_disable);
+#endif
+
 /*
  * More recent versions of libcap are available from:
  *
@@ -115,167 +122,12 @@ 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
- * 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)
@@ -285,7 +137,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);
@@ -295,50 +146,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;
 }
 
-/*
- * 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.
- */
-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->cap_effective;
-       current->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
@@ -366,7 +179,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;
@@ -412,16 +224,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.
  */
@@ -430,6 +240,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;
 
@@ -440,10 +251,13 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
        if (get_user(pid, &header->pid))
                return -EFAULT;
 
-       if (copy_from_user(&kdata, data, tocopy
-                          * sizeof(struct __user_cap_data_struct))) {
+       /* 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;
-       }
 
        for (i = 0; i < tocopy; i++) {
                effective.cap[i] = kdata[i].effective;
@@ -457,32 +271,23 @@ 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);
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
 
-               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);
-       }
+       ret = security_capset(new, current_cred(),
+                             &effective, &inheritable, &permitted);
+       if (ret < 0)
+               goto error;
+
+       ret = audit_log_capset(pid, new, current_cred());
+       if (ret < 0)
+               return ret;
 
+       return commit_creds(new);
 
+error:
+       abort_creds(new);
        return ret;
 }
 
@@ -498,6 +303,11 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
  */
 int capable(int cap)
 {
+       if (unlikely(!cap_valid(cap))) {
+               printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
+               BUG();
+       }
+
        if (has_capability(current, cap)) {
                current->flags |= PF_SUPERPRIV;
                return 1;
index fe00b3b983a86387332234703217abb1d28ca202..dee025f2f2868a93babf4883b44370d57496530a 100644 (file)
@@ -571,8 +571,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;
@@ -1279,6 +1279,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;
+       const struct cred *cred = current_cred(), *tcred;
        int ret;
 
        if (pid) {
@@ -1288,14 +1289,16 @@ static int attach_task_by_pid(struct cgroup *cgrp, u64 pid)
                        rcu_read_unlock();
                        return -ESRCH;
                }
-               get_task_struct(tsk);
-               rcu_read_unlock();
 
-               if ((current->euid) && (current->euid != tsk->uid)
-                   && (current->euid != tsk->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/cred-internals.h b/kernel/cred-internals.h
new file mode 100644 (file)
index 0000000..2dc4fc2
--- /dev/null
@@ -0,0 +1,21 @@
+/* Internal credentials stuff
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+/*
+ * 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
new file mode 100644 (file)
index 0000000..ff7bc07
--- /dev/null
@@ -0,0 +1,588 @@
+/* Task credentials management - see Documentation/credentials.txt
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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>
+#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
+ */
+#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 = {
+       .usage                  = ATOMIC_INIT(4),
+       .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,
+#ifdef CONFIG_KEYS
+       .tgcred                 = &init_tgcred,
+#endif
+};
+
+/*
+ * Dispose of the shared task group credentials
+ */
+#ifdef CONFIG_KEYS
+static void release_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 release_tgcred(struct cred *cred)
+{
+#ifdef CONFIG_KEYS
+       struct thread_group_cred *tgcred = cred->tgcred;
+
+       if (atomic_dec_and_test(&tgcred->usage))
+               call_rcu(&tgcred->rcu, release_tgcred_rcu);
+#endif
+}
+
+/*
+ * 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);
+
+       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);
+       release_tgcred(cred);
+       put_group_info(cred->group_info);
+       free_uid(cred->user);
+       kmem_cache_free(cred_jar, cred);
+}
+
+/**
+ * __put_cred - Destroy a set of credentials
+ * @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);
+
+/**
+ * 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().
+ *
+ * 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.
+ */
+struct cred *prepare_creds(void)
+{
+       struct task_struct *task = current;
+       const struct cred *old;
+       struct cred *new;
+
+       BUG_ON(atomic_read(&task->real_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 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;
+
+       release_tgcred(new);
+       new->tgcred = tgcred;
+#endif
+
+       return new;
+}
+
+/*
+ * 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.
+ *
+ * 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)
+{
+#ifdef CONFIG_KEYS
+       struct thread_group_cred *tgcred;
+#endif
+       struct cred *new;
+       int ret;
+
+       mutex_init(&p->cred_exec_mutex);
+
+       if (
+#ifdef CONFIG_KEYS
+               !p->cred->thread_keyring &&
+#endif
+               clone_flags & CLONE_THREAD
+           ) {
+               p->real_cred = get_cred(p->cred);
+               get_cred(p->cred);
+               atomic_inc(&p->cred->user->processes);
+               return 0;
+       }
+
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       if (clone_flags & CLONE_NEWUSER) {
+               ret = create_user_ns(new);
+               if (ret < 0)
+                       goto error_put;
+       }
+
+#ifdef CONFIG_KEYS
+       /* 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) {
+                       ret = -ENOMEM;
+                       goto error_put;
+               }
+               atomic_set(&tgcred->usage, 1);
+               spin_lock_init(&tgcred->lock);
+               tgcred->process_keyring = NULL;
+               tgcred->session_keyring = key_get(new->tgcred->session_keyring);
+
+               release_tgcred(new);
+               new->tgcred = tgcred;
+       }
+#endif
+
+       atomic_inc(&new->user->processes);
+       p->cred = p->real_cred = get_cred(new);
+       return 0;
+
+error_put:
+       put_cred(new);
+       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.  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.
+ *
+ * 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(task->cred != task->real_cred);
+       BUG_ON(atomic_read(&task->real_cred->usage) < 2);
+       BUG_ON(atomic_read(&new->usage) < 1);
+
+       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 ||
+           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();
+       }
+
+       /* 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->real_cred, new);
+       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);
+
+       /* release the old obj and subj refs both */
+       put_cred(old);
+       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 - Override the current process's subjective credentials
+ * @new: The credentials to be assigned
+ *
+ * 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)
+{
+       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 subjective credentials override
+ * @old: The credentials to be restored
+ *
+ * Revert a temporary set of override subjective credentials to an old set,
+ * discarding the override set.
+ */
+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);
+}
+
+/**
+ * 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);
index 2d8be7ebb0f73499f894a1828fd827f0217290f1..ccb87162ff62ac7ff7979b33191135936175a62e 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/tracehook.h>
+#include <linux/init_task.h>
 #include <trace/sched.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);
 
@@ -164,7 +166,10 @@ void release_task(struct task_struct * p)
        int zap_leader;
 repeat:
        tracehook_prepare_release_task(p);
-       atomic_dec(&p->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);
@@ -339,12 +344,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)
@@ -1078,7 +1083,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);
@@ -1263,12 +1267,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->uid;
                int exit_code = p->exit_code;
                int why, status;
 
@@ -1389,7 +1393,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(uid, &infop->si_uid);
        if (!retval)
                retval = pid;
 
@@ -1454,7 +1458,8 @@ static int wait_task_stopped(int ptrace, struct task_struct *p,
        if (!unlikely(options & WNOWAIT))
                p->exit_code = 0;
 
-       uid = p->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 +1533,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->uid;
        get_task_struct(p);
        read_unlock(&tasklist_lock);
 
index 2a372a0e206fa2de99dbfdd594f86f6eb927bf40..1dd89451fae468b4d350e6a0cb638f730ff52919 100644 (file)
@@ -147,9 +147,8 @@ 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->user);
-       put_group_info(tsk->group_info);
+       put_cred(tsk->real_cred);
+       put_cred(tsk->cred);
        delayacct_tsk_free(tsk);
 
        if (!profile_handoff_task(tsk))
@@ -815,12 +814,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);
@@ -865,7 +858,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 void __cleanup_signal(struct signal_struct *sig)
 {
        thread_group_cputime_free(sig);
-       exit_thread_group_keys(sig);
        tty_kref_put(sig->tty);
        kmem_cache_free(signal_cachep, sig);
 }
@@ -981,16 +973,16 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 #endif
        retval = -EAGAIN;
-       if (atomic_read(&p->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->user != current->nsproxy->user_ns->root_user)
+                   p->real_cred->user != INIT_USER)
                        goto bad_fork_free;
        }
 
-       atomic_inc(&p->user->__count);
-       atomic_inc(&p->user->processes);
-       get_group_info(p->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
@@ -1045,10 +1037,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->security = NULL;
-#endif
-       p->cap_bset = current->cap_bset;
        p->io_context = NULL;
        p->audit_context = NULL;
        cgroup_fork(p);
@@ -1093,10 +1081,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;
@@ -1110,10 +1096,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);
@@ -1278,8 +1262,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);
@@ -1295,8 +1277,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);
@@ -1309,9 +1289,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);
+       atomic_dec(&p->cred->user->processes);
+       put_cred(p->real_cred);
+       put_cred(p->cred);
 bad_fork_free:
        free_task(p);
 fork_out:
@@ -1354,6 +1334,20 @@ long do_fork(unsigned long clone_flags,
        int trace = 0;
        long nr;
 
+       /*
+        * Do some preliminary argument and permissions checking before we
+        * actually start allocating stuff
+        */
+       if (clone_flags & CLONE_NEWUSER) {
+               if (clone_flags & CLONE_THREAD)
+                       return -EINVAL;
+               /* hopefully this check will go away when userns support is
+                * complete
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+       }
+
        /*
         * We hope to recycle these flags after 2.6.26
         */
@@ -1601,8 +1595,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
        err = -EINVAL;
        if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
                                CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
-                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER|
-                               CLONE_NEWNET))
+                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
                goto bad_unshare_out;
 
        /*
index 8af10027514bb1cc9cb2702051330e52bf43a533..4fe790e89d0f34af1cc24359d32bca3b58e970ca 100644 (file)
@@ -439,13 +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;
+       const struct cred *cred = current_cred(), *pcred;
 
        rcu_read_lock();
        p = find_task_by_vpid(pid);
-       if (!p || ((current->euid != p->euid) && (current->euid != p->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();
 
@@ -1829,6 +1836,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
 {
        struct robust_list_head __user *head;
        unsigned long ret;
+       const struct cred *cred = current_cred(), *pcred;
 
        if (!futex_cmpxchg_enabled)
                return -ENOSYS;
@@ -1844,8 +1852,10 @@ 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))
+               pcred = __task_cred(p);
+               if (cred->euid != pcred->euid &&
+                   cred->euid != pcred->uid &&
+                   !capable(CAP_SYS_PTRACE))
                        goto err_unlock;
                head = p->robust_list;
                rcu_read_unlock();
index 04ac3a9e42cf58435dc3d3d689049e1bf1f91a8a..d607a5b9ee29923617d462288e9853327c7d1527 100644 (file)
@@ -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;
+       const struct cred *cred = current_cred(), *pcred;
 
        if (!futex_cmpxchg_enabled)
                return -ENOSYS;
@@ -150,8 +151,10 @@ 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) &&
-                               !capable(CAP_SYS_PTRACE))
+               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;
                read_unlock(&tasklist_lock);
index 3d3c3ea3a023376f2ecf8c16b6c89aed39da67f4..b46dbb908669fa7c0b8713558c8557d0dffd8b01 100644 (file)
@@ -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(current, 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.  */
@@ -362,6 +367,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;
@@ -376,7 +384,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);
 
@@ -444,6 +458,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;
index 1d3ef29a2583e8cec49d46913b448fee86d3a549..63598dca2d0c9080448a5f6ab421d72c542f18c1 100644 (file)
@@ -80,12 +80,6 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
                goto out_pid;
        }
 
-       new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);
-       if (IS_ERR(new_nsp->user_ns)) {
-               err = PTR_ERR(new_nsp->user_ns);
-               goto out_user;
-       }
-
        new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns);
        if (IS_ERR(new_nsp->net_ns)) {
                err = PTR_ERR(new_nsp->net_ns);
@@ -95,9 +89,6 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
        return new_nsp;
 
 out_net:
-       if (new_nsp->user_ns)
-               put_user_ns(new_nsp->user_ns);
-out_user:
        if (new_nsp->pid_ns)
                put_pid_ns(new_nsp->pid_ns);
 out_pid:
@@ -130,7 +121,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
        get_nsproxy(old_ns);
 
        if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                               CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)))
+                               CLONE_NEWPID | CLONE_NEWNET)))
                return 0;
 
        if (!capable(CAP_SYS_ADMIN)) {
@@ -173,8 +164,6 @@ void free_nsproxy(struct nsproxy *ns)
                put_ipc_ns(ns->ipc_ns);
        if (ns->pid_ns)
                put_pid_ns(ns->pid_ns);
-       if (ns->user_ns)
-               put_user_ns(ns->user_ns);
        put_net(ns->net_ns);
        kmem_cache_free(nsproxy_cachep, ns);
 }
@@ -189,7 +178,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
        int err = 0;
 
        if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                              CLONE_NEWUSER | CLONE_NEWNET)))
+                              CLONE_NEWNET)))
                return 0;
 
        if (!capable(CAP_SYS_ADMIN))
index 4c8bcd7dd8e0831aa7a66e5c200324cff682721f..ca2df68faf7631439f276983d7f6e28e5b0771ed 100644 (file)
@@ -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)
 {
+       const struct cred *cred = current_cred(), *tcred;
+
        /* May we inspect the given task?
         * This check is used both for attaching with ptrace
         * and for allowing access to sensitive information in /proc.
@@ -127,13 +129,19 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
        /* 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))
+       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);
@@ -163,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.
@@ -202,6 +218,7 @@ repeat:
 bad:
        write_unlock_irqrestore(&tasklist_lock, flags);
        task_unlock(task);
+       mutex_unlock(&current->cred_exec_mutex);
 out:
        return retval;
 }
index b7480fb5c3dc21a7bf6513a978cf0ed2e8c19a8f..993bc74a290cd4ef32af5e76730e63ab4928739f 100644 (file)
@@ -345,7 +345,9 @@ static inline struct task_group *task_group(struct task_struct *p)
        struct task_group *tg;
 
 #ifdef CONFIG_USER_SCHED
-       tg = p->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);
@@ -5134,6 +5136,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)
 {
@@ -5193,8 +5211,7 @@ recheck:
                        return -EPERM;
 
                /* can't change other user's priorities */
-               if ((current->euid != p->euid) &&
-                   (current->euid != p->uid))
+               if (!check_same_owner(p))
                        return -EPERM;
        }
 
@@ -5426,8 +5443,7 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask)
        read_unlock(&tasklist_lock);
 
        retval = -EPERM;
-       if ((current->euid != p->euid) && (current->euid != p->uid) &&
-                       !capable(CAP_SYS_NICE))
+       if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
                goto out_unlock;
 
        retval = security_task_setscheduler(p, 0, NULL);
index 4530fc65445518272ae851fa44e90378cfd908e1..2a64304ed54b041c327f64910f0cf84ee5a64e2f 100644 (file)
@@ -177,6 +177,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 stop the target task from exiting
+ */
 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
                                         int override_rlimit)
 {
@@ -184,11 +189,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->user;
-       barrier();
+       user = get_uid(__task_cred(t)->user);
        atomic_inc(&user->sigpending);
        if (override_rlimit ||
            atomic_read(&user->sigpending) <=
@@ -196,12 +202,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)
@@ -562,10 +570,12 @@ 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;
        int error;
 
@@ -579,8 +589,11 @@ 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) &&
+       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:
@@ -844,7 +857,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;
@@ -1008,6 +1021,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 +1046,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 +1103,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 +1114,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->suid) && (euid != p->uid)
-           && (uid != p->suid) && (uid != p->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;
        }
@@ -1369,10 +1389,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->uid;
-
        thread_group_cputime(tsk, &cputime);
        info.si_utime = cputime_to_jiffies(cputime.utime);
        info.si_stime = cputime_to_jiffies(cputime.stime);
@@ -1440,10 +1459,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->uid;
-
        info.si_utime = cputime_to_clock_t(tsk->utime);
        info.si_stime = cputime_to_clock_t(tsk->stime);
 
@@ -1598,7 +1616,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);
@@ -1710,7 +1728,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 = task_uid(current->parent);
        }
 
        /* If the (new) signal is now blocked, requeue it.  */
@@ -2211,7 +2229,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);
 }
@@ -2228,7 +2246,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);
index 31deba8f7d160c19bf262b1be13272e2ede1050d..ebe65c2c9873382a6017c35fb2954ad5bb54029b 100644 (file)
@@ -112,12 +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)
 {
+       const struct cred *cred = current_cred(), *pcred = __task_cred(p);
        int no_nice;
 
-       if (p->uid != current->euid &&
-               p->euid != current->euid && !capable(CAP_SYS_NICE)) {
+       if (pcred->uid  != cred->euid &&
+           pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
                error = -EPERM;
                goto out;
        }
@@ -141,6 +146,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;
 
@@ -174,18 +180,18 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
                        } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
                        break;
                case PRIO_USER:
-                       user = current->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->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;
        }
@@ -205,6 +211,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;
 
@@ -236,21 +243,21 @@ asmlinkage long sys_getpriority(int which, int who)
                        } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
                        break;
                case PRIO_USER:
-                       user = current->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->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;
        }
@@ -472,46 +479,48 @@ 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;
-       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) ||
-                   (current->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) ||
-                   (current->egid == egid) ||
-                   (current->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))
-               current->sgid = new_egid;
-       current->fsgid = new_egid;
-       current->egid = new_egid;
-       current->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;
 }
 
 /*
@@ -521,56 +530,54 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
  */
 asmlinkage long sys_setgid(gid_t gid)
 {
-       int old_egid = current->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();
-               }
-               current->gid = current->egid = current->sgid = current->fsgid = gid;
-       } else if ((gid == current->gid) || (gid == current->sgid)) {
-               if (old_egid != gid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
-               }
-               current->egid = current->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_user_ns(), new->uid);
        if (!new_user)
                return -EAGAIN;
 
        if (atomic_read(&new_user->processes) >=
                                current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
-                       new_user != current->nsproxy->user_ns->root_user) {
+                       new_user != INIT_USER) {
                free_uid(new_user);
                return -EAGAIN;
        }
 
-       switch_uid(new_user);
-
-       if (dumpclear) {
-               set_dumpable(current->mm, suid_dumpable);
-               smp_wmb();
-       }
-       current->uid = new_ruid;
+       free_uid(new->user);
+       new->user = new_user;
        return 0;
 }
 
@@ -591,54 +598,56 @@ static int set_user(uid_t new_ruid, int dumpclear)
  */
 asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
 {
-       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 = current->uid;
-       new_euid = old_euid = current->euid;
-       old_suid = current->suid;
+               goto error;
 
+       retval = -EPERM;
        if (ruid != (uid_t) -1) {
-               new_ruid = ruid;
-               if ((old_ruid != ruid) &&
-                   (current->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) &&
-                   (current->euid != euid) &&
-                   (current->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();
-       }
-       current->fsuid = current->euid = new_euid;
        if (ruid != (uid_t) -1 ||
-           (euid != (uid_t) -1 && euid != old_ruid))
-               current->suid = current->euid;
-       current->fsuid = current->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 
@@ -653,36 +662,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
  */
 asmlinkage long sys_setuid(uid_t uid)
 {
-       int old_euid = current->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 = current->uid;
-       old_suid = current->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 != current->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;
        }
-       current->fsuid = current->euid = uid;
-       current->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;
 }
 
 
@@ -692,54 +706,63 @@ 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;
+       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 != current->uid) &&
-                   (ruid != current->euid) && (ruid != current->suid))
-                       return -EPERM;
-               if ((euid != (uid_t) -1) && (euid != current->uid) &&
-                   (euid != current->euid) && (euid != current->suid))
-                       return -EPERM;
-               if ((suid != (uid_t) -1) && (suid != current->uid) &&
-                   (suid != current->euid) && (suid != current->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 != current->uid && set_user(ruid, euid != current->euid) < 0)
-                       return -EAGAIN;
+               new->uid = ruid;
+               if (ruid != old->uid && set_user(new) < 0)
+                       goto error;
        }
-       if (euid != (uid_t) -1) {
-               if (euid != current->euid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
-               }
-               current->euid = euid;
-       }
-       current->fsuid = current->euid;
+       if (euid != (uid_t) -1)
+               new->euid = euid;
        if (suid != (uid_t) -1)
-               current->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)
 {
+       const 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,48 +772,55 @@ 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)
 {
+       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 != current->gid) &&
-                   (rgid != current->egid) && (rgid != current->sgid))
-                       return -EPERM;
-               if ((egid != (gid_t) -1) && (egid != current->gid) &&
-                   (egid != current->egid) && (egid != current->sgid))
-                       return -EPERM;
-               if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
-                   (sgid != current->egid) && (sgid != current->sgid))
-                       return -EPERM;
+               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;
        }
-       if (egid != (gid_t) -1) {
-               if (egid != current->egid) {
-                       set_dumpable(current->mm, suid_dumpable);
-                       smp_wmb();
-               }
-               current->egid = egid;
-       }
-       current->fsgid = current->egid;
+
        if (rgid != (gid_t) -1)
-               current->gid = rgid;
+               new->gid = rgid;
+       if (egid != (gid_t) -1)
+               new->egid = egid;
        if (sgid != (gid_t) -1)
-               current->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)
 {
+       const 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,27 +834,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us
  */
 asmlinkage long sys_setfsuid(uid_t uid)
 {
-       int old_fsuid;
+       const struct cred *old;
+       struct cred *new;
+       uid_t old_fsuid;
 
-       old_fsuid = current->fsuid;
-       if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
-               return old_fsuid;
+       new = prepare_creds();
+       if (!new)
+               return current_fsuid();
+       old = current_cred();
+       old_fsuid = old->fsuid;
 
-       if (uid == current->uid || uid == current->euid ||
-           uid == current->suid || uid == current->fsuid || 
+       if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
+               goto error;
+
+       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;
                }
-               current->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;
 }
 
@@ -833,23 +871,34 @@ asmlinkage long sys_setfsuid(uid_t uid)
  */
 asmlinkage long sys_setfsgid(gid_t gid)
 {
-       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 = current->fsgid;
        if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
-               return old_fsgid;
+               goto error;
 
-       if (gid == current->gid || gid == current->egid ||
-           gid == current->sgid || gid == current->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;
                }
-               current->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;
 }
 
@@ -1118,7 +1167,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;
@@ -1186,7 +1235,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;
 
@@ -1208,51 +1257,74 @@ 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 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, insert it into a set
+ * of credentials.
+ */
+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);
+       new->group_info = group_info;
+       return 0;
+}
+
+EXPORT_SYMBOL(set_groups);
 
-       task_lock(current);
-       old_info = current->group_info;
-       current->group_info = group_info;
-       task_unlock(current);
+/**
+ * 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)
+{
+       struct cred *new;
+       int ret;
 
-       put_group_info(old_info);
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
 
-       return 0;
+       ret = set_groups(new, group_info);
+       if (ret < 0) {
+               abort_creds(new);
+               return ret;
+       }
+
+       return commit_creds(new);
 }
 
 EXPORT_SYMBOL(set_current_groups);
 
 asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
 {
-       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;
 
        /* 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;
                }
@@ -1296,9 +1368,11 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
  */
 int in_group_p(gid_t grp)
 {
+       const 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;
 }
 
@@ -1306,9 +1380,11 @@ EXPORT_SYMBOL(in_group_p);
 
 int in_egroup_p(gid_t grp)
 {
+       const 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;
 }
 
@@ -1624,50 +1700,56 @@ 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 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)) {
                                error = -EINVAL;
                                break;
                        }
-                       current->pdeath_signal = arg2;
+                       me->pdeath_signal = arg2;
+                       error = 0;
                        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);
+                       error = 0;
                        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;
@@ -1675,33 +1757,28 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                case PR_SET_TIMING:
                        if (arg2 != PR_TIMING_STATISTICAL)
                                error = -EINVAL;
+                       else
+                               error = 0;
                        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:
@@ -1725,6 +1802,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                                        current->default_timer_slack_ns;
                        else
                                current->timer_slack_ns = arg2;
+                       error = 0;
                        break;
                default:
                        error = -EINVAL;
index 3d56fe7570daede300fe01f2e6571416107b081b..9d52b57310af1fe953a8f86bdaf35d9ca88acbb7 100644 (file)
@@ -1651,7 +1651,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;
index dbd50fabe4c74ab241523fbf2b427c596e2838c5..566257d1dc10327818f787e5ca04559c05bd2566 100644 (file)
@@ -1192,25 +1192,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
index d86e3252f3000024cfaf31c63ffbee765dafac53..1ee9e4e454a0cded40ffc8f66d799c2e1ef1a2bf 100644 (file)
@@ -246,7 +246,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;
index 8ebcd8532dfb33f80518feb2fc7e1cad1314bc31..2dc06ab357169ba78ea7397e7aab6d03961ffb4e 100644 (file)
@@ -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->uid;
-       stats->ac_gid    = tsk->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();
index 3e41c1673e2f1a5996e6437c6d6ecc6e0e9481ff..2460c3199b5a2e10e4bda0001d76b2c066975410 100644 (file)
@@ -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->uid), ruid)) &&
-           !(retval = put_user(high2lowuid(current->euid), euid)))
-               retval = put_user(high2lowuid(current->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->gid), rgid)) &&
-           !(retval = put_user(high2lowgid(current->egid), egid)))
-               retval = put_user(high2lowgid(current->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->group_info);
-       i = current->group_info->ngroups;
+       i = 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, cred->group_info)) {
                        i = -EFAULT;
                        goto out;
                }
        }
 out:
-       put_group_info(current->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->uid);
+       return high2lowuid(current_uid());
 }
 
 asmlinkage long sys_geteuid16(void)
 {
-       return high2lowuid(current->euid);
+       return high2lowuid(current_euid());
 }
 
 asmlinkage long sys_getgid16(void)
 {
-       return high2lowgid(current->gid);
+       return high2lowgid(current_gid());
 }
 
 asmlinkage long sys_getegid16(void)
 {
-       return high2lowgid(current->egid);
+       return high2lowgid(current_egid());
 }
index 39d6159fae430cf60811839f4e2dbd20aadb9e4a..97202cb29adc333869f160819e1d4167f5576ff6 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/user_namespace.h>
+#include "cred-internals.h"
 
 struct user_namespace init_user_ns = {
        .kref = {
-               .refcount       = ATOMIC_INIT(2),
+               .refcount       = ATOMIC_INIT(1),
        },
-       .root_user = &root_user,
+       .creator = &root_user,
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
@@ -47,12 +48,14 @@ static struct kmem_cache *uid_cachep;
  */
 static DEFINE_SPINLOCK(uidhash_lock);
 
+/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */
 struct user_struct root_user = {
-       .__count        = ATOMIC_INIT(1),
+       .__count        = ATOMIC_INIT(2),
        .processes      = ATOMIC_INIT(1),
        .files          = ATOMIC_INIT(0),
        .sigpending     = ATOMIC_INIT(0),
        .locked_shm     = 0,
+       .user_ns        = &init_user_ns,
 #ifdef CONFIG_USER_SCHED
        .tg             = &init_task_group,
 #endif
@@ -104,16 +107,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 */
 
@@ -319,12 +316,13 @@ done:
  * IRQ state (as stored in flags) is restored and uidhash_lock released
  * upon function exit.
  */
-static inline void free_user(struct user_struct *up, unsigned long flags)
+static void free_user(struct user_struct *up, unsigned long flags)
 {
        /* restore back the count */
        atomic_inc(&up->__count);
        spin_unlock_irqrestore(&uidhash_lock, flags);
 
+       put_user_ns(up->user_ns);
        INIT_WORK(&up->work, remove_user_sysfs_dir);
        schedule_work(&up->work);
 }
@@ -340,13 +338,14 @@ static inline void uids_mutex_unlock(void) { }
  * IRQ state (as stored in flags) is restored and uidhash_lock released
  * upon function exit.
  */
-static inline void free_user(struct user_struct *up, unsigned long flags)
+static void free_user(struct user_struct *up, unsigned long flags)
 {
        uid_hash_remove(up);
        spin_unlock_irqrestore(&uidhash_lock, flags);
        sched_destroy_user(up);
        key_put(up->uid_keyring);
        key_put(up->session_keyring);
+       put_user_ns(up->user_ns);
        kmem_cache_free(uid_cachep, up);
 }
 
@@ -362,7 +361,7 @@ struct user_struct *find_user(uid_t uid)
 {
        struct user_struct *ret;
        unsigned long flags;
-       struct user_namespace *ns = current->nsproxy->user_ns;
+       struct user_namespace *ns = current_user_ns();
 
        spin_lock_irqsave(&uidhash_lock, flags);
        ret = uid_hash_find(uid, uidhashentry(ns, uid));
@@ -409,6 +408,8 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
                if (sched_create_user(new) < 0)
                        goto out_free_user;
 
+               new->user_ns = get_user_ns(ns);
+
                if (uids_user_create(new))
                        goto out_destoy_sched;
 
@@ -432,7 +433,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
                        up = new;
                }
                spin_unlock_irq(&uidhash_lock);
-
        }
 
        uids_mutex_unlock();
@@ -441,6 +441,7 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
 
 out_destoy_sched:
        sched_destroy_user(new);
+       put_user_ns(new->user_ns);
 out_free_user:
        kmem_cache_free(uid_cachep, new);
 out_unlock:
@@ -448,63 +449,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->user;
-       atomic_inc(&new_user->processes);
-       atomic_dec(&old_user->processes);
-       switch_uid_keyring(new_user);
-       current->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)
-{
-       int i;
-       unsigned long flags;
-       struct hlist_head *head;
-       struct hlist_node *nd;
-
-       spin_lock_irqsave(&uidhash_lock, flags);
-       /*
-        * collapse the chains so that the user_struct-s will
-        * be still alive, but not in hashes. subsequent free_uid()
-        * will free them.
-        */
-       for (i = 0; i < UIDHASH_SZ; i++) {
-               head = ns->uidhash_table + i;
-               while (!hlist_empty(head)) {
-                       nd = head->first;
-                       hlist_del_init(nd);
-               }
-       }
-       spin_unlock_irqrestore(&uidhash_lock, flags);
-
-       free_uid(ns->root_user);
-}
-#endif
-
 static int __init uid_cache_init(void)
 {
        int n;
index 532858fa5b882eb8c3848b4c9ce430440297d2c0..79084311ee5779a1e12b411ff37a5f04da08e360 100644 (file)
@@ -9,60 +9,55 @@
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
+#include <linux/cred.h>
 
 /*
- * Clone a new ns copying an original user ns, setting refcount to 1
- * @old_ns: namespace to clone
- * Return NULL on error (failure to kmalloc), new ns otherwise
+ * Create a new user namespace, deriving the creator from the user in the
+ * passed credentials, and replacing that user with the new root user for the
+ * new namespace.
+ *
+ * This is called by copy_creds(), which will finish setting the target task's
+ * credentials.
  */
-static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
+int create_user_ns(struct cred *new)
 {
        struct user_namespace *ns;
-       struct user_struct *new_user;
+       struct user_struct *root_user;
        int n;
 
        ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
        if (!ns)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
        kref_init(&ns->kref);
 
        for (n = 0; n < UIDHASH_SZ; ++n)
                INIT_HLIST_HEAD(ns->uidhash_table + n);
 
-       /* Insert new root user.  */
-       ns->root_user = alloc_uid(ns, 0);
-       if (!ns->root_user) {
+       /* Alloc new root user.  */
+       root_user = alloc_uid(ns, 0);
+       if (!root_user) {
                kfree(ns);
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
        }
 
-       /* Reset current->user with a new one */
-       new_user = alloc_uid(ns, current->uid);
-       if (!new_user) {
-               free_uid(ns->root_user);
-               kfree(ns);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       switch_uid(new_user);
-       return ns;
-}
-
-struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
-{
-       struct user_namespace *new_ns;
-
-       BUG_ON(!old_ns);
-       get_user_ns(old_ns);
-
-       if (!(flags & CLONE_NEWUSER))
-               return old_ns;
+       /* set the new root user in the credentials under preparation */
+       ns->creator = new->user;
+       new->user = root_user;
+       new->uid = new->euid = new->suid = new->fsuid = 0;
+       new->gid = new->egid = new->sgid = new->fsgid = 0;
+       put_group_info(new->group_info);
+       new->group_info = get_group_info(&init_groups);
+#ifdef CONFIG_KEYS
+       key_put(new->request_key_auth);
+       new->request_key_auth = NULL;
+#endif
+       /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
 
-       new_ns = clone_user_ns(old_ns);
+       /* alloc_uid() incremented the userns refcount.  Just set it to 1 */
+       kref_set(&ns->kref, 1);
 
-       put_user_ns(old_ns);
-       return new_ns;
+       return 0;
 }
 
 void free_user_ns(struct kref *kref)
@@ -70,7 +65,7 @@ void free_user_ns(struct kref *kref)
        struct user_namespace *ns;
 
        ns = container_of(kref, struct user_namespace, kref);
-       release_uids(ns);
+       free_uid(ns->creator);
        kfree(ns);
 }
 EXPORT_SYMBOL(free_user_ns);
index d4dc69ddebd7276684e2564737618859e96fbd1c..4952322cba45b05c90999f21b51016612c8144ca 100644 (file)
@@ -84,21 +84,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);
 }
@@ -769,7 +769,7 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 {
        struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
        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);
index 7cb65d85aeb0fd41142facc52c01c365ca2cc729..80fe8a3ec12a63a46ce2fe05841a3e9a6d9d54c2 100644 (file)
@@ -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 (file)
index 0000000..f1ed2fe
--- /dev/null
@@ -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 (dhowells@redhat.com)
+ * - 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;
+}
index e9493b1c1117a4090fa8998b9ea2e29c1239ebbc..e412ffa8e52ea945fb2ffa94a8de388e2de0875e 100644 (file)
@@ -1114,6 +1114,7 @@ asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode,
                const unsigned long __user *old_nodes,
                const unsigned long __user *new_nodes)
 {
+       const struct cred *cred = current_cred(), *tcred;
        struct mm_struct *mm;
        struct task_struct *task;
        nodemask_t old;
@@ -1148,12 +1149,16 @@ 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) &&
+       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? */
index 1e0d6b237f4418c2f8b8ca50e88d85a787adc0a7..0461fc6c961cb841d4cce06287704cc9d3858a58 100644 (file)
@@ -1042,6 +1042,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
                        const int __user *nodes,
                        int __user *status, int flags)
 {
+       const struct cred *cred = current_cred(), *tcred;
        struct task_struct *task;
        struct mm_struct *mm;
        int err;
@@ -1072,12 +1073,16 @@ 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) &&
+       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();
 
        err = security_task_movememory(task);
        if (err)
index a0a01902f551dd45b19385b64435ec6708db249d..558f9afe6e4e6b0085ddb51633a8b845e2518d18 100644 (file)
@@ -128,8 +128,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 (has_capability(p, CAP_SYS_ADMIN) ||
-           has_capability(p, CAP_SYS_RESOURCE))
+       if (has_capability_noaudit(p, CAP_SYS_ADMIN) ||
+           has_capability_noaudit(p, CAP_SYS_RESOURCE))
                points /= 4;
 
        /*
@@ -138,7 +138,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 (has_capability(p, CAP_SYS_RAWIO))
+       if (has_capability_noaudit(p, CAP_SYS_RAWIO))
                points /= 4;
 
        /*
@@ -299,9 +299,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->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);
 }
index 0ed075215e5f6e3e7905fdc4ac3f739062533b42..f1b0d4871f3a72b8cfb9e9650b6e271daf910956 100644 (file)
@@ -1513,8 +1513,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;
@@ -2278,8 +2278,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;
 
index 4b529454616d0427020e5b8b30620249e400c268..821f1ec0b2c38084444b7da0efb32f993f1e363c 100644 (file)
@@ -627,7 +627,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
        memset(&fid->qid, 0, sizeof(struct p9_qid));
        fid->mode = -1;
        fid->rdir_fpos = 0;
-       fid->uid = current->fsuid;
+       fid->uid = current_fsuid();
        fid->clnt = clnt;
        fid->aux = NULL;
 
index 28c71574a781e6b0600f453275e50bf8911dcca9..00d9e5e131582669cab51f01b91b43c204ea0da8 100644 (file)
@@ -1045,7 +1045,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);
index 8672cd84fdf905990afb5810a70c505bc94bded8..c833ba4c45a585514eee55835c5ce61880594c6d 100644 (file)
@@ -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);
index 9174c77d3112c65237cbbd2e063eb55b03b5c39e..89912ae6de651f5931cd76fe79b278e20addf4ad 100644 (file)
@@ -2961,6 +2961,8 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
 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();
 
@@ -2985,15 +2987,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));
+               }
 
                dev_change_rx_flags(dev, IFF_PROMISC);
        }
index b12303dd39d9c68df84271963c2b9132fab7b035..b7ba91b074b33995deee5278fb54c30d100d041b 100644 (file)
 
 static __inline__ int scm_check_creds(struct ucred *creds)
 {
+       const 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;
index fc6ce04a3e35a809049a340edbc3e10470e5f28e..7b5dbe118c091f84cb41ac5638dc88e8ba8fc638 100644 (file)
@@ -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);
        }
 
index 37a4e777e3476e0d59060e2694e374ac7408dcc1..bd3c7b96bbaa627c55f2ec96818fcaf12e50d1de 100644 (file)
@@ -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;
index caa441d0956755e0e59f8aa62c8572d61b2eb89c..871d157cec4eabde6d13fd8a4f1266651eccb368 100644 (file)
@@ -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);
        }
 
index 41e0105d3828c3c9c8dd5d03c3aea4ec4e831658..38f9efd90e8d5ccdd68668e4df57d71ea4453a66 100644 (file)
@@ -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);
index f19ebd9b78f5040b6a16ff84a7771e8530e830c2..22b2a5e881eaf2013b29bd923a91c98c7e6fa327 100644 (file)
@@ -34,12 +34,12 @@ owner_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
                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;
 
@@ -60,12 +60,12 @@ owner_mt6_v0(const struct sk_buff *skb, const struct xt_match_param *par)
                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;
 
@@ -93,14 +93,14 @@ owner_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                       (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;
 
index 9f1ea4a27b356e1f93f8a8fdc5dcb125cf488f0c..e9c05b8f4f4517fc5b13b6295eebfd1cf75e0a1c 100644 (file)
@@ -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);
index 0c1cc76128006e81d39b663f994de9e78f8539f5..01392649b4626d930eaba64175a5e50f1dc1f57c 100644 (file)
@@ -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;
index 9a8ff684da79b3c9c98bc7d61ea10290d54f05ff..ad8c7a782da1f0daabcd7ff1f9076e1785ae0f23 100644 (file)
@@ -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;
index 0ebaff637e31d9bcb13d38e4f1dbba66390bb384..0ef4e3065bcde9d2a33e0a15d5bb2e4ae87f590c 100644 (file)
@@ -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;
 }
 
index 92764d836891833e1cb7f8255a38edacad1f3b7f..b7a562e655e9c01dc2780fbe1aeb0c6245b49c7c 100644 (file)
@@ -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);
index cb216b2df666dc260b79a0d0f2259ac123d5fabf..0443f83494585a634dad0f0b55c75bd2401b7d4b 100644 (file)
@@ -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->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;
index 66d5ac4773abac12f517c84b25916dc078cda007..b152e2b9b9888792700a0a1daf784f232a75aa6c 100644 (file)
@@ -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:
@@ -1126,8 +1125,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);
@@ -1187,8 +1185,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;
index 2458748190361328b3862092c82563fbb587bcf1..b9e391425e6fb5efb1e56fa12771af1cac876e89 100644 (file)
@@ -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;
@@ -330,7 +325,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;
 }
@@ -340,15 +335,29 @@ static int cap_task_create(unsigned long clone_flags)
        return 0;
 }
 
-static int cap_task_alloc_security(struct task_struct *p)
+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_task_free_security(struct task_struct *p)
+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;
@@ -750,7 +759,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 +769,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 +823,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);
@@ -824,11 +832,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);
@@ -890,10 +896,13 @@ 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_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_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 +919,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);
index 3976613db829044ab435ee21b7a6ad2161a6441c..79713545cd631158fc4acd69dbfdcdd3c098e384 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/capability.h>
+#include <linux/audit.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -29,7 +30,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;
 }
 
@@ -39,23 +40,41 @@ 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
+ * @audit: Whether to write an audit message or not
+ *
+ * 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, int audit)
 {
+       __u32 cap_raised;
+
        /* Derived from include/linux/sched.h:capable. */
-       if (cap_raised(tsk->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;
 }
 
+/**
+ * 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))
@@ -63,121 +82,157 @@ 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)
 {
-       /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
-       if (cap_issubset(child->cap_permitted, current->cap_permitted))
-               return 0;
-       if (capable(CAP_SYS_PTRACE))
-               return 0;
-       return -EPERM;
+       int ret = 0;
+
+       rcu_read_lock();
+       if (!cap_issubset(__task_cred(child)->cap_permitted,
+                         current_cred()->cap_permitted) &&
+           !capable(CAP_SYS_PTRACE))
+               ret = -EPERM;
+       rcu_read_unlock();
+       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)
 {
-       /* 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 ret = 0;
+
+       rcu_read_lock();
+       if (!cap_issubset(current_cred()->cap_permitted,
+                         __task_cred(parent)->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)
+/**
+ * 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;
+
        /* Derived from kernel/capability.c:sys_capget. */
-       *effective = target->cap_effective;
-       *inheritable = target->cap_inheritable;
-       *permitted = target->cap_permitted;
+       rcu_read_lock();
+       cred = __task_cred(target);
+       *effective   = cred->cap_effective;
+       *inheritable = cred->cap_inheritable;
+       *permitted   = cred->cap_permitted;
+       rcu_read_unlock();
        return 0;
 }
 
-#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);
-}
-
+/*
+ * 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_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)
-{
-       return !capable(CAP_SETPCAP);
+       /* they are so limited unless the current task has the CAP_SETPCAP
+        * capability
+        */
+       if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+               return 0;
+#endif
+       return 1;
 }
 
-#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
-
-int cap_capset_check (struct task_struct *target, 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,
-                                        current->cap_permitted))) {
+/**
+ * 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,
+              const kernel_cap_t *inheritable,
+              const kernel_cap_t *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(target->cap_inheritable,
-                                      current->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 (target->cap_permitted,
-                                       current->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 (struct task_struct *target, kernel_cap_t *effective,
-                    kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-       target->cap_effective = *effective;
-       target->cap_inheritable = *inheritable;
-       target->cap_permitted = *permitted;
-}
-
+/*
+ * Clear proposed capability sets for execve().
+ */
 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;
 }
 
 #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;
@@ -192,6 +247,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;
@@ -202,19 +265,75 @@ int cap_inode_killpriv(struct dentry *dentry)
        return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
 }
 
-static inline int cap_from_disk(struct vfs_cap_data *caps,
-                               struct linux_binprm *bprm, unsigned size)
+/*
+ * Calculate the new process capability sets from the capability sets attached
+ * to a file.
+ */
+static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
+                                         struct linux_binprm *bprm,
+                                         bool *effective)
+{
+       struct cred *new = bprm->cred;
+       unsigned i;
+       int ret = 0;
+
+       if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
+               *effective = true;
+
+       CAP_FOR_EACH_U32(i) {
+               __u32 permitted = caps->permitted.cap[i];
+               __u32 inheritable = caps->inheritable.cap[i];
+
+               /*
+                * pP' = (X & fP) | (pI & fI)
+                */
+               new->cap_permitted.cap[i] =
+                       (new->cap_bset.cap[i] & permitted) |
+                       (new->cap_inheritable.cap[i] & inheritable);
+
+               if (permitted & ~new->cap_permitted.cap[i])
+                       /* insufficient to execute correctly */
+                       ret = -EPERM;
+       }
+
+       /*
+        * For legacy apps, with no internal support for recognizing they
+        * do not have enough capabilities, we return an error if they are
+        * missing some "forced" (aka file-permitted) capabilities.
+        */
+       return *effective ? ret : 0;
+}
+
+/*
+ * Extract the on-exec-apply capability sets for an executable file.
+ */
+int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
 {
+       struct inode *inode = dentry->d_inode;
        __u32 magic_etc;
        unsigned tocopy, i;
-       int ret;
+       int size;
+       struct vfs_cap_data caps;
+
+       memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
+
+       if (!inode || !inode->i_op || !inode->i_op->getxattr)
+               return -ENODATA;
+
+       size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
+                                  XATTR_CAPS_SZ);
+       if (size == -ENODATA || size == -EOPNOTSUPP)
+               /* no data, that's ok */
+               return -ENODATA;
+       if (size < 0)
+               return size;
 
        if (size < sizeof(magic_etc))
                return -EINVAL;
 
-       magic_etc = le32_to_cpu(caps->magic_etc);
+       cpu_caps->magic_etc = 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;
@@ -229,77 +348,48 @@ 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;
-       }
-
-       ret = 0;
-
        CAP_FOR_EACH_U32(i) {
-               __u32 value_cpu;
-
-               if (i >= tocopy) {
-                       /*
-                        * Legacy capability sets have no upper bits
-                        */
-                       bprm->cap_post_exec_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->cap_bset.cap[i] & value_cpu) |
-                       (current->cap_inheritable.cap[i] &
-                               le32_to_cpu(caps->data[i].inheritable));
-               if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
-                       /*
-                        * insufficient to execute correctly
-                        */
-                       ret = -EPERM;
-               }
+               if (i >= tocopy)
+                       break;
+               cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
+               cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
        }
 
-       /*
-        * For legacy apps, with no internal support for recognizing they
-        * 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 0;
 }
 
-/* Locate any VFS capabilities: */
-static int get_file_caps(struct linux_binprm *bprm)
+/*
+ * 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;
        int rc = 0;
-       struct vfs_cap_data vcaps;
-       struct inode *inode;
+       struct cpu_vfs_cap_data vcaps;
 
        bprm_clear_caps(bprm);
 
+       if (!file_caps_enabled)
+               return 0;
+
        if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
                return 0;
 
        dentry = dget(bprm->file->f_dentry);
-       inode = dentry->d_inode;
-       if (!inode->i_op || !inode->i_op->getxattr)
-               goto out;
 
-       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
-                                  XATTR_CAPS_SZ);
-       if (rc == -ENODATA || rc == -EOPNOTSUPP) {
-               /* no data, that's ok */
-               rc = 0;
+       rc = get_vfs_caps_from_disk(dentry, &vcaps);
+       if (rc < 0) {
+               if (rc == -EINVAL)
+                       printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n",
+                               __func__, rc, bprm->filename);
+               else if (rc == -ENODATA)
+                       rc = 0;
                goto out;
        }
-       if (rc < 0)
-               goto out;
 
-       rc = cap_from_disk(&vcaps, bprm, rc);
+       rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective);
        if (rc == -EINVAL)
                printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
                       __func__, rc, bprm->filename);
@@ -323,18 +413,57 @@ int cap_inode_killpriv(struct dentry *dentry)
        return 0;
 }
 
-static inline int get_file_caps(struct linux_binprm *bprm)
+int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
+{
+       memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
+       return -ENODATA;
+}
+
+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)
+/*
+ * 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)
 {
+       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)) {
                /*
@@ -342,75 +471,113 @@ 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->cap_bset, current->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;
-}
-
-void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
-{
-       if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
-           !cap_issubset(bprm->cap_post_exec_permitted,
-                         current->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 = current->uid;
-                               bprm->e_gid = current->gid;
-                       }
-                       if (cap_limit_ptraced_target()) {
-                               bprm->cap_post_exec_permitted = cap_intersect(
-                                       bprm->cap_post_exec_permitted,
-                                       current->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);
        }
 
-       current->suid = current->euid = current->fsuid = bprm->e_uid;
-       current->sgid = current->egid = current->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)) {
-               current->cap_permitted = bprm->cap_post_exec_permitted;
-               if (bprm->cap_effective)
-                       current->cap_effective = bprm->cap_post_exec_permitted;
+               if (effective)
+                       new->cap_effective = new->cap_permitted;
                else
-                       cap_clear(current->cap_effective);
+                       cap_clear(new->cap_effective);
        }
+       bprm->cap_effective = effective;
 
-       /* AUD: Audit candidate if current->cap_effective is set */
+       /*
+        * Audit candidate if current->cap_effective is set
+        *
+        * We do not bother to audit if 3 things are true:
+        *   1) cap_effective has all caps
+        *   2) we are root
+        *   3) root is supposed to have all caps (SECURE_NOROOT)
+        * Since this is just a normal root execing a process.
+        *
+        * Number 1 above might fail if you don't have a full bset, but I think
+        * that is interesting information to audit.
+        */
+       if (!cap_isclear(new->cap_effective)) {
+               if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
+                   new->euid != 0 || new->uid != 0 ||
+                   issecure(SECURE_NOROOT)) {
+                       ret = audit_log_bprm_fcaps(bprm, new, old);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
 
-       current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+       new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
+       return 0;
 }
 
-int cap_bprm_secureexec (struct linux_binprm *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)
 {
-       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))
+               if (!cap_isclear(cred->cap_permitted))
                        return 1;
        }
 
-       return (current->euid != current->uid ||
-               current->egid != current->gid);
+       return (cred->euid != cred->uid ||
+               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)
 {
@@ -418,28 +585,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.
  *
@@ -453,10 +634,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
@@ -468,61 +649,60 @@ 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)
 {
-       if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
-           (current->uid != 0 && current->euid != 0 && current->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 (current->cap_permitted);
-               cap_clear (current->cap_effective);
-       }
-       if (old_euid == 0 && current->euid != 0) {
-               cap_clear (current->cap_effective);
-       }
-       if (old_euid != 0 && current->euid == 0) {
-               current->cap_effective = current->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)
+/**
+ * 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. */
-               if (!issecure (SECURE_NO_SETUID_FIXUP)) {
-                       cap_emulate_setxuid (old_ruid, old_euid, old_suid);
-               }
+               /* 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:
-               {
-                       uid_t old_fsuid = old_ruid;
 
-                       /* 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 && current->fsuid != 0) {
-                                       current->cap_effective =
-                                               cap_drop_fs_set(
-                                                   current->cap_effective);
-                               }
-                               if (old_fsuid != 0 && current->fsuid == 0) {
-                                       current->cap_effective =
-                                               cap_raise_fs_set(
-                                                   current->cap_effective,
-                                                   current->cap_permitted);
-                               }
-                       }
-                       break;
+       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)
+                               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;
+
        default:
                return -EINVAL;
        }
@@ -543,42 +723,71 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
  */
 static int cap_safe_nice(struct task_struct *p)
 {
-       if (!cap_issubset(p->cap_permitted, current->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;
 }
 
-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(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->cap_bset, cap);
+
+       cap_lower(new->cap_bset, cap);
        return 0;
 }
 
@@ -598,22 +807,42 @@ 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, long *rc_p)
+                  unsigned long arg4, unsigned long arg5)
 {
+       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(current->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
@@ -635,12 +864,12 @@ 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
-                        & ~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, SECURITY_CAP_AUDIT) != 0) /*[4]*/
                        /*
                         * [1] no changing of bits that are locked
                         * [2] no unlocking of locks
@@ -648,65 +877,80 @@ 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 {
-                       current->securebits = arg2;
-               }
-               break;
+                   )
+                       /* cannot change a locked bit */
+                       goto error;
+               new->securebits = arg2;
+               goto changed;
+
        case PR_GET_SECUREBITS:
-               error = current->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)
-                       current->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
-                       current->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;
-}
+changed:
+       return commit_creds(new);
 
-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;
+no_change:
+       error = 0;
+error:
+       abort_creds(new);
+       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;
 
-       if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+       if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0)
                cap_sys_admin = 1;
        return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
-
index 239098f0fd763f846b593de4432f4b887f3fa702..81932abefe7b1b3120c06c44365c07f889a397ec 100644 (file)
@@ -12,8 +12,8 @@
 #ifndef _INTERNAL_H
 #define _INTERNAL_H
 
+#include <linux/sched.h>
 #include <linux/key-type.h>
-#include <linux/key-ui.h>
 
 static inline __attribute__((format(printf, 1, 2)))
 void no_printk(const char *fmt, ...)
@@ -26,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__)
@@ -82,6 +82,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,
@@ -95,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);
@@ -103,13 +106,13 @@ 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_user_keyrings(struct task_struct *tsk);
-extern int install_thread_keyring(struct task_struct *tsk);
-extern int install_process_keyring(struct task_struct *tsk);
+extern int install_user_keyrings(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,
@@ -119,12 +122,39 @@ 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(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,
+                              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_cred(), 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
  */
 struct request_key_auth {
        struct key              *target_key;
-       struct task_struct      *context;
+       struct key              *dest_keyring;
+       const struct cred       *cred;
        void                    *callout_info;
        size_t                  callout_len;
        pid_t                   pid;
@@ -133,7 +163,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);
 
index 14948cf83ef6acc6ea19811465201ff5ae8660f0..f76c8a546fd3688e4cc2cadd076e05debe43f9a3 100644 (file)
@@ -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;
index acc9c89e40a8de6937cba2971c8805e09a4d0f6f..7c72baa02f2e93ff09c76be260201da3315e32e5 100644 (file)
@@ -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;
@@ -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;
        }
@@ -829,6 +829,60 @@ 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;
+}
+
+/*
+ * 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
@@ -839,13 +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;
-       key_ref_t keyring_ref;
+       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;
@@ -853,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->request_key_auth;
+       instkey = cred->request_key_auth;
        if (!instkey)
                goto error;
 
@@ -883,28 +939,20 @@ 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 */
-       if (ret == 0) {
-               key_put(current->request_key_auth);
-               current->request_key_auth = NULL;
-       }
+       if (ret == 0)
+               keyctl_change_reqkey_auth(NULL);
 
 error2:
        if (!vm)
@@ -923,15 +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;
-       key_ref_t keyring_ref;
+       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->request_key_auth;
+       instkey = cred->request_key_auth;
        if (!instkey)
                goto error;
 
@@ -941,27 +991,20 @@ 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 */
-       if (ret == 0) {
-               key_put(current->request_key_auth);
-               current->request_key_auth = NULL;
-       }
+       if (ret == 0)
+               keyctl_change_reqkey_auth(NULL);
 
 error:
        return ret;
@@ -975,35 +1018,56 @@ error:
  */
 long keyctl_set_reqkey_keyring(int reqkey_defl)
 {
-       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(current);
+               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(current);
-               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:
-               current->jit_keyring = reqkey_defl;
+       case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
+               goto set;
 
        case KEY_REQKEY_DEFL_NO_CHANGE:
-               return current->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() */
 
 /*****************************************************************************/
@@ -1018,7 +1082,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;
@@ -1062,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->request_key_auth);
-               current->request_key_auth = NULL;
-               ret = 0;
+               ret = keyctl_change_reqkey_auth(NULL);
                goto error;
        }
 
@@ -1079,10 +1141,12 @@ long keyctl_assume_authority(key_serial_t id)
                goto error;
        }
 
-       key_put(current->request_key_auth);
-       current->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;
 
@@ -1105,7 +1169,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 +1181,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);
        }
index a9ab8affc092d99d1f4d55da9f5c6d10964bb4a1..ed851574d07301ecc07f6920ffaee5be86635efd 100644 (file)
@@ -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"
 
@@ -244,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);
 
@@ -280,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)
@@ -303,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;
@@ -376,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 */
@@ -403,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 */
@@ -458,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() */
index 3b41f9b52537afc86326ebc62a45380d8aefaf69..5d9fc7b93f2e988f0b96c8fb2e89caacac4147cb 100644 (file)
 #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)
 {
        struct key *key;
@@ -29,7 +36,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,15 +44,12 @@ 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);
-
+               ret = groups_search(cred->group_info, key->gid);
                if (ret) {
                        kperm = key->perm >> 8;
                        goto use_these_perms;
@@ -56,6 +60,7 @@ int key_task_permission(const key_ref_t key_ref,
        kperm = key->perm;
 
 use_these_perms:
+
        /* use the top 8-bits of permissions for keys the caller possesses
         * - possessor permissions are additive with other permissions
         */
@@ -68,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() */
 
index f619170da760688f4d40c856ab2adb1a999fff26..7f508def50e319a5110032a7e169a19a5ec02fab 100644 (file)
@@ -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;
 
index 45b240af6dbe2cd1a9dd22b665e60590e0066a15..2f5d89e92b853a3a4e0ea910aa2e023fc749690a 100644 (file)
@@ -40,13 +40,17 @@ struct key_user root_key_user = {
 /*
  * install user and user session keyrings for a particular UID
  */
-int install_user_keyrings(struct task_struct *tsk)
+int install_user_keyrings(void)
 {
-       struct user_struct *user = tsk->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 @@ 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,
+                                                   cred, KEY_ALLOC_IN_QUOTA,
                                                    NULL);
                        if (IS_ERR(uid_keyring)) {
                                ret = PTR_ERR(uid_keyring);
@@ -83,7 +87,7 @@ 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);
+                                             cred, KEY_ALLOC_IN_QUOTA, NULL);
                        if (IS_ERR(session_keyring)) {
                                ret = PTR_ERR(session_keyring);
                                goto error_release;
@@ -115,140 +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(struct task_struct *tsk)
+static int install_thread_keyring(void)
 {
-       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->uid, tsk->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->thread_keyring;
-       tsk->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(struct task_struct *tsk)
+static int install_process_keyring(void)
 {
-       struct key *keyring;
-       char buf[20];
+       struct cred *new;
        int ret;
 
-       might_sleep();
-
-       if (!tsk->signal->process_keyring) {
-               sprintf(buf, "_pid.%u", tsk->tgid);
-
-               keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
-                                       KEY_ALLOC_QUOTA_OVERRUN, NULL);
-               if (IS_ERR(keyring)) {
-                       ret = PTR_ERR(keyring);
-                       goto error;
-               }
-
-               /* attach keyring */
-               spin_lock_irq(&tsk->sighand->siglock);
-               if (!tsk->signal->process_keyring) {
-                       tsk->signal->process_keyring = keyring;
-                       keyring = NULL;
-               }
-               spin_unlock_irq(&tsk->sighand->siglock);
+       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 task_struct *tsk,
-                                  struct key *keyring)
+static int install_session_keyring_to_cred(struct cred *cred,
+                                          struct key *keyring)
 {
        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->signal->session_keyring)
+               if (cred->tgcred->session_keyring)
                        flags = KEY_ALLOC_IN_QUOTA;
 
-               keyring = keyring_alloc(buf, tsk->uid, tsk->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->sighand->siglock);
-       old = tsk->signal->session_keyring;
-       rcu_assign_pointer(tsk->signal->session_keyring, keyring);
-       spin_unlock_irq(&tsk->sighand->siglock);
+       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 */
@@ -258,110 +250,29 @@ static int install_session_keyring(struct task_struct *tsk,
        }
 
        return 0;
+}
 
-} /* end install_session_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)
-{
-       key_check(tsk->thread_keyring);
-       key_check(tsk->request_key_auth);
-
-       /* no thread keyring yet */
-       tsk->thread_keyring = NULL;
-
-       /* copy the request_key() authorisation for this thread */
-       key_get(tsk->request_key_auth);
-
-       return 0;
-
-} /* end copy_keys() */
-
-/*****************************************************************************/
-/*
- * 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)
-{
-       key_put(tsk->thread_keyring);
-       key_put(tsk->request_key_auth);
-
-} /* end exit_keys() */
-
-/*****************************************************************************/
 /*
- * deal with execve()
+ * install a session keyring, discarding the old one
+ * - if a keyring is not supplied, an empty one is invented
  */
-int exec_keys(struct task_struct *tsk)
+static int install_session_keyring(struct key *keyring)
 {
-       struct key *old;
-
-       /* newly exec'd tasks don't get a thread keyring */
-       task_lock(tsk);
-       old = tsk->thread_keyring;
-       tsk->thread_keyring = NULL;
-       task_unlock(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);
-
-       key_put(old);
-
-       return 0;
+       struct cred *new;
+       int ret;
 
-} /* end exec_keys() */
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
 
-/*****************************************************************************/
-/*
- * deal with SUID programs
- * - we might want to make this invent a new session keyring
- */
-int suid_keys(struct task_struct *tsk)
-{
-       return 0;
+       ret = install_session_keyring_to_cred(new, NULL);
+       if (ret < 0) {
+               abort_creds(new);
+               return ret;
+       }
 
-} /* end suid_keys() */
+       return commit_creds(new);
+}
 
 /*****************************************************************************/
 /*
@@ -370,10 +281,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() */
@@ -385,10 +297,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() */
@@ -404,7 +317,7 @@ 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;
        key_ref_t key_ref, ret, err;
@@ -423,10 +336,10 @@ key_ref_t search_process_keyrings(struct key_type *type,
        err = ERR_PTR(-EAGAIN);
 
        /* search the thread keyring first */
-       if (context->thread_keyring) {
+       if (cred->thread_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->thread_keyring, 1),
-                       context, type, description, match);
+                       make_key_ref(cred->thread_keyring, 1),
+                       cred, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -444,10 +357,10 @@ 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),
-                       context, type, description, match);
+                       make_key_ref(cred->tgcred->process_keyring, 1),
+                       cred, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -465,13 +378,13 @@ 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);
+                       cred, type, description, match);
                rcu_read_unlock();
 
                if (!IS_ERR(key_ref))
@@ -490,10 +403,10 @@ key_ref_t search_process_keyrings(struct key_type *type,
                }
        }
        /* or search the user-session keyring */
-       else if (context->user->session_keyring) {
+       else if (cred->user->session_keyring) {
                key_ref = keyring_search_aux(
-                       make_key_ref(context->user->session_keyring, 1),
-                       context, type, description, match);
+                       make_key_ref(cred->user->session_keyring, 1),
+                       cred, type, description, match);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -514,20 +427,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 &&
-           context == current &&
+       if (cred->request_key_auth &&
+           cred == current_cred() &&
            type != &key_type_request_key_auth
            ) {
                /* defend against the auth key being revoked */
-               down_read(&context->request_key_auth->sem);
+               down_read(&cred->request_key_auth->sem);
 
-               if (key_validate(context->request_key_auth) == 0) {
-                       rka = context->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);
+                                                         match, rka->cred);
 
-                       up_read(&context->request_key_auth->sem);
+                       up_read(&cred->request_key_auth->sem);
 
                        if (!IS_ERR(key_ref))
                                goto found;
@@ -544,7 +457,7 @@ key_ref_t search_process_keyrings(struct key_type *type,
                                break;
                        }
                } else {
-                       up_read(&context->request_key_auth->sem);
+                       up_read(&cred->request_key_auth->sem);
                }
        }
 
@@ -572,93 +485,98 @@ 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)
 {
-       key_ref_t key_ref, skey_ref;
+       struct request_key_auth *rka;
+       const struct cred *cred;
        struct key *key;
+       key_ref_t key_ref, skey_ref;
        int ret;
 
-       if (!context)
-               context = current;
-
+try_again:
+       cred = get_current_cred();
        key_ref = ERR_PTR(-ENOKEY);
 
        switch (id) {
        case KEY_SPEC_THREAD_KEYRING:
-               if (!context->thread_keyring) {
+               if (!cred->thread_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_thread_keyring(context);
+                       ret = install_thread_keyring();
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
+                       goto reget_creds;
                }
 
-               key = context->thread_keyring;
+               key = cred->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 (!cred->tgcred->process_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_process_keyring(context);
+                       ret = install_process_keyring();
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
+                       goto reget_creds;
                }
 
-               key = context->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 (!context->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(context);
+                       ret = install_user_keyrings();
                        if (ret < 0)
                                goto error;
                        ret = install_session_keyring(
-                               context, context->user->session_keyring);
+                               cred->user->session_keyring);
+
                        if (ret < 0)
                                goto error;
+                       goto reget_creds;
                }
 
                rcu_read_lock();
-               key = rcu_dereference(context->signal->session_keyring);
+               key = rcu_dereference(cred->tgcred->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 (!cred->user->uid_keyring) {
+                       ret = install_user_keyrings();
                        if (ret < 0)
                                goto error;
                }
 
-               key = context->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 (!context->user->session_keyring) {
-                       ret = install_user_keyrings(context);
+               if (!cred->user->session_keyring) {
+                       ret = install_user_keyrings();
                        if (ret < 0)
                                goto error;
                }
 
-               key = context->user->session_keyring;
+               key = cred->user->session_keyring;
                atomic_inc(&key->usage);
                key_ref = make_key_ref(key, 1);
                break;
@@ -669,7 +587,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 = cred->request_key_auth;
                if (!key)
                        goto error;
 
@@ -677,6 +595,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 (!cred->request_key_auth)
+                       goto error;
+
+               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 = cred->request_key_auth->payload.data;
+                       key = rka->dest_keyring;
+                       atomic_inc(&key->usage);
+               }
+               up_read(&cred->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)
@@ -693,7 +630,7 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
                /* 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,11 +662,12 @@ 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, cred, perm);
        if (ret < 0)
                goto invalid_key;
 
 error:
+       put_cred(cred);
        return key_ref;
 
 invalid_key:
@@ -737,6 +675,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() */
 
 /*****************************************************************************/
@@ -748,20 +692,33 @@ invalid_key:
  */
 long join_session_keyring(const char *name)
 {
-       struct task_struct *tsk = current;
+       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(tsk, NULL);
+               ret = install_session_keyring_to_cred(new, NULL);
                if (ret < 0)
                        goto error;
 
-               rcu_read_lock();
-               ret = rcu_dereference(tsk->signal->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 */
@@ -771,29 +728,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, tsk->uid, tsk->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(tsk, 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() */
+}
index abea08f87fe20e4dc14b75bea5c7bbe67c659ba3..0e04f72ef2d4339c8ac50691d0171e138dc11df2 100644 (file)
@@ -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
  */
@@ -64,7 +66,7 @@ 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;
        char *argv[9], *envp[3], uid_str[12], gid_str[12];
@@ -74,15 +76,17 @@ static int call_sbin_request_key(struct key_construction *cons,
 
        kenter("{%d},{%d},%s", key->serial, authkey->serial, op);
 
-       ret = install_user_keyrings(tsk);
+       ret = install_user_keyrings();
        if (ret < 0)
                goto error_alloc;
 
        /* 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;
@@ -94,29 +98,24 @@ 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->thread_keyring ? tsk->thread_keyring->serial : 0);
+               cred->thread_keyring ? cred->thread_keyring->serial : 0);
 
        prkey = 0;
-       if (tsk->signal->process_keyring)
-               prkey = tsk->signal->process_keyring->serial;
-
-       sprintf(keyring_str[1], "%d", prkey);
+       if (cred->tgcred->process_keyring)
+               prkey = cred->tgcred->process_keyring->serial;
 
-       if (tsk->signal->session_keyring) {
-               rcu_read_lock();
-               sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
-               rcu_read_unlock();
-       } else {
-               sskey = tsk->user->session_keyring->serial;
-       }
+       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);
 
@@ -157,8 +156,8 @@ error_link:
        key_put(keyring);
 
 error_alloc:
-       kleave(" = %d", ret);
        complete_request_key(cons, ret);
+       kleave(" = %d", ret);
        return ret;
 }
 
@@ -167,7 +166,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;
@@ -181,7 +181,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);
@@ -209,46 +210,67 @@ 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 task_struct *tsk = current;
-       struct key *drop = NULL;
+       struct request_key_auth *rka;
+       const struct cred *cred = current_cred();
+       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) {
-               switch (tsk->jit_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 (cred->jit_keyring) {
                case KEY_REQKEY_DEFL_DEFAULT:
+               case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
+                       if (cred->request_key_auth) {
+                               authkey = cred->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(cred->thread_keyring);
                        if (dest_keyring)
                                break;
 
                case KEY_REQKEY_DEFL_PROCESS_KEYRING:
-                       dest_keyring = 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();
-                       drop = dest_keyring;
 
                        if (dest_keyring)
                                break;
 
                case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
-                       dest_keyring = tsk->user->session_keyring;
+                       dest_keyring =
+                               key_get(cred->user->session_keyring);
                        break;
 
                case KEY_REQKEY_DEFL_USER_KEYRING:
-                       dest_keyring = tsk->user->uid_keyring;
+                       dest_keyring = key_get(cred->user->uid_keyring);
                        break;
 
                case KEY_REQKEY_DEFL_GROUP_KEYRING:
@@ -257,10 +279,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;
 }
 
 /*
@@ -275,6 +296,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;
 
@@ -282,33 +304,28 @@ 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;
 
        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
         * 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;
 
-       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));
@@ -346,25 +363,36 @@ static struct key *construct_key_and_link(struct key_type *type,
        struct key *key;
        int ret;
 
-       user = key_user_lookup(current->fsuid);
+       kenter("");
+
+       user = key_user_lookup(current_fsuid());
        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);
-               if (ret < 0)
+               ret = construct_key(key, callout_info, callout_len, aux,
+                                   dest_keyring);
+               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);
 }
 
@@ -383,6 +411,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;
 
@@ -392,7 +421,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);
index bd237b0a6331efffeff58b6ab6b300f823cd76aa..86747151ee5b680ea1591bfb00aed4475e104f5f 100644 (file)
@@ -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,12 +122,13 @@ 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);
+       key_put(rka->dest_keyring);
        kfree(rka->callout_info);
        kfree(rka);
 
@@ -139,9 +140,10 @@ 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;
+       const struct cred *cred = current->cred;
        struct key *authkey = NULL;
        char desc[20];
        int ret;
@@ -163,31 +165,29 @@ 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 (cred->request_key_auth) {
                /* it is - use that instantiation context here too */
-               down_read(&current->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->request_key_auth->flags))
+               if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
                        goto auth_key_revoked;
 
-               irka = current->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->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);
+       rka->dest_keyring = key_get(dest_keyring);
        memcpy(rka->callout_info, callout_info, callout_len);
        rka->callout_len = callout_len;
 
@@ -195,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)) {
@@ -203,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->request_key_auth->sem);
+       up_read(&cred->request_key_auth->sem);
        kfree(rka->callout_info);
        kfree(rka);
        kleave("= -EKEYREVOKED");
@@ -223,6 +223,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);
@@ -254,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;
 
@@ -261,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);
index c3f68b5b372d31c74e7f3bbb8e5fbfc737b25cab..40fb4f15e27b6d360e1634c4d0f795e0edf621c1 100644 (file)
@@ -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,
index c0acfa7177e5d1a01d19375f94bfa1ff819637a3..f0d96a6cc4e91f6083da05314c51ad94b68ba96c 100644 (file)
@@ -145,25 +145,23 @@ 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(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(target, effective, inheritable, permitted);
+       return security_ops->capset(new, old,
+                                   effective, inheritable, permitted);
 }
 
-void security_capset_set(struct task_struct *target,
-                         kernel_cap_t *effective,
-                         kernel_cap_t *inheritable,
-                         kernel_cap_t *permitted)
+int security_capable(struct task_struct *tsk, int cap)
 {
-       security_ops->capset_set(target, effective, inheritable, permitted);
+       return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT);
 }
 
-int security_capable(struct task_struct *tsk, int cap)
+int security_capable_noaudit(struct task_struct *tsk, int cap)
 {
-       return security_ops->capable(tsk, cap);
+       return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT);
 }
 
 int security_acct(struct file *file)
@@ -215,34 +213,24 @@ int security_vm_enough_memory_kern(long pages)
        return security_ops->vm_enough_memory(current->mm, pages);
 }
 
-int security_bprm_alloc(struct linux_binprm *bprm)
-{
-       return security_ops->bprm_alloc_security(bprm);
-}
-
-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_set_creds(struct linux_binprm *bprm)
 {
-       security_ops->bprm_apply_creds(bprm, unsafe);
+       return security_ops->bprm_set_creds(bprm);
 }
 
-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);
+       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);
+       security_ops->bprm_committed_creds(bprm);
 }
 
 int security_bprm_secureexec(struct linux_binprm *bprm)
@@ -603,9 +591,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)
@@ -613,14 +601,29 @@ int security_task_create(unsigned long clone_flags)
        return security_ops->task_create(clone_flags);
 }
 
-int security_task_alloc(struct task_struct *p)
+void security_cred_free(struct cred *cred)
 {
-       return security_ops->task_alloc_security(p);
+       security_ops->cred_free(cred);
 }
 
-void security_task_free(struct task_struct *p)
+int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
 {
-       security_ops->task_free_security(p);
+       return security_ops->cred_prepare(new, old, gfp);
+}
+
+void security_commit_creds(struct cred *new, const struct cred *old)
+{
+       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)
@@ -628,10 +631,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)
@@ -713,14 +716,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)
@@ -1120,9 +1118,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)
@@ -1131,9 +1130,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)
index 64af2d3409ef5e24945ac65032eac831d05eae25..c73aeaa008e81681cdc141dd3fb9b545cf715808 100644 (file)
@@ -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->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;
index f85597a4d733f06d89e69987cf48f02606bb2d27..520f82ab3fbfbea2fc136af8f881bf41420c990a 100644 (file)
@@ -156,33 +156,62 @@ 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 task_alloc_security(struct task_struct *task)
+/*
+ * initialise the security for the init task
+ */
+static void cred_init_security(void)
 {
+       struct cred *cred = (struct cred *) current->real_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;
-       task->security = tsec;
+       tsec->osid = tsec->sid = SECINITSID_KERNEL;
+       cred->security = tsec;
+}
 
-       return 0;
+/*
+ * 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;
 }
 
-static void task_free_security(struct task_struct *task)
+/*
+ * get the objective security ID of a task
+ */
+static inline u32 task_sid(const struct task_struct *task)
 {
-       struct task_security_struct *tsec = task->security;
-       task->security = NULL;
-       kfree(tsec);
+       u32 sid;
+
+       rcu_read_lock();
+       sid = cred_sid(__task_cred(task));
+       rcu_read_unlock();
+       return sid;
 }
 
+/*
+ * get the subjective security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+       const struct task_security_struct *tsec = current_cred()->security;
+
+       return tsec->sid;
+}
+
+/* Allocate and free functions for each kind of security blob. */
+
 static int inode_alloc_security(struct inode *inode)
 {
-       struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
+       u32 sid = current_sid();
 
        isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
        if (!isec)
@@ -193,7 +222,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;
@@ -215,15 +244,15 @@ static void inode_free_security(struct inode *inode)
 
 static int file_alloc_security(struct file *file)
 {
-       struct task_security_struct *tsec = current->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;
@@ -338,8 +367,9 @@ static const 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,
@@ -354,8 +384,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);
@@ -553,8 +584,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->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;
@@ -680,8 +711,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;
 
@@ -695,12 +725,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;
                }
@@ -712,7 +744,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;
 
@@ -730,7 +763,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;
                }
@@ -1345,18 +1378,53 @@ 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 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
+ * - this uses the default subjective creds of tsk1
+ */
+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->security;
-       tsec2 = tsk2->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);
+}
+
+/*
+ * 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
@@ -1365,14 +1433,14 @@ static int task_has_perm(struct task_struct *tsk1,
 
 /* Check whether a task is allowed to use a capability. */
 static int task_has_capability(struct task_struct *tsk,
-                              int cap)
+                              int cap, int audit)
 {
-       struct task_security_struct *tsec;
        struct avc_audit_data ad;
+       struct av_decision avd;
        u16 sclass;
+       u32 sid = task_sid(tsk);
        u32 av = CAP_TO_MASK(cap);
-
-       tsec = tsk->security;
+       int rc;
 
        AVC_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
@@ -1390,37 +1458,39 @@ 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);
+
+       rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
+       if (audit == SECURITY_CAP_AUDIT)
+               avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+       return rc;
 }
 
 /* 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;
+       u32 sid = task_sid(tsk);
 
-       tsec = tsk->security;
-
-       return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
+       return avc_has_perm(sid, SECINITSID_KERNEL,
                            SECCLASS_SYSTEM, perms, NULL);
 }
 
 /* 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)
 {
-       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->security;
+       sid = cred_sid(cred);
        isec = inode->i_security;
 
        if (!adp) {
@@ -1429,23 +1499,24 @@ 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
    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
@@ -1456,33 +1527,35 @@ 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 task_security_struct *tsec = tsk->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 = cred_sid(cred);
        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);
                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. */
@@ -1490,36 +1563,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->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;
 
@@ -1532,11 +1605,9 @@ static int may_create(struct inode *dir,
 static int may_create_key(u32 ksid,
                          struct task_struct *ctx)
 {
-       struct task_security_struct *tsec;
+       u32 sid = task_sid(ctx);
 
-       tsec = ctx->security;
-
-       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
@@ -1549,13 +1620,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->security;
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
@@ -1564,7 +1634,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;
 
@@ -1584,7 +1654,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;
 }
 
@@ -1593,14 +1663,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->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);
@@ -1609,16 +1678,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;
@@ -1628,13 +1697,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)
@@ -1645,18 +1714,16 @@ 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 task_security_struct *tsec;
        struct superblock_security_struct *sbsec;
+       u32 sid = cred_sid(cred);
 
-       tsec = tsk->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. */
@@ -1687,15 +1754,39 @@ static inline u32 file_mask_to_av(int mode, int mask)
        return av;
 }
 
+/* Convert a Linux file to an access vector. */
+static inline u32 file_to_av(struct file *file)
+{
+       u32 av = 0;
+
+       if (file->f_mode & FMODE_READ)
+               av |= FILE__READ;
+       if (file->f_mode & FMODE_WRITE) {
+               if (file->f_flags & O_APPEND)
+                       av |= FILE__APPEND;
+               else
+                       av |= FILE__WRITE;
+       }
+       if (!av) {
+               /*
+                * Special file opened with flags 3 for ioctl-only use.
+                */
+               av = FILE__IOCTL;
+       }
+
+       return av;
+}
+
 /*
- * Convert a file mask to an access vector and include the correct open
+ * Convert a file to an access vector and include the correct open
  * open permission.
  */
-static inline u32 open_file_mask_to_av(int mode, int mask)
+static inline u32 open_file_to_av(struct file *file)
 {
-       u32 av = file_mask_to_av(mode, mask);
+       u32 av = file_to_av(file);
 
        if (selinux_policycap_openperm) {
+               mode_t mode = file->f_path.dentry->d_inode->i_mode;
                /*
                 * lnk files and socks do not really have an 'open'
                 */
@@ -1711,34 +1802,11 @@ static inline u32 open_file_mask_to_av(int mode, int mask)
                        av |= DIR__OPEN;
                else
                        printk(KERN_ERR "SELinux: WARNING: inside %s with "
-                               "unknown mode:%x\n", __func__, mode);
+                               "unknown mode:%o\n", __func__, mode);
        }
        return av;
 }
 
-/* Convert a Linux file to an access vector. */
-static inline u32 file_to_av(struct file *file)
-{
-       u32 av = 0;
-
-       if (file->f_mode & FMODE_READ)
-               av |= FILE__READ;
-       if (file->f_mode & FMODE_WRITE) {
-               if (file->f_flags & O_APPEND)
-                       av |= FILE__APPEND;
-               else
-                       av |= FILE__WRITE;
-       }
-       if (!av) {
-               /*
-                * Special file opened with flags 3 for ioctl-only use.
-                */
-               av = FILE__IOCTL;
-       }
-
-       return av;
-}
-
 /* Hook functions begin here. */
 
 static int selinux_ptrace_may_access(struct task_struct *child,
@@ -1751,13 +1819,12 @@ 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;
-               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);
+       return current_has_perm(child, PROCESS__PTRACE);
 }
 
 static int selinux_ptrace_traceme(struct task_struct *parent)
@@ -1776,40 +1843,37 @@ 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;
 
        return secondary_ops->capget(target, effective, inheritable, permitted);
 }
 
-static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective,
-                               kernel_cap_t *inheritable, 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(target, effective, inheritable, permitted);
+       error = secondary_ops->capset(new, old,
+                                     effective, inheritable, permitted);
        if (error)
                return error;
 
-       return task_has_perm(current, target, PROCESS__SETCAP);
+       return cred_has_perm(old, new, PROCESS__SETCAP);
 }
 
-static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
-                              kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-       secondary_ops->capset_set(target, effective, inheritable, permitted);
-}
-
-static int selinux_capable(struct task_struct *tsk, int cap)
+static int selinux_capable(struct task_struct *tsk, int cap, int audit)
 {
        int rc;
 
-       rc = secondary_ops->capable(tsk, cap);
+       rc = secondary_ops->capable(tsk, cap, audit);
        if (rc)
                return rc;
 
-       return task_has_capability(tsk, cap);
+       return task_has_capability(tsk, cap, audit);
 }
 
 static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
@@ -1857,15 +1921,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->security;
+       sid = current_sid();
 
        rc = selinux_sysctl_get_sid(table, (op == 0001) ?
                                    SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1877,7 +1940,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;
@@ -1886,7 +1949,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);
        }
 
@@ -1895,6 +1958,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)
@@ -1906,14 +1970,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 */
@@ -1924,7 +1986,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)
@@ -1972,16 +2036,8 @@ 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;
-
-       rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
-       if (rc == 0)
-               rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
-                                         SECCLASS_CAPABILITY,
-                                         CAP_TO_MASK(CAP_SYS_ADMIN),
-                                         0,
-                                         NULL);
 
+       rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
        if (rc == 0)
                cap_sys_admin = 1;
 
@@ -1990,59 +2046,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)
-{
-       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)
+static int selinux_bprm_set_creds(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;
        }
@@ -2051,33 +2093,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;
 }
 
@@ -2086,35 +2158,34 @@ 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)
 {
-       struct task_security_struct *tsec = current->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,
-                                        SECCLASS_PROCESS,
-                                        PROCESS__NOATSECURE, NULL);
+               atsecure = avc_has_perm(osid, sid,
+                                       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;
 
 /* 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)
 {
        struct avc_audit_data ad;
        struct file *file, *devnull = NULL;
@@ -2136,7 +2207,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
                           interested in the inode-based check here. */
                        file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list);
                        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;
                        }
@@ -2171,7 +2242,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);
@@ -2185,7 +2256,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);
@@ -2204,94 +2278,78 @@ static inline void flush_unauthorized_files(struct files_struct *files)
        spin_unlock(&files->file_lock);
 }
 
-static void 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;
-       u32 sid;
-       int rc;
-
-       secondary_ops->bprm_apply_creds(bprm, unsafe);
-
-       tsec = current->security;
+       struct task_security_struct *new_tsec;
+       struct rlimit *rlim, *initrlim;
+       int rc, i;
 
-       bsec = bprm->security;
-       sid = bsec->sid;
+       secondary_ops->bprm_committing_creds(bprm);
 
-       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;
-                               return;
-                       }
-               }
+       new_tsec = bprm->cred->security;
+       if (new_tsec->sid == new_tsec->osid)
+               return;
 
-               /* 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;
+       /* Close files for which the new task SID is not authorized. */
+       flush_unauthorized_files(bprm->cred, current->files);
 
-                       rcu_read_lock();
-                       tracer = tracehook_tracer_task(current);
-                       if (likely(tracer != NULL)) {
-                               sec = tracer->security;
-                               ptsid = sec->sid;
-                       }
-                       rcu_read_unlock();
+       /* Always clear parent death signal on SID transitions. */
+       current->pdeath_signal = 0;
 
-                       if (ptsid != 0) {
-                               rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
-                                                 PROCESS__PTRACE, NULL);
-                               if (rc) {
-                                       bsec->unsafe = 1;
-                                       return;
-                               }
-                       }
+       /* 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);
                }
-               tsec->sid = sid;
+               update_rlimit_cpu(rlim->rlim_cur);
        }
 }
 
 /*
- * 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)
 {
-       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;
+       struct sighand_struct *psig;
+       u32 osid, sid;
        int rc, i;
+       unsigned long flags;
 
-       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(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++)
@@ -2304,33 +2362,14 @@ 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);
-               }
-               update_rlimit_cpu(rlim->rlim_cur);
-       }
-
-       /* Wake up the parent if it is waiting so that it can
-          recheck wait permission to the new task SID. */
+       /* Wake up the parent if it is waiting so that it can recheck
+        * wait permission to the new task SID. */
+       read_lock_irq(&tasklist_lock);
+       psig = current->parent->sighand;
+       spin_lock_irqsave(&psig->siglock, flags);
        wake_up_interruptible(&current->parent->signal->wait_chldexit);
+       spin_unlock_irqrestore(&psig->siglock, flags);
+       read_unlock_irq(&tasklist_lock);
 }
 
 /* superblock security operations */
@@ -2437,6 +2476,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;
 
@@ -2446,16 +2486,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,
@@ -2464,6 +2505,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);
@@ -2471,22 +2513,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);
 }
 
@@ -2506,21 +2549,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->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) {
@@ -2623,21 +2667,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);
@@ -2649,12 +2697,13 @@ static int selinux_inode_permission(struct inode *inode, int mask)
                return 0;
        }
 
-       return inode_has_perm(current, inode,
-                              open_file_mask_to_av(inode->i_mode, mask), NULL);
+       return inode_has_perm(cred, inode,
+                             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);
@@ -2666,18 +2715,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)) {
@@ -2692,18 +2745,17 @@ 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,
                                  const void *value, size_t size, int flags)
 {
-       struct task_security_struct *tsec = current->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))
@@ -2719,7 +2771,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;
@@ -2733,12 +2785,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;
@@ -2778,12 +2830,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)
@@ -2806,7 +2862,6 @@ 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 inode_security_struct *isec = inode->i_security;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
@@ -2821,13 +2876,7 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
         * and lack of permission just means that we fall back to the
         * in-core context value, not a denial.
         */
-       error = secondary_ops->capable(current, CAP_MAC_ADMIN);
-       if (!error)
-               error = avc_has_perm_noaudit(tsec->sid, tsec->sid,
-                                            SECCLASS_CAPABILITY2,
-                                            CAPABILITY2__MAC_ADMIN,
-                                            0,
-                                            NULL);
+       error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
        if (!error)
                error = security_sid_to_context_force(isec->sid, &context,
                                                      &size);
@@ -2894,6 +2943,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;
 
@@ -2906,7 +2956,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;
@@ -2917,16 +2967,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->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);
 
@@ -2946,6 +2996,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)
@@ -2955,11 +3006,14 @@ 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();
+       int rc = 0;
+
 #ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
                /*
@@ -2967,9 +3021,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
 
@@ -2984,9 +3038,11 @@ 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;
+
+error:
+       return rc;
 }
 
 static int selinux_file_mmap(struct file *file, unsigned long reqprot,
@@ -2994,7 +3050,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->security))->sid;
+       u32 sid = current_sid();
 
        if (addr < mmap_min_addr)
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
@@ -3013,6 +3069,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);
@@ -3027,12 +3084,11 @@ 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) {
-                       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
@@ -3041,8 +3097,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,
-                                          FILE__EXECMOD);
+                       rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
                }
                if (rc)
                        return rc;
@@ -3054,12 +3109,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) {
@@ -3070,7 +3128,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 */
@@ -3080,7 +3138,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:
@@ -3094,7 +3152,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;
        }
 
@@ -3103,12 +3161,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->security;
        fsec = file->f_security;
-       fsec->fown_sid = tsec->sid;
+       fsec->fown_sid = current_sid();
 
        return 0;
 }
@@ -3117,14 +3173,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->security;
        fsec = file->f_security;
 
        if (!signum)
@@ -3132,20 +3187,23 @@ 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);
 }
 
 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)
+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;
@@ -3166,7 +3224,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, open_file_to_av(file), NULL);
 }
 
 /* task security operations */
@@ -3179,36 +3237,88 @@ 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);
 }
 
-static int selinux_task_alloc_security(struct task_struct *tsk)
+/*
+ * 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 = task_alloc_security(tsk);
-       if (rc)
-               return rc;
-       tsec2 = tsk->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;
 }
 
-static void selinux_task_free_security(struct task_struct *tsk)
+/*
+ * commit new credentials
+ */
+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)
 {
-       task_free_security(tsk);
+       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)
@@ -3222,9 +3332,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)
@@ -3235,23 +3346,22 @@ 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)
 {
-       struct task_security_struct *tsec = p->security;
-       *secid = tsec->sid;
+       *secid = task_sid(p);
 }
 
 static int selinux_task_setgroups(struct group_info *group_info)
@@ -3268,7 +3378,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)
@@ -3279,12 +3389,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)
@@ -3299,9 +3409,9 @@ 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);
+               return current_has_perm(current, PROCESS__SETRLIMIT);
 
        return 0;
 }
@@ -3314,17 +3424,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,
@@ -3332,7 +3442,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)
@@ -3342,11 +3451,11 @@ 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;
        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);
+               rc = current_has_perm(p, perm);
        return rc;
 }
 
@@ -3354,13 +3463,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)
@@ -3368,27 +3476,14 @@ 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->security;
-       tsec->osid = tsec->sid;
-       tsec->sid = SECINITSID_KERNEL;
-       return;
-}
-
 static void selinux_task_to_inode(struct task_struct *p,
                                  struct inode *inode)
 {
-       struct task_security_struct *tsec = p->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 */
@@ -3627,19 +3722,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->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;
@@ -3648,18 +3743,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->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;
@@ -3668,18 +3765,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->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) {
@@ -3714,7 +3819,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;
@@ -3722,7 +3826,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                struct sock *sk = sock->sk;
                u32 sid, node_perm;
 
-               tsec = current->security;
                isec = SOCK_INODE(sock)->i_security;
 
                if (family == PF_INET) {
@@ -4387,7 +4490,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
                                  "SELinux:  unrecognized netlink message"
                                  " type=%hu for sclass=%hu\n",
                                  nlh->nlmsg_type, isec->sclass);
-                       if (!selinux_enforcing)
+                       if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
 
@@ -4763,15 +4866,16 @@ static int ipc_alloc_security(struct task_struct *task,
                              struct kern_ipc_perm *perm,
                              u16 sclass)
 {
-       struct task_security_struct *tsec = task->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;
@@ -4809,17 +4913,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->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)
@@ -4835,22 +4938,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->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);
@@ -4866,17 +4968,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->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);
 }
 
@@ -4910,13 +5011,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->security;
        isec = msq->q_perm.security;
        msec = msg->security;
 
@@ -4928,9 +5028,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;
@@ -4940,16 +5038,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;
 }
@@ -4958,23 +5056,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->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;
 }
@@ -4982,22 +5079,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->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);
@@ -5013,17 +5109,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->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);
 }
 
@@ -5081,22 +5176,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->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);
@@ -5112,17 +5206,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->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);
 }
 
@@ -5212,33 +5305,35 @@ 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;
 
        if (current != p) {
-               error = task_has_perm(current, p, PROCESS__GETATTR);
+               error = current_has_perm(p, PROCESS__GETATTR);
                if (error)
                        return error;
        }
 
-       tsec = p->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;
@@ -5247,6 +5342,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,7 +5353,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;
 
@@ -5270,15 +5370,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)
@@ -5301,87 +5401,75 @@ 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->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;
-               /*
-                * SELinux allows to change context in the following case only.
-                *  - Single threaded processes.
-                *  - Multi threaded processes intend to change its context into
-                *    more restricted domain (defined by TYPEBOUNDS statement).
-                */
-               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);
-                                       error = security_bounded_transition(tsec->sid, sid);
-                                       if (!error)
-                                               goto boundary_ok;
-
-                                       return error;
-                               }
-                       } while_each_thread(g, t);
-                       read_unlock(&tasklist_lock);
+                       goto abort_change;
+
+               /* Only allow single threaded processes to change context */
+               error = -EPERM;
+               if (!is_single_threaded(p)) {
+                       error = security_bounded_transition(tsec->sid, sid);
+                       if (error)
+                               goto abort_change;
                }
-boundary_ok:
 
                /* 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) {
-                       struct task_security_struct *ptsec = tracer->security;
-                       u32 ptsid = ptsec->sid;
-                       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)
@@ -5401,22 +5489,23 @@ 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)
 {
-       struct task_security_struct *tsec = tsk->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;
 
+       tsec = cred->security;
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
                ksec->sid = tsec->sid;
-       k->security = ksec;
 
+       k->security = ksec;
        return 0;
 }
 
@@ -5429,17 +5518,12 @@ 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 task_security_struct *tsec;
        struct key_security_struct *ksec;
-
-       key = key_ref_to_ptr(key_ref);
-
-       tsec = ctx->security;
-       ksec = key->security;
+       u32 sid;
 
        /* if no specific permissions are requested, we skip the
           permission check. No serious, additional covert channels
@@ -5447,8 +5531,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 = cred_sid(cred);
+
+       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)
@@ -5473,8 +5561,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,
@@ -5485,12 +5572,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,
@@ -5549,10 +5634,13 @@ 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_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_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,
@@ -5569,7 +5657,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,
@@ -5665,8 +5752,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;
@@ -5680,10 +5765,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))
-               panic("SELinux:  Failed to initialize initial task.\n");
-       tsec = current->security;
-       tsec->osid = tsec->sid = SECINITSID_KERNEL;
+       cred_init_security();
 
        sel_inode_cache = kmem_cache_create("selinux_inode_security",
                                            sizeof(struct inode_security_struct),
index 1223b4ff9bee4550b953134b82355f8d49b0b30a..c0c885427b91fe2ba57eebf5fa14f1a986410605 100644 (file)
    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")
index c4c51165c505e79c1a4b7708f5232f71d83a6480..0ba79fe00e11e834bd6c91cfd5020ff4563325f1 100644 (file)
 #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
index bd813c366e34d3e00025136fb131967ea3d033ca..21ec786611d411ea1bfd52c9a0add689c0951237 100644 (file)
@@ -72,3 +72,8 @@
     S_(NULL)
     S_("peer")
     S_("capability2")
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_("kernel_service")
index febf8868e8524226c637565802b6efbb411f88be..882f27d66facdbc780cb7ad6468af5d6b0796b78 100644 (file)
@@ -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
index f8be8d7fa26d7962f020e612254653d849f5b226..3cc45168f674fbe6c98c89f9597398af6778a95a 100644 (file)
@@ -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 */
index ff59c0c4804bd0f872cdba331cd0d48d18f59d0b..4ed7bab89c5938675fd21442550a0791826077d8 100644 (file)
@@ -63,6 +63,9 @@ static struct nlmsg_perm nlmsg_route_perms[] =
        { RTM_GETANYCAST,       NETLINK_ROUTE_SOCKET__NLMSG_READ  },
        { RTM_GETNEIGHTBL,      NETLINK_ROUTE_SOCKET__NLMSG_READ  },
        { RTM_SETNEIGHTBL,      NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+       { RTM_NEWADDRLABEL,     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+       { RTM_DELADDRLABEL,     NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+       { RTM_GETADDRLABEL,     NETLINK_ROUTE_SOCKET__NLMSG_READ  },
 };
 
 static struct nlmsg_perm nlmsg_firewall_perms[] =
index 69c9dccc8cf0a116beecd3b093950f5c9a33b791..c86303638235f2633eaff9c5426eed950517f785 100644 (file)
@@ -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->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);
 }
 
index 8f17f542a1160bc44ccff63f8a0fe07e756e86b5..c0eb72013d671a75a155481749b702a262521d65 100644 (file)
@@ -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;
+       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->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->security;
+       const struct task_security_struct *tsec = current_security();
        struct xfrm_sec_ctx *ctx = x->security;
        int rc = 0;
 
index 79ff21ed4c3be11b3f10f974874549617d1141a5..247cec3b5a43abfab3939148c6a8ac97faffee5c 100644 (file)
@@ -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_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))
index 6e2dc0bab70d837a57ac78a452603178761fbbb3..8ad48161cef50405ca55c4174483df3e337e673c 100644 (file)
@@ -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.
  */
@@ -102,7 +104,7 @@ 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_security(), task_security(ctp), MAY_READWRITE);
        if (rc != 0 && capable(CAP_MAC_OVERRIDE))
                return 0;
        return rc;
@@ -124,7 +126,7 @@ 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(task_security(ptp), current_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_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_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_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_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;
@@ -973,33 +975,75 @@ 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_free - "free" task-level security credentials
+ * @cred: the credentials in question
  *
  * Smack isn't using copies of blobs. Everyone
- * points to an immutable list. No alloc required.
- * No data copy required.
+ * points to an immutable list. The blobs never go away.
+ * There is no leak here.
+ */
+static void smack_cred_free(struct cred *cred)
+{
+       cred->security = NULL;
+}
+
+/**
+ * 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_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
  *
- * Always returns 0
+ * Set the security data for a kernel service.
  */
-static int smack_task_alloc_security(struct task_struct *tsk)
+static int smack_kernel_act_as(struct cred *new, u32 secid)
 {
-       tsk->security = current->security;
+       char *smack = smack_from_secid(secid);
+
+       if (smack == NULL)
+               return -EINVAL;
 
+       new->security = smack;
        return 0;
 }
 
 /**
- * smack_task_free_security - "free" a task blob
- * @task: the task with the blob
+ * 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
  *
- * Smack isn't using copies of blobs. Everyone
- * points to an immutable list. The blobs never go away.
- * There is no leak here.
+ * Set the file creation context in a set of credentials to the same
+ * as the objective context of the specified inode
  */
-static void smack_task_free_security(struct task_struct *task)
+static int smack_kernel_create_files_as(struct cred *new,
+                                       struct inode *inode)
 {
-       task->security = NULL;
+       struct inode_smack *isp = inode->i_security;
+
+       new->security = isp->smk_inode;
+       return 0;
 }
 
 /**
@@ -1011,7 +1055,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(task_security(p), MAY_WRITE);
 }
 
 /**
@@ -1022,7 +1066,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(task_security(p), MAY_READ);
 }
 
 /**
@@ -1033,7 +1077,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(task_security(p), MAY_READ);
 }
 
 /**
@@ -1045,7 +1089,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(task_security(p));
 }
 
 /**
@@ -1061,7 +1105,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(task_security(p), MAY_WRITE);
        return rc;
 }
 
@@ -1078,7 +1122,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(task_security(p), MAY_WRITE);
        return rc;
 }
 
@@ -1090,7 +1134,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(task_security(p), MAY_READ);
 }
 
 /**
@@ -1108,7 +1152,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(task_security(p), MAY_WRITE);
        return rc;
 }
 
@@ -1120,7 +1164,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(task_security(p), MAY_READ);
 }
 
 /**
@@ -1131,7 +1175,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(task_security(p), MAY_WRITE);
 }
 
 /**
@@ -1154,13 +1198,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(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->security, MAY_WRITE);
+       return smk_access(smack_from_secid(secid), task_security(p), MAY_WRITE);
 }
 
 /**
@@ -1173,7 +1217,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_security(), task_security(p), MAY_WRITE);
        if (rc == 0)
                return 0;
 
@@ -1204,7 +1248,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 = task_security(p);
 }
 
 /*
@@ -1223,7 +1267,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_security();
        struct socket_smack *ssp;
 
        ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
@@ -1448,7 +1492,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_security();
        return 0;
 }
 
@@ -1484,7 +1528,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_security();
        return 0;
 }
 
@@ -1593,7 +1637,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_security();
        return 0;
 }
 
@@ -1697,7 +1741,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_security();
        return 0;
 }
 
@@ -1852,7 +1896,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_security();
        char *fetched;
        char *final;
        struct dentry *dp;
@@ -2009,7 +2053,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(task_security(p), GFP_KERNEL);
        if (cp == NULL)
                return -ENOMEM;
 
@@ -2033,6 +2077,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;
 
        /*
@@ -2055,7 +2100,11 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        if (newsmack == NULL)
                return -EINVAL;
 
-       p->security = newsmack;
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+       new->security = newsmack;
+       commit_creds(new);
        return size;
 }
 
@@ -2288,8 +2337,7 @@ 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 = ssp->smk_out = current_security();
        ssp->smk_packet[0] = '\0';
 
        rc = smack_netlabel(sk);
@@ -2352,17 +2400,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->security;
+       key->security = cred->security;
        return 0;
 }
 
@@ -2380,14 +2428,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;
 
@@ -2403,10 +2451,10 @@ static int smack_key_permission(key_ref_t key_ref,
        /*
         * This should not occur
         */
-       if (context->security == NULL)
+       if (cred->security == NULL)
                return -EACCES;
 
-       return smk_access(context->security, keyp->security, MAY_READWRITE);
+       return smk_access(cred->security, keyp->security, MAY_READWRITE);
 }
 #endif /* CONFIG_KEYS */
 
@@ -2577,15 +2625,13 @@ 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,
        .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,
@@ -2627,9 +2673,12 @@ 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,
-       .task_post_setuid =             cap_task_post_setuid,
+       .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,
        .task_getsid =                  smack_task_getsid,
@@ -2642,7 +2691,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 +2766,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 +2776,8 @@ static __init int smack_init(void)
        /*
         * Set the security state for the initial task.
         */
-       current->security = &smack_known_floor.smk_known;
+       cred = (struct cred *) current->cred;
+       cred->security = &smack_known_floor.smk_known;
 
        /*
         * Initialize locks
index c21d8c8bf0c789f3af9693fac3cdbd226dd4b8cc..ca257dfdc75d08ccd52bddce447d5bb331a92242 100644 (file)
@@ -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_security());
 
        rc = netlbl_cfg_map_del(NULL, &audit_info);
        if (rc != 0)
@@ -371,7 +371,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_security());
 
        if (oldambient != NULL) {
                rc = netlbl_cfg_map_del(oldambient, &audit_info);
@@ -843,7 +843,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;