diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | nss/nss_files/files-XXX.c | 59 |
3 files changed, 60 insertions, 9 deletions
@@ -1,3 +1,11 @@ +2013-10-30 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #16071] + * nss/nss_files/files-XXX.c (get_contents_ret): New + enumerator. + (get_contents): New function. + (internal_getent): Use it. Expand size of LINEBUFLEN. + 2013-10-30 Mike Frysinger <vapier@gentoo.org> * configure.in: Moved to ... @@ -16,7 +16,7 @@ Version 2.19 15760, 15764, 15797, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859, 15867, 15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909, 15919, 15921, 15923, 15939, 15948, 15963, 15966, 15988, 16032, - 16034, 16036, 16041, 16072, 16074, 16078. + 16034, 16036, 16041, 16071, 16072, 16074, 16078. * CVE-2012-4412 The strcoll implementation caches indices and rules for large collation sequences to optimize multiple passes. This cache diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c index 082d1ea2b7..b62208c324 100644 --- a/nss/nss_files/files-XXX.c +++ b/nss/nss_files/files-XXX.c @@ -179,8 +179,51 @@ CONCAT(_nss_files_end,ENTNAME) (void) return NSS_STATUS_SUCCESS; } -/* Parsing the database file into `struct STRUCTURE' data structures. */ +typedef enum +{ + gcr_ok = 0, + gcr_error = -1, + gcr_overflow = -2 +} get_contents_ret; + +/* Hack around the fact that fgets only accepts int sizes. */ +static get_contents_ret +get_contents (char *linebuf, size_t len, FILE *stream) +{ + size_t remaining_len = len; + char *curbuf = linebuf; + + do + { + int curlen = ((remaining_len > (size_t) INT_MAX) ? INT_MAX + : remaining_len); + char *p = fgets_unlocked (curbuf, curlen, stream); + + ((unsigned char *) curbuf)[curlen - 1] = 0xff; + + /* EOF or read error. */ + if (p == NULL) + return gcr_error; + + /* Done reading in the line. */ + if (((unsigned char *) curbuf)[curlen - 1] == 0xff) + return gcr_ok; + + /* Drop the terminating '\0'. */ + remaining_len -= curlen - 1; + curbuf += curlen - 1; + } + /* fgets copies one less than the input length. Our last iteration is of + REMAINING_LEN and once that is done, REMAINING_LEN is decremented by + REMAINING_LEN - 1, leaving the result as 1. */ + while (remaining_len > 1); + + /* This means that the current buffer was not large enough. */ + return gcr_overflow; +} + +/* Parsing the database file into `struct STRUCTURE' data structures. */ static enum nss_status internal_getent (struct STRUCTURE *result, char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO @@ -188,7 +231,7 @@ internal_getent (struct STRUCTURE *result, { char *p; struct parser_data *data = (void *) buffer; - int linebuflen = buffer + buflen - data->linebuffer; + size_t linebuflen = buffer + buflen - data->linebuffer; int parse_result; if (buflen < sizeof *data + 2) @@ -200,17 +243,16 @@ internal_getent (struct STRUCTURE *result, do { - /* Terminate the line so that we can test for overflow. */ - ((unsigned char *) data->linebuffer)[linebuflen - 1] = '\xff'; + get_contents_ret r = get_contents (data->linebuffer, linebuflen, stream); - p = fgets_unlocked (data->linebuffer, linebuflen, stream); - if (p == NULL) + if (r == gcr_error) { /* End of file or read error. */ H_ERRNO_SET (HOST_NOT_FOUND); return NSS_STATUS_NOTFOUND; } - else if (((unsigned char *) data->linebuffer)[linebuflen - 1] != 0xff) + + if (r == gcr_overflow) { /* The line is too long. Give the user the opportunity to enlarge the buffer. */ @@ -219,7 +261,8 @@ internal_getent (struct STRUCTURE *result, return NSS_STATUS_TRYAGAIN; } - /* Skip leading blanks. */ + /* Everything OK. Now skip leading blanks. */ + p = data->linebuffer; while (isspace (*p)) ++p; } |