Skip to content

Commit e0c8fc7

Browse files
authored
Reapply "[sanitizer] intercept getservent_r, getservbyname_r, getservbyport_r" (llvm#133358) (llvm#133528)
This reverts commit 52d7f14.
1 parent 6767555 commit e0c8fc7

File tree

6 files changed

+223
-0
lines changed

6 files changed

+223
-0
lines changed

compiler-rt/lib/msan/tests/msan_test.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4908,5 +4908,100 @@ TEST(MemorySanitizer, timer_create) {
49084908
EXPECT_POISONED(timer2);
49094909
timer_delete(timer);
49104910
}
4911+
4912+
TEST(MemorySanitizer, getservent_r) {
4913+
if (access("/etc/services", O_RDONLY) != 0)
4914+
GTEST_SKIP() << "Missing /etc/services";
4915+
struct servent result_buf;
4916+
struct servent *result;
4917+
char buf[1024];
4918+
EXPECT_POISONED(result_buf);
4919+
EXPECT_POISONED(result);
4920+
EXPECT_POISONED(buf);
4921+
ASSERT_EQ(getservent_r(&result_buf, buf, sizeof(buf), &result), 0);
4922+
EXPECT_NOT_POISONED(result);
4923+
ASSERT_NE(result, nullptr);
4924+
EXPECT_NOT_POISONED(result_buf);
4925+
EXPECT_NOT_POISONED(buf);
4926+
}
4927+
4928+
TEST(MemorySanitizer, getservbyname_r) {
4929+
if (access("/etc/services", O_RDONLY) != 0)
4930+
GTEST_SKIP() << "Missing /etc/services";
4931+
struct servent result_buf;
4932+
struct servent *result;
4933+
char buf[1024];
4934+
EXPECT_POISONED(result_buf);
4935+
EXPECT_POISONED(result);
4936+
EXPECT_POISONED(buf);
4937+
ASSERT_EQ(
4938+
getservbyname_r("ssh", nullptr, &result_buf, buf, sizeof(buf), &result),
4939+
0);
4940+
EXPECT_NOT_POISONED(result);
4941+
// If this fails, check /etc/services if "ssh" exists. I picked this because
4942+
// it should exist everywhere, if it doesn't, I am sorry. Disable the test
4943+
// then please.
4944+
ASSERT_NE(result, nullptr);
4945+
EXPECT_NOT_POISONED(result_buf);
4946+
EXPECT_NOT_POISONED(buf);
4947+
}
4948+
4949+
TEST(MemorySanitizer, getservbyname_r_unknown) {
4950+
if (access("/etc/services", O_RDONLY) != 0)
4951+
GTEST_SKIP() << "Missing /etc/services";
4952+
struct servent result_buf;
4953+
struct servent *result;
4954+
char buf[1024];
4955+
EXPECT_POISONED(result_buf);
4956+
EXPECT_POISONED(result);
4957+
EXPECT_POISONED(buf);
4958+
ASSERT_EQ(getservbyname_r("invalidhadfuiasdhi", nullptr, &result_buf, buf,
4959+
sizeof(buf), &result),
4960+
0);
4961+
EXPECT_NOT_POISONED(result);
4962+
ASSERT_EQ(result, nullptr);
4963+
EXPECT_POISONED(result_buf);
4964+
EXPECT_POISONED(buf);
4965+
}
4966+
4967+
TEST(MemorySanitizer, getservbyport_r) {
4968+
if (access("/etc/services", O_RDONLY) != 0)
4969+
GTEST_SKIP() << "Missing /etc/services";
4970+
struct servent result_buf;
4971+
struct servent *result;
4972+
char buf[1024];
4973+
EXPECT_POISONED(result_buf);
4974+
EXPECT_POISONED(result);
4975+
EXPECT_POISONED(buf);
4976+
ASSERT_EQ(getservbyport_r(htons(22), nullptr, &result_buf, buf, sizeof(buf),
4977+
&result),
4978+
0);
4979+
EXPECT_NOT_POISONED(result);
4980+
// If this fails, check /etc/services if "ssh" exists. I picked this because
4981+
// it should exist everywhere, if it doesn't, I am sorry. Disable the test
4982+
// then please.
4983+
ASSERT_NE(result, nullptr);
4984+
EXPECT_NOT_POISONED(result_buf);
4985+
EXPECT_NOT_POISONED(buf);
4986+
}
4987+
4988+
TEST(MemorySanitizer, getservbyport_r_smallbuf) {
4989+
if (access("/etc/services", O_RDONLY) != 0)
4990+
GTEST_SKIP() << "Missing /etc/services";
4991+
struct servent result_buf;
4992+
struct servent *result;
4993+
char buf[1];
4994+
EXPECT_POISONED(result_buf);
4995+
EXPECT_POISONED(result);
4996+
EXPECT_POISONED(buf);
4997+
ASSERT_EQ(getservbyport_r(htons(22), nullptr, &result_buf, buf, sizeof(buf),
4998+
&result),
4999+
ERANGE);
5000+
EXPECT_NOT_POISONED(result);
5001+
ASSERT_EQ(result, nullptr);
5002+
EXPECT_POISONED(result_buf);
5003+
EXPECT_POISONED(buf);
5004+
}
5005+
49115006
#endif
49125007
} // namespace

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10279,6 +10279,71 @@ INTERCEPTOR(SSIZE_T, freadlink, int fd, char *buf, SIZE_T bufsiz) {
1027910279
# define INIT_FREADLINK
1028010280
#endif
1028110281

10282+
#if SANITIZER_INTERCEPT_GETSERVENT_R || SANITIZER_INTERCEPT_GETSERVBYNAME_R || \
10283+
SANITIZER_INTERCEPT_GETSERVBYPORT_R
10284+
10285+
UNUSED static void HandleGetServentReentrantResult(
10286+
void *ctx, int res, struct __sanitizer_servent *result_buf, char *buf,
10287+
SIZE_T buflen, struct __sanitizer_servent **result) {
10288+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (char *)result, sizeof(void *));
10289+
if (res)
10290+
return;
10291+
if (*result) {
10292+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (char *)*result,
10293+
sizeof(__sanitizer_servent));
10294+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
10295+
}
10296+
}
10297+
10298+
#endif
10299+
10300+
#if SANITIZER_INTERCEPT_GETSERVENT_R
10301+
INTERCEPTOR(int, getservent_r, struct __sanitizer_servent *result_buf,
10302+
char *buf, SIZE_T buflen, struct __sanitizer_servent **result) {
10303+
void *ctx;
10304+
COMMON_INTERCEPTOR_ENTER(ctx, getservent_r, result_buf, buf, buflen, result);
10305+
int res = REAL(getservent_r)(result_buf, buf, buflen, result);
10306+
HandleGetServentReentrantResult(ctx, res, result_buf, buf, buflen, result);
10307+
return res;
10308+
}
10309+
# define INIT_GETSERVENT_R COMMON_INTERCEPT_FUNCTION(getservent_r)
10310+
#else
10311+
# define INIT_GETSERVENT_R
10312+
#endif
10313+
10314+
#if SANITIZER_INTERCEPT_GETSERVBYNAME_R
10315+
INTERCEPTOR(int, getservbyname_r, const char *name, const char *proto,
10316+
struct __sanitizer_servent *result_buf, char *buf, SIZE_T buflen,
10317+
struct __sanitizer_servent **result) {
10318+
void *ctx;
10319+
COMMON_INTERCEPTOR_ENTER(ctx, getservbyname_r, name, proto, result_buf, buf,
10320+
buflen, result);
10321+
COMMON_INTERCEPTOR_READ_STRING(ctx, name, internal_strlen(name));
10322+
int res = REAL(getservbyname_r)(name, proto, result_buf, buf, buflen, result);
10323+
HandleGetServentReentrantResult(ctx, res, result_buf, buf, buflen, result);
10324+
return res;
10325+
}
10326+
# define INIT_GETSERVBYNAME_R COMMON_INTERCEPT_FUNCTION(getservbyname_r)
10327+
#else
10328+
# define INIT_GETSERVBYNAME_R
10329+
#endif
10330+
10331+
#if SANITIZER_INTERCEPT_GETSERVBYPORT_R
10332+
INTERCEPTOR(int, getservbyport_r, int port, const char *proto,
10333+
struct __sanitizer_servent *result_buf, char *buf, SIZE_T buflen,
10334+
struct __sanitizer_servent **result) {
10335+
void *ctx;
10336+
COMMON_INTERCEPTOR_ENTER(ctx, getservbyport_r, port, proto, result_buf, buf,
10337+
buflen, result);
10338+
int res = REAL(getservbyport_r)(port, proto, result_buf, buf, buflen, result);
10339+
HandleGetServentReentrantResult(ctx, res, result_buf, buf, buflen, result);
10340+
return res;
10341+
}
10342+
# define INIT_GETSERVBYPORT_R COMMON_INTERCEPT_FUNCTION(getservbyport_r)
10343+
#else
10344+
# define INIT_GETSERVBYPORT_R
10345+
#endif
10346+
1028210347
#include "sanitizer_common_interceptors_netbsd_compat.inc"
1028310348

1028410349
namespace __sanitizer {
@@ -10604,4 +10669,7 @@ static void InitializeCommonInterceptors() {
1060410669
INIT_FREADLINK;
1060510670

1060610671
INIT___PRINTF_CHK;
10672+
INIT_GETSERVENT_R;
10673+
INIT_GETSERVBYNAME_R;
10674+
INIT_GETSERVBYPORT_R;
1060710675
}

compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,10 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
645645
# define SI_MAC_OS_DEPLOYMENT_MIN_13_00 0
646646
#endif
647647
#define SANITIZER_INTERCEPT_FREADLINK (SI_MAC && SI_MAC_OS_DEPLOYMENT_MIN_13_00)
648+
#define SANITIZER_INTERCEPT_GETSERVENT_R SI_GLIBC
649+
#define SANITIZER_INTERCEPT_GETSERVBYNAME_R SI_GLIBC
650+
#define SANITIZER_INTERCEPT_GETSERVBYPORT_R SI_GLIBC
651+
648652
// This macro gives a way for downstream users to override the above
649653
// interceptor macros irrespective of the platform they are on. They have
650654
// to do two things:

compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,15 @@ extern unsigned IOCTL_KIOCSOUND;
15091509
extern unsigned IOCTL_PIO_SCRNMAP;
15101510
#endif
15111511

1512+
# if SANITIZER_GLIBC
1513+
struct __sanitizer_servent {
1514+
char *s_name;
1515+
char **s_aliases;
1516+
int s_port;
1517+
char *s_proto;
1518+
};
1519+
# endif
1520+
15121521
extern const int si_SEGV_MAPERR;
15131522
extern const int si_SEGV_ACCERR;
15141523
} // namespace __sanitizer
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %clangxx -O0 %s -o %t && %run %t
2+
3+
// REQUIRES: glibc, netbase
4+
5+
#include <arpa/inet.h>
6+
#include <assert.h>
7+
#include <fcntl.h>
8+
#include <netdb.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <unistd.h>
13+
14+
void CheckResult(const char *file, int line, int ret) {
15+
if (ret != 0) {
16+
fprintf(stderr, "ERROR: %s:%d - %s\n", file, line, strerror(ret));
17+
}
18+
assert(ret == 0);
19+
}
20+
21+
#define CHECK_RESULT(ret) CheckResult(__FILE__, __LINE__, ret)
22+
23+
int main(void) {
24+
assert(access("/etc/services", O_RDONLY) == 0);
25+
struct servent result_buf;
26+
struct servent *result;
27+
char buf[1024];
28+
// If these fail, check /etc/services if "ssh" exists. I picked this because
29+
// it should exist everywhere, if it doesn't, I am sorry. Disable the test
30+
// then please.
31+
CHECK_RESULT(
32+
getservbyname_r("ssh", nullptr, &result_buf, buf, sizeof(buf), &result));
33+
assert(result != nullptr);
34+
CHECK_RESULT(getservbyport_r(htons(22), nullptr, &result_buf, buf,
35+
sizeof(buf), &result));
36+
assert(result != nullptr);
37+
38+
CHECK_RESULT(getservent_r(&result_buf, buf, sizeof(buf), &result));
39+
assert(result != nullptr);
40+
41+
CHECK_RESULT(getservbyname_r("invalidhadfuiasdhi", nullptr, &result_buf, buf,
42+
sizeof(buf), &result));
43+
assert(result == nullptr);
44+
}

compiler-rt/test/sanitizer_common/lit.common.cfg.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,6 @@ def build_invocation(compile_flags):
100100

101101
if config.host_os == "NetBSD":
102102
config.substitutions.insert(0, ("%run", config.netbsd_noaslr_prefix))
103+
104+
if os.path.exists("/etc/services"):
105+
config.available_features.add("netbase")

0 commit comments

Comments
 (0)