handle execveat systemcall on McKernel

Refs: #1366
Change-Id: I921e04a0df8d0d798fc94f675e5112dd2fec190a
This commit is contained in:
Ken Sato
2019-11-14 10:56:28 +09:00
parent d052acab1d
commit 7fc4272b89
10 changed files with 356 additions and 10 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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,14 +3974,24 @@ 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) {
@ -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;

View File

@ -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;

View File

@ -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) {
@ -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
View 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
View 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
View 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していることを確認。

View 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)

View 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)