-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/exec: add file type errno tests
Make sure execve() returns the expected errno values for non-regular files. Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Cc: Marc Zyngier <maz@kernel.org> Link: http://lkml.kernel.org/r/20200813231723.2725102-3-keescook@chromium.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
- Loading branch information
Kees Cook
authored and
Linus Torvalds
committed
Aug 15, 2020
1 parent
fc4177b
commit 0f71241
Showing
3 changed files
with
200 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ execveat.denatured | |
/recursion-depth | ||
xxxxxxxx* | ||
pipe | ||
S_I*.test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include <sys/socket.h> | ||
#include <sys/stat.h> | ||
#include <sys/sysmacros.h> | ||
#include <sys/types.h> | ||
|
||
#include "../kselftest_harness.h" | ||
|
||
/* Remove a file, ignoring the result if it didn't exist. */ | ||
void rm(struct __test_metadata *_metadata, const char *pathname, | ||
int is_dir) | ||
{ | ||
int rc; | ||
|
||
if (is_dir) | ||
rc = rmdir(pathname); | ||
else | ||
rc = unlink(pathname); | ||
|
||
if (rc < 0) { | ||
ASSERT_EQ(errno, ENOENT) { | ||
TH_LOG("Not ENOENT: %s", pathname); | ||
} | ||
} else { | ||
ASSERT_EQ(rc, 0) { | ||
TH_LOG("Failed to remove: %s", pathname); | ||
} | ||
} | ||
} | ||
|
||
FIXTURE(file) { | ||
char *pathname; | ||
int is_dir; | ||
}; | ||
|
||
FIXTURE_VARIANT(file) | ||
{ | ||
const char *name; | ||
int expected; | ||
int is_dir; | ||
void (*setup)(struct __test_metadata *_metadata, | ||
FIXTURE_DATA(file) *self, | ||
const FIXTURE_VARIANT(file) *variant); | ||
int major, minor, mode; /* for mknod() */ | ||
}; | ||
|
||
void setup_link(struct __test_metadata *_metadata, | ||
FIXTURE_DATA(file) *self, | ||
const FIXTURE_VARIANT(file) *variant) | ||
{ | ||
const char * const paths[] = { | ||
"/bin/true", | ||
"/usr/bin/true", | ||
}; | ||
int i; | ||
|
||
for (i = 0; i < ARRAY_SIZE(paths); i++) { | ||
if (access(paths[i], X_OK) == 0) { | ||
ASSERT_EQ(symlink(paths[i], self->pathname), 0); | ||
return; | ||
} | ||
} | ||
ASSERT_EQ(1, 0) { | ||
TH_LOG("Could not find viable 'true' binary"); | ||
} | ||
} | ||
|
||
FIXTURE_VARIANT_ADD(file, S_IFLNK) | ||
{ | ||
.name = "S_IFLNK", | ||
.expected = ELOOP, | ||
.setup = setup_link, | ||
}; | ||
|
||
void setup_dir(struct __test_metadata *_metadata, | ||
FIXTURE_DATA(file) *self, | ||
const FIXTURE_VARIANT(file) *variant) | ||
{ | ||
ASSERT_EQ(mkdir(self->pathname, 0755), 0); | ||
} | ||
|
||
FIXTURE_VARIANT_ADD(file, S_IFDIR) | ||
{ | ||
.name = "S_IFDIR", | ||
.is_dir = 1, | ||
.expected = EACCES, | ||
.setup = setup_dir, | ||
}; | ||
|
||
void setup_node(struct __test_metadata *_metadata, | ||
FIXTURE_DATA(file) *self, | ||
const FIXTURE_VARIANT(file) *variant) | ||
{ | ||
dev_t dev; | ||
int rc; | ||
|
||
dev = makedev(variant->major, variant->minor); | ||
rc = mknod(self->pathname, 0755 | variant->mode, dev); | ||
ASSERT_EQ(rc, 0) { | ||
if (errno == EPERM) | ||
SKIP(return, "Please run as root; cannot mknod(%s)", | ||
variant->name); | ||
} | ||
} | ||
|
||
FIXTURE_VARIANT_ADD(file, S_IFBLK) | ||
{ | ||
.name = "S_IFBLK", | ||
.expected = EACCES, | ||
.setup = setup_node, | ||
/* /dev/loop0 */ | ||
.major = 7, | ||
.minor = 0, | ||
.mode = S_IFBLK, | ||
}; | ||
|
||
FIXTURE_VARIANT_ADD(file, S_IFCHR) | ||
{ | ||
.name = "S_IFCHR", | ||
.expected = EACCES, | ||
.setup = setup_node, | ||
/* /dev/zero */ | ||
.major = 1, | ||
.minor = 5, | ||
.mode = S_IFCHR, | ||
}; | ||
|
||
void setup_fifo(struct __test_metadata *_metadata, | ||
FIXTURE_DATA(file) *self, | ||
const FIXTURE_VARIANT(file) *variant) | ||
{ | ||
ASSERT_EQ(mkfifo(self->pathname, 0755), 0); | ||
} | ||
|
||
FIXTURE_VARIANT_ADD(file, S_IFIFO) | ||
{ | ||
.name = "S_IFIFO", | ||
.expected = EACCES, | ||
.setup = setup_fifo, | ||
}; | ||
|
||
FIXTURE_SETUP(file) | ||
{ | ||
ASSERT_GT(asprintf(&self->pathname, "%s.test", variant->name), 6); | ||
self->is_dir = variant->is_dir; | ||
|
||
rm(_metadata, self->pathname, variant->is_dir); | ||
variant->setup(_metadata, self, variant); | ||
} | ||
|
||
FIXTURE_TEARDOWN(file) | ||
{ | ||
rm(_metadata, self->pathname, self->is_dir); | ||
} | ||
|
||
TEST_F(file, exec_errno) | ||
{ | ||
char * const argv[2] = { (char * const)self->pathname, NULL }; | ||
|
||
EXPECT_LT(execv(argv[0], argv), 0); | ||
EXPECT_EQ(errno, variant->expected); | ||
} | ||
|
||
/* S_IFSOCK */ | ||
FIXTURE(sock) | ||
{ | ||
int fd; | ||
}; | ||
|
||
FIXTURE_SETUP(sock) | ||
{ | ||
self->fd = socket(AF_INET, SOCK_STREAM, 0); | ||
ASSERT_GE(self->fd, 0); | ||
} | ||
|
||
FIXTURE_TEARDOWN(sock) | ||
{ | ||
if (self->fd >= 0) | ||
ASSERT_EQ(close(self->fd), 0); | ||
} | ||
|
||
TEST_F(sock, exec_errno) | ||
{ | ||
char * const argv[2] = { " magic socket ", NULL }; | ||
char * const envp[1] = { NULL }; | ||
|
||
EXPECT_LT(fexecve(self->fd, argv, envp), 0); | ||
EXPECT_EQ(errno, EACCES); | ||
} | ||
|
||
TEST_HARNESS_MAIN |