[sanitizer] Intercept fgetpwent / fgetgrent.

These interceptors require deep unpoisoning of return values.
While at it, we do the same for all other pw/gr interceptors to
reduce dependency on libc implementation details.

llvm-svn: 205004
This commit is contained in:
Evgeniy Stepanov 2014-03-28 13:03:55 +00:00
parent aa3cf1e691
commit 86a4d2c32b
5 changed files with 209 additions and 44 deletions

View File

@ -3149,6 +3149,17 @@ TEST(MemorySanitizer, getpwent_r) {
EXPECT_NOT_POISONED(pwdres);
}
TEST(MemorySanitizer, fgetpwent) {
FILE *fp = fopen("/etc/passwd", "r");
struct passwd *p = fgetpwent(fp);
ASSERT_TRUE(p != NULL);
EXPECT_NOT_POISONED(p->pw_name);
ASSERT_TRUE(p->pw_name != NULL);
EXPECT_NOT_POISONED(p->pw_name[0]);
EXPECT_NOT_POISONED(p->pw_uid);
fclose(fp);
}
TEST(MemorySanitizer, getgrent) {
setgrent();
struct group *p = getgrent();
@ -3159,6 +3170,21 @@ TEST(MemorySanitizer, getgrent) {
EXPECT_NOT_POISONED(p->gr_gid);
}
TEST(MemorySanitizer, fgetgrent) {
FILE *fp = fopen("/etc/group", "r");
struct group *grp = fgetgrent(fp);
ASSERT_TRUE(grp != NULL);
EXPECT_NOT_POISONED(grp->gr_name);
ASSERT_TRUE(grp->gr_name != NULL);
EXPECT_NOT_POISONED(grp->gr_name[0]);
EXPECT_NOT_POISONED(grp->gr_gid);
for (char **p = grp->gr_mem; *p; ++p) {
EXPECT_NOT_POISONED((*p)[0]);
EXPECT_TRUE(strlen(*p) > 0);
}
fclose(fp);
}
TEST(MemorySanitizer, getgrent_r) {
struct group grp;
struct group *grpres;
@ -3173,6 +3199,22 @@ TEST(MemorySanitizer, getgrent_r) {
EXPECT_NOT_POISONED(grpres);
}
TEST(MemorySanitizer, fgetgrent_r) {
FILE *fp = fopen("/etc/group", "r");
struct group grp;
struct group *grpres;
char buf[10000];
setgrent();
int res = fgetgrent_r(fp, &grp, buf, sizeof(buf), &grpres);
ASSERT_EQ(0, res);
EXPECT_NOT_POISONED(grp.gr_name);
ASSERT_TRUE(grp.gr_name != NULL);
EXPECT_NOT_POISONED(grp.gr_name[0]);
EXPECT_NOT_POISONED(grp.gr_gid);
EXPECT_NOT_POISONED(grpres);
fclose(fp);
}
TEST(MemorySanitizer, getgroups) {
int n = getgroups(0, 0);
gid_t *gids = new gid_t[n];

View File

@ -912,35 +912,85 @@ INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
#define INIT_IOCTL
#endif
#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \
SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT
static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) {
if (pwd) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd));
if (pwd->pw_name)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_name,
REAL(strlen)(pwd->pw_name) + 1);
if (pwd->pw_passwd)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_passwd,
REAL(strlen)(pwd->pw_passwd) + 1);
#if !SANITIZER_ANDROID
if (pwd->pw_gecos)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_gecos,
REAL(strlen)(pwd->pw_gecos) + 1);
#endif
#if SANITIZER_MAC
if (pwd->pw_class)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_class,
REAL(strlen)(pwd->pw_class) + 1);
#endif
if (pwd->pw_dir)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_dir,
REAL(strlen)(pwd->pw_dir) + 1);
if (pwd->pw_shell)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(pwd->pw_shell,
REAL(strlen)(pwd->pw_shell) + 1);
}
}
static void unpoison_group(void *ctx, __sanitizer_group *grp) {
if (grp) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, sizeof(*grp));
if (grp->gr_name)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_name,
REAL(strlen)(grp->gr_name) + 1);
if (grp->gr_passwd)
COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_passwd,
REAL(strlen)(grp->gr_passwd) + 1);
char **p = grp->gr_mem;
for (; *p; ++p) {
COMMON_INTERCEPTOR_INITIALIZE_RANGE(*p, REAL(strlen)(*p) + 1);
}
COMMON_INTERCEPTOR_INITIALIZE_RANGE(grp->gr_mem,
(p - grp->gr_mem + 1) * sizeof(*p));
}
}
#endif // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS ||
// SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT
#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
INTERCEPTOR(void *, getpwnam, const char *name) {
INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
void *res = REAL(getpwnam)(name);
if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
__sanitizer_passwd *res = REAL(getpwnam)(name);
if (res != 0) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(void *, getpwuid, u32 uid) {
INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
void *res = REAL(getpwuid)(uid);
if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
__sanitizer_passwd *res = REAL(getpwuid)(uid);
if (res != 0) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(void *, getgrnam, const char *name) {
INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
void *res = REAL(getgrnam)(name);
if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
__sanitizer_group *res = REAL(getgrnam)(name);
if (res != 0) unpoison_group(ctx, res);
return res;
}
INTERCEPTOR(void *, getgrgid, u32 gid) {
INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
void *res = REAL(getgrgid)(gid);
if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
__sanitizer_group *res = REAL(getgrgid)(gid);
if (res != 0) unpoison_group(ctx, res);
return res;
}
#define INIT_GETPWNAM_AND_FRIENDS \
@ -953,51 +1003,51 @@ INTERCEPTOR(void *, getgrgid, u32 gid) {
#endif
#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, char *buf,
SIZE_T buflen, void **result) {
INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
char *buf, SIZE_T buflen, __sanitizer_passwd **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
unpoison_passwd(ctx, pwd);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, char *buf, SIZE_T buflen,
void **result) {
INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
SIZE_T buflen, __sanitizer_passwd **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, struct_passwd_sz);
unpoison_passwd(ctx, pwd);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, char *buf,
SIZE_T buflen, void **result) {
INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
char *buf, SIZE_T buflen, __sanitizer_group **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
unpoison_group(ctx, grp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
}
INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
void **result) {
INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
SIZE_T buflen, __sanitizer_group **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, grp, struct_group_sz);
unpoison_group(ctx, grp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@ -1013,18 +1063,18 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
#endif
#if SANITIZER_INTERCEPT_GETPWENT
INTERCEPTOR(void *, getpwent, int dummy) {
INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy);
void *res = REAL(getpwent)(dummy);
if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
__sanitizer_passwd *res = REAL(getpwent)(dummy);
if (res != 0) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(void *, getgrent, int dummy) {
INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy);
void *res = REAL(getgrent)(dummy);
if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
__sanitizer_group *res = REAL(getgrent)(dummy);
if (res != 0) unpoison_group(ctx, res);;
return res;
}
#define INIT_GETPWENT \
@ -1034,50 +1084,72 @@ INTERCEPTOR(void *, getgrent, int dummy) {
#define INIT_GETPWENT
#endif
#if SANITIZER_INTERCEPT_FGETPWENT
INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp);
__sanitizer_passwd *res = REAL(fgetpwent)(fp);
if (res != 0) unpoison_passwd(ctx, res);
return res;
}
INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp);
__sanitizer_group *res = REAL(fgetgrent)(fp);
if (res != 0) unpoison_group(ctx, res);
return res;
}
#define INIT_FGETPWENT \
COMMON_INTERCEPT_FUNCTION(fgetpwent); \
COMMON_INTERCEPT_FUNCTION(fgetgrent);
#else
#define INIT_FGETPWENT
#endif
#if SANITIZER_INTERCEPT_GETPWENT_R
INTERCEPTOR(int, getpwent_r, void *pwbuf, char *buf, SIZE_T buflen,
void **pwbufp) {
INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
SIZE_T buflen, __sanitizer_passwd **pwbufp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp);
int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbuf, struct_passwd_sz);
unpoison_passwd(ctx, pwbuf);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
INTERCEPTOR(int, fgetpwent_r, void *fp, void *pwbuf, char *buf, SIZE_T buflen,
void **pwbufp) {
INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
SIZE_T buflen, __sanitizer_passwd **pwbufp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbuf, struct_passwd_sz);
unpoison_passwd(ctx, pwbuf);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
INTERCEPTOR(int, getgrent_r, void *pwbuf, char *buf, SIZE_T buflen,
void **pwbufp) {
INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
__sanitizer_group **pwbufp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbuf, struct_group_sz);
unpoison_group(ctx, pwbuf);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
return res;
}
INTERCEPTOR(int, fgetgrent_r, void *fp, void *pwbuf, char *buf, SIZE_T buflen,
void **pwbufp) {
INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
SIZE_T buflen, __sanitizer_group **pwbufp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp);
int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbuf, struct_group_sz);
unpoison_group(ctx, pwbuf);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, buflen);
}
if (pwbufp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwbufp, sizeof(*pwbufp));
@ -3667,6 +3739,7 @@ INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) {
INIT_GETPWNAM_AND_FRIENDS; \
INIT_GETPWNAM_R_AND_FRIENDS; \
INIT_GETPWENT; \
INIT_FGETPWENT; \
INIT_GETPWENT_R; \
INIT_SETPWENT; \
INIT_CLOCK_GETTIME; \

View File

@ -89,6 +89,7 @@
#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
SI_MAC || SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETPWENT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_GETPWENT_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SETPWENT SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX

View File

@ -1086,4 +1086,29 @@ CHECK_SIZE_AND_OFFSET(timeb, millitm);
CHECK_SIZE_AND_OFFSET(timeb, timezone);
CHECK_SIZE_AND_OFFSET(timeb, dstflag);
CHECK_TYPE_SIZE(passwd);
CHECK_SIZE_AND_OFFSET(passwd, pw_name);
CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
#if !SANITIZER_ANDROID
CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
#endif
#if SANITIZER_MAC
CHECK_SIZE_AND_OFFSET(passwd, pw_change);
CHECK_SIZE_AND_OFFSET(passwd, pw_expire);
CHECK_SIZE_AND_OFFSET(passwd, pw_class);
#endif
CHECK_TYPE_SIZE(group);
CHECK_SIZE_AND_OFFSET(group, gr_name);
CHECK_SIZE_AND_OFFSET(group, gr_passwd);
CHECK_SIZE_AND_OFFSET(group, gr_gid);
CHECK_SIZE_AND_OFFSET(group, gr_mem);
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC

View File

@ -25,8 +25,6 @@ namespace __sanitizer {
extern unsigned struct_stat64_sz;
#endif
extern unsigned struct_rusage_sz;
extern unsigned struct_passwd_sz;
extern unsigned struct_group_sz;
extern unsigned siginfo_t_sz;
extern unsigned struct_itimerval_sz;
extern unsigned pthread_t_sz;
@ -276,6 +274,32 @@ namespace __sanitizer {
typedef unsigned __sanitizer_pthread_key_t;
#endif
struct __sanitizer_passwd {
char *pw_name;
char *pw_passwd;
int pw_uid;
int pw_gid;
#if !SANITIZER_ANDROID
char *pw_gecos;
#endif
#if SANITIZER_MAC
long pw_change;
char *pw_class;
#endif
char *pw_dir;
char *pw_shell;
#if SANITIZER_MAC
long pw_expire;
#endif
};
struct __sanitizer_group {
char *gr_name;
char *gr_passwd;
int gr_gid;
char **gr_mem;
};
struct __sanitizer_timeb {
long time;
unsigned short millitm;