Re: [Qemu-devel] [PATCH v3 5/8] block: Fix potential Null pointer dereferences in vvfat.c

2018-10-19 Thread Liam Merwick




On 12/10/18 16:14, Max Reitz wrote:

On 31.08.18 20:16, Liam Merwick wrote:

The calls to bdrv_new_open_driver(), find_mapping_for_cluster(),
and array_get_next() may return NULL but it isn't always checked for
before dereferencing the value returned.

Signed-off-by: Liam Merwick 
Reviewed-by: Darren Kenny 
Reviewed-by: Mark Kanda 
---
  block/vvfat.c | 56 
  1 file changed, 56 insertions(+)

diff --git a/block/vvfat.c b/block/vvfat.c
index fc41841a5c3c..0f1f10a2f94b 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -448,6 +448,9 @@ static direntry_t *create_long_filename(BDRVVVFATState *s, 
const char *filename)
  
  for(i=0;i
  entry=array_get_next(&(s->directory));
+if (entry == NULL) {
+continue;
+}


This is a bug in array_ensure_allocated().  It uses g_realloc() with a
non-zero size, so that function will never return NULL.  It will rather
abort().

Therefore, array_ensure_allocated() cannot fail.  Consequentially,
array_get_next() cannot fail.




I've reverted this (and the rest of the 'As above' comments below)



  entry->attributes=0xf;
  entry->reserved[0]=0;
  entry->begin=0;
@@ -665,6 +668,9 @@ static inline void fat_set(BDRVVVFATState* s,unsigned int 
cluster,uint32_t value
  } else {
  int offset = (cluster*3/2);
  unsigned char* p = array_get(&(s->fat), offset);
+if (p == NULL) {
+return;
+}


This is only reached if array_get_next() was called before.  Therefore,
this cannot return NULL.

However, an assert(array->pointer); in array_get() can't hurt.



Done.




  switch (cluster&1) {
  case 0:
  p[0] = value&0xff;
@@ -730,6 +736,9 @@ static inline direntry_t* 
create_short_and_long_name(BDRVVVFATState* s,
  
  if(is_dot) {

  entry=array_get_next(&(s->directory));
+if (entry == NULL) {
+return NULL;
+}


As above.


  memset(entry->name, 0x20, sizeof(entry->name));
  memcpy(entry->name,filename,strlen(filename));
  return entry;
@@ -844,6 +853,12 @@ static int read_directory(BDRVVVFATState* s, int 
mapping_index)
  /* create mapping for this file */
  if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
  s->current_mapping = array_get_next(&(s->mapping));
+if (s->current_mapping == NULL) {
+fprintf(stderr, "Failed to create mapping for file\n");
+g_free(buffer);
+closedir(dir);
+return -2;
+}


As above.


  s->current_mapping->begin=0;
  s->current_mapping->end=st.st_size;
  /*
@@ -941,6 +956,9 @@ static int init_directories(BDRVVVFATState* s,
  /* add volume label */
  {
  direntry_t* entry=array_get_next(&(s->directory));
+if (entry == NULL) {
+return -1;
+}


As above.


  entry->attributes=0x28; /* archive | volume label */
  memcpy(entry->name, s->volume_label, sizeof(entry->name));
  }
@@ -953,6 +971,9 @@ static int init_directories(BDRVVVFATState* s,
  s->cluster_count=sector2cluster(s, s->sector_count);
  
  mapping = array_get_next(&(s->mapping));

+if (mapping == NULL) {
+return -1;
+}


As above.


  mapping->begin = 0;
  mapping->dir_index = 0;
  mapping->info.dir.parent_mapping_index = -1;
@@ -1630,6 +1651,9 @@ static void schedule_rename(BDRVVVFATState* s,
  uint32_t cluster, char* new_path)
  {
  commit_t* commit = array_get_next(&(s->commits));
+if (commit == NULL) {
+return;
+}


As above.


  commit->path = new_path;
  commit->param.rename.cluster = cluster;
  commit->action = ACTION_RENAME;
@@ -1639,6 +1663,9 @@ static void schedule_writeout(BDRVVVFATState* s,
  int dir_index, uint32_t modified_offset)
  {
  commit_t* commit = array_get_next(&(s->commits));
+if (commit == NULL) {
+return;
+}


As above.


  commit->path = NULL;
  commit->param.writeout.dir_index = dir_index;
  commit->param.writeout.modified_offset = modified_offset;
@@ -1649,6 +1676,9 @@ static void schedule_new_file(BDRVVVFATState* s,
  char* path, uint32_t first_cluster)
  {
  commit_t* commit = array_get_next(&(s->commits));
+if (commit == NULL) {
+return;
+}


As above.


  commit->path = path;
  commit->param.new_file.first_cluster = first_cluster;
  commit->action = ACTION_NEW_FILE;
@@ -1657,6 +1687,9 @@ static void schedule_new_file(BDRVVVFATState* s,
  static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
  {
  commit_t* commit = array_get_next(&(s->commits));
+if (commit == NULL) {
+return;
+}



As above.


  commit->path = path;
  commit->param.mkdir.cluster = cluster;
  commit->action = 

Re: [Qemu-devel] [PATCH v3 5/8] block: Fix potential Null pointer dereferences in vvfat.c

2018-10-12 Thread Max Reitz
On 31.08.18 20:16, Liam Merwick wrote:
> The calls to bdrv_new_open_driver(), find_mapping_for_cluster(),
> and array_get_next() may return NULL but it isn't always checked for
> before dereferencing the value returned.
> 
> Signed-off-by: Liam Merwick 
> Reviewed-by: Darren Kenny 
> Reviewed-by: Mark Kanda 
> ---
>  block/vvfat.c | 56 
>  1 file changed, 56 insertions(+)
> 
> diff --git a/block/vvfat.c b/block/vvfat.c
> index fc41841a5c3c..0f1f10a2f94b 100644
> --- a/block/vvfat.c
> +++ b/block/vvfat.c
> @@ -448,6 +448,9 @@ static direntry_t *create_long_filename(BDRVVVFATState 
> *s, const char *filename)
>  
>  for(i=0;i  entry=array_get_next(&(s->directory));
> +if (entry == NULL) {
> +continue;
> +}

This is a bug in array_ensure_allocated().  It uses g_realloc() with a
non-zero size, so that function will never return NULL.  It will rather
abort().

Therefore, array_ensure_allocated() cannot fail.  Consequentially,
array_get_next() cannot fail.

>  entry->attributes=0xf;
>  entry->reserved[0]=0;
>  entry->begin=0;
> @@ -665,6 +668,9 @@ static inline void fat_set(BDRVVVFATState* s,unsigned int 
> cluster,uint32_t value
>  } else {
>  int offset = (cluster*3/2);
>  unsigned char* p = array_get(&(s->fat), offset);
> +if (p == NULL) {
> +return;
> +}

This is only reached if array_get_next() was called before.  Therefore,
this cannot return NULL.

However, an assert(array->pointer); in array_get() can't hurt.

>  switch (cluster&1) {
>  case 0:
>  p[0] = value&0xff;
> @@ -730,6 +736,9 @@ static inline direntry_t* 
> create_short_and_long_name(BDRVVVFATState* s,
>  
>  if(is_dot) {
>  entry=array_get_next(&(s->directory));
> +if (entry == NULL) {
> +return NULL;
> +}

As above.

>  memset(entry->name, 0x20, sizeof(entry->name));
>  memcpy(entry->name,filename,strlen(filename));
>  return entry;
> @@ -844,6 +853,12 @@ static int read_directory(BDRVVVFATState* s, int 
> mapping_index)
>  /* create mapping for this file */
>  if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
>  s->current_mapping = array_get_next(&(s->mapping));
> +if (s->current_mapping == NULL) {
> +fprintf(stderr, "Failed to create mapping for file\n");
> +g_free(buffer);
> +closedir(dir);
> +return -2;
> +}

As above.

>  s->current_mapping->begin=0;
>  s->current_mapping->end=st.st_size;
>  /*
> @@ -941,6 +956,9 @@ static int init_directories(BDRVVVFATState* s,
>  /* add volume label */
>  {
>  direntry_t* entry=array_get_next(&(s->directory));
> +if (entry == NULL) {
> +return -1;
> +}

As above.

>  entry->attributes=0x28; /* archive | volume label */
>  memcpy(entry->name, s->volume_label, sizeof(entry->name));
>  }
> @@ -953,6 +971,9 @@ static int init_directories(BDRVVVFATState* s,
>  s->cluster_count=sector2cluster(s, s->sector_count);
>  
>  mapping = array_get_next(&(s->mapping));
> +if (mapping == NULL) {
> +return -1;
> +}

As above.

>  mapping->begin = 0;
>  mapping->dir_index = 0;
>  mapping->info.dir.parent_mapping_index = -1;
> @@ -1630,6 +1651,9 @@ static void schedule_rename(BDRVVVFATState* s,
>  uint32_t cluster, char* new_path)
>  {
>  commit_t* commit = array_get_next(&(s->commits));
> +if (commit == NULL) {
> +return;
> +}

As above.

>  commit->path = new_path;
>  commit->param.rename.cluster = cluster;
>  commit->action = ACTION_RENAME;
> @@ -1639,6 +1663,9 @@ static void schedule_writeout(BDRVVVFATState* s,
>  int dir_index, uint32_t modified_offset)
>  {
>  commit_t* commit = array_get_next(&(s->commits));
> +if (commit == NULL) {
> +return;
> +}

As above.

>  commit->path = NULL;
>  commit->param.writeout.dir_index = dir_index;
>  commit->param.writeout.modified_offset = modified_offset;
> @@ -1649,6 +1676,9 @@ static void schedule_new_file(BDRVVVFATState* s,
>  char* path, uint32_t first_cluster)
>  {
>  commit_t* commit = array_get_next(&(s->commits));
> +if (commit == NULL) {
> +return;
> +}

As above.

>  commit->path = path;
>  commit->param.new_file.first_cluster = first_cluster;
>  commit->action = ACTION_NEW_FILE;
> @@ -1657,6 +1687,9 @@ static void schedule_new_file(BDRVVVFATState* s,
>  static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
>  {
>  commit_t* commit = array_get_next(&(s->commits));
> +if (commit == NULL) {
> +return;
> +}


As above.

>  commit->path = path;
>  commit->param.mkdir.cluster =