Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/exec: include cwd in long path calculation

When creating a pathname close to PATH_MAX to test execveat, factor in
the current working directory path otherwise we end up with an absolute
path that is longer than PATH_MAX. While execveat() may succeed, subsequent
calls to the kernel from the runtime environment which are required to
successfully execute the test binary/script may fail because of this.

To keep the semantics of the test the same, rework the relative pathname
part of the test to be relative to the root directory so it isn't
decreased by the length of the current working directory path.

Signed-off-by: Steve Muckle <smuckle.linux@gmail.com>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

Steve Muckle and committed by
Shuah Khan
2d80c92d d54e9a8f

+19 -8
+19 -8
tools/testing/selftests/exec/execveat.c
··· 147 147 } 148 148 149 149 #define XX_DIR_LEN 200 150 - static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script) 150 + static int check_execveat_pathmax(int root_dfd, const char *src, int is_script) 151 151 { 152 152 int fail = 0; 153 153 int ii, count, len; ··· 156 156 157 157 if (*longpath == '\0') { 158 158 /* Create a filename close to PATH_MAX in length */ 159 + char *cwd = getcwd(NULL, 0); 160 + 161 + if (!cwd) { 162 + printf("Failed to getcwd(), errno=%d (%s)\n", 163 + errno, strerror(errno)); 164 + return 2; 165 + } 166 + strcpy(longpath, cwd); 167 + strcat(longpath, "/"); 159 168 memset(longname, 'x', XX_DIR_LEN - 1); 160 169 longname[XX_DIR_LEN - 1] = '/'; 161 170 longname[XX_DIR_LEN] = '\0'; 162 - count = (PATH_MAX - 3) / XX_DIR_LEN; 171 + count = (PATH_MAX - 3 - strlen(cwd)) / XX_DIR_LEN; 163 172 for (ii = 0; ii < count; ii++) { 164 173 strcat(longpath, longname); 165 174 mkdir(longpath, 0755); 166 175 } 167 - len = (PATH_MAX - 3) - (count * XX_DIR_LEN); 176 + len = (PATH_MAX - 3 - strlen(cwd)) - (count * XX_DIR_LEN); 168 177 if (len <= 0) 169 178 len = 1; 170 179 memset(longname, 'y', len); 171 180 longname[len] = '\0'; 172 181 strcat(longpath, longname); 182 + free(cwd); 173 183 } 174 184 exe_cp(src, longpath); 175 185 ··· 200 190 } 201 191 202 192 /* 203 - * Execute as a long pathname relative to ".". If this is a script, 193 + * Execute as a long pathname relative to "/". If this is a script, 204 194 * the interpreter will launch but fail to open the script because its 205 195 * name ("/dev/fd/5/xxx....") is bigger than PATH_MAX. 206 196 * ··· 210 200 * the exit status shall be 126."), so allow either. 211 201 */ 212 202 if (is_script) 213 - fail += check_execveat_invoked_rc(dot_dfd, longpath, 0, 203 + fail += check_execveat_invoked_rc(root_dfd, longpath + 1, 0, 214 204 127, 126); 215 205 else 216 - fail += check_execveat(dot_dfd, longpath, 0); 206 + fail += check_execveat(root_dfd, longpath + 1, 0); 217 207 218 208 return fail; 219 209 } ··· 228 218 int subdir_dfd_ephemeral = open_or_die("subdir.ephemeral", 229 219 O_DIRECTORY|O_RDONLY); 230 220 int dot_dfd = open_or_die(".", O_DIRECTORY|O_RDONLY); 221 + int root_dfd = open_or_die("/", O_DIRECTORY|O_RDONLY); 231 222 int dot_dfd_path = open_or_die(".", O_DIRECTORY|O_RDONLY|O_PATH); 232 223 int dot_dfd_cloexec = open_or_die(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC); 233 224 int fd = open_or_die("execveat", O_RDONLY); ··· 364 353 /* Attempt to execute relative to non-directory => ENOTDIR */ 365 354 fail += check_execveat_fail(fd, "execveat", 0, ENOTDIR); 366 355 367 - fail += check_execveat_pathmax(dot_dfd, "execveat", 0); 368 - fail += check_execveat_pathmax(dot_dfd, "script", 1); 356 + fail += check_execveat_pathmax(root_dfd, "execveat", 0); 357 + fail += check_execveat_pathmax(root_dfd, "script", 1); 369 358 return fail; 370 359 } 371 360