Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144368371
D28687.id83998.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D28687.id83998.diff
View Options
Index: contrib/capsicum-test/capability-fd.cc
===================================================================
--- contrib/capsicum-test/capability-fd.cc
+++ contrib/capsicum-test/capability-fd.cc
@@ -486,6 +486,7 @@
// Given a file descriptor, create a capability with specific rights and
// make sure only those rights work.
#define TRY_FILE_OPS(fd, ...) do { \
+ SCOPED_TRACE(#__VA_ARGS__); \
cap_rights_t rights; \
cap_rights_init(&rights, __VA_ARGS__); \
TryFileOps((fd), rights); \
@@ -1289,7 +1290,10 @@
pid_t child = fork();
if (child == 0) {
// Child: change uid to a lesser being
- setuid(other_uid);
+ ASSERT_NE(0u, other_uid) << "other_uid not initialized correctly, "
+ "please pass the -u <uid> flag.";
+ EXPECT_EQ(0, setuid(other_uid));
+ EXPECT_EQ(other_uid, getuid());
// Attempt to fchmod the file, and fail.
// Having CAP_FCHMOD doesn't bypass the need to comply with DAC policy.
int rc = fchmod(fd, 0666);
Index: contrib/capsicum-test/capsicum-freebsd.h
===================================================================
--- contrib/capsicum-test/capsicum-freebsd.h
+++ contrib/capsicum-test/capsicum-freebsd.h
@@ -35,6 +35,12 @@
#if __FreeBSD_version >= 1101000
#define HAVE_OPENAT_INTERMEDIATE_DOTDOT
#endif
+#if __FreeBSD_version >= 1300116
+// Since FreeBSD commit 6a9c72d901feeca0b0865be8954a3a29d8613b34 any sequence
+// including ".." is valid with O_BENEATH as long as we return back below the start.
+// Capsicum and the stricter O_RESOLVE_BENEATH do no allow escaping at all.
+#define HAVE_O_BENEATH_INTERMEDIATE_DOTDOT
+#endif
#endif
Index: contrib/capsicum-test/capsicum-test.h
===================================================================
--- contrib/capsicum-test/capsicum-test.h
+++ contrib/capsicum-test/capsicum-test.h
@@ -75,7 +75,7 @@
} \
} else if (pid > 0) { \
int rc, status; \
- int remaining_us = 10000000; \
+ int remaining_us = 30000000; \
while (remaining_us > 0) { \
status = 0; \
rc = waitpid(pid, &status, WNOHANG); \
@@ -139,15 +139,17 @@
// Expect a syscall to fail with the given error.
#define EXPECT_SYSCALL_FAIL(E, C) \
do { \
+ SCOPED_TRACE(#C); \
EXPECT_GT(0, C); \
- EXPECT_EQ(E, errno); \
+ EXPECT_EQ(E, errno) << "expected '" << strerror(E) \
+ << "' but got '" << strerror(errno) << "'"; \
} while (0)
// Expect a syscall to fail with anything other than the given error.
#define EXPECT_SYSCALL_FAIL_NOT(E, C) \
do { \
EXPECT_GT(0, C); \
- EXPECT_NE(E, errno); \
+ EXPECT_NE(E, errno) << strerror(E); \
} while (0)
// Expect a void syscall to fail with anything other than the given error.
@@ -162,19 +164,23 @@
// code is OS-specific.
#ifdef O_BENEATH
#define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
- do { \
+ do { \
+ SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \
const int result = openat((fd), (path), (flags)); \
if (((flags) & O_BENEATH) == O_BENEATH) { \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_O_BENEATH, result); \
} else { \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
} \
+ if (result >= 0) { close(result); } \
} while (0)
#else
#define EXPECT_OPENAT_FAIL_TRAVERSAL(fd, path, flags) \
do { \
+ SCOPED_TRACE(GTEST_STRINGIFY_(openat((fd), (path), (flags)))); \
const int result = openat((fd), (path), (flags)); \
EXPECT_SYSCALL_FAIL(E_NO_TRAVERSE_CAPABILITY, result); \
+ if (result >= 0) { close(result); } \
} while (0)
#endif
@@ -197,7 +203,8 @@
int rc = C; \
EXPECT_GT(0, rc); \
EXPECT_TRUE(errno == ECAPMODE || errno == ENOTCAPABLE) \
- << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno; \
+ << #C << " did not fail with ECAPMODE/ENOTCAPABLE but " << errno \
+ << "(" << strerror(errno) << ")"; \
} while (0)
// Ensure that 'rights' are a subset of 'max'.
Index: contrib/capsicum-test/openat.cc
===================================================================
--- contrib/capsicum-test/openat.cc
+++ contrib/capsicum-test/openat.cc
@@ -11,6 +11,7 @@
// Check an open call works and close the resulting fd.
#define EXPECT_OPEN_OK(f) do { \
+ SCOPED_TRACE(#f); \
int _fd = f; \
EXPECT_OK(_fd); \
close(_fd); \
@@ -257,17 +258,30 @@
}
// Check openat(2) policing that is common across capabilities, capability mode and O_BENEATH.
- void CheckPolicing(int oflag) {
+ void CheckPolicing(int oflag, bool allowsIntermediateEscape) {
// OK for normal access.
EXPECT_OPEN_OK(openat(dir_fd_, "topfile", O_RDONLY|oflag));
EXPECT_OPEN_OK(openat(dir_fd_, "subdir/bottomfile", O_RDONLY|oflag));
EXPECT_OPEN_OK(openat(sub_fd_, "bottomfile", O_RDONLY|oflag));
EXPECT_OPEN_OK(openat(sub_fd_, ".", O_RDONLY|oflag));
+ EXPECT_SYSCALL_FAIL(ENOENT, openat(sub_fd_, "foo/../bottomfile", O_RDONLY | oflag));
+ EXPECT_SYSCALL_FAIL(ENOENT, openat(sub_fd_, "foo/../../subdir/bottomfile", O_RDONLY | oflag));
+
// Can't open paths with ".." in them.
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "../topfile", O_RDONLY|oflag);
- EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "../subdir/bottomfile", O_RDONLY|oflag);
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "..", O_RDONLY|oflag);
+ if (allowsIntermediateEscape) {
+ EXPECT_OPEN_OK(openat(sub_fd_, "../subdir/bottomfile", O_RDONLY | oflag));
+ EXPECT_OPEN_OK(openat(sub_fd_, "../../cap_topdir/subdir/bottomfile", O_RDONLY | oflag));
+ EXPECT_OPEN_OK(openat(dir_fd_, "../cap_topdir/subdir/bottomfile", O_RDONLY | oflag));
+ EXPECT_OPEN_OK(openat(dir_fd_, "subdir/../../cap_topdir/topfile", O_RDONLY | oflag));
+ } else {
+ EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "../subdir/bottomfile", O_RDONLY | oflag);
+ EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "../../cap_topdir/subdir/bottomfile", O_RDONLY | oflag);
+ EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "../cap_topdir/subdir/bottomfile", O_RDONLY | oflag);
+ EXPECT_OPENAT_FAIL_TRAVERSAL(dir_fd_, "subdir/../../cap_topdir/topfile", O_RDONLY | oflag);
+ }
#ifdef HAVE_OPENAT_INTERMEDIATE_DOTDOT
// OK for dotdot lookups that don't escape the top directory
@@ -321,14 +335,14 @@
cap_rights_init(&r_rl, CAP_READ, CAP_LOOKUP, CAP_FCHDIR);
EXPECT_OK(cap_rights_limit(dir_fd_, &r_rl));
EXPECT_OK(cap_rights_limit(sub_fd_, &r_rl));
- CheckPolicing(0);
+ CheckPolicing(0, /*allowsIntermediateEscape=*/false);
// Use of AT_FDCWD is independent of use of a capability.
// Can open paths starting with "/" against a capability dfd, because the dfd is ignored.
}
FORK_TEST_F(OpenatTest, InCapabilityMode) {
EXPECT_OK(cap_enter()); // Enter capability mode
- CheckPolicing(0);
+ CheckPolicing(0, /*allowsIntermediateEscape=*/false);
// Use of AT_FDCWD is banned in capability mode.
EXPECT_CAPMODE(openat(AT_FDCWD, "topfile", O_RDONLY));
@@ -341,8 +355,13 @@
}
#ifdef O_BENEATH
-TEST_F(OpenatTest, WithFlag) {
- CheckPolicing(O_BENEATH);
+TEST_F(OpenatTest, WithFlag_O_BENEATH) {
+ bool allowsIntermediateEscape = false;
+ // FreeBSD13+ O_BENEATH allows intermediate .. as long as the final path is below the start.
+#ifdef HAVE_O_BENEATH_INTERMEDIATE_DOTDOT
+ allowsIntermediateEscape = true;
+#endif
+ CheckPolicing(O_BENEATH, allowsIntermediateEscape);
// Check with AT_FDCWD.
EXPECT_OPEN_OK(openat(AT_FDCWD, "topfile", O_RDONLY|O_BENEATH));
@@ -354,8 +373,33 @@
EXPECT_OPENAT_FAIL_TRAVERSAL(sub_fd_, "/etc/passwd", O_RDONLY|O_BENEATH);
}
-FORK_TEST_F(OpenatTest, WithFlagInCapabilityMode) {
+FORK_TEST_F(OpenatTest, WithFlagInCapabilityMode_O_BENEATH) {
+ EXPECT_OK(cap_enter()); // Enter capability mode
+ CheckPolicing(O_BENEATH, /*allowsIntermediateEscape=*/false);
+}
+#endif
+
+#ifdef O_RESOLVE_BENEATH
+TEST_F(OpenatTest, WithFlag_O_RESOLVE_BENEATH) {
+ // O_RESOLVE_BENEATH is similar to O_BENEATH but prevents any (temporary)
+ // escape from the root during resolving.
+ CheckPolicing(O_RESOLVE_BENEATH, /*allowsIntermediateEscape=*/false);
+}
+
+FORK_TEST_F(OpenatTest, WithFlagInCapabilityMode_O_RESOLVE_BENEATH) {
+ EXPECT_OK(cap_enter()); // Enter capability mode
+ CheckPolicing(O_RESOLVE_BENEATH, /*allowsIntermediateEscape=*/false);
+}
+
+#ifdef O_BENEATH
+TEST_F(OpenatTest, WithFlag_O_RESOLVE_BENEATH_and_O_BENEATH) {
+ // If both O_BENEATH and O_RESOLVE_BENEATH are passed, the latter has priority.
+ CheckPolicing(O_RESOLVE_BENEATH | O_BENEATH, /*allowsIntermediateEscape=*/false);
+}
+
+FORK_TEST_F(OpenatTest, WithFlagInCapabilityMode_O_RESOLVE_BENEATH_and_O_BENEATH) {
EXPECT_OK(cap_enter()); // Enter capability mode
- CheckPolicing(O_BENEATH);
+ CheckPolicing(O_RESOLVE_BENEATH | O_BENEATH, /*allowsIntermediateEscape=*/false);
}
#endif
+#endif
Index: contrib/capsicum-test/procdesc.cc
===================================================================
--- contrib/capsicum-test/procdesc.cc
+++ contrib/capsicum-test/procdesc.cc
@@ -531,7 +531,10 @@
usleep(100);
// Now that the second process has been pdfork()ed, change euid.
- setuid(other_uid);
+ ASSERT_NE(0u, other_uid) << "other_uid not initialized correctly, "
+ "please pass the -u <uid> flag.";
+ EXPECT_EQ(0, setuid(other_uid));
+ EXPECT_EQ(other_uid, getuid());
if (verbose) fprintf(stderr, "uid=%d euid=%d\n", getuid(), geteuid());
// Fail to kill child with normal PID operation.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 2:17 AM (13 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28525097
Default Alt Text
D28687.id83998.diff (9 KB)
Attached To
Mode
D28687: WIP: Update capsicum-test after O_BENEATH changes.
Attached
Detach File
Event Timeline
Log In to Comment