Skip to content

Commit 9a185a5

Browse files
authored
Merge pull request #2654 from ghaerr/exec_mm
[kernel] Fix stale mm[] segment pointers on exec and fork
2 parents 09ca1d9 + 96410bf commit 9a185a5

5 files changed

Lines changed: 144 additions & 3 deletions

File tree

elks/fs/exec.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,10 @@ static void FARPROC finalize_exec(struct inode *inode, segment_s *seg_code,
522522

523523
/* From this point, the old code and data segments are not needed anymore */
524524
for (i = 0; i < MAX_SEGS; i++) {
525-
if (currentp->mm[i])
525+
if (currentp->mm[i]) {
526526
seg_put(currentp->mm[i]);
527+
currentp->mm[i] = 0;
528+
}
527529
}
528530

529531
#ifdef CONFIG_EXEC_OS2

elks/kernel/fork.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,10 @@ pid_t do_fork(int virtual)
9494
} else {
9595
t->mm[j] = seg_dup(s);
9696
if (t->mm[j] == 0) {
97-
for (k = 0; k < j; k++)
98-
seg_put(t->mm[k]);
97+
for (k = 0; k < j; k++) {
98+
if (t->mm[k])
99+
seg_put(t->mm[k]);
100+
}
99101
t->state = TASK_UNUSED;
100102
task_slots_unused++;
101103
next_task_slot = t;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* This helper is intended to be built with OpenWatcom as an OS/2 NE binary,
3+
* then converted to ELKS a.out with os2toelks.
4+
*
5+
* Goal: start life as a genuinely multisegment executable, then exec a normal
6+
* 2-segment ELKS binary. On a buggy kernel this can leave stale mm[] entries
7+
* behind in the replacement image.
8+
*/
9+
10+
#include <unistd.h>
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
14+
#ifdef __WATCOMC__
15+
#pragma code_seg("MSCODE1")
16+
static int code1(void) { return 11; }
17+
#pragma code_seg("MSCODE2")
18+
static int code2(void) { return 22; }
19+
#pragma code_seg()
20+
21+
#pragma data_seg("MSDATA1")
22+
static char data1[1024] = { 1 };
23+
#pragma data_seg("MSDATA2")
24+
static char data2[1024] = { 2 };
25+
#pragma data_seg()
26+
#else
27+
static int code1(void) { return 11; }
28+
static int code2(void) { return 22; }
29+
static char data1[1024] = { 1 };
30+
static char data2[1024] = { 2 };
31+
#endif
32+
33+
static int touch_segments(void)
34+
{
35+
data1[0]++;
36+
data2[0]++;
37+
return code1() + code2() + data1[0] + data2[0];
38+
}
39+
40+
int main(int argc, char **argv)
41+
{
42+
char *av[2];
43+
int v = touch_segments();
44+
45+
if (argc < 2) {
46+
fprintf(stderr, "usage: %s /path/to/plain-helper\n", argv[0]);
47+
return 2;
48+
}
49+
50+
/* Keep the segment-touch logic live. */
51+
if (v == -1)
52+
write(1, "impossible\n", 11);
53+
54+
av[0] = argv[1];
55+
av[1] = (char *)0;
56+
execv(argv[1], av);
57+
perror("multiseg: execv(plain)");
58+
return 111;
59+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <sys/types.h>
2+
#include <sys/wait.h>
3+
#include <unistd.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
7+
#define INNER_FORKS 16
8+
9+
int main(void)
10+
{
11+
int i;
12+
int status;
13+
14+
for (i = 0; i < INNER_FORKS; i++) {
15+
pid_t child = fork();
16+
if (child < 0) {
17+
perror("plain: fork");
18+
return 2;
19+
}
20+
if (child == 0)
21+
_exit(0);
22+
if (waitpid(child, &status, 0) != child) {
23+
perror("plain: waitpid");
24+
return 2;
25+
}
26+
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
27+
printf("plain: unexpected child status 0x%04x\n", status);
28+
return 1;
29+
}
30+
}
31+
32+
return 0;
33+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include <sys/types.h>
2+
#include <sys/wait.h>
3+
#include <unistd.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
7+
#define OUTER_ITERS 200
8+
9+
int main(int argc, char **argv)
10+
{
11+
const char *multiseg = (argc > 1)? argv[1]: "/bin/lifecycle_exec_mm_stale_multiseg";
12+
const char *plain = (argc > 2)? argv[2]: "/bin/lifecycle_exec_mm_stale_plain";
13+
int i;
14+
int status;
15+
16+
printf("[exec-mm-stale] starting with multiseg='%s' plain='%s'\n", multiseg, plain);
17+
18+
for (i = 0; i < OUTER_ITERS; i++) {
19+
pid_t child = fork();
20+
if (child < 0) {
21+
perror("runner: fork");
22+
return 2;
23+
}
24+
if (child == 0) {
25+
char *av[3];
26+
av[0] = (char *)multiseg;
27+
av[1] = (char *)plain;
28+
av[2] = (char *)0;
29+
execv(multiseg, av);
30+
perror("runner: execv(multiseg)");
31+
_exit(111);
32+
}
33+
if (waitpid(child, &status, 0) != child) {
34+
perror("runner: waitpid");
35+
return 2;
36+
}
37+
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
38+
printf("[exec-mm-stale] FAIL at iter=%d status=0x%04x\n", i, status);
39+
return 1;
40+
}
41+
}
42+
43+
printf("[exec-mm-stale] PASS (stress completed)\n");
44+
return 0;
45+
}

0 commit comments

Comments
 (0)