diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2014-03-28 13:03:55 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2014-03-28 13:03:55 +0000 |
commit | d5d13e320c78627c14b49be57bc5c2bc0f6cf9c0 (patch) | |
tree | 4517f91e1c0bc03c274f9a8a220f07c243242bee /lib | |
parent | 0a42b0c71171dc5d57c9514c2ee7821862eeb57b (diff) |
[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.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@205004 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/msan/tests/msan_test.cc | 42 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 157 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_interceptors.h | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.cc | 25 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.h | 28 |
5 files changed, 209 insertions, 44 deletions
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index ab7ff43be..3784469ca 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -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]; diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 7a9d9f64c..84c75abaa 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -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; \ diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index b2955bac5..39ae2e6f5 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -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 diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index f5b7a612e..961aeb8ab 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -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 diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 9017086d7..c9cf09229 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -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; |