Compare commits

..

1 Commits

Author SHA1 Message Date
Nilesh Poddar
023c327cbb DO NOT MERGE ANYWHERE - bionic: resolver: exclude a range of ports from random_bind in DNS
Add a new API to set a range of ports which the DNS resolver should
never try to bind

Bug: 20127213
Change-Id: Ie3fca0ec2ee2523625816edd9417a0b5d5f91614
2015-04-23 21:46:36 +09:00
4 changed files with 156 additions and 149 deletions

View File

@@ -75,6 +75,9 @@ int android_getnameinfofornet(const struct sockaddr *, socklen_t, char *, size_t
/* delete the cache associated with a certain network */ /* delete the cache associated with a certain network */
extern void _resolv_delete_cache_for_net(unsigned netid); extern void _resolv_delete_cache_for_net(unsigned netid);
/* set a port range for exclusion in the random_bind */
int _resolv_set_port_exclusion_range(in_port_t min, in_port_t max) __used_in_netd;
__END_DECLS __END_DECLS
#endif /* _RESOLV_NETID_H */ #endif /* _RESOLV_NETID_H */

View File

@@ -137,6 +137,10 @@ __RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $");
#define EXT(res) ((res)->_u._ext) #define EXT(res) ((res)->_u._ext)
#define DBG 0 #define DBG 0
#define MAX_PORT (1 << (sizeof(in_port_t)*8))-1
#define DNS_MIN_PORT (IPPORT_RESERVED+1)
#define DNS_MAX_EXCLUDED_PORTS 5000
static const int highestFD = FD_SETSIZE - 1; static const int highestFD = FD_SETSIZE - 1;
/* Forward. */ /* Forward. */
@@ -164,6 +168,27 @@ static int retrying_select(const int sock, fd_set *readset, fd_set *writeset,
const struct timespec *finish); const struct timespec *finish);
/* BIONIC-BEGIN: implement source port randomization */ /* BIONIC-BEGIN: implement source port randomization */
static volatile in_port_t exclusion_min = 0;
static volatile in_port_t exclusion_max = 0;
int _resolv_set_port_exclusion_range(in_port_t min, in_port_t max)
{
if (min == 0 && max == 0) {
exclusion_min = exclusion_max = 0;
return 0;
}
if (min < DNS_MIN_PORT || min > max
|| (max - min > DNS_MAX_EXCLUDED_PORTS)) {
errno = ERANGE;
return -1;
}
exclusion_min = min;
exclusion_max = max;
return 0;
}
typedef union { typedef union {
struct sockaddr sa; struct sockaddr sa;
struct sockaddr_in sin; struct sockaddr_in sin;
@@ -197,7 +222,13 @@ random_bind( int s, int family )
/* first try to bind to a random source port a few times */ /* first try to bind to a random source port a few times */
for (j = 0; j < 10; j++) { for (j = 0; j < 10; j++) {
/* find a random port between 1025 .. 65534 */ /* find a random port between 1025 .. 65534 */
int port = 1025 + (res_randomid() % (65535-1025)); in_port_t port;
do {
port = DNS_MIN_PORT + (res_randomid() % (MAX_PORT - DNS_MIN_PORT));
} while (exclusion_min
&& exclusion_max
&& port >= exclusion_min && port <= exclusion_max);
if (family == AF_INET) if (family == AF_INET)
u.sin.sin_port = htons(port); u.sin.sin_port = htons(port);
else else

View File

@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
#include <sys/resource.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <sys/resource.h>
#if defined(__GLIBC__) #if defined(__GLIBC__)
/* The host glibc we're currently building with doesn't have prlimit64 yet. */ /* The host glibc we're currently building with doesn't have prlimit64 yet. */
static int prlimit64(pid_t, int resource, const struct rlimit64* new_limit, struct rlimit64* old_limit) { static int prlimit64(pid_t, int resource, const struct rlimit64* new_limit, struct rlimit64* old_limit) {
@@ -29,7 +29,7 @@ static int prlimit64(pid_t, int resource, const struct rlimit64* new_limit, stru
} }
#endif #endif
TEST(sys_resource, rlimit_struct_size) { TEST(sys_resource, smoke) {
#if defined(__LP64__) || defined(__GLIBC__) #if defined(__LP64__) || defined(__GLIBC__)
ASSERT_EQ(sizeof(rlimit), sizeof(rlimit64)); ASSERT_EQ(sizeof(rlimit), sizeof(rlimit64));
ASSERT_EQ(8U, sizeof(rlim_t)); ASSERT_EQ(8U, sizeof(rlim_t));
@@ -37,75 +37,51 @@ TEST(sys_resource, rlimit_struct_size) {
ASSERT_NE(sizeof(rlimit), sizeof(rlimit64)); ASSERT_NE(sizeof(rlimit), sizeof(rlimit64));
ASSERT_EQ(4U, sizeof(rlim_t)); ASSERT_EQ(4U, sizeof(rlim_t));
#endif #endif
}
class SysResourceTest : public ::testing::Test { // Read with getrlimit, getrlimit64, and prlimit64.
protected: // (prlimit is prlimit64 on LP64 and unimplemented on 32-bit.)
virtual void SetUp() { rlimit l32;
ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_)); rlimit64 l64;
ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_)); rlimit64 pr_l64;
ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_)); ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
} ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
void CheckResourceLimits(); ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
protected: ASSERT_EQ(l64.rlim_max, pr_l64.rlim_max);
rlimit l32_; if (l64.rlim_max == RLIM64_INFINITY) {
rlimit64 l64_; ASSERT_EQ(RLIM_INFINITY, l32.rlim_max);
rlimit64 pr_l64_;
};
void SysResourceTest::CheckResourceLimits() {
ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
ASSERT_EQ(l64_.rlim_cur, pr_l64_.rlim_cur);
if (l64_.rlim_cur == RLIM64_INFINITY) {
ASSERT_EQ(RLIM_INFINITY, l32_.rlim_cur);
} else { } else {
ASSERT_EQ(l64_.rlim_cur, l32_.rlim_cur); ASSERT_EQ(l64.rlim_max, l32.rlim_max);
} }
ASSERT_EQ(l64_.rlim_max, pr_l64_.rlim_max); // Write with setrlimit and read back with everything.
if (l64_.rlim_max == RLIM64_INFINITY) { l32.rlim_cur = 123;
ASSERT_EQ(RLIM_INFINITY, l32_.rlim_max); ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32));
} else { ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
ASSERT_EQ(l64_.rlim_max, l32_.rlim_max); ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
} ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
} ASSERT_EQ(123U, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
// Force rlim_max to be bigger than a constant so we can continue following test. // Write with setrlimit64 and read back with everything.
// Change resource limit setting with "ulimit -Hc" in the shell if this test fails. l64.rlim_cur = 456;
TEST_F(SysResourceTest, RLIMIT_CORE_rlim_max_not_zero) { ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &l64));
ASSERT_TRUE(l32_.rlim_max == RLIM_INFINITY || l32_.rlim_max >= 456U) << ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
"RLIMIT_CORE rlim_max = " << l32_.rlim_max; ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
} ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
ASSERT_EQ(456U, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
TEST_F(SysResourceTest, get_resource_limit_equal) { // Write with prlimit64 and read back with everything.
CheckResourceLimits(); l64.rlim_cur = 789;
} ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &l64, NULL));
ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
TEST_F(SysResourceTest, setrlimit) { ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
l32_.rlim_cur = 123U; ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32_)); ASSERT_EQ(789U, l32.rlim_cur);
CheckResourceLimits(); ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
ASSERT_EQ(123U, l32_.rlim_cur); ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
}
TEST_F(SysResourceTest, setrlimit64) {
l64_.rlim_cur = 456U;
ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &l64_));
CheckResourceLimits();
ASSERT_EQ(456U, l64_.rlim_cur);
}
TEST_F(SysResourceTest, prlimit64) {
pr_l64_.rlim_cur = pr_l64_.rlim_max;
ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &pr_l64_, NULL));
CheckResourceLimits();
ASSERT_EQ(pr_l64_.rlim_max, pr_l64_.rlim_cur);
}
TEST_F(SysResourceTest, prlimit) {
// prlimit is prlimit64 on LP64 and unimplemented on 32-bit. So we only test prlimit64.
} }

View File

@@ -21,7 +21,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <stdatomic.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
@@ -140,7 +139,7 @@ void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time
ts.it_value.tv_nsec = value_ns; ts.it_value.tv_nsec = value_ns;
ts.it_interval.tv_sec = interval_s; ts.it_interval.tv_sec = interval_s;
ts.it_interval.tv_nsec = interval_ns; ts.it_interval.tv_nsec = interval_ns;
ASSERT_EQ(0, timer_settime(t, 0, &ts, NULL)); ASSERT_EQ(0, timer_settime(t, TIMER_ABSTIME, &ts, NULL));
} }
static void NoOpNotifyFunction(sigval_t) { static void NoOpNotifyFunction(sigval_t) {
@@ -172,7 +171,7 @@ TEST(time, timer_create) {
ASSERT_EQ(0, timer_delete(timer_id)); ASSERT_EQ(0, timer_delete(timer_id));
} }
static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count; static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) { static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) {
++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count; ++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
ASSERT_EQ(SIGUSR1, signal_number); ASSERT_EQ(SIGUSR1, signal_number);
@@ -187,7 +186,6 @@ TEST(time, timer_create_SIGEV_SIGNAL) {
timer_t timer_id; timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id)); ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));
timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0;
ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler); ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler);
ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count); ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
@@ -204,20 +202,12 @@ TEST(time, timer_create_SIGEV_SIGNAL) {
} }
struct Counter { struct Counter {
private: volatile int value;
atomic_int value;
timer_t timer_id; timer_t timer_id;
sigevent_t se; sigevent_t se;
bool timer_valid; bool timer_valid;
void Create() { Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) {
ASSERT_FALSE(timer_valid);
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
timer_valid = true;
}
public:
Counter(void (*fn)(sigval_t)) : value(ATOMIC_VAR_INIT(0)), timer_valid(false) {
memset(&se, 0, sizeof(se)); memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_THREAD; se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = fn; se.sigev_notify_function = fn;
@@ -225,6 +215,12 @@ struct Counter {
Create(); Create();
} }
void Create() {
ASSERT_FALSE(timer_valid);
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
timer_valid = true;
}
void DeleteTimer() { void DeleteTimer() {
ASSERT_TRUE(timer_valid); ASSERT_TRUE(timer_valid);
ASSERT_EQ(0, timer_delete(timer_id)); ASSERT_EQ(0, timer_delete(timer_id));
@@ -237,30 +233,26 @@ struct Counter {
} }
} }
int Value() {
return atomic_load(&value);
}
void SetTime(time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) { void SetTime(time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns); ::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns);
} }
bool ValueUpdated() { bool ValueUpdated() {
int current_value = atomic_load(&value); volatile int current_value = value;
time_t start = time(NULL); time_t start = time(NULL);
while (current_value == atomic_load(&value) && (time(NULL) - start) < 5) { while (current_value == value && (time(NULL) - start) < 5) {
} }
return current_value != atomic_load(&value); return current_value != value;
} }
static void CountNotifyFunction(sigval_t value) { static void CountNotifyFunction(sigval_t value) {
Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr); Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
atomic_fetch_add(&cd->value, 1); ++cd->value;
} }
static void CountAndDisarmNotifyFunction(sigval_t value) { static void CountAndDisarmNotifyFunction(sigval_t value) {
Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr); Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
atomic_fetch_add(&cd->value, 1); ++cd->value;
// Setting the initial expiration time to 0 disarms the timer. // Setting the initial expiration time to 0 disarms the timer.
cd->SetTime(0, 0, 1, 0); cd->SetTime(0, 0, 1, 0);
@@ -269,29 +261,30 @@ struct Counter {
TEST(time, timer_settime_0) { TEST(time, timer_settime_0) {
Counter counter(Counter::CountAndDisarmNotifyFunction); Counter counter(Counter::CountAndDisarmNotifyFunction);
ASSERT_EQ(0, counter.Value()); ASSERT_TRUE(counter.timer_valid);
counter.SetTime(0, 500000000, 1, 0); ASSERT_EQ(0, counter.value);
sleep(1);
counter.SetTime(0, 1, 1, 0);
usleep(500000);
// The count should just be 1 because we disarmed the timer the first time it fired. // The count should just be 1 because we disarmed the timer the first time it fired.
ASSERT_EQ(1, counter.Value()); ASSERT_EQ(1, counter.value);
} }
TEST(time, timer_settime_repeats) { TEST(time, timer_settime_repeats) {
Counter counter(Counter::CountNotifyFunction); Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value()); ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
counter.SetTime(0, 1, 0, 10); counter.SetTime(0, 1, 0, 10);
ASSERT_TRUE(counter.ValueUpdated()); ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated()); ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated()); ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer();
// Add a sleep as other threads may be calling the callback function when the timer is deleted.
usleep(500000);
} }
static int timer_create_NULL_signal_handler_invocation_count; static int timer_create_NULL_signal_handler_invocation_count = 0;
static void timer_create_NULL_signal_handler(int signal_number) { static void timer_create_NULL_signal_handler(int signal_number) {
++timer_create_NULL_signal_handler_invocation_count; ++timer_create_NULL_signal_handler_invocation_count;
ASSERT_EQ(SIGALRM, signal_number); ASSERT_EQ(SIGALRM, signal_number);
@@ -302,7 +295,6 @@ TEST(time, timer_create_NULL) {
timer_t timer_id; timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id)); ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id));
timer_create_NULL_signal_handler_invocation_count = 0;
ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler); ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler);
ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count); ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
@@ -349,59 +341,22 @@ TEST(time, timer_delete_multiple) {
TEST(time, timer_create_multiple) { TEST(time, timer_create_multiple) {
Counter counter1(Counter::CountNotifyFunction); Counter counter1(Counter::CountNotifyFunction);
ASSERT_TRUE(counter1.timer_valid);
Counter counter2(Counter::CountNotifyFunction); Counter counter2(Counter::CountNotifyFunction);
ASSERT_TRUE(counter2.timer_valid);
Counter counter3(Counter::CountNotifyFunction); Counter counter3(Counter::CountNotifyFunction);
ASSERT_TRUE(counter3.timer_valid);
ASSERT_EQ(0, counter1.Value()); ASSERT_EQ(0, counter1.value);
ASSERT_EQ(0, counter2.Value()); ASSERT_EQ(0, counter2.value);
ASSERT_EQ(0, counter3.Value()); ASSERT_EQ(0, counter3.value);
counter2.SetTime(0, 500000000, 0, 0); counter2.SetTime(0, 1, 0, 0);
sleep(1);
EXPECT_EQ(0, counter1.Value());
EXPECT_EQ(1, counter2.Value());
EXPECT_EQ(0, counter3.Value());
}
// Test to verify that disarming a repeatable timer disables the callbacks.
TEST(time, timer_disarm_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.SetTime(0, 0, 0, 0);
// Add a sleep as the kernel may have pending events when the timer is disarmed.
usleep(500000);
int value = counter.Value();
usleep(500000); usleep(500000);
// Verify the counter has not been incremented. EXPECT_EQ(0, counter1.value);
ASSERT_EQ(value, counter.Value()); EXPECT_EQ(1, counter2.value);
} EXPECT_EQ(0, counter3.value);
// Test to verify that deleting a repeatable timer disables the callbacks.
TEST(time, timer_delete_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer();
// Add a sleep as other threads may be calling the callback function when the timer is deleted.
usleep(500000);
int value = counter.Value();
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.Value());
} }
struct TimerDeleteData { struct TimerDeleteData {
@@ -469,3 +424,45 @@ TEST(time, clock_gettime) {
ASSERT_EQ(0, ts2.tv_sec); ASSERT_EQ(0, ts2.tv_sec);
ASSERT_LT(ts2.tv_nsec, 1000000); ASSERT_LT(ts2.tv_nsec, 1000000);
} }
// Test to verify that disarming a repeatable timer disables the
// callbacks.
TEST(time, timer_disarm_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.SetTime(0, 0, 1, 0);
volatile int value = counter.value;
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.value);
}
// Test to verify that deleting a repeatable timer disables the
// callbacks.
TEST(time, timer_delete_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_TRUE(counter.timer_valid);
ASSERT_EQ(0, counter.value);
counter.SetTime(0, 1, 0, 1);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer();
volatile int value = counter.value;
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.value);
}