@@ -540,7 +540,9 @@ static int parse_cheats(struct Cheats *cheats, FILE *file) {
540540
541541// return variations with/without extensions and other cruft
542542#define CHEAT_MAX_PATHS 16
543- #define CHEAT_MAX_LIST_LENGTH (CHEAT_MAX_PATHS * MAX_PATH)
543+ #define CHEAT_MAX_DISPLAY_PATHS 8
544+ // the list of displayed paths will be a bit shorter, we cant render that much text
545+ #define CHEAT_MAX_LIST_LENGTH (CHEAT_MAX_DISPLAY_PATHS * MAX_PATH)
544546static void Cheat_getPaths (char paths [CHEAT_MAX_PATHS ][MAX_PATH ], int * count ) {
545547 // Generate possible paths, ordered by most likely to be used (pre v6.2.3 style first)
546548 sprintf (paths [(* count )++ ], "%s/%s.cht" , core .cheats_dir , game .name ); // /mnt/SDCARD/Cheats/GB/Super Example World.<ext>.cht
@@ -553,14 +555,37 @@ static void Cheat_getPaths(char paths[CHEAT_MAX_PATHS][MAX_PATH], int* count) {
553555 int i = 0 ;
554556 char * ext ;
555557 char exts [128 ];
556- strcpy (exts ,core .extensions );
557- while ((ext = strtok (i ?NULL :exts ,"|" ))) {
558+ if (core .extensions == NULL || strlen (core .extensions ) >= sizeof (exts )) {
559+ LOG_info ("Invalid or too long core.extensions\n" );
560+ return ;
561+ }
562+
563+ strcpy (exts , core .extensions );
564+ while ((ext = strtok (i ? NULL : exts , "|" ))) {
565+ if (* count >= CHEAT_MAX_PATHS - 1 ) {
566+ LOG_info ("Maximum cheat paths reached, stopping\n" );
567+ break ;
568+ }
569+
558570 char rom_name [MAX_PATH ];
571+ if (strlen (game .alt_name ) >= MAX_PATH ) {
572+ LOG_info ("game.alt_name too long, skipping\n" );
573+ i ++ ;
574+ continue ;
575+ }
576+
559577 strcpy (rom_name , game .alt_name );
560578 char * tmp = strrchr (rom_name , '.' );
561579 if (tmp != NULL && strlen (tmp ) > 2 && strlen (tmp ) <= 5 ) {
562580 tmp [0 ] = '\0' ;
563- sprintf (paths [(* count )++ ], "%s/%s.%s.cht" , core .cheats_dir , rom_name , ext ); // /mnt/SDCARD/Cheats/GB/Super Example World (USA).foo.cht
581+
582+ // Add length check before sprintf to prevent buffer overflow
583+ int needed_len = strlen (core .cheats_dir ) + strlen (rom_name ) + strlen (ext ) + 10 ; // +10 for "/", ".", ".cht", etc.
584+ if (needed_len < MAX_PATH ) {
585+ sprintf (paths [(* count )++ ], "%s/%s.%s.cht" , core .cheats_dir , rom_name , ext );
586+ } else {
587+ LOG_info ("Path too long, skipping: %s/%s.%s.cht\n" , core .cheats_dir , rom_name , ext );
588+ }
564589 }
565590 i ++ ;
566591 }
@@ -573,7 +598,6 @@ static void Cheat_getPaths(char paths[CHEAT_MAX_PATHS][MAX_PATH], int* count) {
573598 char rom_name [MAX_PATH ];
574599 getDisplayName (game .alt_name , rom_name );
575600 sprintf (paths [(* count )++ ], "%s/%s.cht" , core .cheats_dir , rom_name ); // /mnt/SDCARD/Cheats/GB/Super Example World.cht
576-
577601 // Respect map.txt: use alias if available
578602 // eg. 1941.zip -> 1941: Counter Attack
579603 if (getAlias (game .path , rom_name ))
@@ -584,7 +608,6 @@ static void Cheat_getPaths(char paths[CHEAT_MAX_PATHS][MAX_PATH], int* count) {
584608 getDisplayName (game .alt_name , rom_name );
585609 getAlias (game .path , rom_name );
586610 sprintf (paths [(* count )++ ], "%s/%s*.cht" , core .cheats_dir , rom_name ); // /mnt/SDCARD/Cheats/GB/Super Example World*.cht
587-
588611 // Log all path candidates
589612 {
590613 int i ;
@@ -5612,15 +5635,41 @@ static int OptionCheats_openMenu(MenuList* list, int i) {
56125635 // concatenate all paths into one string, and prepend title "No cheat file loaded.\n\n"
56135636 // each path on its own line, and remove the absolute path prefix
56145637 char cheats_path [CHEAT_MAX_LIST_LENGTH ] = {0 };
5638+
5639+ // prepend title with bounds checking
5640+ const char * title = "No cheat file loaded.\n\n" ;
5641+ size_t title_len = strlen (title );
5642+
5643+ strcpy (cheats_path , title ); // Use strcpy for first string
5644+ size_t current_len = title_len ;
56155645
5616- // prepend title
5617- strcat (cheats_path , "No cheat file loaded.\n\n" );
5618-
5619- for (int i = 0 ; i < count ; i ++ ) {
5646+ for (int i = 0 ; i < count && i < CHEAT_MAX_DISPLAY_PATHS ; i ++ ) {
56205647 char * p = basename (paths [i ]);
5621- // append to cheats_path
5648+
5649+ // Check for NULL return from basename
5650+ if (p == NULL ) {
5651+ LOG_info ("basename() returned NULL for path: %s\n" , paths [i ]);
5652+ continue ;
5653+ }
5654+
5655+ size_t p_len = strlen (p );
5656+ size_t newline_len = (i < count - 1 ) ? 1 : 0 ; // "\n" length
5657+
5658+ // Check if adding this path would overflow the buffer
5659+ if (current_len + p_len + newline_len >= CHEAT_MAX_LIST_LENGTH ) {
5660+ LOG_info ("Cheats path buffer would overflow, truncating list\n" );
5661+ strcat (cheats_path , "..." );
5662+ break ;
5663+ }
5664+
5665+ // Safe to append
56225666 strcat (cheats_path , p );
5623- if (i < count - 1 ) strcat (cheats_path , "\n" );
5667+ current_len += p_len ;
5668+
5669+ if (i < count - 1 ) {
5670+ strcat (cheats_path , "\n" );
5671+ current_len += 1 ;
5672+ }
56245673 }
56255674
56265675 Menu_messageWithFont (cheats_path , (char * []){ "B" ,"BACK" , NULL }, font .small );
0 commit comments