Skip to content

Commit 96e02d1

Browse files
heicarsttorvalds
authored andcommitted
exec: fix use-after-free bug in setup_new_exec()
Setting the task name is done within setup_new_exec() by accessing bprm->filename. However this happens after flush_old_exec(). This may result in a use after free bug, flush_old_exec() may "complete" vfork_done, which will wake up the parent which in turn may free the passed in filename. To fix this add a new tcomm field in struct linux_binprm which contains the now early generated task name until it is used. Fixes this bug on s390: Unable to handle kernel pointer dereference at virtual kernel address 0000000039768000 Process kworker/u:3 (pid: 245, task: 000000003a3dc840, ksp: 0000000039453818) Krnl PSW : 0704000180000000 0000000000282e94 (setup_new_exec+0xa0/0x374) Call Trace: ([<0000000000282e2c>] setup_new_exec+0x38/0x374) [<00000000002dd12e>] load_elf_binary+0x402/0x1bf4 [<0000000000280a42>] search_binary_handler+0x38e/0x5bc [<0000000000282b6c>] do_execve_common+0x410/0x514 [<0000000000282cb6>] do_execve+0x46/0x58 [<00000000005bce58>] kernel_execve+0x28/0x70 [<000000000014ba2e>] ____call_usermodehelper+0x102/0x140 [<00000000005bc8da>] kernel_thread_starter+0x6/0xc [<00000000005bc8d4>] kernel_thread_starter+0x0/0xc Last Breaking-Event-Address: [<00000000002830f0>] setup_new_exec+0x2fc/0x374 Kernel panic - not syncing: Fatal exception: panic_on_oops Reported-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 23783f8 commit 96e02d1

File tree

2 files changed

+19
-17
lines changed

2 files changed

+19
-17
lines changed

fs/exec.c

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,21 @@ void set_task_comm(struct task_struct *tsk, char *buf)
10711071
perf_event_comm(tsk);
10721072
}
10731073

1074+
static void filename_to_taskname(char *tcomm, const char *fn, unsigned int len)
1075+
{
1076+
int i, ch;
1077+
1078+
/* Copies the binary name from after last slash */
1079+
for (i = 0; (ch = *(fn++)) != '\0';) {
1080+
if (ch == '/')
1081+
i = 0; /* overwrite what we wrote */
1082+
else
1083+
if (i < len - 1)
1084+
tcomm[i++] = ch;
1085+
}
1086+
tcomm[i] = '\0';
1087+
}
1088+
10741089
int flush_old_exec(struct linux_binprm * bprm)
10751090
{
10761091
int retval;
@@ -1085,6 +1100,7 @@ int flush_old_exec(struct linux_binprm * bprm)
10851100

10861101
set_mm_exe_file(bprm->mm, bprm->file);
10871102

1103+
filename_to_taskname(bprm->tcomm, bprm->filename, sizeof(bprm->tcomm));
10881104
/*
10891105
* Release all of the old mmap stuff
10901106
*/
@@ -1116,10 +1132,6 @@ EXPORT_SYMBOL(would_dump);
11161132

11171133
void setup_new_exec(struct linux_binprm * bprm)
11181134
{
1119-
int i, ch;
1120-
const char *name;
1121-
char tcomm[sizeof(current->comm)];
1122-
11231135
arch_pick_mmap_layout(current->mm);
11241136

11251137
/* This is the point of no return */
@@ -1130,18 +1142,7 @@ void setup_new_exec(struct linux_binprm * bprm)
11301142
else
11311143
set_dumpable(current->mm, suid_dumpable);
11321144

1133-
name = bprm->filename;
1134-
1135-
/* Copies the binary name from after last slash */
1136-
for (i=0; (ch = *(name++)) != '\0';) {
1137-
if (ch == '/')
1138-
i = 0; /* overwrite what we wrote */
1139-
else
1140-
if (i < (sizeof(tcomm) - 1))
1141-
tcomm[i++] = ch;
1142-
}
1143-
tcomm[i] = '\0';
1144-
set_task_comm(current, tcomm);
1145+
set_task_comm(current, bprm->tcomm);
11451146

11461147
/* Set the new mm task size. We have to do that late because it may
11471148
* depend on TIF_32BIT which is only updated in flush_thread() on

include/linux/binfmts.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct pt_regs;
1818
#define BINPRM_BUF_SIZE 128
1919

2020
#ifdef __KERNEL__
21-
#include <linux/list.h>
21+
#include <linux/sched.h>
2222

2323
#define CORENAME_MAX_SIZE 128
2424

@@ -58,6 +58,7 @@ struct linux_binprm {
5858
unsigned interp_flags;
5959
unsigned interp_data;
6060
unsigned long loader, exec;
61+
char tcomm[TASK_COMM_LEN];
6162
};
6263

6364
#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0

0 commit comments

Comments
 (0)