aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/exec.c31
-rw-r--r--fs/nfsd/auth.c92
-rw-r--r--fs/nfsd/nfs4recover.c68
-rw-r--r--fs/nfsd/nfsfh.c11
-rw-r--r--fs/open.c31
-rw-r--r--include/linux/audit.h22
-rw-r--r--include/linux/capability.h2
-rw-r--r--include/linux/cred.h44
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/key.h22
-rw-r--r--include/linux/sched.h6
-rw-r--r--include/linux/security.h178
-rw-r--r--init/main.c1
-rw-r--r--kernel/auditsc.c42
-rw-r--r--kernel/capability.c78
-rw-r--r--kernel/cred-internals.h21
-rw-r--r--kernel/cred.c321
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/fork.c7
-rw-r--r--kernel/kmod.c30
-rw-r--r--kernel/ptrace.c9
-rw-r--r--kernel/signal.c10
-rw-r--r--kernel/sys.c450
-rw-r--r--kernel/user.c37
-rw-r--r--kernel/user_namespace.c12
-rw-r--r--lib/Makefile2
-rw-r--r--net/rxrpc/ar-key.c6
-rw-r--r--security/capability.c21
-rw-r--r--security/commoncap.c265
-rw-r--r--security/keys/internal.h17
-rw-r--r--security/keys/key.c25
-rw-r--r--security/keys/keyctl.c95
-rw-r--r--security/keys/keyring.c14
-rw-r--r--security/keys/permission.c24
-rw-r--r--security/keys/proc.c8
-rw-r--r--security/keys/process_keys.c333
-rw-r--r--security/keys/request_key.c29
-rw-r--r--security/keys/request_key_auth.c41
-rw-r--r--security/security.c58
-rw-r--r--security/selinux/hooks.c286
-rw-r--r--security/smack/smack_lsm.c82
41 files changed, 1603 insertions, 1239 deletions
diff --git a/fs/exec.c b/fs/exec.c
index a5330e1a221..9bd3559ddec 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1007,13 +1007,12 @@ int flush_old_exec(struct linux_binprm * bprm)
*/
current->mm->task_size = TASK_SIZE;
- if (bprm->e_uid != current_euid() || bprm->e_gid != current_egid()) {
- suid_keys(current);
+ if (bprm->e_uid != current_euid() ||
+ bprm->e_gid != current_egid()) {
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
(bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
- suid_keys(current);
set_dumpable(current->mm, suid_dumpable);
}
@@ -1096,10 +1095,8 @@ void compute_creds(struct linux_binprm *bprm)
{
int unsafe;
- if (bprm->e_uid != current_uid()) {
- suid_keys(current);
+ if (bprm->e_uid != current_uid())
current->pdeath_signal = 0;
- }
exec_keys(current);
task_lock(current);
@@ -1709,8 +1706,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;
@@ -1723,12 +1721,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;
}
@@ -1739,12 +1745,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
*/
if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
- current->cred->fsuid = 0; /* Dump root private */
+ cred->fsuid = 0; /* Dump root private */
}
retval = coredump_wait(exit_code, &core_state);
- if (retval < 0)
+ if (retval < 0) {
+ put_cred(cred);
goto fail;
+ }
+
+ old_cred = override_creds(cred);
/*
* Clear any false indication of pending signals that might
@@ -1835,7 +1845,8 @@ fail_unlock:
if (helper_argv)
argv_free(helper_argv);
- current->cred->fsuid = fsuid;
+ revert_creds(old_cred);
+ put_cred(cred);
coredump_finish(mm);
fail:
return retval;
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 808fc03a6fb..836ffa1047d 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,55 +27,67 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
- struct cred *act_as = current->cred ;
- struct svc_cred cred = rqstp->rq_cred;
+ struct group_info *rqgi;
+ struct group_info *gi;
+ struct cred *new;
int i;
int flags = nfsexp_flags(rqstp, exp);
int ret;
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->fsuid = rqstp->rq_cred.cr_uid;
+ new->fsgid = rqstp->rq_cred.cr_gid;
+
+ rqgi = rqstp->rq_cred.cr_group_info;
+
if (flags & NFSEXP_ALLSQUASH) {
- cred.cr_uid = exp->ex_anon_uid;
- cred.cr_gid = exp->ex_anon_gid;
- cred.cr_group_info = groups_alloc(0);
+ new->fsuid = exp->ex_anon_uid;
+ new->fsgid = exp->ex_anon_gid;
+ gi = groups_alloc(0);
} else if (flags & NFSEXP_ROOTSQUASH) {
- struct group_info *gi;
- if (!cred.cr_uid)
- cred.cr_uid = exp->ex_anon_uid;
- if (!cred.cr_gid)
- cred.cr_gid = exp->ex_anon_gid;
- gi = groups_alloc(cred.cr_group_info->ngroups);
- if (gi)
- for (i = 0; i < cred.cr_group_info->ngroups; i++) {
- if (!GROUP_AT(cred.cr_group_info, i))
- GROUP_AT(gi, i) = exp->ex_anon_gid;
- else
- GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
- }
- cred.cr_group_info = gi;
- } else
- get_group_info(cred.cr_group_info);
-
- if (cred.cr_uid != (uid_t) -1)
- act_as->fsuid = cred.cr_uid;
- else
- act_as->fsuid = exp->ex_anon_uid;
- if (cred.cr_gid != (gid_t) -1)
- act_as->fsgid = cred.cr_gid;
- else
- act_as->fsgid = exp->ex_anon_gid;
+ if (!new->fsuid)
+ new->fsuid = exp->ex_anon_uid;
+ if (!new->fsgid)
+ new->fsgid = exp->ex_anon_gid;
- if (!cred.cr_group_info)
- return -ENOMEM;
- ret = set_groups(act_as, cred.cr_group_info);
- put_group_info(cred.cr_group_info);
- if ((cred.cr_uid)) {
- act_as->cap_effective =
- cap_drop_nfsd_set(act_as->cap_effective);
+ gi = groups_alloc(rqgi->ngroups);
+ if (!gi)
+ goto oom;
+
+ for (i = 0; i < rqgi->ngroups; i++) {
+ if (!GROUP_AT(rqgi, i))
+ GROUP_AT(gi, i) = exp->ex_anon_gid;
+ else
+ GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+ }
} else {
- act_as->cap_effective =
- cap_raise_nfsd_set(act_as->cap_effective,
- act_as->cap_permitted);
+ gi = get_group_info(rqgi);
}
+
+ if (new->fsuid == (uid_t) -1)
+ new->fsuid = exp->ex_anon_uid;
+ if (new->fsgid == (gid_t) -1)
+ new->fsgid = exp->ex_anon_gid;
+
+ ret = set_groups(new, gi);
+ put_group_info(gi);
+ if (!ret)
+ goto error;
+
+ if (new->uid)
+ new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
+ else
+ new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
+ return commit_creds(new);
+
+oom:
+ ret = -ENOMEM;
+error:
+ abort_creds(new);
return ret;
}
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 632a50b4b37..9371ea12d7f 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -54,20 +54,26 @@
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->cred->fsuid;
- *savegid = current->cred->fsgid;
- current->cred->fsuid = 0;
- current->cred->fsgid = 0;
+ struct cred *new;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->fsuid = 0;
+ new->fsgid = 0;
+ *original_creds = override_creds(new);
+ put_cred(new);
+ return 0;
}
static void
-nfs4_reset_user(uid_t saveuid, gid_t savegid)
+nfs4_reset_creds(const struct cred *original)
{
- current->cred->fsuid = saveuid;
- current->cred->fsgid = savegid;
+ revert_creds(original);
}
static void
@@ -129,10 +135,9 @@ nfsd4_sync_rec_dir(void)
int
nfsd4_create_clid_dir(struct nfs4_client *clp)
{
+ const struct cred *original_cred;
char *dname = clp->cl_recdir;
struct dentry *dentry;
- uid_t uid;
- gid_t gid;
int status;
dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -140,7 +145,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || clp->cl_firststate)
return 0;
- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ return status;
/* lock the parent */
mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
@@ -168,7 +175,7 @@ out_unlock:
clp->cl_firststate = 1;
nfsd4_sync_rec_dir();
}
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
return status;
}
@@ -211,20 +218,21 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
static int
nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
{
+ const struct cred *original_cred;
struct file *filp;
struct dentry_list_arg dla = {
.parent = dir,
};
struct list_head *dentries = &dla.dentries;
struct dentry_list *child;
- uid_t uid;
- gid_t gid;
int status;
if (!rec_dir_init)
return 0;
- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ return status;
filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
current_cred());
@@ -250,7 +258,7 @@ out:
dput(child->dentry);
kfree(child);
}
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
return status;
}
@@ -312,8 +320,7 @@ out:
void
nfsd4_remove_clid_dir(struct nfs4_client *clp)
{
- uid_t uid;
- gid_t gid;
+ const struct cred *original_cred;
int status;
if (!rec_dir_init || !clp->cl_firststate)
@@ -323,9 +330,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (status)
goto out;
clp->cl_firststate = 0;
- nfs4_save_user(&uid, &gid);
+
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ goto out;
+
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
if (status == 0)
nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.mnt);
@@ -402,16 +413,21 @@ nfsd4_recdir_load(void) {
void
nfsd4_init_recdir(char *rec_dirname)
{
- uid_t uid = 0;
- gid_t gid = 0;
- int status;
+ const struct cred *original_cred;
+ int status;
printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
rec_dirname);
BUG_ON(rec_dir_init);
- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0) {
+ printk("NFSD: Unable to change credentials to find recovery"
+ " directory: error %d\n",
+ status);
+ return;
+ }
status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
&rec_dir);
@@ -421,7 +437,7 @@ nfsd4_init_recdir(char *rec_dirname)
if (!status)
rec_dir_init = 1;
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
}
void
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index e67cfaea086..f0da7d9c3a9 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -186,9 +186,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
* access control settings being in effect, we cannot
* fix that case easily.
*/
- current->cred->cap_effective =
- cap_raise_nfsd_set(current->cred->cap_effective,
- current->cred->cap_permitted);
+ struct cred *new = prepare_creds();
+ if (!new)
+ return nfserrno(-ENOMEM);
+ new->cap_effective =
+ cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
+ put_cred(override_creds(new));
+ put_cred(new);
} else {
error = nfsd_setuser_and_check_port(rqstp, exp);
if (error)
diff --git a/fs/open.c b/fs/open.c
index f96eaab280a..c0a426d5766 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -425,30 +425,33 @@ out:
*/
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
- struct cred *cred = current->cred;
+ const struct cred *old_cred;
+ struct cred *override_cred;
struct path path;
struct inode *inode;
- int old_fsuid, old_fsgid;
- kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
- old_fsuid = cred->fsuid;
- old_fsgid = cred->fsgid;
+ override_cred = prepare_creds();
+ if (!override_cred)
+ return -ENOMEM;
- cred->fsuid = cred->uid;
- cred->fsgid = cred->gid;
+ override_cred->fsuid = override_cred->uid;
+ override_cred->fsgid = override_cred->gid;
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/* Clear the capabilities if we switch to a non-root user */
- if (current->cred->uid)
- old_cap = cap_set_effective(__cap_empty_set);
+ if (override_cred->uid)
+ cap_clear(override_cred->cap_effective);
else
- old_cap = cap_set_effective(cred->cap_permitted);
+ override_cred->cap_effective =
+ override_cred->cap_permitted;
}
+ old_cred = override_creds(override_cred);
+
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
if (res)
goto out;
@@ -485,12 +488,8 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
out_path_release:
path_put(&path);
out:
- cred->fsuid = old_fsuid;
- cred->fsgid = old_fsgid;
-
- if (!issecure(SECURE_NO_SETUID_FIXUP))
- cap_set_effective(old_cap);
-
+ revert_creds(old_cred);
+ put_cred(override_cred);
return res;
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 6fbebac7b1b..0b2fcb698a6 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -454,8 +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 void __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE);
-extern int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm);
+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)
{
@@ -522,16 +524,20 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
*
* -Eric
*/
-static inline void audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE)
+static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
+ const struct cred *new,
+ const struct cred *old)
{
if (unlikely(!audit_dummy_context()))
- __audit_log_bprm_fcaps(bprm, pP, pE);
+ return __audit_log_bprm_fcaps(bprm, new, old);
+ return 0;
}
-static inline int audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm)
+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, eff, inh, perm);
+ return __audit_log_capset(pid, new, old);
return 0;
}
@@ -566,8 +572,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, p, e) do { ; } while (0)
-#define audit_log_capset(pid, e, i, p) ({ 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
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 7f26580a5a4..e22f48c2a46 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -519,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
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 62b9e532422..eaf6fa695a0 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -84,6 +84,8 @@ struct thread_group_cred {
struct key *process_keyring; /* keyring private to this process */
struct rcu_head rcu; /* RCU deletion hook */
};
+
+extern void release_tgcred(struct cred *cred);
#endif
/*
@@ -137,11 +139,30 @@ struct cred {
struct user_struct *user; /* real user ID subscription */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
- spinlock_t lock; /* lock for pointer changes */
};
extern void __put_cred(struct cred *);
extern int copy_creds(struct task_struct *, unsigned long);
+extern struct cred *prepare_creds(void);
+extern struct cred *prepare_usermodehelper_creds(void);
+extern int commit_creds(struct cred *);
+extern void abort_creds(struct cred *);
+extern const struct cred *override_creds(const struct cred *) __deprecated;
+extern void revert_creds(const struct cred *) __deprecated;
+extern void __init cred_init(void);
+
+/**
+ * get_new_cred - Get a reference on a new set of credentials
+ * @cred: The new credentials to reference
+ *
+ * Get a reference on the specified set of new credentials. The caller must
+ * release the reference.
+ */
+static inline struct cred *get_new_cred(struct cred *cred)
+{
+ atomic_inc(&cred->usage);
+ return cred;
+}
/**
* get_cred - Get a reference on a set of credentials
@@ -150,10 +171,9 @@ extern int copy_creds(struct task_struct *, unsigned long);
* Get a reference on the specified set of credentials. The caller must
* release the reference.
*/
-static inline struct cred *get_cred(struct cred *cred)
+static inline const struct cred *get_cred(const struct cred *cred)
{
- atomic_inc(&cred->usage);
- return cred;
+ return get_new_cred((struct cred *) cred);
}
/**
@@ -166,6 +186,8 @@ static inline struct cred *get_cred(struct cred *cred)
static inline void put_cred(const struct cred *_cred)
{
struct cred *cred = (struct cred *) _cred;
+
+ BUG_ON(atomic_read(&(cred)->usage) <= 0);
if (atomic_dec_and_test(&(cred)->usage))
__put_cred(cred);
}
@@ -250,13 +272,13 @@ static inline void put_cred(const struct cred *_cred)
__groups; \
})
-#define task_cred_xxx(task, xxx) \
-({ \
- __typeof__(task->cred->xxx) ___val; \
- rcu_read_lock(); \
- ___val = __task_cred((task))->xxx; \
- rcu_read_unlock(); \
- ___val; \
+#define task_cred_xxx(task, xxx) \
+({ \
+ __typeof__(((struct cred *)NULL)->xxx) ___val; \
+ rcu_read_lock(); \
+ ___val = __task_cred((task))->xxx; \
+ rcu_read_unlock(); \
+ ___val; \
})
#define task_uid(task) (task_cred_xxx((task), uid))
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 5e24c54b6df..08c3b24ad9a 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -150,6 +150,8 @@ extern struct cred init_cred;
.sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \
.cred = &init_cred, \
+ .cred_exec_mutex = \
+ __MUTEX_INITIALIZER(tsk.cred_exec_mutex), \
.comm = "swapper", \
.thread = INIT_THREAD, \
.fs = &init_fs, \
diff --git a/include/linux/key.h b/include/linux/key.h
index 0836cc838b0..69ecf0934b0 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -73,6 +73,7 @@ struct key;
struct seq_file;
struct user_struct;
struct signal_struct;
+struct cred;
struct key_type;
struct key_owner;
@@ -181,7 +182,7 @@ struct key {
extern struct key *key_alloc(struct key_type *type,
const char *desc,
uid_t uid, gid_t gid,
- struct task_struct *ctx,
+ const struct cred *cred,
key_perm_t perm,
unsigned long flags);
@@ -249,7 +250,7 @@ extern int key_unlink(struct key *keyring,
struct key *key);
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- struct task_struct *ctx,
+ const struct cred *cred,
unsigned long flags,
struct key *dest);
@@ -276,22 +277,12 @@ extern ctl_table key_sysctls[];
/*
* the userspace interface
*/
-extern void switch_uid_keyring(struct user_struct *new_user);
-extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
-extern void exit_keys(struct task_struct *tsk);
-extern int suid_keys(struct task_struct *tsk);
+extern int install_thread_keyring_to_cred(struct cred *cred);
extern int exec_keys(struct task_struct *tsk);
extern void key_fsuid_changed(struct task_struct *tsk);
extern void key_fsgid_changed(struct task_struct *tsk);
extern void key_init(void);
-#define __install_session_keyring(keyring) \
-({ \
- struct key *old_session = current->cred->tgcred->session_keyring; \
- current->cred->tgcred->session_keyring = keyring; \
- old_session; \
-})
-
#else /* CONFIG_KEYS */
#define key_validate(k) 0
@@ -303,11 +294,6 @@ extern void key_init(void);
#define make_key_ref(k, p) NULL
#define key_ref_to_ptr(k) NULL
#define is_key_possessed(k) 0
-#define switch_uid_keyring(u) do { } while(0)
-#define __install_session_keyring(k) ({ NULL; })
-#define copy_keys(f,t) 0
-#define exit_keys(t) do { } while(0)
-#define suid_keys(t) do { } while(0)
#define exec_keys(t) do { } while(0)
#define key_fsuid_changed(t) do { } while(0)
#define key_fsgid_changed(t) do { } while(0)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2913252989b..121d655e460 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1145,7 +1145,8 @@ struct task_struct {
struct list_head cpu_timers[3];
/* process credentials */
- struct cred *cred; /* actual/objective task credentials */
+ const struct cred *cred; /* actual/objective task credentials (COW) */
+ struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */
char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
@@ -1720,7 +1721,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>
@@ -1870,6 +1870,8 @@ static inline unsigned long wait_task_inactive(struct task_struct *p,
#define for_each_process(p) \
for (p = &init_task ; (p = next_task(p)) != &init_task ; )
+extern bool is_single_threaded(struct task_struct *);
+
/*
* Careful: do_each_thread/while_each_thread is a double loop so
* 'break' will not work as expected - use goto instead.
diff --git a/include/linux/security.h b/include/linux/security.h
index 7e9fe046a0d..68be1125144 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -53,24 +53,21 @@ extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
-extern int cap_capset_check(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
-extern void cap_capset_set(const kernel_cap_t *effective,
- const kernel_cap_t *inheritable,
- const kernel_cap_t *permitted);
+extern int cap_capset(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted);
extern int cap_bprm_set_security(struct linux_binprm *bprm);
-extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
+extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
-extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
-extern void cap_task_reparent_to_init(struct task_struct *p);
+extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5, long *rc_p);
+ unsigned long arg4, unsigned long arg5);
extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
@@ -170,8 +167,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Compute and set the security attributes of a process being transformed
* by an execve operation based on the old attributes (current->security)
* and the information saved in @bprm->security by the set_security hook.
- * Since this hook function (and its caller) are void, this hook can not
- * return an error. However, it can leave the security attributes of the
+ * Since this function may return an error, in which case the process will
+ * be killed. However, it can leave the security attributes of the
* process unchanged if an access failure occurs at this point.
* bprm_apply_creds is called under task_lock. @unsafe indicates various
* reasons why it may be unsafe to change security state.
@@ -593,15 +590,18 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* manual page for definitions of the @clone_flags.
* @clone_flags contains the flags indicating what should be shared.
* Return 0 if permission is granted.
- * @cred_alloc_security:
- * @cred contains the cred struct for child process.
- * Allocate and attach a security structure to the cred->security field.
- * The security field is initialized to NULL when the task structure is
- * allocated.
- * Return 0 if operation was successful.