CVE-2017-9949: Out-of-bounds Write (CWE-787)
value: The grub_memmove function in shlr/grub/kern/misc.c in radare2 1.5.0 allows remote attackers to cause a denial of service (stack-based buffer underflow and application crash) or possibly have unspecified other impact via a crafted binary file, possibly related to a buffer underflow in fs/ext2.c in GNU GRUB 2.02.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2017-06-26T20:29Z
Repository: https://github.com/radare/radare2
Language: C
Files changed: shlr/Makefile, shlr/gdb/src/gdbserver/core.c, shlr/grub/fs/ext2.c, shlr/grub/fs/fshelp.c, sys/rebuild.sh
Commit date: 2017-06-05 12:38:39 +0200
Commit message: Fix ext2 buffer overflow in r2_sbu_grub_memmove

Diff: diff --git a/shlr/Makefile b/shlr/Makefile
index 5d2f3c62675..65b0f079715 100644
--- a/shlr/Makefile
+++ b/shlr/Makefile
@@ -21,13 +21,13 @@ CS_TAR=https://codeload.github.com/aquynh/capstone/tar.gz/$(CS_VER)
 #CS_TAR=http://capstone-engine.org/download/$(CS_VER)/capstone-$(CS_VER).tgz
 CS_PATCHES=0
 else
 CS_TAR=
 CS_URL=$(GIT_PREFIX)github.com/aquynh/capstone.git
-CS_UPD=20170529
+CS_UPD=20170605
 CS_BRA=next
-CS_TIP=7982670984222e2d3bb8117da6225e06d119f56f
+CS_TIP=1910fd563539fba8498f07a36a0e74cfbdf42a7f
 # REVERT THIS COMMIT BECAUSE ITS WRONG
 CS_REV=
 CS_PATCHES=1
 endif
 
diff --git a/shlr/gdb/src/gdbserver/core.c b/shlr/gdb/src/gdbserver/core.c
index 3ac378d348c..a6a2faaa9bf 100644
--- a/shlr/gdb/src/gdbserver/core.c
+++ b/shlr/gdb/src/gdbserver/core.c
@@ -180,10 +180,11 @@ static int _server_handle_vCont(libgdbr_t *g, int (*cmd_cb) (void*, const char*,
 		default:
 			// TODO support others
 			return send_msg (g, "E01");
 		}
 	}
+	return -1;
 }
 
 static int _server_handle_qAttached(libgdbr_t *g, int (*cmd_cb) (void*, const char*, char*, size_t), void *core_ptr) {
 	if (send_ack (g) < 0) {
 		return -1;
diff --git a/shlr/grub/fs/ext2.c b/shlr/grub/fs/ext2.c
index aa455c7fb45..22a0057c13b 100644
--- a/shlr/grub/fs/ext2.c
+++ b/shlr/grub/fs/ext2.c
@@ -430,14 +430,14 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
           grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
           return -1;
         }
     }
   /* Direct blocks.  */
-  if (fileblock < INDIRECT_BLOCKS)
+  if (fileblock < INDIRECT_BLOCKS) {
     blknr = grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]);
   /* Indirect.  */
-  else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
+  } else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
     {
       grub_uint32_t *indir;
 
       indir = grub_malloc (blksz);
       if (! indir)
@@ -677,27 +677,30 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir,
       if (dirent.direntlen == 0)
         return 0;
 
       if (dirent.namelen != 0)
 	{
-#ifndef _MSC_VER
-	  char filename[dirent.namelen + 1]; 
-#else
 	  char * filename = grub_malloc (dirent.namelen + 1);
-#endif
 	  struct grub_fshelp_node *fdiro;
 	  enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
 
+if (!filename) {
+break;
+}
 	  grub_ext2_read_file (diro, 0, 0, 0,
 			       fpos + sizeof (struct ext2_dirent),
 			       dirent.namelen, filename);
-	  if (grub_errno)
+	  if (grub_errno) {
+            free (filename);
 	    return 0;
+	  }
 
 	  fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
-	  if (! fdiro)
+	  if (! fdiro) {
+            free (filename);
 	    return 0;
+          }
 
 	  fdiro->data = diro->data;
 	  fdiro->ino = grub_le_to_cpu32 (dirent.inode);
 
 	  filename[dirent.namelen] = '\0';
@@ -718,12 +721,12 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir,
 	      /* The filetype can not be read from the dirent, read
 		 the inode to get more information.  */
 	      grub_ext2_read_inode (diro->data,
                                     grub_le_to_cpu32 (dirent.inode),
 				    &fdiro->inode);
-	      if (grub_errno)
-		{
+	      if (grub_errno) {
+                  free (filename);
 		  grub_free (fdiro);
 		  return 0;
 		}
 
 	      fdiro->inode_read = 1;
@@ -737,12 +740,15 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir,
 	      else if ((grub_le_to_cpu16 (fdiro->inode.mode)
 			& FILETYPE_INO_MASK) == FILETYPE_INO_REG)
 		type = GRUB_FSHELP_REG;
 	    }
 
-	  if (hook (filename, type, fdiro, closure))
+	  if (hook (filename, type, fdiro, closure)) {
+            free (filename);
 	    return 1;
+          }
+          free (filename);
 	}
 
       fpos += grub_le_to_cpu16 (dirent.direntlen);
     }
 
diff --git a/shlr/grub/fs/fshelp.c b/shlr/grub/fs/fshelp.c
index 06b99ae8261..338f309997e 100644
--- a/shlr/grub/fs/fshelp.c
+++ b/shlr/grub/fs/fshelp.c
@@ -285,10 +285,14 @@ grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
 
   /* Adjust LEN so it we can't read past the end of the file.  */
   if (pos + len > filesize)
     len = filesize - pos;
 
+  if (len < 1 || len == 0xffffffff) {
+    return -1;
+  }
+
   blockcnt = ((len + pos) + blocksize - 1) >>
     (log2blocksize + GRUB_DISK_SECTOR_BITS);
 
   for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++)
     {
diff --git a/sys/rebuild.sh b/sys/rebuild.sh
index 35003be1cd7..24f4dd246cc 100755
--- a/sys/rebuild.sh
+++ b/sys/rebuild.sh
@@ -53,10 +53,15 @@ RebuildCapstone() {
 RebuildSdb() {
 	Rebuild shlr/sdb
 	Rebuild libr/util
 }
 
+RebuildFs() {
+	Rebuild shlr/grub
+	Rebuild libr/fs
+}
+
 RebuildBin() {
 	Rebuild libr/bin
 	Rebuild libr/core
 }
 
@@ -65,10 +70,11 @@ RebuildGdb() {
 	Rebuild libr/io
 	Rebuild libr/debug
 }
 
 case "$1" in
+fs)     RebuildFs; ;;
 bin)    RebuildBin ; ;;
 gdb)    RebuildGdb ; ;;
 sdb)    RebuildSdb ; ;;
 spp)    RebuildSpp ; ;;
 bin)    RebuildBin ; ;;

Vulnerable code: CS_UPD=20170529
CS_TIP=7982670984222e2d3bb8117da6225e06d119f56f
  if (fileblock < INDIRECT_BLOCKS)
  else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
#ifndef _MSC_VER
	  char filename[dirent.namelen + 1]; 
#else
#endif
	  if (grub_errno)
	  if (! fdiro)
	      if (grub_errno)
		{
	  if (hook (filename, type, fdiro, closure))
Fixed code: CS_UPD=20170605
CS_TIP=1910fd563539fba8498f07a36a0e74cfbdf42a7f
	return -1;
  if (fileblock < INDIRECT_BLOCKS) {
  } else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
if (!filename) {
break;
}
	  if (grub_errno) {
            free (filename);
	  }
	  if (! fdiro) {
            free (filename);
          }
	      if (grub_errno) {
                  free (filename);
	  if (hook (filename, type, fdiro, closure)) {
            free (filename);
          }
          free (filename);
  if (len < 1 || len == 0xffffffff) {
    return -1;
  }

RebuildFs() {
	Rebuild shlr/grub
	Rebuild libr/fs
}

fs)     RebuildFs; ;;