handle execveat systemcall on McKernel
Refs: #1366 Change-Id: I921e04a0df8d0d798fc94f675e5112dd2fec190a
This commit is contained in:
@ -119,6 +119,7 @@ SYSCALL_DELEGATED(241, perf_event_open)
|
||||
SYSCALL_HANDLED(260, wait4)
|
||||
SYSCALL_HANDLED(270, process_vm_readv)
|
||||
SYSCALL_HANDLED(271, process_vm_writev)
|
||||
SYSCALL_HANDLED(281, execveat)
|
||||
SYSCALL_HANDLED(700, get_cpu_id)
|
||||
#ifdef PROFILE_ENABLE
|
||||
SYSCALL_HANDLED(__NR_profile, profile)
|
||||
|
||||
@ -163,6 +163,7 @@ SYSCALL_HANDLED(303, mod_call)
|
||||
SYSCALL_HANDLED(309, getcpu)
|
||||
SYSCALL_HANDLED(310, process_vm_readv)
|
||||
SYSCALL_HANDLED(311, process_vm_writev)
|
||||
SYSCALL_HANDLED(322, execveat)
|
||||
SYSCALL_HANDLED(700, get_cpu_id)
|
||||
#ifdef PROFILE_ENABLE
|
||||
SYSCALL_HANDLED(__NR_profile, profile)
|
||||
|
||||
@ -3521,6 +3521,39 @@ again:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* for execveat */
|
||||
static int getpath_execveat(int dirfd, const char *filename, int flags,
|
||||
char *pathbuf, size_t size)
|
||||
{
|
||||
int rc, ret = 0;
|
||||
size_t len;
|
||||
|
||||
if (filename[0] == '/' || dirfd == AT_FDCWD) {
|
||||
len = snprintf(pathbuf, size, "%s", filename);
|
||||
}
|
||||
else if (flags & AT_EMPTY_PATH && filename[0] == '\0') {
|
||||
len = snprintf(pathbuf, size, "/dev/fd/%d", dirfd);
|
||||
}
|
||||
else {
|
||||
len = snprintf(pathbuf, size, "/dev/fd/%d/%s", dirfd, filename);
|
||||
}
|
||||
|
||||
if (len >= size) {
|
||||
ret = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & AT_SYMLINK_NOFOLLOW) {
|
||||
if ((rc = readlink(filename, pathbuf, PATH_MAX)) != -1) {
|
||||
ret = ELOOP;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main_loop(struct thread_data_s *my_thread)
|
||||
{
|
||||
struct syscall_wait_desc w;
|
||||
@ -3929,6 +3962,7 @@ fork_err:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Actually, performing execveat() for McKernel */
|
||||
case __NR_execve: {
|
||||
|
||||
/* Execve phase */
|
||||
@ -3940,15 +3974,25 @@ fork_err:
|
||||
char *shebang_argv_flat;
|
||||
char *buffer;
|
||||
size_t size;
|
||||
int ret;
|
||||
int ret, dirfd, flags;
|
||||
|
||||
/* Load descriptor phase */
|
||||
case 1:
|
||||
shebang_argv = NULL;
|
||||
buffer = NULL;
|
||||
desc = NULL;
|
||||
filename = (char *)w.sr.args[1];
|
||||
dirfd = (int)w.sr.args[1];
|
||||
filename = (char *)w.sr.args[2];
|
||||
flags = (int)w.sr.args[4];
|
||||
|
||||
ret = getpath_execveat(dirfd,
|
||||
filename, flags,
|
||||
pathbuf, PATH_MAX);
|
||||
if (ret) {
|
||||
goto return_execve1;
|
||||
}
|
||||
filename = pathbuf;
|
||||
|
||||
if ((ret = load_elf_desc_shebang(filename, &desc,
|
||||
&shebang_argv, 0)) != 0) {
|
||||
goto return_execve1;
|
||||
@ -3987,7 +4031,7 @@ fork_err:
|
||||
|
||||
/* Copy descriptor to co-kernel side */
|
||||
trans.userp = buffer;
|
||||
trans.rphys = w.sr.args[2];
|
||||
trans.rphys = w.sr.args[3];
|
||||
trans.size = size;
|
||||
trans.direction = MCEXEC_UP_TRANSFER_TO_REMOTE;
|
||||
|
||||
|
||||
@ -122,6 +122,11 @@
|
||||
# define CLONE_NEWNET 0x40000000 /* New network namespace. */
|
||||
# define CLONE_IO 0x80000000 /* Clone I/O context. */
|
||||
|
||||
/* for execveat() */
|
||||
#define AT_FDCWD -100
|
||||
#define AT_SYMLINK_NOFOLLOW 0x100
|
||||
#define AT_EMPTY_PATH 0x1000
|
||||
|
||||
struct user_desc {
|
||||
unsigned int entry_number;
|
||||
unsigned int base_addr;
|
||||
|
||||
@ -2493,13 +2493,11 @@ static void munmap_all(void)
|
||||
return;
|
||||
} /* munmap_all() */
|
||||
|
||||
SYSCALL_DECLARE(execve)
|
||||
static int do_execveat(ihk_mc_user_context_t *ctx, int dirfd,
|
||||
const char *filename, char **argv, char **envp, int flags)
|
||||
{
|
||||
int error;
|
||||
long ret;
|
||||
const char *filename = (const char *)ihk_mc_syscall_arg0(ctx);
|
||||
char **argv = (char **)ihk_mc_syscall_arg1(ctx);
|
||||
char **envp = (char **)ihk_mc_syscall_arg2(ctx);
|
||||
|
||||
char *argv_flat = NULL;
|
||||
int argv_flat_len = 0;
|
||||
@ -2538,8 +2536,10 @@ SYSCALL_DECLARE(execve)
|
||||
/* Request host to open executable and load ELF section descriptions */
|
||||
request.number = __NR_execve;
|
||||
request.args[0] = 1; /* 1st phase - get ELF desc */
|
||||
request.args[1] = (unsigned long)filename;
|
||||
request.args[2] = virt_to_phys(desc);
|
||||
request.args[1] = dirfd;
|
||||
request.args[2] = (unsigned long)filename;
|
||||
request.args[3] = virt_to_phys(desc);
|
||||
request.args[4] = flags;
|
||||
ret = do_syscall(&request, ihk_mc_get_processor_id());
|
||||
|
||||
if (ret != 0) {
|
||||
@ -2626,7 +2626,7 @@ SYSCALL_DECLARE(execve)
|
||||
}
|
||||
|
||||
/* Request host to transfer ELF image */
|
||||
request.number = __NR_execve;
|
||||
request.number = __NR_execve;
|
||||
request.args[0] = 2; /* 2nd phase - transfer ELF image */
|
||||
request.args[1] = virt_to_phys(desc);
|
||||
request.args[2] = sizeof(struct program_load_desc) +
|
||||
@ -2687,6 +2687,14 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(execve)
|
||||
{
|
||||
return do_execveat(ctx, AT_FDCWD,
|
||||
(const char *)ihk_mc_syscall_arg0(ctx),
|
||||
(char **)ihk_mc_syscall_arg1(ctx),
|
||||
(char **)ihk_mc_syscall_arg2(ctx), 0);
|
||||
}
|
||||
|
||||
unsigned long do_fork(int clone_flags, unsigned long newsp,
|
||||
unsigned long parent_tidptr, unsigned long child_tidptr,
|
||||
unsigned long tlsblock_base, unsigned long curpc,
|
||||
@ -3569,6 +3577,39 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(execveat)
|
||||
{
|
||||
int dirfd = (int)ihk_mc_syscall_arg0(ctx);
|
||||
const char *filename = (const char *)ihk_mc_syscall_arg1(ctx);
|
||||
int flags = (int)ihk_mc_syscall_arg4(ctx);
|
||||
long ret;
|
||||
|
||||
/* validate flags */
|
||||
if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (filename[0] == '/' || dirfd == AT_FDCWD) {
|
||||
/* behave same as execve */
|
||||
goto exec;
|
||||
}
|
||||
|
||||
/* validate dirfd */
|
||||
if (dirfd < 0 && dirfd != AT_FDCWD) {
|
||||
ret = -EBADF;
|
||||
goto out;
|
||||
}
|
||||
|
||||
exec:
|
||||
ret = do_execveat(ctx, dirfd, filename,
|
||||
(char **)ihk_mc_syscall_arg2(ctx),
|
||||
(char **)ihk_mc_syscall_arg3(ctx), flags);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(close)
|
||||
{
|
||||
int fd = ihk_mc_syscall_arg0(ctx);
|
||||
|
||||
29
test/issues/1366/C1366.sh
Executable file
29
test/issues/1366/C1366.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#/bin/sh
|
||||
|
||||
USELTP=1
|
||||
USEOSTEST=0
|
||||
|
||||
. ../../common.sh
|
||||
|
||||
issue=1366
|
||||
tid=01
|
||||
|
||||
cp ${LTPBIN}/execve_* ./
|
||||
cp ${LTPBIN}/execveat_* ./
|
||||
|
||||
for tp in execveat01 execveat02 execveat03 execve01 execve02 execve03 execve05
|
||||
do
|
||||
tname=`printf "C${issue}T%02d" ${tid}`
|
||||
echo "*** ${tname} start *******************************"
|
||||
sudo PATH=${LTPBIN}:${PATH} $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
|
||||
|
||||
11
test/issues/1366/Makefile
Normal file
11
test/issues/1366/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS=-g
|
||||
LDFLAGS=
|
||||
|
||||
TARGET=
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
test: all
|
||||
./C1366.sh
|
||||
clean:
|
||||
rm -f $(TARGET) *.o *.txt execve_* execveat_*
|
||||
24
test/issues/1366/README
Normal file
24
test/issues/1366/README
Normal file
@ -0,0 +1,24 @@
|
||||
【Issue#1366 動作確認】
|
||||
□ テスト内容
|
||||
1. 以下のLTPを用いてexecveat機能がMckernelで動作することを確認
|
||||
- execveat01
|
||||
- execveat02
|
||||
- execveat03
|
||||
|
||||
2. 以下のLTPを用いて既存のexecve機能に影響が無いことを確認
|
||||
- execve01
|
||||
- execve02
|
||||
- execve03
|
||||
- execve05
|
||||
|
||||
□ 実行手順
|
||||
$ 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していることを確認。
|
||||
95
test/issues/1366/aarch64_result.log
Normal file
95
test/issues/1366/aarch64_result.log
Normal file
@ -0,0 +1,95 @@
|
||||
*** C1366T01 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
|
||||
Summary:
|
||||
passed 4
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T01 PASSED (4)
|
||||
|
||||
*** C1366T02 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execveat02.c:64: PASS: execveat() fails as expected: EBADF
|
||||
execveat02.c:64: PASS: execveat() fails as expected: EINVAL
|
||||
execveat02.c:64: PASS: execveat() fails as expected: ELOOP
|
||||
execveat02.c:64: PASS: execveat() fails as expected: ENOTDIR
|
||||
|
||||
Summary:
|
||||
passed 4
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T02 PASSED (4)
|
||||
|
||||
*** C1366T03 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
|
||||
Summary:
|
||||
passed 1
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T03 PASSED (1)
|
||||
|
||||
*** C1366T04 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve01_child.c:46: PASS: execve01_child executed
|
||||
|
||||
Summary:
|
||||
passed 1
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T04 PASSED (1)
|
||||
|
||||
*** C1366T05 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve02.c:66: PASS: execve() failed expectedly: EACCES
|
||||
|
||||
Summary:
|
||||
passed 1
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T05 PASSED (1)
|
||||
|
||||
*** C1366T06 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve03.c:144: PASS: execve failed as expected: ENAMETOOLONG
|
||||
execve03.c:144: PASS: execve failed as expected: ENOENT
|
||||
execve03.c:144: PASS: execve failed as expected: ENOTDIR
|
||||
execve03.c:144: PASS: execve failed as expected: EFAULT
|
||||
execve03.c:144: PASS: execve failed as expected: EACCES
|
||||
execve03.c:144: PASS: execve failed as expected: ENOEXEC
|
||||
|
||||
Summary:
|
||||
passed 6
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T06 PASSED (6)
|
||||
|
||||
*** C1366T07 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
|
||||
Summary:
|
||||
passed 8
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T07 PASSED (8)
|
||||
|
||||
95
test/issues/1366/x86_64_result.log
Normal file
95
test/issues/1366/x86_64_result.log
Normal file
@ -0,0 +1,95 @@
|
||||
*** C1366T01 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
|
||||
Summary:
|
||||
passed 4
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T01 PASSED (4)
|
||||
|
||||
*** C1366T02 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execveat02.c:64: PASS: execveat() fails as expected: EBADF
|
||||
execveat02.c:64: PASS: execveat() fails as expected: EINVAL
|
||||
execveat02.c:64: PASS: execveat() fails as expected: ELOOP
|
||||
execveat02.c:64: PASS: execveat() fails as expected: ENOTDIR
|
||||
|
||||
Summary:
|
||||
passed 4
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T02 PASSED (4)
|
||||
|
||||
*** C1366T03 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execveat_child.c:36: PASS: execveat_child run as expected
|
||||
|
||||
Summary:
|
||||
passed 1
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T03 PASSED (1)
|
||||
|
||||
*** C1366T04 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve01_child.c:46: PASS: execve01_child executed
|
||||
|
||||
Summary:
|
||||
passed 1
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T04 PASSED (1)
|
||||
|
||||
*** C1366T05 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve02.c:66: PASS: execve() failed expectedly: EACCES
|
||||
|
||||
Summary:
|
||||
passed 1
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T05 PASSED (1)
|
||||
|
||||
*** C1366T06 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve03.c:144: PASS: execve failed as expected: ENAMETOOLONG
|
||||
execve03.c:144: PASS: execve failed as expected: ENOENT
|
||||
execve03.c:144: PASS: execve failed as expected: ENOTDIR
|
||||
execve03.c:144: PASS: execve failed as expected: EFAULT
|
||||
execve03.c:144: PASS: execve failed as expected: EACCES
|
||||
execve03.c:144: PASS: execve failed as expected: ENOEXEC
|
||||
|
||||
Summary:
|
||||
passed 6
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T06 PASSED (6)
|
||||
|
||||
*** C1366T07 start *******************************
|
||||
tst_test.c:1096: INFO: Timeout per run is 0h 05m 00s
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
execve_child.c:34: PASS: argv[1] is canary, expected 'canary'
|
||||
|
||||
Summary:
|
||||
passed 8
|
||||
failed 0
|
||||
skipped 0
|
||||
warnings 0
|
||||
*** C1366T07 PASSED (8)
|
||||
|
||||
Reference in New Issue
Block a user