From 306dfba9e1daac21ab5a45256b367aea9cf9c3ee Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 4 Dec 2012 16:14:13 +0100 Subject: Properly check for short writes when sending the response in nscd --- ChangeLog | 8 ++++++++ nscd/grpcache.c | 40 +++++++++++++++++++++++----------------- nscd/initgrcache.c | 36 ++++++++++++++++++++++-------------- nscd/pwdcache.c | 40 ++++++++++++++++++++++++---------------- nscd/servicescache.c | 37 ++++++++++++++++++++++--------------- 5 files changed, 99 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2284d7faf0..27917240d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2013-04-15 Andreas Schwab + + * nscd/grpcache.c (cache_addgr): Properly check for short write. + * nscd/initgrcache.c (addinitgroupsX): Likewise. + * nscd/pwdcache.c (cache_addpw): Likewise. + * nscd/servicescache.c (cache_addserv): Likewise. Don't write + more than recsize. + 2013-04-15 Siddhesh Poyarekar * benchtests/Makefile (bench): Write all output to diff --git a/nscd/grpcache.c b/nscd/grpcache.c index d25d8e92f2..5658792445 100644 --- a/nscd/grpcache.c +++ b/nscd/grpcache.c @@ -75,8 +75,8 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, const void *key, struct group *grp, uid_t owner, struct hashentry *const he, struct datahead *dh, int errval) { + bool all_written = true; ssize_t total; - ssize_t written; time_t t = time (NULL); /* We allocate all data in one memory block: the iov vector, @@ -105,7 +105,7 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, /* Reload with the same time-to-live value. */ timeout = dh->timeout = t + db->postimeout; - written = total = 0; + total = 0; } else { @@ -113,11 +113,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, case. */ total = sizeof (notfound); - if (fd != -1) - written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, - MSG_NOSIGNAL)); - else - written = total; + if (fd != -1 + && TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)) != total) + all_written = false; /* If we have a transient error or cannot permanently store the result, so be it. */ @@ -197,9 +196,9 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, gr_mem_len_total += gr_mem_len[gr_mem_cnt]; } - written = total = (offsetof (struct dataset, strdata) - + gr_mem_cnt * sizeof (uint32_t) - + gr_name_len + gr_passwd_len + gr_mem_len_total); + total = (offsetof (struct dataset, strdata) + + gr_mem_cnt * sizeof (uint32_t) + + gr_name_len + gr_passwd_len + gr_mem_len_total); /* If we refill the cache, first assume the reconrd did not change. Allocate memory on the cache since it is likely @@ -328,20 +327,27 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, <= (sizeof (struct database_pers_head) + db->head->module * sizeof (ref_t) + db->head->data_size)); - written = sendfileall (fd, db->wr_fd, - (char *) &dataset->resp - - (char *) db->head, dataset->head.recsize); + ssize_t written = sendfileall (fd, db->wr_fd, + (char *) &dataset->resp + - (char *) db->head, + dataset->head.recsize); + if (written != dataset->head.recsize) + { # ifndef __ASSUME_SENDFILE - if (written == -1 && errno == ENOSYS) - goto use_write; + if (written == -1 && errno == ENOSYS) + goto use_write; # endif + all_written = false; + } } else # ifndef __ASSUME_SENDFILE use_write: # endif #endif - written = writeall (fd, &dataset->resp, dataset->head.recsize); + if (writeall (fd, &dataset->resp, dataset->head.recsize) + != dataset->head.recsize) + all_written = false; } /* Add the record to the database. But only if it has not been @@ -401,7 +407,7 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req, } } - if (__builtin_expect (written != total, 0) && debug_level > 0) + if (__builtin_expect (!all_written, 0) && debug_level > 0) { char buf[256]; dbg_log (_("short write in %s: %s"), __FUNCTION__, diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c index 196407c870..462780e624 100644 --- a/nscd/initgrcache.c +++ b/nscd/initgrcache.c @@ -171,15 +171,16 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, nip = nip->next; } + bool all_written; ssize_t total; - ssize_t written; time_t timeout; out: + all_written = true; timeout = MAX_TIMEOUT_VALUE; if (!any_success) { /* Nothing found. Create a negative result record. */ - written = total = sizeof (notfound); + total = sizeof (notfound); if (he != NULL && all_tryagain) { @@ -197,9 +198,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, { /* We have no data. This means we send the standard reply for this case. */ - if (fd != -1) - written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, - MSG_NOSIGNAL)); + if (fd != -1 + && TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)) != total) + all_written = false; /* If we have a transient error or cannot permanently store the result, so be it. */ @@ -251,8 +253,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, else { - written = total = (offsetof (struct dataset, strdata) - + start * sizeof (int32_t)); + total = offsetof (struct dataset, strdata) + start * sizeof (int32_t); /* If we refill the cache, first assume the reconrd did not change. Allocate memory on the cache since it is likely @@ -365,20 +366,27 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, <= (sizeof (struct database_pers_head) + db->head->module * sizeof (ref_t) + db->head->data_size)); - written = sendfileall (fd, db->wr_fd, - (char *) &dataset->resp - - (char *) db->head, dataset->head.recsize); + ssize_t written = sendfileall (fd, db->wr_fd, + (char *) &dataset->resp + - (char *) db->head, + dataset->head.recsize); + if (written != dataset->head.recsize) + { # ifndef __ASSUME_SENDFILE - if (written == -1 && errno == ENOSYS) - goto use_write; + if (written == -1 && errno == ENOSYS) + goto use_write; # endif + all_written = false; + } } else # ifndef __ASSUME_SENDFILE use_write: # endif #endif - written = writeall (fd, &dataset->resp, dataset->head.recsize); + if (writeall (fd, &dataset->resp, dataset->head.recsize) + != dataset->head.recsize) + all_written = false; } @@ -405,7 +413,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, free (groups); - if (__builtin_expect (written != total, 0) && debug_level > 0) + if (__builtin_expect (!all_written, 0) && debug_level > 0) { char buf[256]; dbg_log (_("short write in %s: %s"), __FUNCTION__, diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c index ef492b58c1..4f3fb416da 100644 --- a/nscd/pwdcache.c +++ b/nscd/pwdcache.c @@ -81,8 +81,8 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req, const void *key, struct passwd *pwd, uid_t owner, struct hashentry *const he, struct datahead *dh, int errval) { + bool all_written = true; ssize_t total; - ssize_t written; time_t t = time (NULL); /* We allocate all data in one memory block: the iov vector, @@ -111,17 +111,18 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req, /* Reload with the same time-to-live value. */ timeout = dh->timeout = t + db->postimeout; - written = total = 0; + total = 0; } else { /* We have no data. This means we send the standard reply for this case. */ - written = total = sizeof (notfound); + total = sizeof (notfound); - if (fd != -1) - written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, - MSG_NOSIGNAL)); + if (fd != -1 + && TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)) != total) + all_written = false; /* If we have a transient error or cannot permanently store the result, so be it. */ @@ -189,9 +190,9 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req, n = snprintf (buf, buf_len, "%d%c%n%s", pwd->pw_uid, '\0', &key_offset, (char *) key) + 1; - written = total = (offsetof (struct dataset, strdata) - + pw_name_len + pw_passwd_len - + pw_gecos_len + pw_dir_len + pw_shell_len); + total = (offsetof (struct dataset, strdata) + + pw_name_len + pw_passwd_len + + pw_gecos_len + pw_dir_len + pw_shell_len); /* If we refill the cache, first assume the reconrd did not change. Allocate memory on the cache since it is likely @@ -304,20 +305,27 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req, <= (sizeof (struct database_pers_head) + db->head->module * sizeof (ref_t) + db->head->data_size)); - written = sendfileall (fd, db->wr_fd, - (char *) &dataset->resp - - (char *) db->head, dataset->head.recsize ); + ssize_t written = sendfileall (fd, db->wr_fd, + (char *) &dataset->resp + - (char *) db->head, + dataset->head.recsize); + if (written != dataset->head.recsize) + { # ifndef __ASSUME_SENDFILE - if (written == -1 && errno == ENOSYS) - goto use_write; + if (written == -1 && errno == ENOSYS) + goto use_write; # endif + all_written = false; + } } else # ifndef __ASSUME_SENDFILE use_write: # endif #endif - written = writeall (fd, &dataset->resp, dataset->head.recsize); + if (writeall (fd, &dataset->resp, dataset->head.recsize) + != dataset->head.recsize) + all_written = false; } @@ -377,7 +385,7 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req, } } - if (__builtin_expect (written != total, 0) && debug_level > 0) + if (__builtin_expect (!all_written, 0) && debug_level > 0) { char buf[256]; dbg_log (_("short write in %s: %s"), __FUNCTION__, diff --git a/nscd/servicescache.c b/nscd/servicescache.c index d29cde7d63..ebb8c454f6 100644 --- a/nscd/servicescache.c +++ b/nscd/servicescache.c @@ -65,8 +65,8 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req, const void *key, struct servent *serv, uid_t owner, struct hashentry *const he, struct datahead *dh, int errval) { + bool all_written = true; ssize_t total; - ssize_t written; time_t t = time (NULL); /* We allocate all data in one memory block: the iov vector, @@ -95,17 +95,18 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req, /* Reload with the same time-to-live value. */ timeout = dh->timeout = t + db->postimeout; - written = total = 0; + total = 0; } else { /* We have no data. This means we send the standard reply for this case. */ - written = total = sizeof (notfound); + total = sizeof (notfound); - if (fd != -1) - written = TEMP_FAILURE_RETRY (send (fd, ¬found, total, - MSG_NOSIGNAL)); + if (fd != -1 + && TEMP_FAILURE_RETRY (send (fd, ¬found, total, + MSG_NOSIGNAL)) != total) + all_written = false; /* If we have a transient error or cannot permanently store the result, so be it. */ @@ -182,7 +183,6 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req, + s_name_len + s_proto_len + s_aliases_cnt * sizeof (uint32_t)); - written = total; /* If we refill the cache, first assume the reconrd did not change. Allocate memory on the cache since it is likely @@ -290,25 +290,32 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req, { assert (db->wr_fd != -1); assert ((char *) &dataset->resp > (char *) db->data); - assert ((char *) &dataset->resp - (char *) db->head + assert ((char *) dataset - (char *) db->head + total <= (sizeof (struct database_pers_head) + db->head->module * sizeof (ref_t) + db->head->data_size)); - written = sendfileall (fd, db->wr_fd, - (char *) &dataset->resp - - (char *) db->head, total); + ssize_t written = sendfileall (fd, db->wr_fd, + (char *) &dataset->resp + - (char *) db->head, + dataset->head.recsize); + if (written != dataset->head.recsize) + { # ifndef __ASSUME_SENDFILE - if (written == -1 && errno == ENOSYS) - goto use_write; + if (written == -1 && errno == ENOSYS) + goto use_write; # endif + all_written = false; + } } else # ifndef __ASSUME_SENDFILE use_write: # endif #endif - written = writeall (fd, &dataset->resp, total); + if (writeall (fd, &dataset->resp, dataset->head.recsize) + != dataset->head.recsize) + all_written = false; } /* Add the record to the database. But only if it has not been @@ -332,7 +339,7 @@ cache_addserv (struct database_dyn *db, int fd, request_header *req, } } - if (__builtin_expect (written != total, 0) && debug_level > 0) + if (__builtin_expect (!all_written, 0) && debug_level > 0) { char buf[256]; dbg_log (_("short write in %s: %s"), __FUNCTION__, -- cgit 1.4.1