• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 MediaTek Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 or any later of the GNU General Public License
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Started by Eddie Horng <eddie.horng@mediatek.com>
24  *
25  * DESCRIPTION
26  *     Check if an unlinked executable can run in overlayfs mount.
27  *     The regression is introduced from 8db6c34f1dbc ("Introduce v3
28  *     namespaced file capabilities"). in security/commoncap.c,
29  *     cap_inode_getsecurity() use d_find_alias() cause unhashed dentry
30  *     can't be found. The solution could use d_find_any_alias() instead of
31  *     d_find_alias().
32  *
33  *     Starting with kernel 4.14, this case fails, execveat shall
34  *     returns EINVAL.
35  *
36  *     This has been fixed by:
37  *       355139a8dba4 ("cap_inode_getsecurity: use d_find_any_alias()
38  *                      instead of d_find_alias()")
39  */
40 
41 #define _GNU_SOURCE
42 #include "config.h"
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <sys/syscall.h>
51 #include <sys/mount.h>
52 #include <fcntl.h>
53 #include "tst_test.h"
54 #include "lapi/execveat.h"
55 #include "lapi/fcntl.h"
56 #include "execveat.h"
57 
58 #define OVL_MNT "ovl"
59 #define TEST_APP "execveat_child"
60 #define TEST_FILE_PATH OVL_MNT"/"TEST_APP
61 
62 static int ovl_mounted;
63 
do_child(void)64 static void do_child(void)
65 {
66 	char *argv[2] = {TEST_FILE_PATH, NULL};
67 	int fd;
68 
69 	SAFE_CP(TEST_APP, TEST_FILE_PATH);
70 
71 	fd = SAFE_OPEN(TEST_FILE_PATH, O_PATH);
72 	SAFE_UNLINK(TEST_FILE_PATH);
73 
74 	TEST(execveat(fd, "", argv, environ, AT_EMPTY_PATH));
75 	tst_res(TFAIL | TERRNO, "execveat() returned unexpected errno");
76 }
77 
verify_execveat(void)78 static void verify_execveat(void)
79 {
80 	pid_t pid;
81 
82 	pid = SAFE_FORK();
83 	if (pid == 0)
84 		do_child();
85 }
86 
setup(void)87 static void setup(void)
88 {
89 	int ret;
90 
91 	check_execveat();
92 
93 	/* Setup an overlay mount with lower file */
94 	SAFE_MKDIR("lower", 0755);
95 	SAFE_MKDIR("upper", 0755);
96 	SAFE_MKDIR("work", 0755);
97 	SAFE_MKDIR(OVL_MNT, 0755);
98 	ret = mount("overlay", OVL_MNT, "overlay", 0,
99 		    "lowerdir=lower,upperdir=upper,workdir=work");
100 	if (ret < 0) {
101 		if (errno == ENODEV) {
102 			tst_brk(TCONF,
103 				"overlayfs is not configured in this kernel.");
104 		}
105 		tst_brk(TBROK | TERRNO, "overlayfs mount failed");
106 	}
107 	ovl_mounted = 1;
108 }
109 
cleanup(void)110 static void cleanup(void)
111 {
112 	if (ovl_mounted)
113 		SAFE_UMOUNT(OVL_MNT);
114 }
115 
116 static const char *const resource_files[] = {
117 	TEST_APP,
118 	NULL,
119 };
120 
121 static struct tst_test test = {
122 	.needs_root = 1,
123 	.needs_tmpdir = 1,
124 	.forks_child = 1,
125 	.child_needs_reinit = 1,
126 	.setup = setup,
127 	.cleanup = cleanup,
128 	.test_all = verify_execveat,
129 	.resource_files = resource_files,
130 };
131