diff options
| -rw-r--r-- | arch/parisc/hpux/fs.c | 15 | ||||
| -rw-r--r-- | fs/exec.c | 45 | ||||
| -rw-r--r-- | fs/namei.c | 30 | ||||
| -rw-r--r-- | include/linux/binfmts.h | 1 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 | ||||
| -rw-r--r-- | include/linux/sched.h | 3 | ||||
| -rw-r--r-- | init/main.c | 2 | ||||
| -rw-r--r-- | kernel/auditsc.c | 2 | ||||
| -rw-r--r-- | kernel/kmod.c | 2 |
9 files changed, 58 insertions, 43 deletions
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 88d0962de65a..2bedafea3d94 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c | |||
| @@ -33,22 +33,9 @@ | |||
| 33 | 33 | ||
| 34 | int hpux_execve(struct pt_regs *regs) | 34 | int hpux_execve(struct pt_regs *regs) |
| 35 | { | 35 | { |
| 36 | int error; | 36 | return do_execve(getname((const char __user *) regs->gr[26]), |
| 37 | struct filename *filename; | ||
| 38 | |||
| 39 | filename = getname((const char __user *) regs->gr[26]); | ||
| 40 | error = PTR_ERR(filename); | ||
| 41 | if (IS_ERR(filename)) | ||
| 42 | goto out; | ||
| 43 | |||
| 44 | error = do_execve(filename->name, | ||
| 45 | (const char __user *const __user *) regs->gr[25], | 37 | (const char __user *const __user *) regs->gr[25], |
| 46 | (const char __user *const __user *) regs->gr[24]); | 38 | (const char __user *const __user *) regs->gr[24]); |
| 47 | |||
| 48 | putname(filename); | ||
| 49 | |||
| 50 | out: | ||
| 51 | return error; | ||
| 52 | } | 39 | } |
| 53 | 40 | ||
| 54 | struct hpux_dirent { | 41 | struct hpux_dirent { |
| @@ -748,11 +748,10 @@ EXPORT_SYMBOL(setup_arg_pages); | |||
| 748 | 748 | ||
| 749 | #endif /* CONFIG_MMU */ | 749 | #endif /* CONFIG_MMU */ |
| 750 | 750 | ||
| 751 | struct file *open_exec(const char *name) | 751 | static struct file *do_open_exec(struct filename *name) |
| 752 | { | 752 | { |
| 753 | struct file *file; | 753 | struct file *file; |
| 754 | int err; | 754 | int err; |
| 755 | struct filename tmp = { .name = name }; | ||
| 756 | static const struct open_flags open_exec_flags = { | 755 | static const struct open_flags open_exec_flags = { |
| 757 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, | 756 | .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, |
| 758 | .acc_mode = MAY_EXEC | MAY_OPEN, | 757 | .acc_mode = MAY_EXEC | MAY_OPEN, |
| @@ -760,7 +759,7 @@ struct file *open_exec(const char *name) | |||
| 760 | .lookup_flags = LOOKUP_FOLLOW, | 759 | .lookup_flags = LOOKUP_FOLLOW, |
| 761 | }; | 760 | }; |
| 762 | 761 | ||
| 763 | file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags); | 762 | file = do_filp_open(AT_FDCWD, name, &open_exec_flags); |
| 764 | if (IS_ERR(file)) | 763 | if (IS_ERR(file)) |
| 765 | goto out; | 764 | goto out; |
| 766 | 765 | ||
| @@ -784,6 +783,12 @@ exit: | |||
| 784 | fput(file); | 783 | fput(file); |
| 785 | return ERR_PTR(err); | 784 | return ERR_PTR(err); |
| 786 | } | 785 | } |
| 786 | |||
| 787 | struct file *open_exec(const char *name) | ||
| 788 | { | ||
| 789 | struct filename tmp = { .name = name }; | ||
| 790 | return do_open_exec(&tmp); | ||
| 791 | } | ||
| 787 | EXPORT_SYMBOL(open_exec); | 792 | EXPORT_SYMBOL(open_exec); |
| 788 | 793 | ||
| 789 | int kernel_read(struct file *file, loff_t offset, | 794 | int kernel_read(struct file *file, loff_t offset, |
| @@ -1162,7 +1167,7 @@ int prepare_bprm_creds(struct linux_binprm *bprm) | |||
| 1162 | return -ENOMEM; | 1167 | return -ENOMEM; |
| 1163 | } | 1168 | } |
| 1164 | 1169 | ||
| 1165 | void free_bprm(struct linux_binprm *bprm) | 1170 | static void free_bprm(struct linux_binprm *bprm) |
| 1166 | { | 1171 | { |
| 1167 | free_arg_pages(bprm); | 1172 | free_arg_pages(bprm); |
| 1168 | if (bprm->cred) { | 1173 | if (bprm->cred) { |
| @@ -1432,7 +1437,7 @@ static int exec_binprm(struct linux_binprm *bprm) | |||
| 1432 | /* | 1437 | /* |
| 1433 | * sys_execve() executes a new program. | 1438 | * sys_execve() executes a new program. |
| 1434 | */ | 1439 | */ |
| 1435 | static int do_execve_common(const char *filename, | 1440 | static int do_execve_common(struct filename *filename, |
| 1436 | struct user_arg_ptr argv, | 1441 | struct user_arg_ptr argv, |
| 1437 | struct user_arg_ptr envp) | 1442 | struct user_arg_ptr envp) |
| 1438 | { | 1443 | { |
| @@ -1441,6 +1446,9 @@ static int do_execve_common(const char *filename, | |||
| 1441 | struct files_struct *displaced; | 1446 | struct files_struct *displaced; |
| 1442 | int retval; | 1447 | int retval; |
| 1443 | 1448 | ||
| 1449 | if (IS_ERR(filename)) | ||
| 1450 | return PTR_ERR(filename); | ||
| 1451 | |||
| 1444 | /* | 1452 | /* |
| 1445 | * We move the actual failure in case of RLIMIT_NPROC excess from | 1453 | * We move the actual failure in case of RLIMIT_NPROC excess from |
| 1446 | * set*uid() to execve() because too many poorly written programs | 1454 | * set*uid() to execve() because too many poorly written programs |
| @@ -1473,7 +1481,7 @@ static int do_execve_common(const char *filename, | |||
| 1473 | check_unsafe_exec(bprm); | 1481 | check_unsafe_exec(bprm); |
| 1474 | current->in_execve = 1; | 1482 | current->in_execve = 1; |
| 1475 | 1483 | ||
| 1476 | file = open_exec(filename); | 1484 | file = do_open_exec(filename); |
| 1477 | retval = PTR_ERR(file); | 1485 | retval = PTR_ERR(file); |
| 1478 | if (IS_ERR(file)) | 1486 | if (IS_ERR(file)) |
| 1479 | goto out_unmark; | 1487 | goto out_unmark; |
| @@ -1481,8 +1489,7 @@ static int do_execve_common(const char *filename, | |||
| 1481 | sched_exec(); | 1489 | sched_exec(); |
| 1482 | 1490 | ||
| 1483 | bprm->file = file; | 1491 | bprm->file = file; |
| 1484 | bprm->filename = filename; | 1492 | bprm->filename = bprm->interp = filename->name; |
| 1485 | bprm->interp = filename; | ||
| 1486 | 1493 | ||
| 1487 | retval = bprm_mm_init(bprm); | 1494 | retval = bprm_mm_init(bprm); |
| 1488 | if (retval) | 1495 | if (retval) |
| @@ -1523,6 +1530,7 @@ static int do_execve_common(const char *filename, | |||
| 1523 | acct_update_integrals(current); | 1530 | acct_update_integrals(current); |
| 1524 | task_numa_free(current); | 1531 | task_numa_free(current); |
| 1525 | free_bprm(bprm); | 1532 | free_bprm(bprm); |
| 1533 | putname(filename); | ||
| 1526 | if (displaced) | 1534 | if (displaced) |
| 1527 | put_files_struct(displaced); | 1535 | put_files_struct(displaced); |
| 1528 | return retval; | 1536 | return retval; |
| @@ -1544,10 +1552,11 @@ out_files: | |||
| 1544 | if (displaced) | 1552 | if (displaced) |
| 1545 | reset_files_struct(displaced); | 1553 | reset_files_struct(displaced); |
| 1546 | out_ret: | 1554 | out_ret: |
| 1555 | putname(filename); | ||
| 1547 | return retval; | 1556 | return retval; |
| 1548 | } | 1557 | } |
| 1549 | 1558 | ||
| 1550 | int do_execve(const char *filename, | 1559 | int do_execve(struct filename *filename, |
| 1551 | const char __user *const __user *__argv, | 1560 | const char __user *const __user *__argv, |
| 1552 | const char __user *const __user *__envp) | 1561 | const char __user *const __user *__envp) |
| 1553 | { | 1562 | { |
| @@ -1557,7 +1566,7 @@ int do_execve(const char *filename, | |||
| 1557 | } | 1566 | } |
| 1558 | 1567 | ||
| 1559 | #ifdef CONFIG_COMPAT | 1568 | #ifdef CONFIG_COMPAT |
| 1560 | static int compat_do_execve(const char *filename, | 1569 | static int compat_do_execve(struct filename *filename, |
| 1561 | const compat_uptr_t __user *__argv, | 1570 | const compat_uptr_t __user *__argv, |
| 1562 | const compat_uptr_t __user *__envp) | 1571 | const compat_uptr_t __user *__envp) |
| 1563 | { | 1572 | { |
| @@ -1607,25 +1616,13 @@ SYSCALL_DEFINE3(execve, | |||
| 1607 | const char __user *const __user *, argv, | 1616 | const char __user *const __user *, argv, |
| 1608 | const char __user *const __user *, envp) | 1617 | const char __user *const __user *, envp) |
| 1609 | { | 1618 | { |
| 1610 | struct filename *path = getname(filename); | 1619 | return do_execve(getname(filename), argv, envp); |
| 1611 | int error = PTR_ERR(path); | ||
| 1612 | if (!IS_ERR(path)) { | ||
| 1613 | error = do_execve(path->name, argv, envp); | ||
| 1614 | putname(path); | ||
| 1615 | } | ||
| 1616 | return error; | ||
| 1617 | } | 1620 | } |
| 1618 | #ifdef CONFIG_COMPAT | 1621 | #ifdef CONFIG_COMPAT |
| 1619 | asmlinkage long compat_sys_execve(const char __user * filename, | 1622 | asmlinkage long compat_sys_execve(const char __user * filename, |
| 1620 | const compat_uptr_t __user * argv, | 1623 | const compat_uptr_t __user * argv, |
| 1621 | const compat_uptr_t __user * envp) | 1624 | const compat_uptr_t __user * envp) |
| 1622 | { | 1625 | { |
| 1623 | struct filename *path = getname(filename); | 1626 | return compat_do_execve(getname(filename), argv, envp); |
| 1624 | int error = PTR_ERR(path); | ||
| 1625 | if (!IS_ERR(path)) { | ||
| 1626 | error = compat_do_execve(path->name, argv, envp); | ||
| 1627 | putname(path); | ||
| 1628 | } | ||
| 1629 | return error; | ||
| 1630 | } | 1627 | } |
| 1631 | #endif | 1628 | #endif |
diff --git a/fs/namei.c b/fs/namei.c index d580df2e6804..385f7817bfcc 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -196,6 +196,7 @@ recopy: | |||
| 196 | goto error; | 196 | goto error; |
| 197 | 197 | ||
| 198 | result->uptr = filename; | 198 | result->uptr = filename; |
| 199 | result->aname = NULL; | ||
| 199 | audit_getname(result); | 200 | audit_getname(result); |
| 200 | return result; | 201 | return result; |
| 201 | 202 | ||
| @@ -210,6 +211,35 @@ getname(const char __user * filename) | |||
| 210 | return getname_flags(filename, 0, NULL); | 211 | return getname_flags(filename, 0, NULL); |
| 211 | } | 212 | } |
| 212 | 213 | ||
| 214 | /* | ||
| 215 | * The "getname_kernel()" interface doesn't do pathnames longer | ||
| 216 | * than EMBEDDED_NAME_MAX. Deal with it - you're a kernel user. | ||
| 217 | */ | ||
| 218 | struct filename * | ||
| 219 | getname_kernel(const char * filename) | ||
| 220 | { | ||
| 221 | struct filename *result; | ||
| 222 | char *kname; | ||
| 223 | int len; | ||
| 224 | |||
| 225 | len = strlen(filename); | ||
| 226 | if (len >= EMBEDDED_NAME_MAX) | ||
| 227 | return ERR_PTR(-ENAMETOOLONG); | ||
| 228 | |||
| 229 | result = __getname(); | ||
| 230 | if (unlikely(!result)) | ||
| 231 | return ERR_PTR(-ENOMEM); | ||
| 232 | |||
| 233 | kname = (char *)result + sizeof(*result); | ||
| 234 | result->name = kname; | ||
| 235 | result->uptr = NULL; | ||
| 236 | result->aname = NULL; | ||
| 237 | result->separate = false; | ||
| 238 | |||
| 239 | strlcpy(kname, filename, EMBEDDED_NAME_MAX); | ||
| 240 | return result; | ||
| 241 | } | ||
| 242 | |||
| 213 | #ifdef CONFIG_AUDITSYSCALL | 243 | #ifdef CONFIG_AUDITSYSCALL |
| 214 | void putname(struct filename *name) | 244 | void putname(struct filename *name) |
| 215 | { | 245 | { |
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index fd8bf3219ef7..b4a745d7d9a9 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h | |||
| @@ -115,7 +115,6 @@ extern int copy_strings_kernel(int argc, const char *const *argv, | |||
| 115 | extern int prepare_bprm_creds(struct linux_binprm *bprm); | 115 | extern int prepare_bprm_creds(struct linux_binprm *bprm); |
| 116 | extern void install_exec_creds(struct linux_binprm *bprm); | 116 | extern void install_exec_creds(struct linux_binprm *bprm); |
| 117 | extern void set_binfmt(struct linux_binfmt *new); | 117 | extern void set_binfmt(struct linux_binfmt *new); |
| 118 | extern void free_bprm(struct linux_binprm *); | ||
| 119 | extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t); | 118 | extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t); |
| 120 | 119 | ||
| 121 | #endif /* _LINUX_BINFMTS_H */ | 120 | #endif /* _LINUX_BINFMTS_H */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 09f553c59813..d79678c188ad 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -2079,6 +2079,7 @@ extern struct file * dentry_open(const struct path *, int, const struct cred *); | |||
| 2079 | extern int filp_close(struct file *, fl_owner_t id); | 2079 | extern int filp_close(struct file *, fl_owner_t id); |
| 2080 | 2080 | ||
| 2081 | extern struct filename *getname(const char __user *); | 2081 | extern struct filename *getname(const char __user *); |
| 2082 | extern struct filename *getname_kernel(const char *); | ||
| 2082 | 2083 | ||
| 2083 | enum { | 2084 | enum { |
| 2084 | FILE_CREATED = 1, | 2085 | FILE_CREATED = 1, |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 68a0e84463a0..a781dec1cd0b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -128,6 +128,7 @@ struct bio_list; | |||
| 128 | struct fs_struct; | 128 | struct fs_struct; |
| 129 | struct perf_event_context; | 129 | struct perf_event_context; |
| 130 | struct blk_plug; | 130 | struct blk_plug; |
| 131 | struct filename; | ||
| 131 | 132 | ||
| 132 | /* | 133 | /* |
| 133 | * List of flags we want to share for kernel threads, | 134 | * List of flags we want to share for kernel threads, |
| @@ -2311,7 +2312,7 @@ extern void do_group_exit(int); | |||
| 2311 | extern int allow_signal(int); | 2312 | extern int allow_signal(int); |
| 2312 | extern int disallow_signal(int); | 2313 | extern int disallow_signal(int); |
| 2313 | 2314 | ||
| 2314 | extern int do_execve(const char *, | 2315 | extern int do_execve(struct filename *, |
| 2315 | const char __user * const __user *, | 2316 | const char __user * const __user *, |
| 2316 | const char __user * const __user *); | 2317 | const char __user * const __user *); |
| 2317 | extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); | 2318 | extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); |
diff --git a/init/main.c b/init/main.c index 2fd9cef70ee8..eb03090cdced 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -812,7 +812,7 @@ void __init load_default_modules(void) | |||
| 812 | static int run_init_process(const char *init_filename) | 812 | static int run_init_process(const char *init_filename) |
| 813 | { | 813 | { |
| 814 | argv_init[0] = init_filename; | 814 | argv_init[0] = init_filename; |
| 815 | return do_execve(init_filename, | 815 | return do_execve(getname_kernel(init_filename), |
| 816 | (const char __user *const __user *)argv_init, | 816 | (const char __user *const __user *)argv_init, |
| 817 | (const char __user *const __user *)envp_init); | 817 | (const char __user *const __user *)envp_init); |
| 818 | } | 818 | } |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 10176cd5956a..7aef2f4b6c64 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -1719,7 +1719,7 @@ void audit_putname(struct filename *name) | |||
| 1719 | struct audit_context *context = current->audit_context; | 1719 | struct audit_context *context = current->audit_context; |
| 1720 | 1720 | ||
| 1721 | BUG_ON(!context); | 1721 | BUG_ON(!context); |
| 1722 | if (!context->in_syscall) { | 1722 | if (!name->aname || !context->in_syscall) { |
| 1723 | #if AUDIT_DEBUG == 2 | 1723 | #if AUDIT_DEBUG == 2 |
| 1724 | printk(KERN_ERR "%s:%d(:%d): final_putname(%p)\n", | 1724 | printk(KERN_ERR "%s:%d(:%d): final_putname(%p)\n", |
| 1725 | __FILE__, __LINE__, context->serial, name); | 1725 | __FILE__, __LINE__, context->serial, name); |
diff --git a/kernel/kmod.c b/kernel/kmod.c index b086006c59e7..6b375af4958d 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -239,7 +239,7 @@ static int ____call_usermodehelper(void *data) | |||
| 239 | 239 | ||
| 240 | commit_creds(new); | 240 | commit_creds(new); |
| 241 | 241 | ||
| 242 | retval = do_execve(sub_info->path, | 242 | retval = do_execve(getname_kernel(sub_info->path), |
| 243 | (const char __user *const __user *)sub_info->argv, | 243 | (const char __user *const __user *)sub_info->argv, |
| 244 | (const char __user *const __user *)sub_info->envp); | 244 | (const char __user *const __user *)sub_info->envp); |
| 245 | if (!retval) | 245 | if (!retval) |
