summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2019-10-12 16:58:38 +0200
committerChristophe Grenier <grenier@cgsecurity.org>2019-10-12 16:58:38 +0200
commitc315a2a6a73e8dcea9f14485082c2ad7e9118ceb (patch)
tree5c27c6fbca8b11b64a332ed588b82199873ab6c9
parente0e4d24cc959f4c270ebba548b8129e979dc47c7 (diff)
src/filegen.c: avoid recursive call in file_rename() and file_rename_unicode()
-rw-r--r--src/filegen.c123
-rw-r--r--src/filegen.h15
2 files changed, 136 insertions, 2 deletions
diff --git a/src/filegen.c b/src/filegen.c
index deba440..eb960cc 100644
--- a/src/filegen.c
+++ b/src/filegen.c
@@ -366,6 +366,72 @@ file_stat_t * init_file_stats(file_enable_t *files_enable)
return file_stats;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((const char*)&file_recovery->filename);
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
+static int file_rename_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+{
+ /* new_filename is large enough to avoid a buffer overflow */
+ char *new_filename;
+ const char *src=file_recovery->filename;
+ const char *ext=NULL;
+ char *dst;
+ char *directory_sep;
+ int len;
+ len=strlen(src)+1;
+ if(new_ext!=NULL)
+ len+=strlen(new_ext);
+ new_filename=(char*)MALLOC(len);
+ dst=new_filename;
+ directory_sep=new_filename;
+ while(*src!='\0')
+ {
+ if(*src=='/')
+ {
+ directory_sep=dst;
+ ext=NULL;
+ }
+ if(*src=='.')
+ ext=src;
+ *dst++ = *src++;
+ }
+ *dst='\0';
+ dst=directory_sep;
+ while(*dst!='.' && *dst!='\0')
+ dst++;
+ /* Add extension */
+ if(new_ext!=NULL)
+ {
+ src=new_ext;
+ *dst++ = '.';
+ while(*src!='\0')
+ *dst++ = *src++;
+ }
+ else if(append_original_ext>0)
+ {
+ if(ext!=NULL)
+ {
+ while(*ext!='\0')
+ *dst++ = *ext++;
+ }
+ }
+ *dst='\0';
+ if(rename(file_recovery->filename, new_filename)<0)
+ {
+ /* Rename has failed */
+ free(new_filename);
+ return -1;
+ }
+ if(strlen(new_filename)<sizeof(file_recovery->filename))
+ {
+ strcpy(file_recovery->filename, new_filename);
+ }
+ free(new_filename);
+ return 0;
+}
+
/* The original filename begins at offset in buffer and is null terminated */
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
@@ -473,7 +539,7 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
if(buffer==NULL)
return -1;
/* Try without the original filename */
- return file_rename(file_recovery, NULL, 0, 0, new_ext, append_original_ext);
+ return file_rename_aux(file_recovery, new_ext, append_original_ext);
}
if(strlen(new_filename)<sizeof(file_recovery->filename))
{
@@ -483,6 +549,59 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
return 0;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((const char*)&file_recovery->filename);
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
+static int file_rename_unicode_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+{
+ char *new_filename;
+ const char *src=file_recovery->filename;
+ const char *ext=src;
+ char *dst;
+ char *directory_sep;
+ unsigned int len=strlen(file_recovery->filename)+1;
+ /*@ assert len < sizeof(file_recovery->filename); */
+ if(new_ext!=NULL)
+ len+=strlen(new_ext);
+ if(len > sizeof(file_recovery->filename))
+ return -1;
+ new_filename=(char*)MALLOC(len);
+ strcpy(new_filename, (char *)&file_recovery->filename);
+ directory_sep=strrchr(file_recovery->filename, '/');
+ ext=strrchr(file_recovery->filename, '.');
+ /*@ assert directory_sep != \null; */
+#if 1
+ dst=directory_sep;
+ while(*dst!='.' && *dst!='\0')
+ dst++;
+ /* Add extension */
+ if(new_ext!=NULL)
+ {
+ src=new_ext;
+ *dst++ = '.';
+ while(*src!='\0')
+ *dst++ = *src++;
+ }
+ else if(append_original_ext>0)
+ {
+ while(*ext!='\0')
+ *dst++ = *ext++;
+ }
+ *dst='\0';
+#endif
+ if(rename(file_recovery->filename, new_filename)<0)
+ {
+ /* Rename has failed */
+ free(new_filename);
+ return -1;
+ }
+ strcpy(file_recovery->filename, new_filename);
+ free(new_filename);
+ return 0;
+}
+
/* The original filename begins at offset in buffer and is null terminated */
int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
@@ -583,7 +702,7 @@ int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, cons
if(buffer==NULL)
return -1;
/* Try without the original filename */
- return file_rename_unicode(file_recovery, NULL, 0, 0, new_ext, append_original_ext);
+ return file_rename_unicode_aux(file_recovery, new_ext, append_original_ext);
}
if(strlen(new_filename)<sizeof(file_recovery->filename))
{
diff --git a/src/filegen.h b/src/filegen.h
index 352a15e..d187fe9 100644
--- a/src/filegen.h
+++ b/src/filegen.h
@@ -133,8 +133,23 @@ void register_header_check(const unsigned int offset, const void *value, const u
const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new),
file_stat_t *file_stat);
file_stat_t * init_file_stats(file_enable_t *files_enable);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
+
void header_ignored_cond_reset(uint64_t start, uint64_t end);
void header_ignored(const file_recovery_t *file_recovery_new);
int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery_t *file_recovery_new);