fix: fork's race-condition caused by child and grand-child
Refs: #1329 Change-Id: Ia2d7641d1203f40155fef5db718d1bb2c583c1c5
This commit is contained in:
committed by
Masamichi Takagi
parent
5b26fe2956
commit
911b07f507
43
test/issues/1324/C1324.sh
Executable file
43
test/issues/1324/C1324.sh
Executable file
@ -0,0 +1,43 @@
|
||||
#/bin/sh
|
||||
|
||||
USELTP=1
|
||||
USEOSTEST=0
|
||||
|
||||
BOOTPARAM="-m 1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0,1G@0 -O"
|
||||
|
||||
. ../../common.sh
|
||||
|
||||
issue="1324"
|
||||
tid=01
|
||||
|
||||
for tno in 01 02 03
|
||||
do
|
||||
tname=`printf "C${issue}T%02d" ${tid}`
|
||||
echo "*** ${tname} start *******************************"
|
||||
${MCEXEC} ./C1324+1329T${tno}
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "*** ${tname} PASSED ******************************"
|
||||
else
|
||||
echo "*** ${tname} FAILED ******************************"
|
||||
fi
|
||||
let tid++
|
||||
echo ""
|
||||
done
|
||||
|
||||
for tp in fork14 fork01 fork02 fork03 fork04 fork05 fork06 fork07 fork08 fork09 fork10 fork11
|
||||
do
|
||||
tname=`printf "C${issue}T%02d" ${tid}`
|
||||
echo "*** ${tname} start *******************************"
|
||||
sudo $MCEXEC $LTPBIN/$tp 2>&1 | tee $tp.txt
|
||||
ok=`grep PASS $tp.txt | wc -l`
|
||||
ng=`grep FAIL $tp.txt | wc -l`
|
||||
if [ $ng = 0 ]; then
|
||||
echo "*** ${tname} PASSED ($ok)"
|
||||
else
|
||||
echo "*** ${tname} FAILED (ok=$ok ng=%ng)"
|
||||
fi
|
||||
let tid++
|
||||
echo ""
|
||||
done
|
||||
|
||||
100
test/issues/1324/C1324T01.c
Normal file
100
test/issues/1324/C1324T01.c
Normal file
@ -0,0 +1,100 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
#define GB (1024 * 1024 * 1024)
|
||||
#define MAP_SIZE (1 * GB)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc, ret = 0;
|
||||
int pid, status;
|
||||
void *addr;
|
||||
unsigned long test_val = 0x1129;
|
||||
ssize_t val_size = sizeof(test_val);
|
||||
ssize_t offset = MAP_SIZE - val_size;
|
||||
|
||||
addr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (addr == MAP_FAILED) {
|
||||
ret = -1;
|
||||
perror("failed to mmap: ");
|
||||
goto out;
|
||||
}
|
||||
memset(addr, '0', MAP_SIZE);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
ret = -1;
|
||||
perror("failed to fork: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
printf("[OK] fork is successful\n");
|
||||
|
||||
rc = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
|
||||
if (rc < 0) {
|
||||
printf("[NG]: traceme is failed\n");
|
||||
}
|
||||
raise(SIGSTOP);
|
||||
|
||||
if (*((unsigned long *)(addr + offset)) == test_val) {
|
||||
printf("[OK] POKED value is correct!!\n");
|
||||
}
|
||||
else {
|
||||
printf("[NG] POKED value is NOT correct!!\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
waitpid(pid, &status, 0);
|
||||
if (!WIFSTOPPED(status)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ptrace(PTRACE_POKETEXT, pid, addr + offset, test_val);
|
||||
if (rc < 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
||||
if (rc < 0) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
waitpid(pid, &status, 0);
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) == 0) {
|
||||
printf("[OK] child exited normaly\n");
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
printf("[NG] Test Program failed\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
67
test/issues/1324/C1324T02.c
Normal file
67
test/issues/1324/C1324T02.c
Normal file
@ -0,0 +1,67 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define GB (1024 * 1024 * 1024)
|
||||
#define MAP_SIZE (1 * GB)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc, ret;
|
||||
void *addr1, *addr2;
|
||||
stack_t *ss, *oss;
|
||||
ssize_t stack_t_size = sizeof(stack_t);
|
||||
|
||||
addr1 = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (addr1 == MAP_FAILED) {
|
||||
ret = -1;
|
||||
perror("failed to mmap 1st: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
addr2 = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (addr2 == MAP_FAILED) {
|
||||
ret = -1;
|
||||
perror("failed to mmap 2nd: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
oss = addr1 + MAP_SIZE - stack_t_size;
|
||||
memset(oss, '0', stack_t_size);
|
||||
ss = addr2 + MAP_SIZE - stack_t_size;
|
||||
memset(ss, '0', stack_t_size);
|
||||
|
||||
rc = sigaltstack(NULL, oss);
|
||||
if (rc == 0) {
|
||||
printf("[OK] sigaltstack 1st is successful\n");
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
perror("[NG] failed to sigaltstack 1st: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ss->ss_sp = oss->ss_sp;
|
||||
ss->ss_flags = oss->ss_flags;
|
||||
ss->ss_size = oss->ss_size;
|
||||
rc = sigaltstack(ss, NULL);
|
||||
if (rc == 0) {
|
||||
printf("[OK] sigaltstack 2nd is successful\n");
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
perror("[NG] failed to sigaltstack 2nd: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
54
test/issues/1324/C1324T03.c
Normal file
54
test/issues/1324/C1324T03.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define GB (1024 * 1024 * 1024)
|
||||
#define MAP_SIZE (1 * GB)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd = -1, ret = 0;
|
||||
void *addr;
|
||||
unsigned long test_val = 0x1129;
|
||||
ssize_t val_size = sizeof(test_val);
|
||||
unsigned long buf;
|
||||
ssize_t offset = MAP_SIZE - val_size;
|
||||
|
||||
addr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (addr == MAP_FAILED) {
|
||||
ret = -1;
|
||||
perror("failed to mmap: ");
|
||||
goto out;
|
||||
}
|
||||
memcpy(addr + offset, &test_val, val_size);
|
||||
|
||||
fd = open("/proc/self/mem", O_RDWR);
|
||||
lseek(fd, (off_t)addr + offset, SEEK_SET);
|
||||
|
||||
read(fd, &buf, val_size);
|
||||
|
||||
if (buf == test_val) {
|
||||
printf("[OK] value read by proc_mem is correct\n");
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
if (ret) {
|
||||
printf("[NG] Test Program failed\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
11
test/issues/1324/Makefile
Normal file
11
test/issues/1324/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS=-g
|
||||
LDFLAGS=
|
||||
|
||||
TARGET=C1324T01 C1324T02 C1324T03
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
test: all
|
||||
./C1324.sh
|
||||
clean:
|
||||
rm -f $(TARGET) *.o *.txt
|
||||
61
test/issues/1324/README
Normal file
61
test/issues/1324/README
Normal file
@ -0,0 +1,61 @@
|
||||
【Issue#1324 動作確認】
|
||||
□ テスト内容
|
||||
本Issueの症状は、以下の操作の際に操作対象メモリの物理メモリが
|
||||
McKernelに割り当てられたメモリチャンクの終端になっている場合に発生する
|
||||
- fork時などのcopy_user_pte()
|
||||
- POKE{TEXT,DATA}指定のptrace
|
||||
- copy_{from,to}_user()
|
||||
- /proc/<pid>/mem への読み書き
|
||||
|
||||
1GBのmmapで確保したメモリ領域がメモリチャンクと重なるように、
|
||||
mcreboot.sh -m 1G@0,1G@0,1G@0... としてMcKernelを起動した状態で
|
||||
本テストを実行する
|
||||
|
||||
1. 下記のテストプログラムを実行し、症状が発生しないことを確認する
|
||||
C1324+1329T01:
|
||||
1. PRIVATE|ANONYMOUSな1GBのメモリ領域をmmapで確保
|
||||
2. fork()が正常に行われることを確認
|
||||
3. 子プロセスはptrace(TRACEME)を行い、停止
|
||||
4. 親プロセスは、ptrace(POKETEXT)で、確保したメモリ領域の終端に
|
||||
テスト用の値を書き込む
|
||||
5. ptrace(DETACH)で子プロセスを再開
|
||||
6. 子プロセスは、書き込まれたテスト用の値を確認
|
||||
|
||||
C1324+1329T02:
|
||||
(copy_{from,to}_user()を伴うシンプルなシステムコールとして、sigaltstackを利用)
|
||||
1. PRIVATE|ANONYMOUSな1GBのメモリ領域を2つ、mmapで確保
|
||||
2. sigaltstack()で授受する構造体を、それぞれ確保したメモリ領域の終端に配置
|
||||
3. sigaltstack()での情報の授受が成功することを確認
|
||||
|
||||
C1324+1329T03:
|
||||
1. PRIVATE|ANONYMOUSな1GBのメモリ領域をmmapで確保
|
||||
2. 確保したメモリ領域の終端にテスト用の値を書き込む
|
||||
3. /proc/self/mem を介して、2.で書き込んだテスト用の値を確認
|
||||
|
||||
2. 以下のLTPを用いてIssueで報告された症状が発生しないことを確認
|
||||
- fork14
|
||||
|
||||
3. 以下のLTPを用いて既存のfork機能に影響が無いことを確認
|
||||
- fork01
|
||||
- fork02
|
||||
- fork03
|
||||
- fork04
|
||||
- fork05
|
||||
- fork06
|
||||
- fork07
|
||||
- fork08
|
||||
- fork09
|
||||
- fork10
|
||||
- fork11
|
||||
|
||||
□ 実行手順
|
||||
$ make test
|
||||
|
||||
McKernelのインストール先や、OSTEST, LTPの配置場所は、
|
||||
$HOME/.mck_test_config を参照している
|
||||
.mck_test_config は、McKernelをビルドした際に生成されるmck_test_config.sample ファイルを
|
||||
$HOMEにコピーし、適宜編集する
|
||||
|
||||
□ 実行結果
|
||||
x86_64_result.log aarch64_result.log 参照。
|
||||
すべての項目をPASSしていることを確認。
|
||||
94
test/issues/1324/aarch64_result.log
Normal file
94
test/issues/1324/aarch64_result.log
Normal file
@ -0,0 +1,94 @@
|
||||
*** C1324T01 start *******************************
|
||||
[OK] fork is successful
|
||||
[OK] POKED value is correct!!
|
||||
[OK] child exited normaly
|
||||
*** C1324T01 PASSED ******************************
|
||||
|
||||
*** C1324T02 start *******************************
|
||||
[OK] sigaltstack 1st is successful
|
||||
[OK] sigaltstack 2nd is successful
|
||||
*** C1324T02 PASSED ******************************
|
||||
|
||||
*** C1324T03 start *******************************
|
||||
[OK] value read by proc_mem is correct
|
||||
*** C1324T03 PASSED ******************************
|
||||
|
||||
*** C1324T04 start *******************************
|
||||
fork14 1 TPASS : fork failed as expected.
|
||||
*** C1324T04 PASSED (1)
|
||||
|
||||
*** C1324T05 start *******************************
|
||||
fork01 1 TPASS : fork() returned 35497
|
||||
fork01 2 TPASS : child pid and fork() return agree: 35497
|
||||
*** C1324T05 PASSED (2)
|
||||
|
||||
*** C1324T06 start *******************************
|
||||
fork02 0 TINFO : Inside parent
|
||||
fork02 0 TINFO : exit status of wait 0
|
||||
fork02 1 TPASS : test 1 PASSED
|
||||
*** C1324T06 PASSED (1)
|
||||
|
||||
*** C1324T07 start *******************************
|
||||
fork03 0 TINFO : process id in parent of child from fork : 35581
|
||||
fork03 1 TPASS : test 1 PASSED
|
||||
*** C1324T07 PASSED (1)
|
||||
|
||||
*** C1324T08 start *******************************
|
||||
fork04 1 TPASS : Env var TERM unchanged after fork(): xterm
|
||||
fork04 2 TPASS : Env var NoTSetzWq unchanged after fork(): getenv() does not find variable set
|
||||
fork04 3 TPASS : Env var TESTPROG unchanged after fork(): FRKTCS04
|
||||
*** C1324T08 PASSED (3)
|
||||
|
||||
*** C1324T09 start *******************************
|
||||
fork05 0 TINFO : %fs test only for ix86
|
||||
*** C1324T09 PASSED (0)
|
||||
|
||||
*** C1324T10 start *******************************
|
||||
fork06 0 TINFO : tries 1000
|
||||
fork06 0 TINFO : successes 1000
|
||||
fork06 0 TINFO : failures 0
|
||||
fork06 0 TINFO : There were no children to wait for
|
||||
*** C1324T10 PASSED (0)
|
||||
|
||||
*** C1324T11 start *******************************
|
||||
fork07 0 TINFO : Forking 100 children
|
||||
fork07 0 TINFO : Forked all 100 children, now collecting
|
||||
fork07 0 TINFO : Collected all 100 children
|
||||
fork07 1 TPASS : 100/100 children read correctly from an inheritted fd
|
||||
*** C1324T11 PASSED (1)
|
||||
|
||||
*** C1324T12 start *******************************
|
||||
fork08 0 TINFO : parent forksval: 1
|
||||
fork08 0 TINFO : second child got char: b
|
||||
fork08 1 TPASS : Test passed in childnumber 2
|
||||
fork08 0 TINFO : parent forksval: 1
|
||||
fork08 0 TINFO : parent forksval: 2
|
||||
fork08 0 TINFO : exit status of wait expected 0 got 0
|
||||
fork08 1 TPASS : parent test PASSED
|
||||
fork08 0 TINFO : exit status of wait expected 0 got 0
|
||||
fork08 2 TPASS : parent test PASSED
|
||||
fork08 0 TINFO : exit status of wait expected 0 got 0
|
||||
fork08 3 TPASS : parent test PASSED
|
||||
fork08 0 TINFO : Number of processes forked is 2
|
||||
*** C1324T12 PASSED (4)
|
||||
|
||||
*** C1324T13 start *******************************
|
||||
fork09 0 TINFO : OPEN_MAX is 1024
|
||||
fork09 0 TINFO : first file descriptor is 8
|
||||
fork09 0 TINFO : Parent reporting 1023 files open
|
||||
fork09 0 TINFO : Child opened new file #1023
|
||||
fork09 0 TINFO : OPEN_MAX is 1024
|
||||
fork09 0 TINFO : first file descriptor is 8
|
||||
fork09 0 TINFO : Parent reporting 1023 files open
|
||||
fork09 1 TPASS : test 1 PASSED
|
||||
*** C1324T13 PASSED (1)
|
||||
|
||||
*** C1324T14 start *******************************
|
||||
fork10 0 TINFO : fork child A
|
||||
fork10 1 TPASS : test 1 PASSED
|
||||
*** C1324T14 PASSED (1)
|
||||
|
||||
*** C1324T15 start *******************************
|
||||
fork11 1 TPASS : fork test passed, 100 processes
|
||||
*** C1324T15 PASSED (1)
|
||||
|
||||
94
test/issues/1324/x86_64_result.log
Normal file
94
test/issues/1324/x86_64_result.log
Normal file
@ -0,0 +1,94 @@
|
||||
*** C1324T01 start *******************************
|
||||
[OK] fork is successful
|
||||
[OK] POKED value is correct!!
|
||||
[OK] child exited normaly
|
||||
*** C1324T01 PASSED ******************************
|
||||
|
||||
*** C1324T02 start *******************************
|
||||
[OK] sigaltstack 1st is successful
|
||||
[OK] sigaltstack 2nd is successful
|
||||
*** C1324T02 PASSED ******************************
|
||||
|
||||
*** C1324T03 start *******************************
|
||||
[OK] value read by proc_mem is correct
|
||||
*** C1324T03 PASSED ******************************
|
||||
|
||||
*** C1324T04 start *******************************
|
||||
fork14 1 TPASS : fork failed as expected.
|
||||
*** C1324T04 PASSED (1)
|
||||
|
||||
*** C1324T05 start *******************************
|
||||
fork01 1 TPASS : fork() returned 12305
|
||||
fork01 2 TPASS : child pid and fork() return agree: 12305
|
||||
*** C1324T05 PASSED (2)
|
||||
|
||||
*** C1324T06 start *******************************
|
||||
fork02 0 TINFO : Inside parent
|
||||
fork02 0 TINFO : exit status of wait 0
|
||||
fork02 1 TPASS : test 1 PASSED
|
||||
*** C1324T06 PASSED (1)
|
||||
|
||||
*** C1324T07 start *******************************
|
||||
fork03 0 TINFO : process id in parent of child from fork : 12365
|
||||
fork03 1 TPASS : test 1 PASSED
|
||||
*** C1324T07 PASSED (1)
|
||||
|
||||
*** C1324T08 start *******************************
|
||||
fork04 1 TPASS : Env var TERM unchanged after fork(): xterm-256color
|
||||
fork04 2 TPASS : Env var NoTSetzWq unchanged after fork(): getenv() does not find variable set
|
||||
fork04 3 TPASS : Env var TESTPROG unchanged after fork(): FRKTCS04
|
||||
*** C1324T08 PASSED (3)
|
||||
|
||||
*** C1324T09 start *******************************
|
||||
fork05 0 TINFO : %fs test only for ix86
|
||||
*** C1324T09 PASSED (0)
|
||||
|
||||
*** C1324T10 start *******************************
|
||||
fork06 0 TINFO : tries 1000
|
||||
fork06 0 TINFO : successes 1000
|
||||
fork06 0 TINFO : failures 0
|
||||
fork06 0 TINFO : There were no children to wait for
|
||||
*** C1324T10 PASSED (0)
|
||||
|
||||
*** C1324T11 start *******************************
|
||||
fork07 0 TINFO : Forking 100 children
|
||||
fork07 0 TINFO : Forked all 100 children, now collecting
|
||||
fork07 0 TINFO : Collected all 100 children
|
||||
fork07 1 TPASS : 100/100 children read correctly from an inheritted fd
|
||||
*** C1324T11 PASSED (1)
|
||||
|
||||
*** C1324T12 start *******************************
|
||||
fork08 0 TINFO : parent forksval: 1
|
||||
fork08 0 TINFO : second child got char: b
|
||||
fork08 1 TPASS : Test passed in childnumber 2
|
||||
fork08 0 TINFO : parent forksval: 1
|
||||
fork08 0 TINFO : parent forksval: 2
|
||||
fork08 0 TINFO : exit status of wait expected 0 got 0
|
||||
fork08 1 TPASS : parent test PASSED
|
||||
fork08 0 TINFO : exit status of wait expected 0 got 0
|
||||
fork08 2 TPASS : parent test PASSED
|
||||
fork08 0 TINFO : exit status of wait expected 0 got 0
|
||||
fork08 3 TPASS : parent test PASSED
|
||||
fork08 0 TINFO : Number of processes forked is 2
|
||||
*** C1324T12 PASSED (4)
|
||||
|
||||
*** C1324T13 start *******************************
|
||||
fork09 0 TINFO : OPEN_MAX is 1024
|
||||
fork09 0 TINFO : first file descriptor is 8
|
||||
fork09 0 TINFO : Parent reporting 1023 files open
|
||||
fork09 0 TINFO : Child opened new file #1023
|
||||
fork09 0 TINFO : OPEN_MAX is 1024
|
||||
fork09 0 TINFO : first file descriptor is 8
|
||||
fork09 0 TINFO : Parent reporting 1023 files open
|
||||
fork09 1 TPASS : test 1 PASSED
|
||||
*** C1324T13 PASSED (1)
|
||||
|
||||
*** C1324T14 start *******************************
|
||||
fork10 0 TINFO : fork child A
|
||||
fork10 1 TPASS : test 1 PASSED
|
||||
*** C1324T14 PASSED (1)
|
||||
|
||||
*** C1324T15 start *******************************
|
||||
fork11 1 TPASS : fork test passed, 100 processes
|
||||
*** C1324T15 PASSED (1)
|
||||
|
||||
Reference in New Issue
Block a user