From: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> write(2) can return early with the input buffer only partially written. Add a wrapper to call write(2) until the full buffer has been written or an error has occurred. Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> --- libsemanage/src/direct_api.c | 4 ++-- libsemanage/src/semanage_store.c | 8 ++++---- libsemanage/src/utilities.c | 22 ++++++++++++++++++++++ libsemanage/src/utilities.h | 13 +++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c index a262fe09..aa1485e3 100644 --- a/libsemanage/src/direct_api.c +++ b/libsemanage/src/direct_api.c @@ -462,7 +462,7 @@ static int write_file(semanage_handle_t * sh, ERR(sh, "Could not open %s for writing.", filename); return -1; } - if (write(out, data, num_bytes) == -1) { + if (write_full(out, data, num_bytes) == -1) { ERR(sh, "Error while writing to %s.", filename); close(out); return -1; @@ -724,7 +724,7 @@ static int semanage_pipe_data(semanage_handle_t *sh, char *path, char *in_data, goto cleanup; } - retval = write(input_fd[PIPE_WRITE], in_data, in_data_len); + retval = write_full(input_fd[PIPE_WRITE], in_data, in_data_len); if (retval == -1) { ERR(sh, "Failed to write data to input pipe: %s\n", strerror(errno)); goto cleanup; diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c index c9bb9c97..cb5bc149 100644 --- a/libsemanage/src/semanage_store.c +++ b/libsemanage/src/semanage_store.c @@ -739,7 +739,7 @@ int semanage_copy_file(const char *src, const char *dst, mode_t mode, } umask(mask); while (retval == 0 && (amount_read = read(in, buf, sizeof(buf))) > 0) { - if (write(out, buf, amount_read) != amount_read) { + if (write_full(out, buf, amount_read) == -1) { if (errno) errsv = errno; else @@ -1555,14 +1555,14 @@ int semanage_split_fc(semanage_handle_t * sh) !strncmp(buf, "HOME_ROOT", 9) || strstr(buf, "ROLE") || strstr(buf, "USER")) { /* This contains one of the template variables, write it to homedir.template */ - if (write(hd, buf, strlen(buf)) < 0) { + if (write_full(hd, buf, strlen(buf)) < 0) { ERR(sh, "Write to %s failed.", semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL)); goto cleanup; } } else { - if (write(fc, buf, strlen(buf)) < 0) { + if (write_full(fc, buf, strlen(buf)) < 0) { ERR(sh, "Write to %s failed.", semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC)); goto cleanup; @@ -1764,7 +1764,7 @@ static int semanage_commit_sandbox(semanage_handle_t * sh) commit_filename); return -1; } - amount_written = write(fd, write_buf, sizeof(write_buf)); + amount_written = write_full(fd, write_buf, sizeof(write_buf)); if (amount_written == -1) { ERR(sh, "Error while writing commit number to %s.", commit_filename); diff --git a/libsemanage/src/utilities.c b/libsemanage/src/utilities.c index 3702cbe1..4beccb5b 100644 --- a/libsemanage/src/utilities.c +++ b/libsemanage/src/utilities.c @@ -25,6 +25,7 @@ #include <ctype.h> #include <string.h> #include <sys/types.h> +#include <unistd.h> #include <assert.h> #define TRUE 1 @@ -328,3 +329,24 @@ semanage_list_t *semanage_slurp_file_filter(FILE * file, return head.next; } + +int write_full(int fd, const void *buf, size_t len) +{ + ssize_t w; + const unsigned char *p = buf; + + while (len > 0) { + w = write(fd, p, len); + if (w == -1) { + if (errno == EINTR) + continue; + + return -1; + } + + p += w; + len -= (size_t)w; + } + + return 0; +} diff --git a/libsemanage/src/utilities.h b/libsemanage/src/utilities.h index 6bbe9f5b..78f1f96e 100644 --- a/libsemanage/src/utilities.h +++ b/libsemanage/src/utilities.h @@ -144,4 +144,17 @@ void semanage_keep_until_space(char *data); semanage_list_t *semanage_slurp_file_filter(FILE * file, int (*pred) (const char *)) WARN_UNUSED; + +/** + * Wrapper around write(2), which retries on short writes. + * + * @param fd file descriptor to write to + * @param buf buffer to be written + * @param len number of bytes to be written from buffer + * + * @return 0 on success, -1 else (with errno set) + */ + +int write_full(int fd, const void *buf, size_t len) WARN_UNUSED; + #endif -- 2.45.2