Fix TFTP reading of zero-size files in efiboot:

The AllocatePages EFI call returns an error when the allocation
size is 0.  Skip allocating memory and actually transferring the
file when it is empty.

Properly return the number of unread bytes so that a read() of n
bytes does not return n if no bytes were read.

While here, disallow lseek() beyond the TFTP file buffer for SEEK_CUR
as we already do for SEEK_SET.

----

Tested on aarch64.  Can somebody test this on amd64?
OK?


Index: arch/amd64/stand/efiboot/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/conf.c,v
retrieving revision 1.12
diff -u -p -r1.12 conf.c
--- arch/amd64/stand/efiboot/conf.c     25 Nov 2017 19:02:07 -0000      1.12
+++ arch/amd64/stand/efiboot/conf.c     25 Jan 2018 22:39:37 -0000
@@ -39,7 +39,7 @@
 #include "efidev.h"
 #include "efipxe.h"
 
-const char version[] = "3.36";
+const char version[] = "3.37";
 
 #ifdef EFI_DEBUG
 int    debug = 0;
Index: arch/amd64/stand/efiboot/efipxe.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/efipxe.c,v
retrieving revision 1.2
diff -u -p -r1.2 efipxe.c
--- arch/amd64/stand/efiboot/efipxe.c   21 Jan 2018 21:37:01 -0000      1.2
+++ arch/amd64/stand/efiboot/efipxe.c   25 Jan 2018 22:46:15 -0000
@@ -143,6 +143,9 @@ tftp_open(char *path, struct open_file *
        }
        tftpfile->inbufsize = size;
 
+       if (tftpfile->inbufsize == 0)
+               goto out;
+
        status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData,
            EFI_SIZE_TO_PAGES(tftpfile->inbufsize), &addr);
        if (status != EFI_SUCCESS) {
@@ -157,7 +160,7 @@ tftp_open(char *path, struct open_file *
                free(tftpfile, sizeof(*tftpfile));
                return ENXIO;
        }
-
+out:
        f->f_fsdata = tftpfile;
        return 0;
 }
@@ -167,8 +170,9 @@ tftp_close(struct open_file *f)
 {
        struct tftp_handle *tftpfile = f->f_fsdata;
 
-       EFI_CALL(BS->FreePages, (paddr_t)tftpfile->inbuf,
-           EFI_SIZE_TO_PAGES(tftpfile->inbufsize));
+       if (tftpfile->inbuf != NULL)
+               EFI_CALL(BS->FreePages, (paddr_t)tftpfile->inbuf,
+                   EFI_SIZE_TO_PAGES(tftpfile->inbufsize));
        free(tftpfile, sizeof(*tftpfile));
        return 0;
 }
@@ -184,15 +188,11 @@ tftp_read(struct open_file *f, void *add
        else
                toread = size;
 
-       if (toread == 0) {
-               if (resid != NULL)
-                       *resid = 0;
-               return (0);
+       if (toread != 0) {
+               memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread);
+               tftpfile->inbufoff += toread;
        }
 
-       memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread);
-       tftpfile->inbufoff += toread;
-
        if (resid != NULL)
                *resid = size - toread;
        return 0;
@@ -211,7 +211,8 @@ tftp_seek(struct open_file *f, off_t off
 
        switch(where) {
        case SEEK_CUR:
-               if (tftpfile->inbufoff + offset < 0) {
+               if (tftpfile->inbufoff + offset < 0 ||
+                   tftpfile->inbufoff + offset > tftpfile->inbufsize) {
                        errno = EOFFSET;
                        break;
                }
Index: arch/arm64/stand/efiboot/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/stand/efiboot/conf.c,v
retrieving revision 1.10
diff -u -p -r1.10 conf.c
--- arch/arm64/stand/efiboot/conf.c     21 Jan 2018 21:35:34 -0000      1.10
+++ arch/arm64/stand/efiboot/conf.c     25 Jan 2018 20:42:46 -0000
@@ -36,7 +36,7 @@
 #include "efidev.h"
 #include "efipxe.h"
 
-const char version[] = "0.9";
+const char version[] = "0.10";
 int    debug = 0;
 
 struct fs_ops file_system[] = {
Index: arch/arm64/stand/efiboot/efipxe.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/stand/efiboot/efipxe.c,v
retrieving revision 1.1
diff -u -p -r1.1 efipxe.c
--- arch/arm64/stand/efiboot/efipxe.c   21 Jan 2018 21:35:34 -0000      1.1
+++ arch/arm64/stand/efiboot/efipxe.c   25 Jan 2018 22:45:08 -0000
@@ -139,6 +139,9 @@ tftp_open(char *path, struct open_file *
        }
        tftpfile->inbufsize = size;
 
+       if (tftpfile->inbufsize == 0)
+               goto out;
+
        status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData,
            EFI_SIZE_TO_PAGES(tftpfile->inbufsize), &addr);
        if (status != EFI_SUCCESS) {
@@ -153,7 +156,7 @@ tftp_open(char *path, struct open_file *
                free(tftpfile, sizeof(*tftpfile));
                return ENXIO;
        }
-
+out:
        f->f_fsdata = tftpfile;
        return 0;
 }
@@ -163,8 +166,9 @@ tftp_close(struct open_file *f)
 {
        struct tftp_handle *tftpfile = f->f_fsdata;
 
-       EFI_CALL(BS->FreePages, (paddr_t)tftpfile->inbuf,
-           EFI_SIZE_TO_PAGES(tftpfile->inbufsize));
+       if (tftpfile->inbuf != NULL)
+               EFI_CALL(BS->FreePages, (paddr_t)tftpfile->inbuf,
+                   EFI_SIZE_TO_PAGES(tftpfile->inbufsize));
        free(tftpfile, sizeof(*tftpfile));
        return 0;
 }
@@ -180,15 +184,11 @@ tftp_read(struct open_file *f, void *add
        else
                toread = size;
 
-       if (toread == 0) {
-               if (resid != NULL)
-                       *resid = 0;
-               return (0);
+       if (toread != 0) {
+               memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread);
+               tftpfile->inbufoff += toread;
        }
 
-       memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread);
-       tftpfile->inbufoff += toread;
-
        if (resid != NULL)
                *resid = size - toread;
        return 0;
@@ -207,7 +207,8 @@ tftp_seek(struct open_file *f, off_t off
 
        switch(where) {
        case SEEK_CUR:
-               if (tftpfile->inbufoff + offset < 0) {
+               if (tftpfile->inbufoff + offset < 0 ||
+                   tftpfile->inbufoff + offset > tftpfile->inbufsize) {
                        errno = EOFFSET;
                        break;
                }
-- 
Christian "naddy" Weisgerber                          [email protected]

Reply via email to