Skip to content

Commit 65e4751

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge changes from topic "bionic_fdsan"
* changes: crasher: add close(fileno(FILE*)) and close(dirfd(DIR*)). debuggerd_handler: use syscall(__NR_close) instead of close. base: add support for tagged fd closure to unique_fd.
2 parents 881be58 + 3fa9637 commit 65e4751

File tree

5 files changed

+182
-51
lines changed

5 files changed

+182
-51
lines changed

base/Android.bp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ cc_test {
135135
"strings_test.cpp",
136136
"test_main.cpp",
137137
"test_utils_test.cpp",
138+
"unique_fd_test.cpp",
138139
],
139140
target: {
140141
android: {

base/include/android-base/unique_fd.h

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,51 +42,105 @@
4242
//
4343
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
4444
// you find this class if you're searching for one of those names.
45+
46+
#if defined(__BIONIC__)
47+
#include <android/fdsan.h>
48+
#endif
49+
4550
namespace android {
4651
namespace base {
4752

4853
struct DefaultCloser {
54+
#if defined(__BIONIC__)
55+
static void Tag(int fd, void* old_addr, void* new_addr) {
56+
uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
57+
reinterpret_cast<uint64_t>(old_addr));
58+
uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
59+
reinterpret_cast<uint64_t>(new_addr));
60+
android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
61+
}
62+
static void Close(int fd, void* addr) {
63+
uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
64+
reinterpret_cast<uint64_t>(addr));
65+
android_fdsan_close_with_tag(fd, tag);
66+
}
67+
#else
4968
static void Close(int fd) {
5069
// Even if close(2) fails with EINTR, the fd will have been closed.
5170
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
5271
// else's fd.
5372
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
5473
::close(fd);
5574
}
75+
#endif
5676
};
5777

5878
template <typename Closer>
5979
class unique_fd_impl final {
6080
public:
61-
unique_fd_impl() : value_(-1) {}
81+
unique_fd_impl() {}
6282

63-
explicit unique_fd_impl(int value) : value_(value) {}
83+
explicit unique_fd_impl(int fd) { reset(fd); }
6484
~unique_fd_impl() { reset(); }
6585

66-
unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
86+
unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
6787
unique_fd_impl& operator=(unique_fd_impl&& s) {
68-
reset(s.release());
88+
int fd = s.fd_;
89+
s.fd_ = -1;
90+
reset(fd, &s);
6991
return *this;
7092
}
7193

72-
void reset(int new_value = -1) {
73-
if (value_ != -1) {
74-
Closer::Close(value_);
75-
}
76-
value_ = new_value;
77-
}
94+
void reset(int new_value = -1) { reset(new_value, nullptr); }
7895

79-
int get() const { return value_; }
96+
int get() const { return fd_; }
8097
operator int() const { return get(); }
8198

8299
int release() __attribute__((warn_unused_result)) {
83-
int ret = value_;
84-
value_ = -1;
100+
tag(fd_, this, nullptr);
101+
int ret = fd_;
102+
fd_ = -1;
85103
return ret;
86104
}
87105

88106
private:
89-
int value_;
107+
void reset(int new_value, void* previous_tag) {
108+
if (fd_ != -1) {
109+
close(fd_, this);
110+
}
111+
112+
fd_ = new_value;
113+
if (new_value != -1) {
114+
tag(new_value, previous_tag, this);
115+
}
116+
}
117+
118+
int fd_ = -1;
119+
120+
// Template magic to use Closer::Tag if available, and do nothing if not.
121+
// If Closer::Tag exists, this implementation is preferred, because int is a better match.
122+
// If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
123+
template <typename T = Closer>
124+
static auto tag(int fd, void* old_tag, void* new_tag)
125+
-> decltype(T::Tag(fd, old_tag, new_tag), void()) {
126+
T::Tag(fd, old_tag, new_tag);
127+
}
128+
129+
template <typename T = Closer>
130+
static void tag(long, void*, void*) {
131+
// No-op.
132+
}
133+
134+
// Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
135+
template <typename T = Closer>
136+
static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
137+
T::Close(fd, tag_value);
138+
}
139+
140+
template <typename T = Closer>
141+
static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
142+
T::Close(fd);
143+
}
90144

91145
unique_fd_impl(const unique_fd_impl&);
92146
void operator=(const unique_fd_impl&);
@@ -97,7 +151,8 @@ using unique_fd = unique_fd_impl<DefaultCloser>;
97151
#if !defined(_WIN32)
98152

99153
// Inline functions, so that they can be used header-only.
100-
inline bool Pipe(unique_fd* read, unique_fd* write) {
154+
template <typename Closer>
155+
inline bool Pipe(unique_fd_impl<Closer>* read, unique_fd_impl<Closer>* write) {
101156
int pipefd[2];
102157

103158
#if defined(__linux__)
@@ -121,7 +176,9 @@ inline bool Pipe(unique_fd* read, unique_fd* write) {
121176
return true;
122177
}
123178

124-
inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, unique_fd* right) {
179+
template <typename Closer>
180+
inline bool Socketpair(int domain, int type, int protocol, unique_fd_impl<Closer>* left,
181+
unique_fd_impl<Closer>* right) {
125182
int sockfd[2];
126183
if (socketpair(domain, type, protocol, sockfd) != 0) {
127184
return false;
@@ -131,7 +188,8 @@ inline bool Socketpair(int domain, int type, int protocol, unique_fd* left, uniq
131188
return true;
132189
}
133190

134-
inline bool Socketpair(int type, unique_fd* left, unique_fd* right) {
191+
template <typename Closer>
192+
inline bool Socketpair(int type, unique_fd_impl<Closer>* left, unique_fd_impl<Closer>* right) {
135193
return Socketpair(AF_UNIX, type, 0, left, right);
136194
}
137195

base/unique_fd_test.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) 2018 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "android-base/unique_fd.h"
18+
19+
#include <gtest/gtest.h>
20+
21+
#include <errno.h>
22+
#include <fcntl.h>
23+
#include <unistd.h>
24+
25+
using android::base::unique_fd;
26+
27+
TEST(unique_fd, unowned_close) {
28+
#if defined(__BIONIC__)
29+
unique_fd fd(open("/dev/null", O_RDONLY));
30+
EXPECT_DEATH(close(fd.get()), "incorrect tag");
31+
#endif
32+
}
33+
34+
TEST(unique_fd, untag_on_release) {
35+
unique_fd fd(open("/dev/null", O_RDONLY));
36+
close(fd.release());
37+
}
38+
39+
TEST(unique_fd, move) {
40+
unique_fd fd(open("/dev/null", O_RDONLY));
41+
unique_fd fd_moved = std::move(fd);
42+
ASSERT_EQ(-1, fd.get());
43+
ASSERT_GT(fd_moved.get(), -1);
44+
}
45+
46+
TEST(unique_fd, unowned_close_after_move) {
47+
#if defined(__BIONIC__)
48+
unique_fd fd(open("/dev/null", O_RDONLY));
49+
unique_fd fd_moved = std::move(fd);
50+
ASSERT_EQ(-1, fd.get());
51+
ASSERT_GT(fd_moved.get(), -1);
52+
EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
53+
#endif
54+
}

debuggerd/crasher/crasher.cpp

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ static int usage() {
183183
fprintf(stderr, " exit call exit(1)\n");
184184
fprintf(stderr, "\n");
185185
fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n");
186+
fprintf(stderr, " fdsan_file close a file descriptor that's owned by a FILE*\n");
187+
fprintf(stderr, " fdsan_dir close a file descriptor that's owned by a DIR*\n");
186188
fprintf(stderr, " seccomp fail a seccomp check\n");
187189
#if defined(__arm__)
188190
fprintf(stderr, " kuser_helper_version call kuser_helper_version\n");
@@ -236,39 +238,45 @@ noinline int do_action(const char* arg) {
236238

237239
// Actions.
238240
if (!strcasecmp(arg, "SIGSEGV-non-null")) {
239-
sigsegv_non_null();
241+
sigsegv_non_null();
240242
} else if (!strcasecmp(arg, "smash-stack")) {
241-
volatile int len = 128;
242-
return smash_stack(&len);
243+
volatile int len = 128;
244+
return smash_stack(&len);
243245
} else if (!strcasecmp(arg, "stack-overflow")) {
244-
overflow_stack(nullptr);
246+
overflow_stack(nullptr);
245247
} else if (!strcasecmp(arg, "nostack")) {
246-
crashnostack();
248+
crashnostack();
247249
} else if (!strcasecmp(arg, "exit")) {
248-
exit(1);
250+
exit(1);
249251
} else if (!strcasecmp(arg, "call-null")) {
250252
return crash_null();
251253
} else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
252-
return crash(42);
254+
return crash(42);
253255
} else if (!strcasecmp(arg, "abort")) {
254-
maybe_abort();
256+
maybe_abort();
255257
} else if (!strcasecmp(arg, "assert")) {
256-
__assert("some_file.c", 123, "false");
258+
__assert("some_file.c", 123, "false");
257259
} else if (!strcasecmp(arg, "assert2")) {
258-
__assert2("some_file.c", 123, "some_function", "false");
260+
__assert2("some_file.c", 123, "some_function", "false");
259261
} else if (!strcasecmp(arg, "fortify")) {
260-
char buf[10];
261-
__read_chk(-1, buf, 32, 10);
262-
while (true) pause();
262+
char buf[10];
263+
__read_chk(-1, buf, 32, 10);
264+
while (true) pause();
265+
} else if (!strcasecmp(arg, "fdsan_file")) {
266+
FILE* f = fopen("/dev/null", "r");
267+
close(fileno(f));
268+
} else if (!strcasecmp(arg, "fdsan_dir")) {
269+
DIR* d = opendir("/dev/");
270+
close(dirfd(d));
263271
} else if (!strcasecmp(arg, "LOG(FATAL)")) {
264-
LOG(FATAL) << "hello " << 123;
272+
LOG(FATAL) << "hello " << 123;
265273
} else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL")) {
266-
LOG_ALWAYS_FATAL("hello %s", "world");
274+
LOG_ALWAYS_FATAL("hello %s", "world");
267275
} else if (!strcasecmp(arg, "LOG_ALWAYS_FATAL_IF")) {
268-
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
276+
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
269277
} else if (!strcasecmp(arg, "SIGFPE")) {
270-
raise(SIGFPE);
271-
return EXIT_SUCCESS;
278+
raise(SIGFPE);
279+
return EXIT_SUCCESS;
272280
} else if (!strcasecmp(arg, "SIGILL")) {
273281
#if defined(__aarch64__)
274282
__asm__ volatile(".word 0\n");
@@ -280,28 +288,28 @@ noinline int do_action(const char* arg) {
280288
#error
281289
#endif
282290
} else if (!strcasecmp(arg, "SIGTRAP")) {
283-
raise(SIGTRAP);
284-
return EXIT_SUCCESS;
291+
raise(SIGTRAP);
292+
return EXIT_SUCCESS;
285293
} else if (!strcasecmp(arg, "fprintf-NULL")) {
286-
fprintf_null();
294+
fprintf_null();
287295
} else if (!strcasecmp(arg, "readdir-NULL")) {
288-
readdir_null();
296+
readdir_null();
289297
} else if (!strcasecmp(arg, "strlen-NULL")) {
290-
return strlen_null();
298+
return strlen_null();
291299
} else if (!strcasecmp(arg, "pthread_join-NULL")) {
292-
return pthread_join(0, nullptr);
300+
return pthread_join(0, nullptr);
293301
} else if (!strcasecmp(arg, "heap-usage")) {
294-
abuse_heap();
302+
abuse_heap();
295303
} else if (!strcasecmp(arg, "leak")) {
296-
leak();
304+
leak();
297305
} else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
298-
char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
299-
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
300-
munmap(map, sizeof(int));
301-
map[0] = '8';
306+
char* map = reinterpret_cast<char*>(
307+
mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
308+
munmap(map, sizeof(int));
309+
map[0] = '8';
302310
} else if (!strcasecmp(arg, "seccomp")) {
303-
set_system_seccomp_filter();
304-
syscall(99999);
311+
set_system_seccomp_filter();
312+
syscall(99999);
305313
#if defined(__arm__)
306314
} else if (!strcasecmp(arg, "kuser_helper_version")) {
307315
return __kuser_helper_version;

debuggerd/handler/debuggerd_handler.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,16 @@
5959
#include "protocol.h"
6060

6161
using android::base::Pipe;
62-
using android::base::unique_fd;
62+
63+
// We muck with our fds in a 'thread' that doesn't share the same fd table.
64+
// Close fds in that thread with a raw close syscall instead of going through libc.
65+
struct FdsanBypassCloser {
66+
static void Close(int fd) {
67+
syscall(__NR_close, fd);
68+
}
69+
};
70+
71+
using unique_fd = android::base::unique_fd_impl<FdsanBypassCloser>;
6372

6473
// see man(2) prctl, specifically the section about PR_GET_NAME
6574
#define MAX_TASK_NAME_LEN (16)
@@ -299,7 +308,8 @@ static int debuggerd_dispatch_pseudothread(void* arg) {
299308
debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg);
300309

301310
for (int i = 0; i < 1024; ++i) {
302-
close(i);
311+
// Don't use close to avoid bionic's file descriptor ownership checks.
312+
syscall(__NR_close, i);
303313
}
304314

305315
int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));

0 commit comments

Comments
 (0)