Merge branch 'next' into for-linus
This commit is contained in:
commit
cbacc2c7f0
223 changed files with 5707 additions and 3351 deletions
183
fs/exec.c
183
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
|
||||
|
@ -1270,6 +1281,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);
|
||||
}
|
||||
|
||||
|
@ -1295,10 +1308,20 @@ int do_execve(char * filename,
|
|||
if (!bprm)
|
||||
goto out_files;
|
||||
|
||||
retval = mutex_lock_interruptible(¤t->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();
|
||||
|
||||
|
@ -1312,14 +1335,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);
|
||||
|
@ -1341,21 +1360,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;
|
||||
|
||||
/* execve succeeded */
|
||||
mutex_unlock(¤t->cred_exec_mutex);
|
||||
acct_update_integrals(current);
|
||||
free_bprm(bprm);
|
||||
if (displaced)
|
||||
put_files_struct(displaced);
|
||||
return retval;
|
||||
|
||||
out:
|
||||
if (bprm->security)
|
||||
security_bprm_free(bprm);
|
||||
|
||||
out_mm:
|
||||
if (bprm->mm)
|
||||
mmput (bprm->mm);
|
||||
|
||||
|
@ -1364,7 +1380,11 @@ out_file:
|
|||
allow_write_access(bprm->file);
|
||||
fput(bprm->file);
|
||||
}
|
||||
out_kfree:
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(¤t->cred_exec_mutex);
|
||||
|
||||
out_free:
|
||||
free_bprm(bprm);
|
||||
|
||||
out_files:
|
||||
|
@ -1396,6 +1416,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;
|
||||
|
@ -1432,7 +1453,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;
|
||||
|
@ -1440,7 +1461,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;
|
||||
|
@ -1716,8 +1737,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;
|
||||
|
@ -1730,12 +1752,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;
|
||||
}
|
||||
|
||||
|
@ -1746,12 +1776,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
|
||||
|
@ -1823,7 +1857,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;
|
||||
|
@ -1842,7 +1876,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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue