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 */
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
#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 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;
/* Forward. */
@@ -164,6 +168,27 @@ static int retrying_select(const int sock, fd_set *readset, fd_set *writeset,
const struct timespec *finish);
/* 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 {
struct sockaddr sa;
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 */
for (j = 0; j < 10; j++) {
/* 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)
u.sin.sin_port = htons(port);
else

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
#include <sys/resource.h>
#include <gtest/gtest.h>
#include <sys/resource.h>
#if defined(__GLIBC__)
/* 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) {
@@ -29,7 +29,7 @@ static int prlimit64(pid_t, int resource, const struct rlimit64* new_limit, stru
}
#endif
TEST(sys_resource, rlimit_struct_size) {
TEST(sys_resource, smoke) {
#if defined(__LP64__) || defined(__GLIBC__)
ASSERT_EQ(sizeof(rlimit), sizeof(rlimit64));
ASSERT_EQ(8U, sizeof(rlim_t));
@@ -37,75 +37,51 @@ TEST(sys_resource, rlimit_struct_size) {
ASSERT_NE(sizeof(rlimit), sizeof(rlimit64));
ASSERT_EQ(4U, sizeof(rlim_t));
#endif
}
class SysResourceTest : public ::testing::Test {
protected:
virtual void SetUp() {
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();
protected:
rlimit l32_;
rlimit64 l64_;
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);
// Read with getrlimit, getrlimit64, and prlimit64.
// (prlimit is prlimit64 on LP64 and unimplemented on 32-bit.)
rlimit l32;
rlimit64 l64;
rlimit64 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));
ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
ASSERT_EQ(l64.rlim_max, pr_l64.rlim_max);
if (l64.rlim_max == RLIM64_INFINITY) {
ASSERT_EQ(RLIM_INFINITY, l32.rlim_max);
} 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);
if (l64_.rlim_max == RLIM64_INFINITY) {
ASSERT_EQ(RLIM_INFINITY, l32_.rlim_max);
} else {
ASSERT_EQ(l64_.rlim_max, l32_.rlim_max);
}
}
// Write with setrlimit and read back with everything.
l32.rlim_cur = 123;
ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32));
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(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.
// Change resource limit setting with "ulimit -Hc" in the shell if this test fails.
TEST_F(SysResourceTest, RLIMIT_CORE_rlim_max_not_zero) {
ASSERT_TRUE(l32_.rlim_max == RLIM_INFINITY || l32_.rlim_max >= 456U) <<
"RLIMIT_CORE rlim_max = " << l32_.rlim_max;
}
// Write with setrlimit64 and read back with everything.
l64.rlim_cur = 456;
ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &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));
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) {
CheckResourceLimits();
}
TEST_F(SysResourceTest, setrlimit) {
l32_.rlim_cur = 123U;
ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32_));
CheckResourceLimits();
ASSERT_EQ(123U, l32_.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.
// Write with prlimit64 and read back with everything.
l64.rlim_cur = 789;
ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &l64, NULL));
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(789U, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
}

View File

@@ -21,7 +21,6 @@
#include <gtest/gtest.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <sys/syscall.h>
#include <sys/types.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_interval.tv_sec = interval_s;
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) {
@@ -172,7 +171,7 @@ TEST(time, timer_create) {
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) {
++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count;
ASSERT_EQ(SIGUSR1, signal_number);
@@ -187,7 +186,6 @@ TEST(time, timer_create_SIGEV_SIGNAL) {
timer_t 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);
ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count);
@@ -204,20 +202,12 @@ TEST(time, timer_create_SIGEV_SIGNAL) {
}
struct Counter {
private:
atomic_int value;
volatile int value;
timer_t timer_id;
sigevent_t se;
bool timer_valid;
void Create() {
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) {
Counter(void (*fn)(sigval_t)) : value(0), timer_valid(false) {
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = fn;
@@ -225,6 +215,12 @@ struct Counter {
Create();
}
void Create() {
ASSERT_FALSE(timer_valid);
ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id));
timer_valid = true;
}
void DeleteTimer() {
ASSERT_TRUE(timer_valid);
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) {
::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns);
}
bool ValueUpdated() {
int current_value = atomic_load(&value);
volatile int current_value = value;
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) {
Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr);
atomic_fetch_add(&cd->value, 1);
++cd->value;
}
static void CountAndDisarmNotifyFunction(sigval_t value) {
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.
cd->SetTime(0, 0, 1, 0);
@@ -269,29 +261,30 @@ struct Counter {
TEST(time, timer_settime_0) {
Counter counter(Counter::CountAndDisarmNotifyFunction);
ASSERT_EQ(0, counter.Value());
ASSERT_TRUE(counter.timer_valid);
counter.SetTime(0, 500000000, 1, 0);
sleep(1);
ASSERT_EQ(0, counter.value);
counter.SetTime(0, 1, 1, 0);
usleep(500000);
// 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) {
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);
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) {
++timer_create_NULL_signal_handler_invocation_count;
ASSERT_EQ(SIGALRM, signal_number);
@@ -302,7 +295,6 @@ TEST(time, timer_create_NULL) {
timer_t 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);
ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count);
@@ -349,59 +341,22 @@ TEST(time, timer_delete_multiple) {
TEST(time, timer_create_multiple) {
Counter counter1(Counter::CountNotifyFunction);
ASSERT_TRUE(counter1.timer_valid);
Counter counter2(Counter::CountNotifyFunction);
ASSERT_TRUE(counter2.timer_valid);
Counter counter3(Counter::CountNotifyFunction);
ASSERT_TRUE(counter3.timer_valid);
ASSERT_EQ(0, counter1.Value());
ASSERT_EQ(0, counter2.Value());
ASSERT_EQ(0, counter3.Value());
ASSERT_EQ(0, counter1.value);
ASSERT_EQ(0, counter2.value);
ASSERT_EQ(0, counter3.value);
counter2.SetTime(0, 500000000, 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();
counter2.SetTime(0, 1, 0, 0);
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_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());
EXPECT_EQ(0, counter1.value);
EXPECT_EQ(1, counter2.value);
EXPECT_EQ(0, counter3.value);
}
struct TimerDeleteData {
@@ -469,3 +424,45 @@ TEST(time, clock_gettime) {
ASSERT_EQ(0, ts2.tv_sec);
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);
}