Add wrapper for write(2)

write(2) may not write the complete given buffer.  Add a wrapper to
avoid short writes.
This commit is contained in:
Christian Göttsche
2023-02-28 16:35:05 +01:00
committed by Serge Hallyn
parent d63f3a0c0a
commit 969549fdf0
13 changed files with 75 additions and 54 deletions
+2 -1
View File
@@ -66,7 +66,8 @@ libshadow_la_SOURCES = \
shadowio.c \
shadowio.h \
shadowmem.c \
spawn.c
spawn.c \
write_full.c
if WITH_TCB
libshadow_la_SOURCES += tcbfuncs.c tcbfuncs.h
+1 -1
View File
@@ -140,7 +140,7 @@ static int do_lock_file (const char *file, const char *lock, bool log)
pid = getpid ();
snprintf (buf, sizeof buf, "%lu", (unsigned long) pid);
len = (ssize_t) strlen (buf) + 1;
if (write (fd, buf, (size_t) len) != len) {
if (write_full (fd, buf, (size_t) len) != len) {
if (log) {
(void) fprintf (shadow_logfd,
"%s: %s file write error: %s\n",
+3
View File
@@ -526,6 +526,9 @@ extern unsigned long active_sessions_count(const char *name,
/* valid.c */
extern bool valid (const char *, const struct passwd *);
/* write_full.c */
extern ssize_t write_full(int fd, const void *buf, size_t count);
/* xgetpwnam.c */
extern /*@null@*/ /*@only@*/struct passwd *xgetpwnam (const char *);
/* xprefix_getpwnam.c */
+52
View File
@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2023, Christian Göttsche <cgzones@googlemail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <config.h>
#ident "$Id$"
#include "prototypes.h"
#include <errno.h>
#include <unistd.h>
/*
* write_full - write entire buffer
*
* Write up to count bytes from the buffer starting at buf to the
* file referred to by the file descriptor fd.
* Retry in case of a short write.
*
* Returns the number of bytes written on success, -1 on error.
*/
ssize_t write_full(int fd, const void *buf, size_t count) {
ssize_t written = 0;
while (count > 0) {
ssize_t res;
res = write(fd, buf, count);
if (res < 0) {
if (errno == EINTR) {
continue;
}
return res;
}
if (res == 0) {
break;
}
written += res;
buf = (const unsigned char*)buf + res;
count -= res;
}
return written;
}
+1 -37
View File
@@ -740,42 +740,6 @@ static int copy_special (const struct path_info *src, const struct path_info *ds
return err;
}
/*
* full_write - write entire buffer
*
* Write up to count bytes from the buffer starting at buf to the
* file referred to by the file descriptor fd.
* Retry in case of a short write.
*
* Returns the number of bytes written on success, -1 on error.
*/
static ssize_t full_write(int fd, const void *buf, size_t count) {
ssize_t written = 0;
while (count > 0) {
ssize_t res;
res = write(fd, buf, count);
if (res < 0) {
if (errno == EINTR) {
continue;
}
return res;
}
if (res == 0) {
break;
}
written += res;
buf = (const unsigned char*)buf + res;
count -= res;
}
return written;
}
/*
* copy_file - copy a file
*
@@ -852,7 +816,7 @@ static int copy_file (const struct path_info *src, const struct path_info *dst,
break;
}
if (full_write (ofd, buf, cnt) < 0) {
if (write_full (ofd, buf, cnt) < 0) {
(void) close (ofd);
(void) close (ifd);
return -1;
+3 -2
View File
@@ -17,6 +17,7 @@
#include "defines.h"
#include "faillog.h"
#include "failure.h"
#include "prototypes.h"
#define YEAR (365L*DAY)
/*
* failure - make failure entry
@@ -85,7 +86,7 @@ void failure (uid_t uid, const char *tty, struct faillog *fl)
*/
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|| (write (fd, fl, sizeof *fl) != (ssize_t) sizeof *fl)
|| (write_full (fd, fl, sizeof *fl) != (ssize_t) sizeof *fl)
|| (close (fd) != 0)) {
SYSLOG ((LOG_WARN,
"Can't write faillog entry for UID %lu in %s.",
@@ -184,7 +185,7 @@ int failcheck (uid_t uid, struct faillog *fl, bool failed)
fail.fail_cnt = 0;
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|| (write (fd, &fail, sizeof fail) != (ssize_t) sizeof fail)
|| (write_full (fd, &fail, sizeof fail) != (ssize_t) sizeof fail)
|| (close (fd) != 0)) {
SYSLOG ((LOG_WARN,
"Can't reset faillog entry for UID %lu in %s.",
+1 -1
View File
@@ -215,7 +215,7 @@ void write_mapping(int proc_dir_fd, int ranges, const struct map_range *mappings
log_get_progname(), map_file, strerror(errno));
exit(EXIT_FAILURE);
}
if (write(fd, buf, pos - buf) != (pos - buf)) {
if (write_full(fd, buf, pos - buf) != (pos - buf)) {
fprintf(log_get_logfd(), _("%s: write to %s failed: %s\n"),
log_get_progname(), map_file, strerror(errno));
exit(EXIT_FAILURE);
+1 -1
View File
@@ -82,7 +82,7 @@ void dolastlog (
strncpy (newlog.ll_host, host, sizeof (newlog.ll_host) - 1);
#endif
if ( (lseek (fd, offset, SEEK_SET) != offset)
|| (write (fd, &newlog, sizeof newlog) != (ssize_t) sizeof newlog)
|| (write_full (fd, &newlog, sizeof newlog) != (ssize_t) sizeof newlog)
|| (close (fd) != 0)) {
SYSLOG ((LOG_WARN,
"Can't write lastlog entry for UID %lu in %s.",
+2 -2
View File
@@ -97,7 +97,7 @@ static void failtmp (const char *username, const struct utmp *failent)
* Append the new failure record and close the log file.
*/
if ( (write (fd, failent, sizeof *failent) != (ssize_t) sizeof *failent)
if ( (write_full (fd, failent, sizeof *failent) != (ssize_t) sizeof *failent)
|| (close (fd) != 0)) {
SYSLOG ((LOG_WARN,
"Can't append failure of user %s to %s.",
@@ -194,7 +194,7 @@ static void updwtmp (const char *filename, const struct utmp *ut)
fd = open (filename, O_APPEND | O_WRONLY, 0);
if (fd >= 0) {
write (fd, ut, sizeof (*ut));
write_full (fd, ut, sizeof (*ut));
close (fd);
}
}
+1 -1
View File
@@ -400,7 +400,7 @@ static void exit_handler (unused int sig)
static void alarm_handler (unused int sig)
{
write (STDERR_FILENO, tmsg, strlen (tmsg));
write_full (STDERR_FILENO, tmsg, strlen (tmsg));
signal(SIGALRM, exit_handler);
alarm(2);
}
+2 -2
View File
@@ -164,9 +164,9 @@ static void kill_child (int unused(s))
{
if (0 != pid_child) {
(void) kill (-pid_child, SIGKILL);
(void) write (STDERR_FILENO, kill_msg, strlen (kill_msg));
(void) write_full (STDERR_FILENO, kill_msg, strlen (kill_msg));
} else {
(void) write (STDERR_FILENO, wait_msg, strlen (wait_msg));
(void) write_full (STDERR_FILENO, wait_msg, strlen (wait_msg));
}
_exit (255);
}
+2 -2
View File
@@ -2067,7 +2067,7 @@ static void faillog_reset (uid_t uid)
return;
}
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|| (write (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl))
|| (write_full (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl))
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to reset the faillog entry of UID %lu: %s\n"),
@@ -2112,7 +2112,7 @@ static void lastlog_reset (uid_t uid)
return;
}
if ( (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|| (write (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll))
|| (write_full (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll))
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to reset the lastlog entry of UID %lu: %s\n"),
+4 -4
View File
@@ -1941,7 +1941,7 @@ static void update_lastlog (void)
&& (read (fd, &ll, sizeof ll) == (ssize_t) sizeof ll)) {
/* Copy the old entry to its new location */
if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid)
|| (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll)
|| (write_full (fd, &ll, sizeof ll) != (ssize_t) sizeof ll)
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"),
@@ -1957,7 +1957,7 @@ static void update_lastlog (void)
/* Reset the new uid's lastlog entry */
memzero (&ll, sizeof (ll));
if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid)
|| (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll)
|| (write_full (fd, &ll, sizeof ll) != (ssize_t) sizeof ll)
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"),
@@ -2001,7 +2001,7 @@ static void update_faillog (void)
&& (read (fd, &fl, sizeof fl) == (ssize_t) sizeof fl)) {
/* Copy the old entry to its new location */
if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid)
|| (write (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)
|| (write_full (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)
|| (fsync (fd) != 0)) {
fprintf (stderr,
_("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"),
@@ -2017,7 +2017,7 @@ static void update_faillog (void)
/* Reset the new uid's faillog entry */
memzero (&fl, sizeof (fl));
if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid)
|| (write (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)) {
|| (write_full (fd, &fl, sizeof fl) != (ssize_t) sizeof fl)) {
fprintf (stderr,
_("%s: failed to copy the faillog entry of user %lu to user %lu: %s\n"),
Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno));