#include <linux/binfmts.h>
#include <linux/swap.h>
#include <linux/utsname.h>
+#include <linux/pid_namespace.h>
#include <linux/module.h>
#include <linux/namei.h>
#include <linux/proc_fs.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
-#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
#include <linux/audit.h>
+#include <linux/signalfd.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#endif
int core_uses_pid;
-char core_pattern[65] = "core";
+char core_pattern[CORENAME_MAX_SIZE] = "core";
int suid_dumpable = 0;
EXPORT_SYMBOL(suid_dumpable);
while (*tmp) {
if (fmt == *tmp) {
*tmp = fmt->next;
+ fmt->next = NULL;
write_unlock(&binfmt_lock);
return 0;
}
if (error)
goto out;
+ error = -EACCES;
+ if (nd.mnt->mnt_flags & MNT_NOEXEC)
+ goto exit;
error = -EINVAL;
if (!S_ISREG(nd.dentry->d_inode->i_mode))
goto exit;
bprm->loader += stack_base;
bprm->exec += stack_base;
- mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
if (!mpnt)
return -ENOMEM;
- memset(mpnt, 0, sizeof(*mpnt));
-
down_write(&mm->mmap_sem);
{
mpnt->vm_mm = mm;
struct task_struct *leader = NULL;
int count;
+ /*
+ * Tell all the sighand listeners that this sighand has
+ * been detached. The signalfd_detach() function grabs the
+ * sighand lock, if signal listeners are present on the sighand.
+ */
+ signalfd_detach(tsk);
+
/*
* If we don't share sighandlers, then we aren't sharing anything
* and we can just re-use it all.
* Reparenting needs write_lock on tasklist_lock,
* so it is safe to do it under read_lock.
*/
- if (unlikely(tsk->group_leader == child_reaper))
- child_reaper = tsk;
+ if (unlikely(tsk->group_leader == child_reaper(tsk)))
+ tsk->nsproxy->pid_ns->child_reaper = tsk;
zap_other_threads(tsk);
read_unlock(&tasklist_lock);
*/
detach_pid(tsk, PIDTYPE_PID);
tsk->pid = leader->pid;
- attach_pid(tsk, PIDTYPE_PID, tsk->pid);
+ attach_pid(tsk, PIDTYPE_PID, find_pid(tsk->pid));
transfer_pid(leader, tsk, PIDTYPE_PGID);
transfer_pid(leader, tsk, PIDTYPE_SID);
list_replace_rcu(&leader->tasks, &tsk->tasks);
spin_unlock(&oldsighand->siglock);
write_unlock_irq(&tasklist_lock);
- if (atomic_dec_and_test(&oldsighand->count))
- kmem_cache_free(sighand_cachep, oldsighand);
+ __cleanup_sighand(oldsighand);
}
BUG_ON(!thread_group_leader(tsk));
j++;
i = j * __NFDBITS;
fdt = files_fdtable(files);
- if (i >= fdt->max_fds || i >= fdt->max_fdset)
+ if (i >= fdt->max_fds)
break;
set = fdt->close_on_exec->fds_bits[j];
if (!set)
return 0;
mmap_failed:
- put_files_struct(current->files);
- current->files = files;
+ reset_files_struct(current, files);
out:
return retval;
}
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
- struct inode * inode = bprm->file->f_dentry->d_inode;
+ struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;
mode = inode->i_mode;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
- if(!(bprm->file->f_vfsmnt->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;
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
+ * the first '\0' encountered.
+ */
void remove_arg_zero(struct linux_binprm *bprm)
{
if (bprm->argc) {
- unsigned long offset;
- char * kaddr;
- struct page *page;
+ char ch;
+
+ do {
+ unsigned long offset;
+ unsigned long index;
+ char *kaddr;
+ struct page *page;
- offset = bprm->p % PAGE_SIZE;
- goto inside;
+ offset = bprm->p & ~PAGE_MASK;
+ index = bprm->p >> PAGE_SHIFT;
- while (bprm->p++, *(kaddr+offset++)) {
- if (offset != PAGE_SIZE)
- continue;
- offset = 0;
- kunmap_atomic(kaddr, KM_USER0);
-inside:
- page = bprm->page[bprm->p/PAGE_SIZE];
+ page = bprm->page[index];
kaddr = kmap_atomic(page, KM_USER0);
- }
- kunmap_atomic(kaddr, KM_USER0);
+
+ /* run through page until we reach end or find NUL */
+ do {
+ ch = *(kaddr + offset);
+
+ /* discard that character... */
+ bprm->p++;
+ offset++;
+ } while (offset < PAGE_SIZE && ch != '\0');
+
+ kunmap_atomic(kaddr, KM_USER0);
+
+ /* free the old page */
+ if (offset == PAGE_SIZE) {
+ __free_page(page);
+ bprm->page[index] = NULL;
+ }
+ } while (ch != '\0');
+
bprm->argc--;
}
}
-
EXPORT_SYMBOL(remove_arg_zero);
/*
EXPORT_SYMBOL(set_binfmt);
-#define CORENAME_MAX_SIZE 64
-
/* format_corename will inspect the pattern parameter, and output a
* name into corename, which must have space for at least
* CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
*/
-static void format_corename(char *corename, const char *pattern, long signr)
+static int format_corename(char *corename, const char *pattern, long signr)
{
const char *pat_ptr = pattern;
char *out_ptr = corename;
char *const out_end = corename + CORENAME_MAX_SIZE;
int rc;
int pid_in_pattern = 0;
+ int ispipe = 0;
+
+ if (*pattern == '|')
+ ispipe = 1;
/* Repeat as long as we have more pattern to process and more output
space */
case 'h':
down_read(&uts_sem);
rc = snprintf(out_ptr, out_end - out_ptr,
- "%s", system_utsname.nodename);
+ "%s", utsname()->nodename);
up_read(&uts_sem);
if (rc > out_end - out_ptr)
goto out;
*
* If core_pattern does not include a %p (as is the default)
* and core_uses_pid is set, then .%pid will be appended to
- * the filename */
- if (!pid_in_pattern
+ * the filename. Do not do this for piped commands. */
+ if (!ispipe && !pid_in_pattern
&& (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) {
rc = snprintf(out_ptr, out_end - out_ptr,
".%d", current->tgid);
goto out;
out_ptr += rc;
}
- out:
+out:
*out_ptr = 0;
+ return ispipe;
}
static void zap_process(struct task_struct *start)
int retval = 0;
int fsuid = current->fsuid;
int flag = 0;
+ int ispipe = 0;
+
+ audit_core_dumps(signr);
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
* uses lock_kernel()
*/
lock_kernel();
- format_corename(corename, core_pattern, signr);
+ ispipe = format_corename(corename, core_pattern, signr);
unlock_kernel();
- file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600);
+ if (ispipe) {
+ /* SIGPIPE can happen, but it's just never processed */
+ if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
+ printk(KERN_INFO "Core dump to %s pipe failed\n",
+ corename);
+ goto fail_unlock;
+ }
+ } else
+ file = filp_open(corename,
+ O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
+ 0600);
if (IS_ERR(file))
goto fail_unlock;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
- if (d_unhashed(file->f_dentry))
+ if (!ispipe && d_unhashed(file->f_path.dentry))
goto close_fail;
- if (!S_ISREG(inode->i_mode))
+ /* AK: actually i see no reason to not allow this for named pipes etc.,
+ but keep the previous behaviour for now. */
+ if (!ispipe && !S_ISREG(inode->i_mode))
goto close_fail;
if (!file->f_op)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
- if (do_truncate(file->f_dentry, 0, 0, file) != 0)
+ if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);