Message ID | 1532678306.28611.1.camel@mtkswgap22 |
---|---|
State | Changes Requested |
Headers | show |
Series | syscalls/execveat01: new test to verify execveat unlinked fd | expand |
Hi! > diff --git a/testcases/kernel/syscalls/execveat/.gitignore > b/testcases/kernel/syscalls/execveat/.gitignore > new file mode 100644 > index 000000000..c0d418603 > --- /dev/null > +++ b/testcases/kernel/syscalls/execveat/.gitignore > @@ -0,0 +1,2 @@ > +/execveat01 > +/execveat_child > diff --git a/testcases/kernel/syscalls/execveat/Makefile > b/testcases/kernel/syscalls/execveat/Makefile > new file mode 100644 > index 000000000..0bab6dc83 > --- /dev/null > +++ b/testcases/kernel/syscalls/execveat/Makefile > @@ -0,0 +1,23 @@ > +# > +# Copyright (C) 2018 MediaTek Inc. All Rights Reserved. > +# > +# This program is free software; you can redistribute it and/or > modify First of all it looks like evolution line wrapped the patch, you should turn off that for attachements. See: https://www.kernel.org/doc/html/v4.10/process/email-clients.html > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > +# the GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA > 02110-1301 USA > +# > + > +top_srcdir ?= ../../../.. > + > +include $(top_srcdir)/include/mk/testcases.mk > + > +include $(top_srcdir)/include/mk/generic_leaf_target.mk > diff --git a/testcases/kernel/syscalls/execveat/execveat.h > b/testcases/kernel/syscalls/execveat/execveat.h > new file mode 100644 > index 000000000..e87974d9c > --- /dev/null > +++ b/testcases/kernel/syscalls/execveat/execveat.h > @@ -0,0 +1,42 @@ > +/* > + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. > + * > + * This program is free software; you can redistribute it and/or modify > it > + * under the terms of version 2 or any later of the GNU General Public > License > + * as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it would be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > + * > + * Further, this software is distributed without any warranty that it > is > + * free of the rightful claim of any third person regarding > infringement > + * or the like. Any license provided herein, whether implied or > + * otherwise, applies only to this software file. Patent licenses, if > + * any, provided herein do not apply to combinations of this program > with > + * other software, or any other product whatsoever. > + * > + * You should have received a copy of the GNU General Public License > along > + * with this program; if not, write the Free Software Foundation, Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > + * > + */ > + > +#ifndef EXECVEAT_H > +#define EXECVEAT_H > + > +#include <sys/types.h> > +#include "config.h" > +#include "lapi/syscalls.h" > + > +#if !defined(HAVE_EXECVEAT) > +int execveat(int dirfd, const char *pathname, > + char *const argv[], char *const envp[], > + int flags) > +{ > + return tst_syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); > +} > +#endif > + > + > +#endif /* EXECVEAT_H */ > \ No newline at end of file > diff --git a/testcases/kernel/syscalls/execveat/execveat01.c > b/testcases/kernel/syscalls/execveat/execveat01.c > new file mode 100644 > index 000000000..fec675fad > --- /dev/null > +++ b/testcases/kernel/syscalls/execveat/execveat01.c > @@ -0,0 +1,142 @@ > +/* > + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. > + * > + * This program is free software; you can redistribute it and/or modify > it > + * under the terms of version 2 or any later of the GNU General Public > License > + * as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it would be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > + * > + * Further, this software is distributed without any warranty that it > is > + * free of the rightful claim of any third person regarding > infringement > + * or the like. Any license provided herein, whether implied or > + * otherwise, applies only to this software file. Patent licenses, if > + * any, provided herein do not apply to combinations of this program > with > + * other software, or any other product whatsoever. > + * > + * You should have received a copy of the GNU General Public License > along > + * with this program; if not, write the Free Software Foundation, Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > + * > + * Started by Eddie Horng <eddie.horng@mediatek.com> > + * > + * DESCRIPTION > + * Check if an unlinked executable can run in overlayfs mount. > + * The regression is introduced from 8db6c34f1dbc ("Introduce v3 > + * namespaced file capabilities"). in security/commoncap.c, > + * cap_inode_getsecurity() use d_find_alias() cause unhashed > dentry > + * can't be found. The solution could use d_find_any_alias() > instead of > + * d_find_alias(). > + * > + * From kernel 4.14, this case is expected fails, execveat shell > + * return EINVAL. > + * > + */ > + > +#define _GNU_SOURCE > +#include "config.h" > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <sys/stat.h> > +#include <sys/types.h> > +#include <errno.h> > +#include <string.h> > +#include <sys/syscall.h> > +#include <sys/mount.h> > +#include <fcntl.h> > +#include "tst_test.h" > +#include "execveat.h" > + > +#define OVL_MNT "ovl" > +#define TEST_APP "execveat_child" > +#define TEST_FILE_PATH OVL_MNT"/"TEST_APP > + > +static int ovl_mounted; > + > +static void do_child(void) > +{ > + > + char path[PATH_MAX]; > + char *argv[2] = {TEST_APP, NULL}; > + int fd; > + > + if (tst_get_path(TEST_APP, path, sizeof(path))) { > + tst_brk(TBROK | TERRNO, > + "Couldn't found "TEST_APP" binary in $PATH"); > + } > + SAFE_CP(path, TEST_FILE_PATH); We do have a better API for this, have a look at creat07.c > + fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH); > + SAFE_UNLINK(TEST_FILE_PATH); > + > + argv[0] = TEST_FILE_PATH; > + TEST(execveat(fd, "", argv, NULL, AT_EMPTY_PATH)); > + if (TEST_ERRNO == ENOSYS) { > + tst_brk(TCONF, > + "execveat is not supported in this kernel."); > + } I suppose that we should handle EINVAL here, I think that we will get EINVAL rather than ENOSYS when kernel will not recognize __NR_execveat > + else if (TEST_RETURN) { > + tst_res(TFAIL | TERRNO, > + "execveat() returned unexpected errno"); > + close(fd); > + exit(1); No need for the else branch here, since tst_brk() exits the test execution. Also there is no need to propagate the result with the exit value, the tst_res() already did that for you. > + } > +} There are several trailing whitespaces and style violations here, you can check for these with checkpatch.pl that is part of the linux kernel source tree. > +static void verify_execveat(void) > +{ > + pid_t pid; > + int status; > + > + pid = SAFE_FORK(); > + if (pid == 0) { > + do_child(); > + } > + else { > + SAFE_WAITPID(pid, &status, 0); > + if (status == 0) > + tst_res(TPASS, "execveat() can run an unlinked executable"); > + } > +} > + > +static void setup(void) > +{ > + int ret; > + > + /* Setup an overlay mount with lower file */ > + SAFE_MKDIR("lower", 0755); > + SAFE_MKDIR("upper", 0755); > + SAFE_MKDIR("work", 0755); > + SAFE_MKDIR(OVL_MNT, 0755); > + ret = mount("overlay", OVL_MNT, "overlay", 0, > + "lowerdir=lower,upperdir=upper,workdir=work"); > + if (ret < 0) { > + if (errno == ENODEV) { > + tst_brk(TCONF, > + "overlayfs is not configured in this kernel."); > + } else { > + tst_brk(TBROK | TERRNO, > + "overlayfs mount failed"); > + } here as well no need for the else branch after the tst_brk(); > + } > + ovl_mounted = 1; > +} > + > +static void cleanup(void) > +{ > + if (ovl_mounted) > + SAFE_UMOUNT(OVL_MNT); > +} > + > +static struct tst_test test = { > + .needs_root = 1, > + .needs_tmpdir = 1, > + .forks_child = 1, > + .setup = setup, > + .cleanup = cleanup, > + .test_all = verify_execveat, > +}; > + > diff --git a/testcases/kernel/syscalls/execveat/execveat_child.c > b/testcases/kernel/syscalls/execveat/execveat_child.c > new file mode 100644 > index 000000000..b2611dc9b > --- /dev/null > +++ b/testcases/kernel/syscalls/execveat/execveat_child.c > @@ -0,0 +1,32 @@ > +/* > + * > + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. > + * > + * This program is free software; you can redistribute it and/or > modify > + * it under the terms of the GNU General Public License as published > by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > + * the GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > 02110-1301 USA > + */ > + > +/* > + * execveat_child.c > + * dummy program which is used by execveat01.c testcase > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > + > +int main(void) > +{ > + printf("Hello World\n"); > + exit(0); You can print the TPASS message from here and the result will be propagated to the parent program. You just need to call tst_reinit() that will initialize the test library. See creat07_child.c. > +} > -- > 2.12.5 > > > > -- > Mailing list info: https://lists.linux.it/listinfo/ltp
2018-07-27 17:47 GMT+08:00 Cyril Hrubis <chrubis@suse.cz>: > Hi! Hi Cyril, Thanks your detail review and suggestions, I have couples of questions as below: >> +static void do_child(void) >> +{ >> + >> + char path[PATH_MAX]; >> + char *argv[2] = {TEST_APP, NULL}; >> + int fd; >> + >> + if (tst_get_path(TEST_APP, path, sizeof(path))) { >> + tst_brk(TBROK | TERRNO, >> + "Couldn't found "TEST_APP" binary in $PATH"); >> + } >> + SAFE_CP(path, TEST_FILE_PATH); > > We do have a better API for this, have a look at creat07.c Could you have more detail guide on this? ie. copy TEST_APP to ovl mount path. >> + fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH); >> + SAFE_UNLINK(TEST_FILE_PATH); >> + >> + argv[0] = TEST_FILE_PATH; >> + TEST(execveat(fd, "", argv, NULL, AT_EMPTY_PATH)); >> + if (TEST_ERRNO == ENOSYS) { >> + tst_brk(TCONF, >> + "execveat is not supported in this kernel."); >> + } > > I suppose that we should handle EINVAL here, I think that we will get > EINVAL rather than ENOSYS when kernel will not recognize __NR_execveat EINVAL is happened to be the same return code of this testcase is expecting -- the regression introduced from 8db6c34f1dbc ("Introduce v3 namespaced file capabilities"), therefore I might need another way to test whether kernel recognize __NR_execveat, so that I can differentiate not recognize and the regression. Do you have suggestion on this? >> +int main(void) >> +{ >> + printf("Hello World\n"); >> + exit(0); > > You can print the TPASS message from here and the result will be > propagated to the parent program. You just need to call tst_reinit() > that will initialize the test library. See creat07_child.c. I change execveat_child.c as below and get errors as: tst_test.c:144: BROK: LTP_IPC_PATH is not defined tst_test.c:869: BROK: Test haven't reported results! I think the cause is execveat() doesn't pass environment variables to its child, but SAFE_EXECL in creat07.c does. Do you suggest pass LTP_IPC_PATH in execveat() to make tst_reinit() in execveat_child run properly, or something else? #define TST_NO_DEFAULT_MAIN #include "tst_test.h" int main() { tst_reinit(); tst_res(TPASS, "execveat_child is lunched as expcted"); return 0; } thanks, Eddie
Hi! > >> +static void do_child(void) > >> +{ > >> + > >> + char path[PATH_MAX]; > >> + char *argv[2] = {TEST_APP, NULL}; > >> + int fd; > >> + > >> + if (tst_get_path(TEST_APP, path, sizeof(path))) { > >> + tst_brk(TBROK | TERRNO, > >> + "Couldn't found "TEST_APP" binary in $PATH"); > >> + } > >> + SAFE_CP(path, TEST_FILE_PATH); > > > > We do have a better API for this, have a look at creat07.c > > Could you have more detail guide on this? ie. copy TEST_APP to > ovl mount path If you specify the child executable as a resource file as in: https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#2222-datafiles It will be compied to the test temporary directory before the test is executed, then you can SAFE_CP() the file when you need it. Alternatively I can also change the resource file mechanims in the test library so that we can pass destionation there as well or export the TST_RESOURCE_COPY() macro to the new library. Then you can use it to copy the file into its final destination. > >> + fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH); > >> + SAFE_UNLINK(TEST_FILE_PATH); > >> + > >> + argv[0] = TEST_FILE_PATH; > >> + TEST(execveat(fd, "", argv, NULL, AT_EMPTY_PATH)); > >> + if (TEST_ERRNO == ENOSYS) { > >> + tst_brk(TCONF, > >> + "execveat is not supported in this kernel."); > >> + } > > > > I suppose that we should handle EINVAL here, I think that we will get > > EINVAL rather than ENOSYS when kernel will not recognize __NR_execveat > > EINVAL is happened to be the same return code of this testcase is expecting -- > the regression introduced from 8db6c34f1dbc ("Introduce v3 namespaced > file capabilities"), therefore I might need another way to test whether kernel > recognize __NR_execveat, so that I can differentiate not recognize and the > regression. Do you have suggestion on this? We usually specify minimal kernel version for the testcase in the tst_test structure in that case and the test is skipped automatically on old kernels that do not have the execveat() syscall implemented. > >> +int main(void) > >> +{ > >> + printf("Hello World\n"); > >> + exit(0); > > > > You can print the TPASS message from here and the result will be > > propagated to the parent program. You just need to call tst_reinit() > > that will initialize the test library. See creat07_child.c. > > I change execveat_child.c as below and get errors as: > tst_test.c:144: BROK: LTP_IPC_PATH is not defined > tst_test.c:869: BROK: Test haven't reported results! > > I think the cause is execveat() doesn't pass environment variables > to its child, but SAFE_EXECL in creat07.c does. > Do you suggest pass LTP_IPC_PATH in execveat() to make > tst_reinit() in execveat_child run properly, or something else? Yes, the LTP_IPC_PATH has to be passed manually in this case so that the library could be re-initialized. > #define TST_NO_DEFAULT_MAIN > #include "tst_test.h" > > int main() > { > tst_reinit(); > tst_res(TPASS, "execveat_child is lunched as expcted"); > return 0; > } > > thanks, > Eddie
2018-07-27 17:47 GMT+08:00 Cyril Hrubis <chrubis@suse.cz>: >> +int main(void) >> +{ >> + printf("Hello World\n"); >> + exit(0); > > You can print the TPASS message from here and the result will be > propagated to the parent program. You just need to call tst_reinit() > that will initialize the test library. See creat07_child.c. > Hi Cyril, I removed "if (status == 0) tst_res(TPASS, ..." from execveat01.c and add "tst_res(TPASS, ..." in execveat_child.c, but I got a no reported result error: execveat_child.c:44: PASS: execveat_child run as expected tst_test.c:869: BROK: Test haven't reported results! It seems child's test result doesn't propagated to parent. Do I use wrong API in child or miss something in parent? thanks, Eddie
Hi! > I removed "if (status == 0) tst_res(TPASS, ..." from execveat01.c and > add "tst_res(TPASS, ..." in execveat_child.c, but I got a no reported > result error: > > execveat_child.c:44: PASS: execveat_child run as expected > tst_test.c:869: BROK: Test haven't reported results! > > It seems child's test result doesn't propagated to parent. > Do I use wrong API in child or miss something in parent? You are right, this is supposed to work but nobody checked that and while the IPC is mapped the results pointer is not initialized in the test library. It should work with following patch: diff --git a/lib/tst_test.c b/lib/tst_test.c index 008bcefe0..bb3908d6c 100644 --- a/lib/tst_test.c +++ b/lib/tst_test.c @@ -152,6 +152,7 @@ void tst_reinit(void) fd = SAFE_OPEN(path, O_RDWR); ptr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + results = ptr; tst_futexes = (char*)ptr + sizeof(struct results); tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t);
diff --git a/configure.ac b/configure.ac index 9208f1c6c..373d72689 100644 --- a/configure.ac +++ b/configure.ac @@ -196,6 +196,7 @@ LTP_CHECK_FSTATAT LTP_CHECK_MKNODAT LTP_CHECK_READLINKAT LTP_CHECK_OPENAT +LTP_CHECK_EXECVEAT LTP_CHECK_RENAMEAT LTP_CHECK_RENAMEAT2 LTP_CHECK_FALLOCATE diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in index 71a4b713d..c44adcd7e 100644 --- a/include/lapi/syscalls/arm.in +++ b/include/lapi/syscalls/arm.in @@ -340,4 +340,5 @@ sched_getattr (__NR_SYSCALL_BASE+381) renameat2 (__NR_SYSCALL_BASE+382) getrandom (__NR_SYSCALL_BASE+384) memfd_create (__NR_SYSCALL_BASE+385) +execveat (__NR_SYSCALL_BASE+387) copy_file_range (__NR_SYSCALL_BASE+391) diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in index 0f9601472..19f0148fe 100644 --- a/include/lapi/syscalls/i386.in +++ b/include/lapi/syscalls/i386.in @@ -340,4 +340,5 @@ sched_getattr 352 renameat2 354 getrandom 355 memfd_create 356 +execveat 358 copy_file_range 377 diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in index 98c861f36..d95b282f8 100644 --- a/include/lapi/syscalls/s390.in +++ b/include/lapi/syscalls/s390.in @@ -331,4 +331,5 @@ sched_getattr 346 renameat2 347 getrandom 349 memfd_create 350 +execveat 354 copy_file_range 375 diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in index 89db79404..7907c3108 100644 --- a/include/lapi/syscalls/x86_64.in +++ b/include/lapi/syscalls/x86_64.in @@ -307,4 +307,5 @@ sched_getattr 315 renameat2 316 getrandom 318 memfd_create 319 +execveat 322 copy_file_range 326 diff --git a/m4/ltp-execveat.m4 b/m4/ltp-execveat.m4 new file mode 100644 index 000000000..8cb614715 --- /dev/null +++ b/m4/ltp-execveat.m4 @@ -0,0 +1,25 @@ +dnl +dnl Copyright (c) Linux Test Project, 2014 +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +dnl the GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +dnl + +dnl +dnl LTP_CHECK_EXECVEAT +dnl ---------------------------- +dnl +AC_DEFUN([LTP_CHECK_EXECVEAT],[ +AC_CHECK_FUNCS(execveat,,) +]) diff --git a/testcases/kernel/syscalls/execveat/.gitignore b/testcases/kernel/syscalls/execveat/.gitignore new file mode 100644 index 000000000..c0d418603 --- /dev/null +++ b/testcases/kernel/syscalls/execveat/.gitignore @@ -0,0 +1,2 @@ +/execveat01 +/execveat_child diff --git a/testcases/kernel/syscalls/execveat/Makefile b/testcases/kernel/syscalls/execveat/Makefile new file mode 100644 index 000000000..0bab6dc83 --- /dev/null +++ b/testcases/kernel/syscalls/execveat/Makefile @@ -0,0 +1,23 @@ +# +# Copyright (C) 2018 MediaTek Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/execveat/execveat.h b/testcases/kernel/syscalls/execveat/execveat.h new file mode 100644 index 000000000..e87974d9c --- /dev/null +++ b/testcases/kernel/syscalls/execveat/execveat.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 or any later of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef EXECVEAT_H +#define EXECVEAT_H + +#include <sys/types.h> +#include "config.h" +#include "lapi/syscalls.h" + +#if !defined(HAVE_EXECVEAT) +int execveat(int dirfd, const char *pathname, + char *const argv[], char *const envp[], + int flags) +{ + return tst_syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); +} +#endif + + +#endif /* EXECVEAT_H */ \ No newline at end of file diff --git a/testcases/kernel/syscalls/execveat/execveat01.c b/testcases/kernel/syscalls/execveat/execveat01.c new file mode 100644 index 000000000..fec675fad --- /dev/null +++ b/testcases/kernel/syscalls/execveat/execveat01.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 or any later of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Started by Eddie Horng <eddie.horng@mediatek.com> + * + * DESCRIPTION + * Check if an unlinked executable can run in overlayfs mount. + * The regression is introduced from 8db6c34f1dbc ("Introduce v3 + * namespaced file capabilities"). in security/commoncap.c, + * cap_inode_getsecurity() use d_find_alias() cause unhashed dentry + * can't be found. The solution could use d_find_any_alias() instead of + * d_find_alias(). + * + * From kernel 4.14, this case is expected fails, execveat shell + * return EINVAL. + * + */ + +#define _GNU_SOURCE +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <string.h> +#include <sys/syscall.h> +#include <sys/mount.h> +#include <fcntl.h> +#include "tst_test.h" +#include "execveat.h" + +#define OVL_MNT "ovl" +#define TEST_APP "execveat_child" +#define TEST_FILE_PATH OVL_MNT"/"TEST_APP + +static int ovl_mounted; + +static void do_child(void) +{ + + char path[PATH_MAX]; + char *argv[2] = {TEST_APP, NULL}; + int fd; + + if (tst_get_path(TEST_APP, path, sizeof(path))) { + tst_brk(TBROK | TERRNO, + "Couldn't found "TEST_APP" binary in $PATH"); + } + SAFE_CP(path, TEST_FILE_PATH); + + fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH); + SAFE_UNLINK(TEST_FILE_PATH); + + argv[0] = TEST_FILE_PATH; + TEST(execveat(fd, "", argv, NULL, AT_EMPTY_PATH)); + if (TEST_ERRNO == ENOSYS) { + tst_brk(TCONF, + "execveat is not supported in this kernel."); + } + else if (TEST_RETURN) { + tst_res(TFAIL | TERRNO, + "execveat() returned unexpected errno"); + close(fd); + exit(1); + } +} + +static void verify_execveat(void) +{ + pid_t pid; + int status; + + pid = SAFE_FORK(); + if (pid == 0) { + do_child(); + } + else { + SAFE_WAITPID(pid, &status, 0); + if (status == 0) + tst_res(TPASS, "execveat() can run an unlinked executable"); + } +} + +static void setup(void) +{ + int ret; + + /* Setup an overlay mount with lower file */ + SAFE_MKDIR("lower", 0755); + SAFE_MKDIR("upper", 0755); + SAFE_MKDIR("work", 0755); + SAFE_MKDIR(OVL_MNT, 0755); + ret = mount("overlay", OVL_MNT, "overlay", 0, + "lowerdir=lower,upperdir=upper,workdir=work"); + if (ret < 0) { + if (errno == ENODEV) { + tst_brk(TCONF, + "overlayfs is not configured in this kernel."); + } else { + tst_brk(TBROK | TERRNO, + "overlayfs mount failed"); + } + } + ovl_mounted = 1; +} + +static void cleanup(void) +{ + if (ovl_mounted) + SAFE_UMOUNT(OVL_MNT); +} + +static struct tst_test test = { + .needs_root = 1, + .needs_tmpdir = 1, + .forks_child = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_execveat, +}; + diff --git a/testcases/kernel/syscalls/execveat/execveat_child.c b/testcases/kernel/syscalls/execveat/execveat_child.c new file mode 100644 index 000000000..b2611dc9b --- /dev/null +++ b/testcases/kernel/syscalls/execveat/execveat_child.c @@ -0,0 +1,32 @@ +/* + * + * Copyright (C) 2018 MediaTek Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * execveat_child.c + * dummy program which is used by execveat01.c testcase + */ + +#include <stdlib.h> +#include <stdio.h> + +int main(void) +{
Exercise the execveat() syscall to verify an executable is opened then unlinked can be executed. The regression is introduced from 8db6c34f1dbc ("Introduce v3 namespaced file capabilities"). Overlayfs and possibly other networking filesystems unhash the dentry on unlink, fail on this test with above change. Signed-off-by: Eddie Horng <eddie.horng@mediatek.com> --- configure.ac | 1 + include/lapi/syscalls/arm.in | 1 + include/lapi/syscalls/i386.in | 1 + include/lapi/syscalls/s390.in | 1 + include/lapi/syscalls/x86_64.in | 1 + m4/ltp-execveat.m4 | 25 ++++ testcases/kernel/syscalls/execveat/.gitignore | 2 + testcases/kernel/syscalls/execveat/Makefile | 23 ++++ testcases/kernel/syscalls/execveat/execveat.h | 42 ++++++ testcases/kernel/syscalls/execveat/execveat01.c | 142 +++++++++++++++++++++ .../kernel/syscalls/execveat/execveat_child.c | 32 +++++ 11 files changed, 271 insertions(+) create mode 100644 m4/ltp-execveat.m4 create mode 100644 testcases/kernel/syscalls/execveat/.gitignore create mode 100644 testcases/kernel/syscalls/execveat/Makefile create mode 100644 testcases/kernel/syscalls/execveat/execveat.h create mode 100644 testcases/kernel/syscalls/execveat/execveat01.c create mode 100644 testcases/kernel/syscalls/execveat/execveat_child.c + printf("Hello World\n"); + exit(0); +}