CVE-2023-34095: Stack-based Buffer Overflow (CWE-121)
value: cpdb-libs provides frontend and backend libraries for the Common Printing Dialog Backends (CPDB) project. In versions 1.0 through 2.0b4, cpdb-libs is vulnerable to buffer overflows via improper use of `scanf(3)`. cpdb-libs uses the `fscanf()` and `scanf()` functions to parse command lines and configuration files, dropping the read string components into fixed-length buffers, but does not limit the length of the strings to be read by `fscanf()` and `scanf()` causing buffer overflows when a string is longer than 1023 characters. A patch for this issue is available at commit f181bd1f14757c2ae0f17cc76dc20421a40f30b7. As all buffers have a length of 1024 characters, the patch limits the maximum string length to be read to 1023 by replacing all occurrences of `%s` with `%1023s` in all calls of the `fscanf()` and `scanf()` functions.

CWE description: A stack-based buffer overflow condition is a condition where the buffer being overwritten is allocated on the stack (i.e., is a local variable or, rarely, a parameter to a function).
CVSS v3 base score: 9.8
Published: 2023-06-14T17:15Z
Repository: https://github.com/OpenPrinting/cpdb-libs
Language: C
Files changed: cpdb/cpdb-frontend.c, tools/cpdb-text-frontend.c
Commit date: 2023-06-14 18:45:28 +0200
Commit message: Merge pull request from GHSA-25j7-9gfc-f46x

cpdb-libs uses the fscanf() and scanf() functions to parse command
lines and configuration files, dropping the read string components
into fixed-length buffers, but does not limit the length of the
strings to be read by fscanf() and scanf() causing buffer overflows
when a string is longer than 1023 characters.

As all buffers have a length of 1024 characters we limit the maximum string
length to be read to 1023 by replaceing all occurences of "%s" by "%1023s"
in all calls of the fscanf() and scanf() functions.

Simply done by

perl -p -i -e 's/(scanf\(.*?".*?)%s/\1%1023s/' cpdb/cpdb-frontend.c tools/cpdb-text-frontend.c

and verifying with

grep scanf */*.c
Diff: diff --git a/cpdb/cpdb-frontend.c b/cpdb/cpdb-frontend.c
index e650140..ed391ea 100644
--- a/cpdb/cpdb-frontend.c
+++ b/cpdb/cpdb-frontend.c
@@ -389,11 +389,11 @@ PrintBackend *cpdbCreateBackendFromFile(GDBusConnection *connection,
         logerror("Error creating backend %s : Couldn't open %s for reading\n",
                     backend_name, path);
         free(path);
         return NULL;
     }
-    if (fscanf(file, "%s", obj_path) == 0)
+    if (fscanf(file, "%1023s", obj_path) == 0)
     {
         logerror("Error creating backend %s : Couldn't parse %s\n",
                     backend_name, path);
         free(path);
         fclose(file);
diff --git a/tools/cpdb-text-frontend.c b/tools/cpdb-text-frontend.c
index 3f9bfc1..518aef5 100644
--- a/tools/cpdb-text-frontend.c
+++ b/tools/cpdb-text-frontend.c
@@ -157,11 +157,11 @@ gpointer parse_commands(gpointer user_data)
     char buf[BUFSIZE];
     while (1)
     {
         printf("> ");
         fflush(stdout);
-        scanf("%s", buf);
+        scanf("%1023s", buf);
         if (strcmp(buf, "stop") == 0)
         {
             cpdbDeleteFrontendObj(f);
             g_message("Stopping front end..\n");
             exit(0);
@@ -193,11 +193,11 @@ gpointer parse_commands(gpointer user_data)
         }
         else if (strcmp(buf, "get-all-options") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             g_message("Getting all attributes ..\n");
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
 
             if(p == NULL)
               continue;
@@ -216,11 +216,11 @@ gpointer parse_commands(gpointer user_data)
         }
         else if (strcmp(buf, "get-all-media") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             g_message("Getting all attributes ..\n");
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
 
             if(p == NULL)
               continue;
@@ -238,79 +238,79 @@ gpointer parse_commands(gpointer user_data)
             }
         }
         else if (strcmp(buf, "get-default") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE];
-            scanf("%s%s%s", option_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             char *ans = cpdbGetDefault(p, option_name);
             if (!ans)
                 printf("cpdb_option_t %s doesn't exist.", option_name);
             else
                 printf("Default : %s\n", ans);
         }
         else if (strcmp(buf, "get-setting") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE], setting_name[BUFSIZE];
-            scanf("%s%s%s", setting_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", setting_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             char *ans = cpdbGetSetting(p, setting_name);
             if (!ans)
                 printf("Setting %s doesn't exist.\n", setting_name);
             else
                 printf("Setting value : %s\n", ans);
         }
         else if (strcmp(buf, "get-current") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE];
-            scanf("%s%s%s", option_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             char *ans = cpdbGetCurrent(p, option_name);
             if (!ans)
                 printf("cpdb_option_t %s doesn't exist.", option_name);
             else
                 printf("Current value : %s\n", ans);
         }
         else if (strcmp(buf, "add-setting") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE], option_val[BUFSIZE];
-            scanf("%s %s %s %s", option_name, option_val, printer_id, backend_name);
+            scanf("%1023s %1023s %1023s %1023s", option_name, option_val, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("%s : %s\n", option_name, option_val);
             cpdbAddSettingToPrinter(p, cpdbGetStringCopy(option_name), cpdbGetStringCopy(option_val));
         }
         else if (strcmp(buf, "clear-setting") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE];
-            scanf("%s%s%s", option_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             cpdbClearSettingFromPrinter(p, option_name);
         }
         else if (strcmp(buf, "get-state") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("%s\n", cpdbGetState(p));
         }
         else if (strcmp(buf, "is-accepting-jobs") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("Accepting jobs ? : %d \n", cpdbIsAcceptingJobs(p));
         }
         else if (strcmp(buf, "help") == 0)
         {
             display_help();
         }
         else if (strcmp(buf, "ping") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             print_backend_call_ping_sync(p->backend_proxy, p->id, NULL, NULL);
         }
         else if (strcmp(buf, "get-default-printer") == 0)
         {
@@ -321,11 +321,11 @@ gpointer parse_commands(gpointer user_data)
                 printf("No default printer found\n");
         }
         else if (strcmp(buf, "get-default-printer-for-backend") == 0)
         {
             char backend_name[BUFSIZE];
-            scanf("%s", backend_name);
+            scanf("%1023s", backend_name);
             /**
              * Backend name = The last part of the backend dbus service
              * Eg. "CUPS" or "GCP"
              */
             cpdb_printer_obj_t *p = cpdbGetDefaultPrinterForBackend(f, backend_name);
@@ -333,11 +333,11 @@ gpointer parse_commands(gpointer user_data)
         }
         else if (strcmp(buf, "set-user-default-printer") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             if (p)
             {
                 if (cpdbSetUserDefaultPrinter(p))
                     printf("Set printer as user default\n");
@@ -347,11 +347,11 @@ gpointer parse_commands(gpointer user_data)
         }
         else if (strcmp(buf, "set-system-default-printer") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             if (p)
             {
                 if (cpdbSetSystemDefaultPrinter(p))
                     printf("Set printer as system default\n");
@@ -360,21 +360,21 @@ gpointer parse_commands(gpointer user_data)
             }
         }
         else if (strcmp(buf, "print-file") == 0)
         {
             char printer_id[BUFSIZE], backend_name[BUFSIZE], file_path[BUFSIZE];
-            scanf("%s%s%s", file_path, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", file_path, printer_id, backend_name);
             /**
              * Try adding some settings here .. change them and experiment
              */
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
 
             if(strcmp(backend_name, "FILE") == 0)
             {
               char final_file_path[BUFSIZE];
               printf("Please give the final file path: ");
-              scanf("%s", final_file_path);
+              scanf("%1023s", final_file_path);
               cpdbPrintFilePath(p, file_path, final_file_path);
               continue;
             }
 
             cpdbAddSettingToPrinter(p, "copies", "3");
@@ -382,11 +382,11 @@ gpointer parse_commands(gpointer user_data)
         }
         else if (strcmp(buf, "get-active-jobs-count") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("%d jobs currently active.\n", cpdbGetActiveJobsCount(p));
         }
         else if (strcmp(buf, "get-all-jobs") == 0)
         {
@@ -404,11 +404,11 @@ gpointer parse_commands(gpointer user_data)
         else if (strcmp(buf, "cancel-job") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char job_id[BUFSIZE];
-            scanf("%s%s%s", job_id, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", job_id, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             if (cpdbCancelJob(p, job_id))
                 printf("cpdb_job_t %s has been cancelled.\n", job_id);
             else
                 printf("Unable to cancel job %s\n", job_id);
@@ -416,69 +416,69 @@ gpointer parse_commands(gpointer user_data)
         else if (strcmp(buf, "pickle-printer") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char job_id[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             cpdbPicklePrinterToFile(p, "/tmp/.printer-pickle", f);
         }
         else if (strcmp(buf, "get-option-translation") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char option_name[BUFSIZE];
-            scanf("%s%s%s", option_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("%s\n", cpdbGetOptionTranslation(p, option_name, locale));
         }
         else if (strcmp(buf, "get-choice-translation") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char option_name[BUFSIZE];
             char choice_name[BUFSIZE];
-            scanf("%s%s%s%s", option_name, choice_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s%1023s", option_name, choice_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("%s\n", cpdbGetChoiceTranslation(p, option_name, choice_name, locale));
         }
         else if (strcmp(buf, "get-group-translation") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char group_name[BUFSIZE];
-            scanf("%s%s%s", group_name, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", group_name, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             printf("%s\n", cpdbGetGroupTranslation(p, group_name, locale));
         }
         else if (strcmp(buf, "get-all-translations") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             cpdbGetAllTranslations(p, locale);
             printTranslations(p);
         }
         else if (strcmp(buf, "get-media-size") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char media[BUFSIZE];
             int width, length;
-            scanf("%s%s%s", media, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", media, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             int ok = cpdbGetMediaSize(p, media, &width, &length);
             if (ok)
                 printf("%dx%d\n", width, length);
         }
         else if (strcmp(buf, "get-media-margins") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
             char media[BUFSIZE];
-            scanf("%s%s%s", media, printer_id, backend_name);
+            scanf("%1023s%1023s%1023s", media, printer_id, backend_name);
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
 
             cpdb_margin_t *margins;
             int num_margins = cpdbGetMediaMargins(p, media, &margins);
             for (int i = 0; i < num_margins; i++)
@@ -486,11 +486,11 @@ gpointer parse_commands(gpointer user_data)
         }
         else if (strcmp(buf, "acquire-details") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             if(p == NULL)
               continue;
 
@@ -499,11 +499,11 @@ gpointer parse_commands(gpointer user_data)
 		}
         else if (strcmp(buf, "acquire-translations") == 0)
         {
             char printer_id[BUFSIZE];
             char backend_name[BUFSIZE];
-            scanf("%s%s", printer_id, backend_name);
+            scanf("%1023s%1023s", printer_id, backend_name);
             
             cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name);
             if(p == NULL)
               continue;
 

Vulnerable code:     if (fscanf(file, "%s", obj_path) == 0)
        scanf("%s", buf);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s%s", option_name, printer_id, backend_name);
            scanf("%s%s%s", setting_name, printer_id, backend_name);
            scanf("%s%s%s", option_name, printer_id, backend_name);
            scanf("%s %s %s %s", option_name, option_val, printer_id, backend_name);
            scanf("%s%s%s", option_name, printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s", backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s%s", file_path, printer_id, backend_name);
              scanf("%s", final_file_path);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s%s", job_id, printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s%s", option_name, printer_id, backend_name);
            scanf("%s%s%s%s", option_name, choice_name, printer_id, backend_name);
            scanf("%s%s%s", group_name, printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s%s", media, printer_id, backend_name);
            scanf("%s%s%s", media, printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
            scanf("%s%s", printer_id, backend_name);
Fixed code:     if (fscanf(file, "%1023s", obj_path) == 0)
        scanf("%1023s", buf);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
            scanf("%1023s%1023s%1023s", setting_name, printer_id, backend_name);
            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
            scanf("%1023s %1023s %1023s %1023s", option_name, option_val, printer_id, backend_name);
            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s", backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s%1023s", file_path, printer_id, backend_name);
              scanf("%1023s", final_file_path);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s%1023s", job_id, printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name);
            scanf("%1023s%1023s%1023s%1023s", option_name, choice_name, printer_id, backend_name);
            scanf("%1023s%1023s%1023s", group_name, printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s%1023s", media, printer_id, backend_name);
            scanf("%1023s%1023s%1023s", media, printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);
            scanf("%1023s%1023s", printer_id, backend_name);