rufimelo/DeltaSecommits huggingface dataset:
Vulnerability: An arbitrary memory overwrite vulnerability in Asylo versions up to 0.6.0 allows an attacker to make a host call to enc_untrusted_create_wait_queue that uses a pointer queue that relies on UntrustedLocalMemcpy, which fails to validate where the pointer is located. This allows an attacker to write memory values from within the enclave. We recommend upgrading past commit a37fb6a0e7daf30134dbbf357c9a518a1026aa02
Vulnerability ID: CVE-2020-8937
CWE: CWE-787
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/host_call/trusted/concurrency.cc
Commit message: Check untrusted queue is in outside enclave

PiperOrigin-RevId: 333370935
Change-Id: Ic3f15d5db1302d95c7cb199b44172474fecb81ca
Commit author: Chong Cai

Vulnerable version (before fix):
 int32_t *enc_untrusted_create_wait_queue() {   CheckStatusAndParamCount(status, output, "enc_untrusted_create_wait_queue",                            2);   int32_t *queue = reinterpret_cast<int32_t *>(output.next<uintptr_t>());   int klinux_errno = output.next<int>();   if (queue == nullptr) {     errno = FromkLinuxErrorNumber(klinux_errno);

Fixed version (after fix):
 int32_t *enc_untrusted_create_wait_queue() {   CheckStatusAndParamCount(status, output, "enc_untrusted_create_wait_queue",                            2);   int32_t *queue = reinterpret_cast<int32_t *>(output.next<uintptr_t>());   if (!TrustedPrimitives::IsOutsideEnclave(queue, sizeof(int32_t))) {     TrustedPrimitives::BestEffortAbort(         "enc_untrusted_create_wait_queue: queue should be in untrusted memory");   }   int klinux_errno = output.next<int>();   if (queue == nullptr) {     errno = FromkLinuxErrorNumber(klinux_errno);

Patch:
patch: @@ -93,6 +93,10 @@ int32_t *enc_untrusted_create_wait_queue() {
   CheckStatusAndParamCount(status, output, "enc_untrusted_create_wait_queue",
                            2);
   int32_t *queue = reinterpret_cast<int32_t *>(output.next<uintptr_t>());
+  if (!TrustedPrimitives::IsOutsideEnclave(queue, sizeof(int32_t))) {
+    TrustedPrimitives::BestEffortAbort(
+        "enc_untrusted_create_wait_queue: queue should be in untrusted memory");
+  }
   int klinux_errno = output.next<int>();
   if (queue == nullptr) {
     errno = FromkLinuxErrorNumber(klinux_errno);
path: asylo/platform/host_call/trusted/concurrency.cc
Vulnerability: An out of bounds read on the enc_untrusted_inet_ntop function allows an attack to extend the result size that is used by memcpy() to read memory from within the enclave heap. We recommend upgrading past commit 6ff3b77ffe110a33a2f93848a6333f33616f02c4
Vulnerability ID: CVE-2020-8939
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/host_call/trusted/host_calls.cc
Commit message: Check for result size in dst in inet_ntop

PiperOrigin-RevId: 333814318
Change-Id: Id7766ed598809f5df42d457f224d6f3dea06c224
Commit author: Chong Cai

Vulnerable version (before fix):
 const char *enc_untrusted_inet_ntop(int af, const void *src, char *dst,     return nullptr;   }    memcpy(dst, result.data(),          std::min(static_cast<size_t>(size),                   static_cast<size_t>(INET6_ADDRSTRLEN)));   return dst; } 

Fixed version (after fix):
 const char *enc_untrusted_inet_ntop(int af, const void *src, char *dst,     return nullptr;   }    memcpy(       dst, result.data(),       std::min({static_cast<size_t>(size), static_cast<size_t>(result.size()),                 static_cast<size_t>(INET6_ADDRSTRLEN)}));   return dst; } 

Patch:
patch: @@ -1325,9 +1325,10 @@ const char *enc_untrusted_inet_ntop(int af, const void *src, char *dst,
     return nullptr;
   }
 
-  memcpy(dst, result.data(),
-         std::min(static_cast<size_t>(size),
-                  static_cast<size_t>(INET6_ADDRSTRLEN)));
+  memcpy(
+      dst, result.data(),
+      std::min({static_cast<size_t>(size), static_cast<size_t>(result.size()),
+                static_cast<size_t>(INET6_ADDRSTRLEN)}));
   return dst;
 }
path: asylo/platform/host_call/trusted/host_calls.cc
Vulnerability: An arbitrary memory read vulnerability in Asylo versions up to 0.6.0 allows an untrusted attacker to make a call to enc_untrusted_recvmsg using an attacker controlled result parameter. The parameter size is unchecked allowing the attacker to read memory locations outside of the intended buffer size including memory addresses within the secure enclave. We recommend upgrading or past commit fa6485c5d16a7355eab047d4a44345a73bc9131e
Vulnerability ID: CVE-2020-8940
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/host_call/trusted/host_calls.cc
Commit message: Check return result in recvmsg

PiperOrigin-RevId: 333411798
Change-Id: I61986b5a1bffd79c0e1950013aa9de09cf4a5d61
Commit author: Chong Cai

Vulnerable version (before fix):
 ssize_t enc_untrusted_recvmsg(int sockfd, struct msghdr *msg, int flags) {     return result;   }    auto msg_name_extent = output.next();   // The returned |msg_namelen| should not exceed the buffer size.   if (msg_name_extent.size() <= msg->msg_namelen) {

Fixed version (after fix):
 ssize_t enc_untrusted_recvmsg(int sockfd, struct msghdr *msg, int flags) {     return result;   }    if (result > total_buffer_size) {     ::asylo::primitives::TrustedPrimitives::BestEffortAbort(         "enc_untrusted_recvmsg: result exceeds requested");   }    auto msg_name_extent = output.next();   // The returned |msg_namelen| should not exceed the buffer size.   if (msg_name_extent.size() <= msg->msg_namelen) {

Patch:
patch: @@ -822,6 +822,11 @@ ssize_t enc_untrusted_recvmsg(int sockfd, struct msghdr *msg, int flags) {
     return result;
   }
 
+  if (result > total_buffer_size) {
+    ::asylo::primitives::TrustedPrimitives::BestEffortAbort(
+        "enc_untrusted_recvmsg: result exceeds requested");
+  }
+
   auto msg_name_extent = output.next();
   // The returned |msg_namelen| should not exceed the buffer size.
   if (msg_name_extent.size() <= msg->msg_namelen) {
path: asylo/platform/host_call/trusted/host_calls.cc
Vulnerability: An arbitrary memory read vulnerability in Asylo versions up to 0.6.0 allows an untrusted attacker to make a call to enc_untrusted_inet_pton using an attacker controlled klinux_addr_buffer parameter. The parameter size is unchecked allowing the attacker to read memory locations outside of the intended buffer size including memory addresses within the secure enclave. We recommend upgrading past commit 8fed5e334131abaf9c5e17307642fbf6ce4a57ec
Vulnerability ID: CVE-2020-8941
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/host_call/trusted/host_calls.cc
Commit message: Check sockaddr size in inet_pton

PiperOrigin-RevId: 333821843
Change-Id: Ie0b694f1edd3f7a4a3de6df964d68566961accf6
Commit author: Chong Cai

Vulnerable version (before fix):
 int enc_untrusted_inet_pton(int af, const char *src, void *dst) {   auto klinux_addr_buffer = output.next();   size_t max_size = 0;   if (af == AF_INET) {     max_size = sizeof(struct in_addr);   } else if (af == AF_INET6) {     max_size = sizeof(struct in6_addr);   }   memcpy(dst, klinux_addr_buffer.data(),

Fixed version (after fix):
 int enc_untrusted_inet_pton(int af, const char *src, void *dst) {   auto klinux_addr_buffer = output.next();   size_t max_size = 0;   if (af == AF_INET) {     if (klinux_addr_buffer.size() != sizeof(klinux_in_addr)) {       ::asylo::primitives::TrustedPrimitives::BestEffortAbort(           "enc_untrusted_inet_pton: unexpected output size");     }     max_size = sizeof(struct in_addr);   } else if (af == AF_INET6) {     if (klinux_addr_buffer.size() != sizeof(klinux_in6_addr)) {       ::asylo::primitives::TrustedPrimitives::BestEffortAbort(           "enc_untrusted_inet_pton: unexpected output size");     }     max_size = sizeof(struct in6_addr);   }   memcpy(dst, klinux_addr_buffer.data(),

Patch:
patch: @@ -1283,8 +1283,16 @@ int enc_untrusted_inet_pton(int af, const char *src, void *dst) {
   auto klinux_addr_buffer = output.next();
   size_t max_size = 0;
   if (af == AF_INET) {
+    if (klinux_addr_buffer.size() != sizeof(klinux_in_addr)) {
+      ::asylo::primitives::TrustedPrimitives::BestEffortAbort(
+          "enc_untrusted_inet_pton: unexpected output size");
+    }
     max_size = sizeof(struct in_addr);
   } else if (af == AF_INET6) {
+    if (klinux_addr_buffer.size() != sizeof(klinux_in6_addr)) {
+      ::asylo::primitives::TrustedPrimitives::BestEffortAbort(
+          "enc_untrusted_inet_pton: unexpected output size");
+    }
     max_size = sizeof(struct in6_addr);
   }
   memcpy(dst, klinux_addr_buffer.data(),
path: asylo/platform/host_call/trusted/host_calls.cc
Vulnerability: An arbitrary memory read vulnerability in Asylo versions up to 0.6.0 allows an untrusted attacker to make a call to enc_untrusted_read whose return size was not validated against the requrested size. The parameter size is unchecked allowing the attacker to read memory locations outside of the intended buffer size including memory addresses within the secure enclave. We recommend upgrading past commit b1d120a2c7d7446d2cc58d517e20a1b184b82200
Vulnerability ID: CVE-2020-8942
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/host_call/trusted/host_calls.cc
Commit message: Check for return size in enc_untrusted_read

Check return size does not exceed requested. The returned result and
content still cannot be trusted, but it's expected behavior when not
using a secure file system.

PiperOrigin-RevId: 333827386
Change-Id: I0bdec0aec9356ea333dc8c647eba5d2772875f29
Commit author: Chong Cai

Vulnerable version (before fix):
 int enc_untrusted_rename(const char *oldpath, const char *newpath) { }  ssize_t enc_untrusted_read(int fd, void *buf, size_t count) {   return static_cast<ssize_t>(EnsureInitializedAndDispatchSyscall(       asylo::system_call::kSYS_read, fd, buf, count)); }  ssize_t enc_untrusted_write(int fd, const void *buf, size_t count) {

Fixed version (after fix):
 int enc_untrusted_rename(const char *oldpath, const char *newpath) { }  ssize_t enc_untrusted_read(int fd, void *buf, size_t count) {   ssize_t ret = static_cast<ssize_t>(EnsureInitializedAndDispatchSyscall(       asylo::system_call::kSYS_read, fd, buf, count));   if (ret != -1 && ret > count) {     ::asylo::primitives::TrustedPrimitives::BestEffortAbort(         "enc_untrusted_read: read result exceeds requested");   }   return ret; }  ssize_t enc_untrusted_write(int fd, const void *buf, size_t count) {

Patch:
patch: @@ -226,8 +226,13 @@ int enc_untrusted_rename(const char *oldpath, const char *newpath) {
 }
 
 ssize_t enc_untrusted_read(int fd, void *buf, size_t count) {
-  return static_cast<ssize_t>(EnsureInitializedAndDispatchSyscall(
+  ssize_t ret = static_cast<ssize_t>(EnsureInitializedAndDispatchSyscall(
       asylo::system_call::kSYS_read, fd, buf, count));
+  if (ret != -1 && ret > count) {
+    ::asylo::primitives::TrustedPrimitives::BestEffortAbort(
+        "enc_untrusted_read: read result exceeds requested");
+  }
+  return ret;
 }
 
 ssize_t enc_untrusted_write(int fd, const void *buf, size_t count) {
path: asylo/platform/host_call/trusted/host_calls.cc
Vulnerability: An arbitrary memory read vulnerability in Asylo versions up to 0.6.0 allows an untrusted attacker to make a call to enc_untrusted_recvfrom whose return size was not validated against the requested size. The parameter size is unchecked allowing the attacker to read memory locations outside of the intended buffer size including memory addresses within the secure enclave. We recommend upgrading past commit 6e158d558abd3c29a0208e30c97c9a8c5bd4230f
Vulnerability ID: CVE-2020-8943
CWE: CWE-125
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/host_call/trusted/host_calls.cc
Commit message: Check for result of recvfrom

PiperOrigin-RevId: 333399155
Change-Id: I3d79e1e3f45f75d4c4360d42499e511d84b9aff7
Commit author: Chong Cai

Vulnerable version (before fix):
 ssize_t enc_untrusted_recvfrom(int sockfd, void *buf, size_t len, int flags,     return result;   }    auto buffer_received = output.next();   memcpy(buf, buffer_received.data(), std::min(len, buffer_received.size())); 

Fixed version (after fix):
 ssize_t enc_untrusted_recvfrom(int sockfd, void *buf, size_t len, int flags,     return result;   }    if (result > len) {     ::asylo::primitives::TrustedPrimitives::BestEffortAbort(         "enc_untrusted_recvfrom: result exceeds requested");   }    auto buffer_received = output.next();   memcpy(buf, buffer_received.data(), std::min(len, buffer_received.size())); 

Patch:
patch: @@ -981,6 +981,11 @@ ssize_t enc_untrusted_recvfrom(int sockfd, void *buf, size_t len, int flags,
     return result;
   }
 
+  if (result > len) {
+    ::asylo::primitives::TrustedPrimitives::BestEffortAbort(
+        "enc_untrusted_recvfrom: result exceeds requested");
+  }
+
   auto buffer_received = output.next();
   memcpy(buf, buffer_received.data(), std::min(len, buffer_received.size()));
path: asylo/platform/host_call/trusted/host_calls.cc
Vulnerability: An arbitrary memory write vulnerability in Asylo versions up to 0.6.0 allows an untrusted attacker to make a call to ecall_restore using the attribute output which fails to check the range of a pointer. An attacker can use this pointer to write to arbitrary memory addresses including those within the secure enclave We recommend upgrading past commit 382da2b8b09cbf928668a2445efb778f76bd9c8a
Vulnerability ID: CVE-2020-8944
CWE: CWE-787
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/primitives/sgx/ecalls.cc
Commit message: Check output of ecall_restore is outside enclave

PiperOrigin-RevId: 334265380
Change-Id: Ifbaead6bce56f01b2a4d69f53ca508d0138f6f61
Commit author: Chong Cai

Vulnerable version (before fix):
 int ecall_restore(const char *input, uint64_t input_len, char **output,   if (!asylo::primitives::TrustedPrimitives::IsOutsideEnclave(input,                                                               input_len) ||       !asylo::primitives::TrustedPrimitives::IsOutsideEnclave(           output_len, sizeof(uint64_t))) {     asylo::primitives::TrustedPrimitives::BestEffortAbort(         "ecall_restore: input/output found to not be in untrusted memory.");   }

Fixed version (after fix):
 int ecall_restore(const char *input, uint64_t input_len, char **output,   if (!asylo::primitives::TrustedPrimitives::IsOutsideEnclave(input,                                                               input_len) ||       !asylo::primitives::TrustedPrimitives::IsOutsideEnclave(           output_len, sizeof(uint64_t)) ||       !asylo::primitives::TrustedPrimitives::IsOutsideEnclave(output,                                                               *output_len)) {     asylo::primitives::TrustedPrimitives::BestEffortAbort(         "ecall_restore: input/output found to not be in untrusted memory.");   }

Patch:
patch: @@ -64,7 +64,9 @@ int ecall_restore(const char *input, uint64_t input_len, char **output,
   if (!asylo::primitives::TrustedPrimitives::IsOutsideEnclave(input,
                                                               input_len) ||
       !asylo::primitives::TrustedPrimitives::IsOutsideEnclave(
-          output_len, sizeof(uint64_t))) {
+          output_len, sizeof(uint64_t)) ||
+      !asylo::primitives::TrustedPrimitives::IsOutsideEnclave(output,
+                                                              *output_len)) {
     asylo::primitives::TrustedPrimitives::BestEffortAbort(
         "ecall_restore: input/output found to not be in untrusted memory.");
   }
path: asylo/platform/primitives/sgx/ecalls.cc
Vulnerability: A cross-site scripting (XSS) vulnerability was discovered in the Source Integration plugin before 1.6.2 and 2.x before 2.3.1 for MantisBT. The repo_delete.php Delete Repository page allows execution of arbitrary code via a repo name (if CSP settings permit it). This is related to CVE-2018-16362.
Vulnerability ID: CVE-2020-8981
CWE: CWE-79
Severity score: 2.9
Project: https://github.com/mantisbt-plugins/source-integration
Published: 2020-02-13
File: Source/pages/repo_delete.php
Commit message: Fix XSS in Delete Repository page

Fixes #338
Commit author: Damien Regad

Vulnerable version (before fix):
  $t_repo = SourceRepo::load( $f_repo_id );  helper_ensure_confirmed( sprintf( plugin_lang_get( 'ensure_delete' ), $t_repo->name ), plugin_lang_get( 'delete_repository' ) );  SourceRepo::delete( $t_repo->id ); 

Fixed version (after fix):
  $t_repo = SourceRepo::load( $f_repo_id );  $t_message = sprintf( plugin_lang_get( 'ensure_delete' ), string_attribute( $t_repo->name ) ); helper_ensure_confirmed( $t_message, plugin_lang_get( 'delete_repository' ) );  SourceRepo::delete( $t_repo->id ); 

Patch:
patch: @@ -10,7 +10,8 @@
 
 $t_repo = SourceRepo::load( $f_repo_id );
 
-helper_ensure_confirmed( sprintf( plugin_lang_get( 'ensure_delete' ), $t_repo->name ), plugin_lang_get( 'delete_repository' ) );
+$t_message = sprintf( plugin_lang_get( 'ensure_delete' ), string_attribute( $t_repo->name ) );
+helper_ensure_confirmed( $t_message, plugin_lang_get( 'delete_repository' ) );
 
 SourceRepo::delete( $t_repo->id );
path: Source/pages/repo_delete.php
Vulnerability: An issue was discovered in the Linux kernel 3.16 through 5.5.6. set_fdc in drivers/block/floppy.c leads to a wait_til_ready out-of-bounds read because the FDC index is not checked for errors before assigning it, aka CID-2e90ca68b0d2.
Vulnerability ID: CVE-2020-9383
CWE: CWE-125
Severity score: 4.9
Project: https://github.com/torvalds/linux
Published: 2020-02-25
File: drivers/block/floppy.c
Commit message: floppy: check FDC index for errors before assigning it

Jordy Zomer reported a KASAN out-of-bounds read in the floppy driver in
wait_til_ready().

Which on the face of it can't happen, since as Willy Tarreau points out,
the function does no particular memory access.  Except through the FDCS
macro, which just indexes a static allocation through teh current fdc,
which is always checked against N_FDC.

Except the checking happens after we've already assigned the value.

The floppy driver is a disgrace (a lot of it going back to my original
horrd "design"), and has no real maintainer.  Nobody has the hardware,
and nobody really cares.  But it still gets used in virtual environment
because it's one of those things that everybody supports.

The whole thing should be re-written, or at least parts of it should be
seriously cleaned up.  The 'current fdc' index, which is used by the
FDCS macro, and which is often shadowed by a local 'fdc' variable, is a
prime example of how not to write code.

But because nobody has the hardware or the motivation, let's just fix up
the immediate problem with a nasty band-aid: test the fdc index before
actually assigning it to the static 'fdc' variable.

Reported-by: Jordy Zomer <jordy@simplyhacker.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Commit author: Linus Torvalds

Vulnerable version (before fix):
 static void reset_fdc_info(int mode) /* selects the fdc and drive, and enables the fdc's input/dma. */ static void set_fdc(int drive) { 	if (drive >= 0 && drive < N_DRIVE) { 		fdc = FDC(drive); 		current_drive = drive; 	} 	if (fdc != 1 && fdc != 0) { 		pr_info("bad fdc value\n"); 		return; 	} 	set_dor(fdc, ~0, 8); #if N_FDC > 1 	set_dor(1 - fdc, ~8, 0);

Fixed version (after fix):
 static void reset_fdc_info(int mode) /* selects the fdc and drive, and enables the fdc's input/dma. */ static void set_fdc(int drive) { 	unsigned int new_fdc = fdc;  	if (drive >= 0 && drive < N_DRIVE) { 		new_fdc = FDC(drive); 		current_drive = drive; 	} 	if (new_fdc >= N_FDC) { 		pr_info("bad fdc value\n"); 		return; 	} 	fdc = new_fdc; 	set_dor(fdc, ~0, 8); #if N_FDC > 1 	set_dor(1 - fdc, ~8, 0);

Patch:
patch: @@ -853,14 +853,17 @@ static void reset_fdc_info(int mode)
 /* selects the fdc and drive, and enables the fdc's input/dma. */
 static void set_fdc(int drive)
 {
+	unsigned int new_fdc = fdc;
+
 	if (drive >= 0 && drive < N_DRIVE) {
-		fdc = FDC(drive);
+		new_fdc = FDC(drive);
 		current_drive = drive;
 	}
-	if (fdc != 1 && fdc != 0) {
+	if (new_fdc >= N_FDC) {
 		pr_info("bad fdc value\n");
 		return;
 	}
+	fdc = new_fdc;
 	set_dor(fdc, ~0, 8);
 #if N_FDC > 1
 	set_dor(1 - fdc, ~8, 0);
path: drivers/block/floppy.c
Vulnerability: kamadak-exif is an exif parsing library written in pure Rust. In kamadak-exif version 0.5.2, there is an infinite loop in parsing crafted PNG files. Specifically, reader::read_from_container can cause an infinite loop when a crafted PNG file is given. This is fixed in version 0.5.3. No workaround is available. Applications that do not pass files with the PNG signature to Reader::read_from_container are not affected.
Vulnerability ID: CVE-2021-21235
CWE: CWE-400
Severity score: 2.9
Project: https://github.com/kamadak/exif-rs
Published: 2021-01-06
File: src/util.rs
Commit message: Fix an infinite loop in reading PNG files.
Commit author: KAMADA Ken'ichi

Vulnerable version (before fix):
 impl<T> BufReadExt for T where T: io::BufRead {     fn discard_exact(&mut self, mut len: usize) -> io::Result<()> {         while len > 0 {             let consume_len = match self.fill_buf() {                 Ok(buf) => buf.len().min(len),                 Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,                 Err(e) => return Err(e), mod tests {     use std::io::Read;     use super::*;      #[test]     fn read8_len() {         let mut reader = Cursor::new([]);

Fixed version (after fix):
 impl<T> BufReadExt for T where T: io::BufRead {     fn discard_exact(&mut self, mut len: usize) -> io::Result<()> {         while len > 0 {             let consume_len = match self.fill_buf() {                 Ok(buf) if buf.is_empty() =>                     return Err(io::Error::new(                         io::ErrorKind::UnexpectedEof, "unexpected EOF")),                 Ok(buf) => buf.len().min(len),                 Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,                 Err(e) => return Err(e), mod tests {     use std::io::Read;     use super::*;      #[test]     fn discard_exact() {         let mut buf = b"abc".as_ref();         buf.discard_exact(1).unwrap();         assert_eq!(buf, b"bc");         buf.discard_exact(2).unwrap();         assert_eq!(buf, b"");         buf.discard_exact(1).unwrap_err();     }      #[test]     fn read8_len() {         let mut reader = Cursor::new([]);

Patch:
patch: @@ -56,6 +56,9 @@ impl<T> BufReadExt for T where T: io::BufRead {
     fn discard_exact(&mut self, mut len: usize) -> io::Result<()> {
         while len > 0 {
             let consume_len = match self.fill_buf() {
+                Ok(buf) if buf.is_empty() =>
+                    return Err(io::Error::new(
+                        io::ErrorKind::UnexpectedEof, "unexpected EOF")),
                 Ok(buf) => buf.len().min(len),
                 Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
                 Err(e) => return Err(e),
@@ -99,6 +102,16 @@ mod tests {
     use std::io::Read;
     use super::*;
 
+    #[test]
+    fn discard_exact() {
+        let mut buf = b"abc".as_ref();
+        buf.discard_exact(1).unwrap();
+        assert_eq!(buf, b"bc");
+        buf.discard_exact(2).unwrap();
+        assert_eq!(buf, b"");
+        buf.discard_exact(1).unwrap_err();
+    }
+
     #[test]
     fn read8_len() {
         let mut reader = Cursor::new([]);
path: src/util.rs