load_ramdisk_fd: improved IO error handling
- while loop terminates on read error **without** resetting `seems_ok` to 0, thus read errors won't be noticed - no check if bytes_read matches the expected image size - ram_fd is leaked on write error - short writes are treated as errors (when in fact they are perfectly fine) Therefore: - Handle *all* read errors, not just the very first one - If the image size is known in advance verify if we actually read the whole image - close `ram_fd` in error code paths - Handle short writes properly Closes: #40803
This commit is contained in:
parent
dc87263d47
commit
63008e11b2
75
tools.c
75
tools.c
@ -294,15 +294,63 @@ static void save_stuff_for_rescue(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief copy exactly len bytes from buffer to file descriptor
|
||||||
|
*/
|
||||||
|
static int write_exactly(int fd, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t dl;
|
||||||
|
while (len > 0) {
|
||||||
|
dl = write(fd, buf, len);
|
||||||
|
if (dl < 0) {
|
||||||
|
log_message("%s: write: %s", __func__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf += (size_t)dl;
|
||||||
|
len -= (size_t)dl;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Copy size bytes from src_fd to dst_fd
|
||||||
|
* @param exact if non-zero check if exactly size bytes have been copied
|
||||||
|
* @return 0 on success, -1 on error
|
||||||
|
* @note if size == 0 keep copying until EOF on src_fd
|
||||||
|
*/
|
||||||
|
static int copy_loop(int dst_fd, int src_fd, unsigned long size)
|
||||||
|
{
|
||||||
|
char buf[32768];
|
||||||
|
unsigned long bytes_written = 0;
|
||||||
|
ssize_t dl;
|
||||||
|
for (;;) {
|
||||||
|
dl = read(src_fd, buf, sizeof(buf));
|
||||||
|
if (dl < 0) {
|
||||||
|
log_message("%s: read: %s", __func__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
} else if (dl == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (write_exactly(dst_fd, buf, (size_t)dl) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bytes_written += (size_t)dl;
|
||||||
|
update_progression((int)BYTES2MB(bytes_written));
|
||||||
|
}
|
||||||
|
if (size > 0 && bytes_written != size) {
|
||||||
|
log_message("%s: expected %lu bytes, copied %lu instead\n",
|
||||||
|
__func__, size, bytes_written);
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
||||||
{
|
{
|
||||||
char * ramdisk = "/dev/ram3"; /* warning, verify that this file exists in the initrd, and that root=/dev/ram3 is actually passed to the kernel at boot time */
|
char * ramdisk = "/dev/ram3"; /* warning, verify that this file exists in the initrd, and that root=/dev/ram3 is actually passed to the kernel at boot time */
|
||||||
int ram_fd;
|
int ram_fd;
|
||||||
char buffer[32768];
|
|
||||||
char * wait_msg = "Loading program into memory...";
|
char * wait_msg = "Loading program into memory...";
|
||||||
unsigned long bytes_read = 0;
|
|
||||||
ssize_t actually;
|
|
||||||
int seems_ok = 0;
|
|
||||||
|
|
||||||
ram_fd = open(ramdisk, O_WRONLY);
|
ram_fd = open(ramdisk, O_WRONLY);
|
||||||
if (ram_fd == -1) {
|
if (ram_fd == -1) {
|
||||||
@ -312,22 +360,8 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
init_progression(wait_msg, (int)BYTES2MB(size));
|
init_progression(wait_msg, (int)BYTES2MB(size));
|
||||||
|
if (copy_loop(ram_fd, source_fd, size) < 0) {
|
||||||
while ((actually = read(source_fd, buffer, sizeof(buffer))) > 0) {
|
log_message("%s: failed to load image to RAM", __func__);
|
||||||
seems_ok = 1;
|
|
||||||
if (write(ram_fd, buffer, actually) != actually) {
|
|
||||||
log_perror("writing ramdisk");
|
|
||||||
remove_wait_message();
|
|
||||||
return RETURN_ERROR;
|
|
||||||
}
|
|
||||||
bytes_read += actually;
|
|
||||||
update_progression((int)BYTES2MB(bytes_read));
|
|
||||||
if (bytes_read == size)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!seems_ok) {
|
|
||||||
log_message("reading compressed ramdisk: %s", strerror(errno));
|
|
||||||
close(ram_fd);
|
close(ram_fd);
|
||||||
remove_wait_message();
|
remove_wait_message();
|
||||||
stg1_error_message("Could not load second stage ramdisk. "
|
stg1_error_message("Could not load second stage ramdisk. "
|
||||||
@ -335,7 +369,6 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
|||||||
"(this may be caused by a hardware failure or a Linux kernel bug)");
|
"(this may be caused by a hardware failure or a Linux kernel bug)");
|
||||||
return RETURN_ERROR;
|
return RETURN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_progression();
|
end_progression();
|
||||||
|
|
||||||
close(ram_fd);
|
close(ram_fd);
|
||||||
|
Loading…
Reference in New Issue
Block a user