[Toybox] [PATCH 2/2] Detect all errors with xreadall/xwrite.

Samanta Navarro ferivoz at riseup.net
Sat Aug 7 05:12:31 PDT 2021


If xreadall is called with SIZE_MAX as length, then no error is
detected.

The problem is that readall return value is not explicitly tested for
-1. If len is SIZE_MAX and readall returns -1, then the return value is
promoted to size_t and both values are considered to be equal.

It is unsafe to call xreadall with SIZE_MAX because it ultimately means
that no bound checking for buf is in place. 64 bit systems return EFAULT
when SIZE_MAX reads are performed but 32 bit systems actually start
reading!

I have added an if statement to protect 32 bit systems from such a read
by following style of 64 bit error handling.

The same logic applies to xwrite as well.
---
Proof of Concept (compile Toybox with ASAN=1):

cat > poc.tar.xz.b64 << EOF
/Td6WFoAAATm1rRGAgAhARwAAAAQz1jM4Cf/AGRdADedyhr9nOMBzEAy3Ecv/5ryFigBxe/ACXcH
zFn6/mBaXBzyT3AoV2CbUJCO0Th3OivX+tc868G+6vrnM9H+RXoklVlEq3qM8k/nFHmeMuvp4jlP
9rIYPbgGUyM+SMXXI1gbhQAAihVHNwEYT0EAAYABgFAAAD5xYGGxxGf7AgAAAAAEWVo=
EOF
base64 -d poc.tar.xz.b64 | xz -d > poc.tar

tar -tf poc.tar
---
 lib/xwrap.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/lib/xwrap.c b/lib/xwrap.c
index a58707cc..9d89efeb 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -512,6 +512,11 @@ size_t xread(int fd, void *buf, size_t len)
 
 void xreadall(int fd, void *buf, size_t len)
 {
+  // Avoid readall with invalid len on all architectures.
+  if (len == SIZE_MAX) {
+    errno = EFAULT;
+    perror_exit("xreadall");
+  }
   if (len != readall(fd, buf, len)) perror_exit("xreadall");
 }
 
@@ -521,6 +526,11 @@ void xreadall(int fd, void *buf, size_t len)
 
 void xwrite(int fd, void *buf, size_t len)
 {
+  // Avoid writeall with invalid len on all architectures.
+  if (len == SIZE_MAX) {
+    errno = EFAULT;
+    perror_exit("xwriteall");
+  }
   if (len != writeall(fd, buf, len)) perror_exit("xwrite");
 }
 
-- 
2.32.0



More information about the Toybox mailing list