[PATCH] imfs: Fix index underrun when extending empty file

Christian Mauderer christian.mauderer at embedded-brains.de
Mon Apr 4 14:23:52 UTC 2022


Currently the following sequence causes a endless loop when extending an
IMFS file:

- Create a file with zero length and close it.
- Make sure nearly no allocatable memory is left.
- Open the file and write enough data into it that more than the
  remaining memory will be used.

In that case when extending the IMFS file, the file currently need zero
blocks. If allocating enough new blocks fails, the already allocated new
blocks will be freed again.

The comparison of block>=old_blocks that has been used prior to this
patch compared two unsigned numbers. If old_blocks was zero, the
comparison of these two numbers always evaluated to true.

This patch frees the last block in a separate step to avoid this
problem.

Fixes #4639
---
 cpukit/libfs/src/imfs/imfs_memfile.c |  3 ++-
 testsuites/psxtests/psximfs02/init.c | 30 +++++++++++++++++++++++++++-
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/cpukit/libfs/src/imfs/imfs_memfile.c b/cpukit/libfs/src/imfs/imfs_memfile.c
index 23c7192717..769a570ecf 100644
--- a/cpukit/libfs/src/imfs/imfs_memfile.c
+++ b/cpukit/libfs/src/imfs/imfs_memfile.c
@@ -208,9 +208,10 @@ static int IMFS_memfile_extend(
           offset = 0;
        }
     } else {
-       for ( ; block>=old_blocks ; block-- ) {
+       for ( ; block>old_blocks ; block-- ) {
          IMFS_memfile_remove_block( memfile, block );
        }
+       IMFS_memfile_remove_block( memfile, old_blocks );
        rtems_set_errno_and_return_minus_one( ENOSPC );
     }
   }
diff --git a/testsuites/psxtests/psximfs02/init.c b/testsuites/psxtests/psximfs02/init.c
index 15b9137121..04f806f565 100644
--- a/testsuites/psxtests/psximfs02/init.c
+++ b/testsuites/psxtests/psximfs02/init.c
@@ -23,6 +23,8 @@
 #include <rtems/malloc.h>
 #include <rtems/libcsupport.h>
 
+#define MEMFILE_BYTES_PER_BLOCK 16
+
 const char rtems_test_name[] = "PSXIMFS 2";
 
 /* forward declarations to avoid warnings */
@@ -43,12 +45,17 @@ rtems_task Init(
   static const uintptr_t slink_2_name_size [] = {
     sizeof( slink_2_name )
   };
+  static const uintptr_t some_blocks [] = {
+    MEMFILE_BYTES_PER_BLOCK * 10
+  };
+  static const char some_data[MEMFILE_BYTES_PER_BLOCK * 11];
 
   int status = 0;
   void *opaque;
   char linkname_n[32] = {0};
   char linkname_p[32] = {0};
   int i;
+  int fd;
   struct stat stat_buf;
 
   TEST_BEGIN();
@@ -102,6 +109,27 @@ rtems_task Init(
   rtems_test_assert( status == -1 );
   rtems_test_assert( errno == EACCES );
 
+  puts( "Allocate most of heap with a little bit left" );
+  opaque = rtems_heap_greedy_allocate( some_blocks, 1 );
+
+  puts( "Create an empty file.");
+  status = mknod( "/foo", S_IFREG | S_IRWXU, 0LL );
+  rtems_test_assert( status == 0 );
+
+  puts( "Then increase it's size to more than remaining space" );
+  fd = open( "/foo", O_WRONLY | O_TRUNC);
+  rtems_test_assert( fd >= 0 );
+  status = write(fd, some_data, sizeof(some_data));
+  rtems_test_assert( status == -1);
+  rtems_test_assert( errno == ENOSPC );
+
+  puts( "Clean up again" );
+  status = close(fd);
+  rtems_test_assert( status == 0);
+  status = remove( "/foo" );
+  rtems_test_assert( status == 0);
+  rtems_heap_greedy_free( opaque );
+
   puts( "Allocate most of heap" );
   opaque = rtems_heap_greedy_allocate( mount_table_entry_size, 1 );
 
@@ -202,7 +230,7 @@ rtems_task Init(
 #define CONFIGURE_FILESYSTEM_IMFS
 
 #define CONFIGURE_MAXIMUM_TASKS                  1
-#define CONFIGURE_IMFS_MEMFILE_BYTES_PER_BLOCK   16
+#define CONFIGURE_IMFS_MEMFILE_BYTES_PER_BLOCK   MEMFILE_BYTES_PER_BLOCK
 #define CONFIGURE_IMFS_ENABLE_MKFIFO
 #define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
-- 
2.34.1



More information about the devel mailing list