diff options
Diffstat (limited to 'fs/coredump.c')
| -rw-r--r-- | fs/coredump.c | 121 |
1 files changed, 59 insertions, 62 deletions
diff --git a/fs/coredump.c b/fs/coredump.c index dafafbafa731..72f816d6cad9 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
| @@ -45,69 +45,79 @@ | |||
| 45 | #include <trace/events/sched.h> | 45 | #include <trace/events/sched.h> |
| 46 | 46 | ||
| 47 | int core_uses_pid; | 47 | int core_uses_pid; |
| 48 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | ||
| 49 | unsigned int core_pipe_limit; | 48 | unsigned int core_pipe_limit; |
| 49 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | ||
| 50 | static int core_name_size = CORENAME_MAX_SIZE; | ||
| 50 | 51 | ||
| 51 | struct core_name { | 52 | struct core_name { |
| 52 | char *corename; | 53 | char *corename; |
| 53 | int used, size; | 54 | int used, size; |
| 54 | }; | 55 | }; |
| 55 | static atomic_t call_count = ATOMIC_INIT(1); | ||
| 56 | 56 | ||
| 57 | /* The maximal length of core_pattern is also specified in sysctl.c */ | 57 | /* The maximal length of core_pattern is also specified in sysctl.c */ |
| 58 | 58 | ||
| 59 | static int expand_corename(struct core_name *cn) | 59 | static int expand_corename(struct core_name *cn, int size) |
| 60 | { | 60 | { |
| 61 | char *old_corename = cn->corename; | 61 | char *corename = krealloc(cn->corename, size, GFP_KERNEL); |
| 62 | |||
| 63 | cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count); | ||
| 64 | cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); | ||
| 65 | 62 | ||
| 66 | if (!cn->corename) { | 63 | if (!corename) |
| 67 | kfree(old_corename); | ||
| 68 | return -ENOMEM; | 64 | return -ENOMEM; |
| 69 | } | ||
| 70 | 65 | ||
| 66 | if (size > core_name_size) /* racy but harmless */ | ||
| 67 | core_name_size = size; | ||
| 68 | |||
| 69 | cn->size = ksize(corename); | ||
| 70 | cn->corename = corename; | ||
| 71 | return 0; | 71 | return 0; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static int cn_vprintf(struct core_name *cn, const char *fmt, va_list arg) | ||
| 75 | { | ||
| 76 | int free, need; | ||
| 77 | |||
| 78 | again: | ||
| 79 | free = cn->size - cn->used; | ||
| 80 | need = vsnprintf(cn->corename + cn->used, free, fmt, arg); | ||
| 81 | if (need < free) { | ||
| 82 | cn->used += need; | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | if (!expand_corename(cn, cn->size + need - free + 1)) | ||
| 87 | goto again; | ||
| 88 | |||
| 89 | return -ENOMEM; | ||
| 90 | } | ||
| 91 | |||
| 74 | static int cn_printf(struct core_name *cn, const char *fmt, ...) | 92 | static int cn_printf(struct core_name *cn, const char *fmt, ...) |
| 75 | { | 93 | { |
| 76 | char *cur; | ||
| 77 | int need; | ||
| 78 | int ret; | ||
| 79 | va_list arg; | 94 | va_list arg; |
| 95 | int ret; | ||
| 80 | 96 | ||
| 81 | va_start(arg, fmt); | 97 | va_start(arg, fmt); |
| 82 | need = vsnprintf(NULL, 0, fmt, arg); | 98 | ret = cn_vprintf(cn, fmt, arg); |
| 83 | va_end(arg); | 99 | va_end(arg); |
| 84 | 100 | ||
| 85 | if (likely(need < cn->size - cn->used - 1)) | 101 | return ret; |
| 86 | goto out_printf; | 102 | } |
| 87 | 103 | ||
| 88 | ret = expand_corename(cn); | 104 | static int cn_esc_printf(struct core_name *cn, const char *fmt, ...) |
| 89 | if (ret) | 105 | { |
| 90 | goto expand_fail; | 106 | int cur = cn->used; |
| 107 | va_list arg; | ||
| 108 | int ret; | ||
| 91 | 109 | ||
| 92 | out_printf: | ||
| 93 | cur = cn->corename + cn->used; | ||
| 94 | va_start(arg, fmt); | 110 | va_start(arg, fmt); |
| 95 | vsnprintf(cur, need + 1, fmt, arg); | 111 | ret = cn_vprintf(cn, fmt, arg); |
| 96 | va_end(arg); | 112 | va_end(arg); |
| 97 | cn->used += need; | ||
| 98 | return 0; | ||
| 99 | 113 | ||
| 100 | expand_fail: | 114 | for (; cur < cn->used; ++cur) { |
| 115 | if (cn->corename[cur] == '/') | ||
| 116 | cn->corename[cur] = '!'; | ||
| 117 | } | ||
| 101 | return ret; | 118 | return ret; |
| 102 | } | 119 | } |
| 103 | 120 | ||
| 104 | static void cn_escape(char *str) | ||
| 105 | { | ||
| 106 | for (; *str; str++) | ||
| 107 | if (*str == '/') | ||
| 108 | *str = '!'; | ||
| 109 | } | ||
| 110 | |||
| 111 | static int cn_print_exe_file(struct core_name *cn) | 121 | static int cn_print_exe_file(struct core_name *cn) |
| 112 | { | 122 | { |
| 113 | struct file *exe_file; | 123 | struct file *exe_file; |
| @@ -115,12 +125,8 @@ static int cn_print_exe_file(struct core_name *cn) | |||
| 115 | int ret; | 125 | int ret; |
| 116 | 126 | ||
| 117 | exe_file = get_mm_exe_file(current->mm); | 127 | exe_file = get_mm_exe_file(current->mm); |
| 118 | if (!exe_file) { | 128 | if (!exe_file) |
| 119 | char *commstart = cn->corename + cn->used; | 129 | return cn_esc_printf(cn, "%s (path unknown)", current->comm); |
| 120 | ret = cn_printf(cn, "%s (path unknown)", current->comm); | ||
| 121 | cn_escape(commstart); | ||
| 122 | return ret; | ||
| 123 | } | ||
| 124 | 130 | ||
| 125 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); | 131 | pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY); |
| 126 | if (!pathbuf) { | 132 | if (!pathbuf) { |
| @@ -134,9 +140,7 @@ static int cn_print_exe_file(struct core_name *cn) | |||
| 134 | goto free_buf; | 140 | goto free_buf; |
| 135 | } | 141 | } |
| 136 | 142 | ||
| 137 | cn_escape(path); | 143 | ret = cn_esc_printf(cn, "%s", path); |
| 138 | |||
| 139 | ret = cn_printf(cn, "%s", path); | ||
| 140 | 144 | ||
| 141 | free_buf: | 145 | free_buf: |
| 142 | kfree(pathbuf); | 146 | kfree(pathbuf); |
| @@ -157,19 +161,19 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
| 157 | int pid_in_pattern = 0; | 161 | int pid_in_pattern = 0; |
| 158 | int err = 0; | 162 | int err = 0; |
| 159 | 163 | ||
| 160 | cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count); | ||
| 161 | cn->corename = kmalloc(cn->size, GFP_KERNEL); | ||
| 162 | cn->used = 0; | 164 | cn->used = 0; |
| 163 | 165 | cn->corename = NULL; | |
| 164 | if (!cn->corename) | 166 | if (expand_corename(cn, core_name_size)) |
| 165 | return -ENOMEM; | 167 | return -ENOMEM; |
| 168 | cn->corename[0] = '\0'; | ||
| 169 | |||
| 170 | if (ispipe) | ||
| 171 | ++pat_ptr; | ||
| 166 | 172 | ||
| 167 | /* Repeat as long as we have more pattern to process and more output | 173 | /* Repeat as long as we have more pattern to process and more output |
| 168 | space */ | 174 | space */ |
| 169 | while (*pat_ptr) { | 175 | while (*pat_ptr) { |
| 170 | if (*pat_ptr != '%') { | 176 | if (*pat_ptr != '%') { |
| 171 | if (*pat_ptr == 0) | ||
| 172 | goto out; | ||
| 173 | err = cn_printf(cn, "%c", *pat_ptr++); | 177 | err = cn_printf(cn, "%c", *pat_ptr++); |
| 174 | } else { | 178 | } else { |
| 175 | switch (*++pat_ptr) { | 179 | switch (*++pat_ptr) { |
| @@ -210,22 +214,16 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
| 210 | break; | 214 | break; |
| 211 | } | 215 | } |
| 212 | /* hostname */ | 216 | /* hostname */ |
| 213 | case 'h': { | 217 | case 'h': |
| 214 | char *namestart = cn->corename + cn->used; | ||
| 215 | down_read(&uts_sem); | 218 | down_read(&uts_sem); |
| 216 | err = cn_printf(cn, "%s", | 219 | err = cn_esc_printf(cn, "%s", |
| 217 | utsname()->nodename); | 220 | utsname()->nodename); |
| 218 | up_read(&uts_sem); | 221 | up_read(&uts_sem); |
| 219 | cn_escape(namestart); | ||
| 220 | break; | 222 | break; |
| 221 | } | ||
| 222 | /* executable */ | 223 | /* executable */ |
| 223 | case 'e': { | 224 | case 'e': |
| 224 | char *commstart = cn->corename + cn->used; | 225 | err = cn_esc_printf(cn, "%s", current->comm); |
| 225 | err = cn_printf(cn, "%s", current->comm); | ||
| 226 | cn_escape(commstart); | ||
| 227 | break; | 226 | break; |
| 228 | } | ||
| 229 | case 'E': | 227 | case 'E': |
| 230 | err = cn_print_exe_file(cn); | 228 | err = cn_print_exe_file(cn); |
| 231 | break; | 229 | break; |
| @@ -244,6 +242,7 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
| 244 | return err; | 242 | return err; |
| 245 | } | 243 | } |
| 246 | 244 | ||
| 245 | out: | ||
| 247 | /* Backward compatibility with core_uses_pid: | 246 | /* Backward compatibility with core_uses_pid: |
| 248 | * | 247 | * |
| 249 | * If core_pattern does not include a %p (as is the default) | 248 | * If core_pattern does not include a %p (as is the default) |
| @@ -254,7 +253,6 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm) | |||
| 254 | if (err) | 253 | if (err) |
| 255 | return err; | 254 | return err; |
| 256 | } | 255 | } |
| 257 | out: | ||
| 258 | return ispipe; | 256 | return ispipe; |
| 259 | } | 257 | } |
| 260 | 258 | ||
| @@ -549,7 +547,7 @@ void do_coredump(siginfo_t *siginfo) | |||
| 549 | if (ispipe < 0) { | 547 | if (ispipe < 0) { |
| 550 | printk(KERN_WARNING "format_corename failed\n"); | 548 | printk(KERN_WARNING "format_corename failed\n"); |
| 551 | printk(KERN_WARNING "Aborting core\n"); | 549 | printk(KERN_WARNING "Aborting core\n"); |
| 552 | goto fail_corename; | 550 | goto fail_unlock; |
| 553 | } | 551 | } |
| 554 | 552 | ||
| 555 | if (cprm.limit == 1) { | 553 | if (cprm.limit == 1) { |
| @@ -584,7 +582,7 @@ void do_coredump(siginfo_t *siginfo) | |||
| 584 | goto fail_dropcount; | 582 | goto fail_dropcount; |
| 585 | } | 583 | } |
| 586 | 584 | ||
| 587 | helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL); | 585 | helper_argv = argv_split(GFP_KERNEL, cn.corename, NULL); |
| 588 | if (!helper_argv) { | 586 | if (!helper_argv) { |
| 589 | printk(KERN_WARNING "%s failed to allocate memory\n", | 587 | printk(KERN_WARNING "%s failed to allocate memory\n", |
| 590 | __func__); | 588 | __func__); |
| @@ -601,7 +599,7 @@ void do_coredump(siginfo_t *siginfo) | |||
| 601 | 599 | ||
| 602 | argv_free(helper_argv); | 600 | argv_free(helper_argv); |
| 603 | if (retval) { | 601 | if (retval) { |
| 604 | printk(KERN_INFO "Core dump to %s pipe failed\n", | 602 | printk(KERN_INFO "Core dump to |%s pipe failed\n", |
| 605 | cn.corename); | 603 | cn.corename); |
| 606 | goto close_fail; | 604 | goto close_fail; |
| 607 | } | 605 | } |
| @@ -669,7 +667,6 @@ fail_dropcount: | |||
| 669 | atomic_dec(&core_dump_count); | 667 | atomic_dec(&core_dump_count); |
| 670 | fail_unlock: | 668 | fail_unlock: |
| 671 | kfree(cn.corename); | 669 | kfree(cn.corename); |
| 672 | fail_corename: | ||
| 673 | coredump_finish(mm, core_dumped); | 670 | coredump_finish(mm, core_dumped); |
| 674 | revert_creds(old_cred); | 671 | revert_creds(old_cred); |
| 675 | fail_creds: | 672 | fail_creds: |
