漏洞发现官方Qualys研究人员称影响范围是glibc2.2--glibc2.17之间的各个版本。
实际上在glibc2.18已经修正了这个错误,时间是2013年。但gnu官方并没有将此列为漏洞处理,可能觉得这个漏洞非常难以利用吧。
需要研究源代码的可以到gnu官网下载相应版本的源代码。
漏洞的发生位置是int __nss_hostname_digits_dots(...)函数。这个函数实现在nss/digits_dots.c(glibc2.17)。
35. int
36. __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
37. char **buffer, size_t *buffer_size,
38. size_t buflen, struct hostent **result,
39. enum nss_status *status, int af, int *h_errnop)
对这个函数的调用发生在gethostbyname和gethostbyname_r(前一个函数的reenter版,支持多线程)函数中。这两个函数在glibc的源代码中寻找起来比较坑爹,不过又学到了超级大牛们是如何写代码的(充分利用宏)。
函数gethostbyname实现在nss/getXXbyYY.c文件中。实际上这个文件如同文件名一样,定义了一个通用的方法,XX和YY根据不同的宏定义,可以实现不同的接口名称。gethostbyname只是其中的一个接口名称。
50. /* To make the real sources a bit prettier. */
51. #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
52. #define APPEND_R(name) APPEND_R1 (name)
53. #define APPEND_R1(name) name##_r
54. #define INTERNAL(name) INTERNAL1 (name)
56. #define INTERNAL1(name) __##name
...
86. LOOKUP_TYPE *
87. FUNCTION_NAME (ADD_PARAMS)
88. {
...
接口定义在inet/gethstbynm.c文件中。
#define LOOKUP_TYPE struct hostent
#define FUNCTION_NAME gethostbyname
#define DATABASE_NAME hosts
#define ADD_PARAMS const char *name
#define ADD_VARIABLES name
#define BUFLEN 1024
#define NEED_H_ERRNO 1
#define HANDLE_DIGITS_DOTS 1
#include <nss/getXXbyYY.c>
函数gethostbyname_r就更坑爹了。其实现在nss/getXXbyYY_r.c文件中。同上面一样,这个文件也是定义了一个通用的方法,通过一系列宏,来确定接口名称,只是更复杂一些。
69. #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
70. #ifdef FUNCTION2_NAME
71. # define REENTRANT2_NAME APPEND_R (FUNCTION2_NAME)
72. #else
73. # define REENTRANT2_NAME NULL
74. #endif
75. #define APPEND_R(name) APPEND_R1 (name)
76. #define APPEND_R1(name) name##_r
77. #define INTERNAL(name) INTERNAL1 (name)
78. #define INTERNAL1(name) __##name
...
146. int
147. INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
148. size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM
149. EXTRA_PARAMS)
150. {
...
319. #ifdef NO_COMPAT_NEEDED
320. strong_alias (INTERNAL (REENTRANT_NAME), REENTRANT_NAME);
可见里面使用带参数的宏,在定义的name后面加上_r,前面加上__。这样如果#define FUNCTION_NAME gethostbyname的话,经过转换,接口定义就变成了__gethostbyname_r。怎么没有gethostbyname_r?实际上,这个接口名称是在Ln 320定义的一个函数的别名。
此函数的接口定义在inet/gethstbynm_r.c文件中。
#define LOOKUP_TYPE struct hostent
#define FUNCTION_NAME gethostbyname
#define DATABASE_NAME hosts
#define ADD_PARAMS const char *name
#define ADD_VARIABLES name
...
#include "../nss/getXXbyYY_r.c"