[v2] syscalls/execveat01: new test to verify execveat unlinked fd

Message ID 1533111474.1176.4.camel@mtkswgap22
State Accepted
Headers show
Series
  • [v2] syscalls/execveat01: new test to verify execveat unlinked fd
Related show

Commit Message

Eddie.Horng Aug. 1, 2018, 8:17 a.m.
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>
---
Changes in v2:
 - use resource file for TEST_APP
 - pass environ to execveat()
 - specific min kernel version 3.19.0 to make sure execveat is supported
 - add needs_ipc_path = 1
 - execveat_child print TPASS to propagate result to parent
---
 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    | 128 +++++++++++++++++++++
 .../kernel/syscalls/execveat/execveat_child.c      |  41 +++++++
 11 files changed, 266 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

Comments

Li Wang Aug. 1, 2018, 11:17 a.m. | #1
On Wed, Aug 1, 2018 at 4:17 PM, Eddie.Horng <eddie.horng@mediatek.com>
wrote:

>
> 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>
> ---
> Changes in v2:
>  - use resource file for TEST_APP
>  - pass environ to execveat()
>  - specific min kernel version 3.19.0 to make sure execveat is supported
>  - add needs_ipc_path = 1
>  - execveat_child print TPASS to propagate result to parent
> ---
>  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 +
>

why not adding other arches?

$ git grep __NR_execveat
alpha/include/uapi/asm/unistd.h:#define __NR_execveat                   513
arm64/include/asm/unistd32.h:#define __NR_execveat 387
arm64/include/asm/unistd32.h:__SYSCALL(__NR_execveat, compat_sys_execveat)
ia64/include/uapi/asm/unistd.h:#define __NR_execveat                    1342
m68k/include/uapi/asm/unistd.h:#define __NR_execveat            355
microblaze/include/uapi/asm/unistd.h:#define __NR_execveat              388
mips/include/uapi/asm/unistd.h:#define __NR_execveat
(__NR_Linux + 356)
mips/include/uapi/asm/unistd.h:#define __NR_execveat
(__NR_Linux + 316)
mips/include/uapi/asm/unistd.h:#define __NR_execveat
(__NR_Linux + 320)
parisc/include/uapi/asm/unistd.h:#define __NR_execveat          (__NR_Linux
+ 342)
powerpc/include/uapi/asm/unistd.h:#define __NR_execveat         362
sh/include/uapi/asm/unistd_32.h:#define __NR_execveat           376
sh/include/uapi/asm/unistd_64.h:#define __NR_execveat           387
sparc/include/uapi/asm/unistd.h:#define __NR_execveat           350
x86/ia32/audit.c:       case __NR_execveat:
x86/kernel/audit_64.c:  case __NR_execveat:
xtensa/include/uapi/asm/unistd.h:#define __NR_execveat
    341

 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    | 128
> +++++++++++++++++++++
>  .../kernel/syscalls/execveat/execveat_child.c      |  41 +++++++
>  11 files changed, 266 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
>
> 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..53c8be8a5
> --- /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 */
> diff --git a/testcases/kernel/syscalls/execveat/execveat01.c
> b/testcases/kernel/syscalls/execveat/execveat01.c
> new file mode 100644
> index 000000000..768b196d3
> --- /dev/null
> +++ b/testcases/kernel/syscalls/execveat/execveat01.c
> @@ -0,0 +1,128 @@
> +/*
> + * 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 *argv[2] = {TEST_FILE_PATH, NULL};
> +       int fd;
> +
> +       SAFE_CP(TEST_APP, TEST_FILE_PATH);
> +
> +       fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH);
> +       SAFE_UNLINK(TEST_FILE_PATH);
> +
> +       TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
>

Shouldn't we handle EINVAL here? As the comment says from kernel-4.14,
this case is expected to fail with EINVAL.

something maybe like:
-----------------------------
if (TST_RET == -1) {
if (TST_ERR == EINVAL)
tst_res(TCONF, "execveat() return EINVAL as we expected");
else
tst_res(TFAIL | TERRNO, "execveat() returned unexpected errno");
} else {
tst_res(TFAIL, "On success, execveat() shouldn't return");
}



> +       tst_res(TFAIL | TERRNO, "execveat() returned unexpected errno");
> +}
> +
> +static void verify_execveat(void)
> +{
> +       pid_t pid;
> +
> +       pid = SAFE_FORK();
> +       if (pid == 0) {
> +               do_child();
> +               exit(1);
> +       }
> +       SAFE_WAITPID(pid, NULL, 0);
> +}
> +
> +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.");
> +               }
> +               tst_brk(TBROK | TERRNO, "overlayfs mount failed");
> +       }
> +       ovl_mounted = 1;
> +}
> +
> +static void cleanup(void)
> +{
> +       if (ovl_mounted)
> +               SAFE_UMOUNT(OVL_MNT);
> +}
> +
> +static const char *const resource_files[] = {
> +       TEST_APP,
> +       NULL,
> +};
> +
> +static struct tst_test test = {
> +       .needs_root = 1,
> +       .needs_tmpdir = 1,
> +       .forks_child = 1,
> +       .needs_ipc_path = 1,
> +       .setup = setup,
> +       .cleanup = cleanup,
> +       .test_all = verify_execveat,
> +       .resource_files = resource_files,
> +       .min_kver = "3.19.0",
> +};
> +
> diff --git a/testcases/kernel/syscalls/execveat/execveat_child.c
> b/testcases/kernel/syscalls/execveat/execveat_child.c
> new file mode 100644
> index 000000000..68fcd1325
> --- /dev/null
> +++ b/testcases/kernel/syscalls/execveat/execveat_child.c
> @@ -0,0 +1,41 @@
> +/*
> + * 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.
> + *
> + */
> +
> +/*
> + * execveat_child.c
> + * dummy program which is used by execveat01.c testcase
> + */
> +
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include "tst_test.h"
> +
> +
> +int main(void)
> +{
> +       tst_reinit();
> +       tst_res(TPASS, "execveat_child run as expected");
> +       return 0;
> +}
> +
> --
> 2.12.5
>
>
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
Cyril Hrubis Aug. 1, 2018, 12:53 p.m. | #2
Hi!
> > +static void do_child(void)
> > +{
> > +       char *argv[2] = {TEST_FILE_PATH, NULL};
> > +       int fd;
> > +
> > +       SAFE_CP(TEST_APP, TEST_FILE_PATH);
> > +
> > +       fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH);
> > +       SAFE_UNLINK(TEST_FILE_PATH);
> > +
> > +       TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
> >
> 
> Shouldn't we handle EINVAL here? As the comment says from kernel-4.14,
> this case is expected to fail with EINVAL.

I already asked about this, apparently the syscall returns EINVAL when
the bug is hit, hence this would render the testcase useless.

So we decided to set minimal kernel version that has the call
implemented rather than handle EINVAL.

Well I guess that the best option would be trying execveat() before we
unlink the file and TCONF if we got EINVAL and proceed with the testing
otherwise...
Eddie Horng Aug. 3, 2018, 9:32 a.m. | #3
2018-08-01 19:17 GMT+08:00 Li Wang <liwang@redhat.com>:
> why not adding other arches?
>
> $ git grep __NR_execveat
> alpha/include/uapi/asm/unistd.h:#define __NR_execveat                   513
> arm64/include/asm/unistd32.h:#define __NR_execveat 387
> arm64/include/asm/unistd32.h:__SYSCALL(__NR_execveat, compat_sys_execveat)

Hi Li,
Thanks your tips on finding syscall id, but I still can't find all
arches listed in
[ltp]/include/lapi/syscalls from [kernel]/arch, should I just add the id as much
as I can find from [kernel]/arch?


>> +       fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH);
>> +       SAFE_UNLINK(TEST_FILE_PATH);
>> +
>> +       TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
>
>
> Shouldn't we handle EINVAL here? As the comment says from kernel-4.14,
> this case is expected to fail with EINVAL.
>
> something maybe like:
> -----------------------------
> if (TST_RET == -1) {
> if (TST_ERR == EINVAL)
> tst_res(TCONF, "execveat() return EINVAL as we expected");
> else
> tst_res(TFAIL | TERRNO, "execveat() returned unexpected errno");
> } else {
> tst_res(TFAIL, "On success, execveat() shouldn't return");
> }
>

So Cryil's suggestion works for the case? Same EINVAL error for
both verifying TCONF and expected TFAIL.

thanks,
Eddie
Li Wang Aug. 6, 2018, 9:26 a.m. | #4
Hi Eddie,

Eddie Horng <eddiehorng.tw@gmail.com> wrote:

> 2018-08-01 19:17 GMT+08:00 Li Wang <liwang@redhat.com>:
> > why not adding other arches?
> >
> > $ git grep __NR_execveat
> > alpha/include/uapi/asm/unistd.h:#define __NR_execveat
>  513
> > arm64/include/asm/unistd32.h:#define __NR_
> execveat 387
> > arm64/include/asm/unistd32.h:__SYSCALL(__NR_execveat,
> compat_sys_execveat)
>
> Hi Li,
> Thanks your tips on finding syscall id, but I still can't find all
> arches listed in
> [ltp]/include/lapi/syscalls from [kernel]/arch, should I just add the id
> as much
> as I can find from [kernel]/arch?
>

I think at least we'd better adding support as LTP(/include/lapi/syscalls)
has.


> So Cryil's suggestion works for the case? Same EINVAL error for
> both verifying TCONF and expected TFAIL.
>
>
Hmm, from your patch I got these information:

kernel < 3.19    :
execveat() not support
3.19 <= kernel < 4.14  :
execveat() fully support
kernel >= 4.14  :
execveat() return EINVAL expectly

If I was right, so Cyril's suggestion should be like:

static void do_child(void)
{
    ...

    /* Check if system support execveat() correctly */
    TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
    /* Do TCONF if we get EINVAL here */

    SAFE_UNLINK(TEST_FILE_PATH);

    /* Do your testing */
    TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
    /* Here if we get EINVAL again that means hit a bug! */
}

Did I miss anything?
Cyril Hrubis Aug. 8, 2018, 2:41 p.m. | #5
Hi!
> static void do_child(void)
> {
>     ...
> 
>     /* Check if system support execveat() correctly */
>     TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
>     /* Do TCONF if we get EINVAL here */
> 
>     SAFE_UNLINK(TEST_FILE_PATH);
> 
>     /* Do your testing */
>     TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
>     /* Here if we get EINVAL again that means hit a bug! */
> }
> 
> Did I miss anything?

It's a bit more complicated than that, we have to fork() first and run
the check in the child otherwise we will never get to the test code, as
we will either do tst_brk(TBROK) or execute the child code instead...

I will write the code to check it and amend the test before applying to
the tree.
Cyril Hrubis Aug. 8, 2018, 2:48 p.m. | #6
Hi!
> I will write the code to check it and amend the test before applying to
> the tree.

Actually it seems to be easier than this, if we do
execveat(-1, "", NULL, NULL, AT_EMPTY_PATH); we get EBADFD if execveat is
supported and EINVAL if not.
Cyril Hrubis Aug. 9, 2018, 9:04 a.m. | #7
Hi!
Pushed with minor changes, thanks.

* Added check for execveat() support to the test setup and dropped the
  minimal kernel version from test structure

* Renamed the test to execveat03 so that we can add execveat01 and
  execveat02 that would test the cases without overlay being involved

* Removed SAFE_WAITPID() from the verify_execveat() since the child
  has to be waited for in the test library so that errors are propagated
  correctly

* Moved the execveat.h to the include/lapi/ directory

* Added syscalls/runtest entry so that the test is executed during the
  tesrun
Eddie Horng Aug. 10, 2018, 9:32 a.m. | #8
2018-08-09 17:04 GMT+08:00 Cyril Hrubis <chrubis@suse.cz>:
> Hi!
> Pushed with minor changes, thanks.
>
> * Added check for execveat() support to the test setup and dropped the
>   minimal kernel version from test structure
>
> * Renamed the test to execveat03 so that we can add execveat01 and
>   execveat02 that would test the cases without overlay being involved
>
> * Removed SAFE_WAITPID() from the verify_execveat() since the child
>   has to be waited for in the test library so that errors are propagated
>   correctly
>
> * Moved the execveat.h to the include/lapi/ directory
>
> * Added syscalls/runtest entry so that the test is executed during the
>   tesrun
>

Hi Cyril, Li,
Thanks your modifications and all the suggestions, reviews on this testcase.

Eddie
Jan Stancek Sept. 11, 2018, 3:24 p.m. | #9
----- Original Message -----
> + * 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.
> + *
> + */

We should fix this for release. If EINVAL is expected behaviour,
test should give PASS.

It's failing with 4.18:

tst_test.c:1063: INFO: Timeout per run is 0h 05m 00s
execveat03.c:71: FAIL: execveat() returned unexpected errno: EINVAL

Summary:
passed   0
failed   1
skipped  0
warnings 0

Regards,
Jan
Eddie Horng Sept. 12, 2018, 1:44 a.m. | #10
Jan Stancek <jstancek@redhat.com> 於 2018年9月11日 週二 下午11:24寫道:
> We should fix this for release. If EINVAL is expected behaviour,
> test should give PASS.
>
> It's failing with 4.18:
>
> tst_test.c:1063: INFO: Timeout per run is 0h 05m 00s
> execveat03.c:71: FAIL: execveat() returned unexpected errno: EINVAL
>

Hi Jan,
The fix of original regression, ie. EINVAL returns in execveat03 test case,
has been added to 4.18-stable and 4.14-stable:
https://www.spinics.net/lists/stable/msg255906.html
https://www.spinics.net/lists/stable/msg255724.html
If give EINVAL as PASS, the case will PASS with or without the regression
fix. I'm not sure which behavior of execveat03 is more appropriate.
Please advise.

Thanks,
Eddie
Jan Stancek Sept. 12, 2018, 7:04 a.m. | #11
----- Original Message -----
> Jan Stancek <jstancek@redhat.com> 於 2018年9月11日 週二 下午11:24寫道:
> > We should fix this for release. If EINVAL is expected behaviour,
> > test should give PASS.
> >
> > It's failing with 4.18:
> >
> > tst_test.c:1063: INFO: Timeout per run is 0h 05m 00s
> > execveat03.c:71: FAIL: execveat() returned unexpected errno: EINVAL
> >
> 
> Hi Jan,
> The fix of original regression, ie. EINVAL returns in execveat03 test case,
> has been added to 4.18-stable and 4.14-stable:
> https://www.spinics.net/lists/stable/msg255906.html
> https://www.spinics.net/lists/stable/msg255724.html
> If give EINVAL as PASS, the case will PASS with or without the regression
> fix. I'm not sure which behavior of execveat03 is more appropriate.
> Please advise.

Hi Eddie,

thanks for the links. I think I confused myself with the comment in testcase.
I thought EINVAL is expected behavior with the fix.

For now, I only added comment with commit id of the fix to testcase.

Thanks,
Jan

> 
> Thanks,
> Eddie
>

Patch

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..53c8be8a5
--- /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 */
diff --git a/testcases/kernel/syscalls/execveat/execveat01.c b/testcases/kernel/syscalls/execveat/execveat01.c
new file mode 100644
index 000000000..768b196d3
--- /dev/null
+++ b/testcases/kernel/syscalls/execveat/execveat01.c
@@ -0,0 +1,128 @@ 
+/*
+ * 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 *argv[2] = {TEST_FILE_PATH, NULL};
+	int fd;
+
+	SAFE_CP(TEST_APP, TEST_FILE_PATH);
+
+	fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH);
+	SAFE_UNLINK(TEST_FILE_PATH);
+
+	TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
+	tst_res(TFAIL | TERRNO, "execveat() returned unexpected errno");
+}
+
+static void verify_execveat(void)
+{
+	pid_t pid;
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_child();
+		exit(1);
+	}
+	SAFE_WAITPID(pid, NULL, 0);
+}
+
+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.");
+		}
+		tst_brk(TBROK | TERRNO, "overlayfs mount failed");
+	}
+	ovl_mounted = 1;
+}
+
+static void cleanup(void)
+{
+	if (ovl_mounted)
+		SAFE_UMOUNT(OVL_MNT);
+}
+
+static const char *const resource_files[] = {
+	TEST_APP,
+	NULL,
+};
+
+static struct tst_test test = {
+	.needs_root = 1,
+	.needs_tmpdir = 1,
+	.forks_child = 1,
+	.needs_ipc_path = 1,
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = verify_execveat,
+	.resource_files = resource_files,
+	.min_kver = "3.19.0",
+};
+
diff --git a/testcases/kernel/syscalls/execveat/execveat_child.c b/testcases/kernel/syscalls/execveat/execveat_child.c
new file mode 100644
index 000000000..68fcd1325
--- /dev/null
+++ b/testcases/kernel/syscalls/execveat/execveat_child.c
@@ -0,0 +1,41 @@ 
+/*
+ * 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.
+ *
+ */
+
+/*
+ * execveat_child.c
+ * dummy program which is used by execveat01.c testcase
+ */
+
+
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+
+int main(void)
+{
+	tst_reinit();
+	tst_res(TPASS, "execveat_child run as expected");
+	return 0;
+}
+