Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 247949
b: refs/heads/master
c: 0e02846
h: refs/heads/master
i:
  247947: e5634ee
v: v3
  • Loading branch information
Oleg Nesterov committed Apr 9, 2011
1 parent 2e473a9 commit 331594d
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 252 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ba2d01629d0d167598cfea85adc7926822bbfc45
refs/heads/master: 0e028465d18b7c6797fcbdea632299d16097c5cd
235 changes: 0 additions & 235 deletions trunk/fs/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1306,241 +1306,6 @@ compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int
return do_sys_open(dfd, filename, flags, mode);
}

/*
* compat_count() counts the number of arguments/envelopes. It is basically
* a copy of count() from fs/exec.c, except that it works with 32 bit argv
* and envp pointers.
*/
static int compat_count(compat_uptr_t __user *argv, int max)
{
int i = 0;

if (argv != NULL) {
for (;;) {
compat_uptr_t p;

if (get_user(p, argv))
return -EFAULT;
if (!p)
break;
argv++;
if (i++ >= max)
return -E2BIG;

if (fatal_signal_pending(current))
return -ERESTARTNOHAND;
cond_resched();
}
}
return i;
}

/*
* compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
* except that it works with 32 bit argv and envp pointers.
*/
static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
struct linux_binprm *bprm)
{
struct page *kmapped_page = NULL;
char *kaddr = NULL;
unsigned long kpos = 0;
int ret;

while (argc-- > 0) {
compat_uptr_t str;
int len;
unsigned long pos;

if (get_user(str, argv+argc) ||
!(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
ret = -EFAULT;
goto out;
}

if (len > MAX_ARG_STRLEN) {
ret = -E2BIG;
goto out;
}

/* We're going to work our way backwords. */
pos = bprm->p;
str += len;
bprm->p -= len;

while (len > 0) {
int offset, bytes_to_copy;

if (fatal_signal_pending(current)) {
ret = -ERESTARTNOHAND;
goto out;
}
cond_resched();

offset = pos % PAGE_SIZE;
if (offset == 0)
offset = PAGE_SIZE;

bytes_to_copy = offset;
if (bytes_to_copy > len)
bytes_to_copy = len;

offset -= bytes_to_copy;
pos -= bytes_to_copy;
str -= bytes_to_copy;
len -= bytes_to_copy;

if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
struct page *page;

page = get_arg_page(bprm, pos, 1);
if (!page) {
ret = -E2BIG;
goto out;
}

if (kmapped_page) {
flush_kernel_dcache_page(kmapped_page);
kunmap(kmapped_page);
put_page(kmapped_page);
}
kmapped_page = page;
kaddr = kmap(kmapped_page);
kpos = pos & PAGE_MASK;
flush_cache_page(bprm->vma, kpos,
page_to_pfn(kmapped_page));
}
if (copy_from_user(kaddr+offset, compat_ptr(str),
bytes_to_copy)) {
ret = -EFAULT;
goto out;
}
}
}
ret = 0;
out:
if (kmapped_page) {
flush_kernel_dcache_page(kmapped_page);
kunmap(kmapped_page);
put_page(kmapped_page);
}
return ret;
}

/*
* compat_do_execve() is mostly a copy of do_execve(), with the exception
* that it processes 32 bit argv and envp pointers.
*/
int compat_do_execve(char * filename,
compat_uptr_t __user *argv,
compat_uptr_t __user *envp,
struct pt_regs * regs)
{
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
bool clear_in_exec;
int retval;

retval = unshare_files(&displaced);
if (retval)
goto out_ret;

retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm)
goto out_files;

retval = prepare_bprm_creds(bprm);
if (retval)
goto out_free;

retval = check_unsafe_exec(bprm);
if (retval < 0)
goto out_free;
clear_in_exec = retval;
current->in_execve = 1;

file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
goto out_unmark;

sched_exec();

bprm->file = file;
bprm->filename = filename;
bprm->interp = filename;

retval = bprm_mm_init(bprm);
if (retval)
goto out_file;

bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
goto out;

bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
goto out;

retval = prepare_binprm(bprm);
if (retval < 0)
goto out;

retval = copy_strings_kernel(1, &bprm->filename, bprm);
if (retval < 0)
goto out;

bprm->exec = bprm->p;
retval = compat_copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
goto out;

retval = compat_copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;

retval = search_binary_handler(bprm, regs);
if (retval < 0)
goto out;

/* execve succeeded */
current->fs->in_exec = 0;
current->in_execve = 0;
acct_update_integrals(current);
free_bprm(bprm);
if (displaced)
put_files_struct(displaced);
return retval;

out:
if (bprm->mm) {
acct_arg_size(bprm, 0);
mmput(bprm->mm);
}

out_file:
if (bprm->file) {
allow_write_access(bprm->file);
fput(bprm->file);
}

out_unmark:
if (clear_in_exec)
current->fs->in_exec = 0;
current->in_execve = 0;

out_free:
free_bprm(bprm);

out_files:
if (displaced)
reset_files_struct(displaced);
out_ret:
return retval;
}

#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))

static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
Expand Down
62 changes: 50 additions & 12 deletions trunk/fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <linux/fs_struct.h>
#include <linux/pipe_fs_i.h>
#include <linux/oom.h>
#include <linux/compat.h>

#include <asm/uaccess.h>
#include <asm/mmu_context.h>
Expand Down Expand Up @@ -167,7 +168,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)

#ifdef CONFIG_MMU

void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
{
struct mm_struct *mm = current->mm;
long diff = (long)(pages - bprm->vma_pages);
Expand All @@ -186,7 +187,7 @@ void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
#endif
}

struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
int write)
{
struct page *page;
Expand Down Expand Up @@ -305,11 +306,11 @@ static bool valid_arg_len(struct linux_binprm *bprm, long len)

#else

void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages)
{
}

struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
int write)
{
struct page *page;
Expand Down Expand Up @@ -399,17 +400,36 @@ int bprm_mm_init(struct linux_binprm *bprm)
}

struct user_arg_ptr {
const char __user *const __user *native;
#ifdef CONFIG_COMPAT
bool is_compat;
#endif
union {
const char __user *const __user *native;
#ifdef CONFIG_COMPAT
compat_uptr_t __user *compat;
#endif
} ptr;
};

static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
const char __user *ptr;
const char __user *native;

#ifdef CONFIG_COMPAT
if (unlikely(argv.is_compat)) {
compat_uptr_t compat;

if (get_user(compat, argv.ptr.compat + nr))
return ERR_PTR(-EFAULT);

if (get_user(ptr, argv.native + nr))
return compat_ptr(compat);
}
#endif

if (get_user(native, argv.ptr.native + nr))
return ERR_PTR(-EFAULT);

return ptr;
return native;
}

/*
Expand All @@ -419,7 +439,7 @@ static int count(struct user_arg_ptr argv, int max)
{
int i = 0;

if (argv.native != NULL) {
if (argv.ptr.native != NULL) {
for (;;) {
const char __user *p = get_user_arg_ptr(argv, i);

Expand Down Expand Up @@ -542,7 +562,7 @@ int copy_strings_kernel(int argc, const char *const *__argv,
int r;
mm_segment_t oldfs = get_fs();
struct user_arg_ptr argv = {
.native = (const char __user *const __user *)__argv,
.ptr.native = (const char __user *const __user *)__argv,
};

set_fs(KERNEL_DS);
Expand Down Expand Up @@ -1516,10 +1536,28 @@ int do_execve(const char *filename,
const char __user *const __user *__envp,
struct pt_regs *regs)
{
struct user_arg_ptr argv = { .native = __argv };
struct user_arg_ptr envp = { .native = __envp };
struct user_arg_ptr argv = { .ptr.native = __argv };
struct user_arg_ptr envp = { .ptr.native = __envp };
return do_execve_common(filename, argv, envp, regs);
}

#ifdef CONFIG_COMPAT
int compat_do_execve(char *filename,
compat_uptr_t __user *__argv,
compat_uptr_t __user *__envp,
struct pt_regs *regs)
{
struct user_arg_ptr argv = {
.is_compat = true,
.ptr.compat = __argv,
};
struct user_arg_ptr envp = {
.is_compat = true,
.ptr.compat = __envp,
};
return do_execve_common(filename, argv, envp, regs);
}
#endif

void set_binfmt(struct linux_binfmt *new)
{
Expand Down
4 changes: 0 additions & 4 deletions trunk/include/linux/binfmts.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ struct linux_binprm {
unsigned long loader, exec;
};

extern void acct_arg_size(struct linux_binprm *bprm, unsigned long pages);
extern struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
int write);

#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)

Expand Down

0 comments on commit 331594d

Please sign in to comment.