* yet more dir-less .cache DEP updates
[t2sde.git] / package / printing / cups-filters / CVE-2023-24805.patch
blob58a44fe606ba62eade8ff05d8027c9a861f0a1d5
1 # --- T2-COPYRIGHT-NOTE-BEGIN ---
2 # T2 SDE: package/*/cups-filters/CVE-2023-24805.patch
3 # Copyright (C) 2023 The T2 SDE Project
4 #
5 # This Copyright note is generated by scripts/Create-CopyPatch,
6 # more information can be found in the files COPYING and README.
7 #
8 # This patch file is dual-licensed. It is available under the license the
9 # patched project is licensed under, as long as it is an OpenSource license
10 # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
11 # of the GNU General Public License version 2 as used by the T2 SDE.
12 # --- T2-COPYRIGHT-NOTE-END ---
14 Patch-Source: https://github.com/OpenPrinting/cups-filters/commit/93e60d3df358c0ae6f3dba79e1c9684657683d89
16 From 93e60d3df358c0ae6f3dba79e1c9684657683d89 Mon Sep 17 00:00:00 2001
17 From: Till Kamppeter <till.kamppeter@gmail.com>
18 Date: Wed, 17 May 2023 11:11:29 +0200
19 Subject: [PATCH] beh backend: Use execv() instead of system() - CVE-2023-24805
21 With execv() command line arguments are passed as separate strings and
22 not the full command line in a single string. This prevents arbitrary
23 command execution by escaping the quoting of the arguments in a job
24 with a forged job title.
26 In addition, done the following fixes and improvements:
28 - Do not allow '/' in the scheme of the URI (= backend executable
29 name), to assure that only backends inside /usr/lib/cups/backend/
30 are used.
32 - URI must have ':', to split off scheme, otherwise error out.
34 - Check return value of snprintf() to create call path for backend, to
35 error out on truncation of a too long scheme or on complete failure
36 due to a completely odd scheme.
38 - Use strncat() instead of strncpy() for getting scheme from URI, the latter
39 does not require setting terminating zero byte in case of truncation.
41 - Also exclude "." or ".." as scheme, as directories are not valid CUPS
42 backends.
44 - Do not use fprintf() in sigterm_handler(), to not interfere with a
45 fprintf() which could be running in the main process when
46 sigterm_handler() is triggered.
48 - Use "static volatile int" for global variable job_canceled.
49 ---
50 backend/beh.c | 107 +++++++++++++++++++++++++++++++++++++++-----------
51 1 file changed, 84 insertions(+), 23 deletions(-)
53 diff --git a/backend/beh.c b/backend/beh.c
54 index 225fd27d5..8d51235b1 100644
55 --- a/backend/beh.c
56 +++ b/backend/beh.c
57 @@ -22,12 +22,13 @@
58 #include "backend-private.h"
59 #include <cups/array.h>
60 #include <ctype.h>
61 +#include <sys/wait.h>
64 * Local globals...
67 -static int job_canceled = 0; /* Set to 1 on SIGTERM */
68 +static volatile int job_canceled = 0; /* Set to 1 on SIGTERM */
71 * Local functions...
72 @@ -213,21 +214,40 @@ call_backend(char *uri, /* I - URI of final destination */
73 char **argv, /* I - Command-line arguments */
74 char *filename) { /* I - File name of input data */
75 const char *cups_serverbin; /* Location of programs */
76 + char *backend_argv[8]; /* Arguments for backend */
77 char scheme[1024], /* Scheme from URI */
78 *ptr, /* Pointer into scheme */
79 - cmdline[65536]; /* Backend command line */
80 - int retval;
81 + backend_path[2048]; /* Backend path */
82 + int pid = 0, /* Process ID of backend */
83 + wait_pid, /* Process ID from wait() */
84 + wait_status, /* Status from child */
85 + retval = 0;
86 + int bytes;
89 * Build the backend command line...
92 - strncpy(scheme, uri, sizeof(scheme) - 1);
93 - if (strlen(uri) > 1023)
94 - scheme[1023] = '\0';
95 + scheme[0] = '\0';
96 + strncat(scheme, uri, sizeof(scheme) - 1);
97 if ((ptr = strchr(scheme, ':')) != NULL)
98 *ptr = '\0';
100 + else {
101 + fprintf(stderr,
102 + "ERROR: beh: Invalid URI, no colon (':') to mark end of scheme part.\n");
103 + exit (CUPS_BACKEND_FAILED);
105 + if (strchr(scheme, '/')) {
106 + fprintf(stderr,
107 + "ERROR: beh: Invalid URI, scheme contains a slash ('/').\n");
108 + exit (CUPS_BACKEND_FAILED);
110 + if (!strcmp(scheme, ".") || !strcmp(scheme, "..")) {
111 + fprintf(stderr,
112 + "ERROR: beh: Invalid URI, scheme (\"%s\") is a directory.\n",
113 + scheme);
114 + exit (CUPS_BACKEND_FAILED);
116 if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
117 cups_serverbin = CUPS_SERVERBIN;
119 @@ -235,16 +255,29 @@ call_backend(char *uri, /* I - URI of final destination */
120 fprintf(stderr,
121 "ERROR: beh: Direct output into a file not supported.\n");
122 exit (CUPS_BACKEND_FAILED);
123 - } else
124 - snprintf(cmdline, sizeof(cmdline),
125 - "%s/backend/%s '%s' '%s' '%s' '%s' '%s' %s",
126 - cups_serverbin, scheme, argv[1], argv[2], argv[3],
127 - /* Apply number of copies only if beh was called with a
128 - file name and not with the print data in stdin, as
129 - backends should handle copies only if they are called
130 - with a file name */
131 - (argc == 6 ? "1" : argv[4]),
132 - argv[5], filename);
135 + backend_argv[0] = uri;
136 + backend_argv[1] = argv[1];
137 + backend_argv[2] = argv[2];
138 + backend_argv[3] = argv[3];
139 + /* Apply number of copies only if beh was called with a file name
140 + and not with the print data in stdin, as backends should handle
141 + copies only if they are called with a file name */
142 + backend_argv[4] = (argc == 6 ? "1" : argv[4]);
143 + backend_argv[5] = argv[5];
144 + backend_argv[6] = filename;
145 + backend_argv[7] = NULL;
147 + bytes = snprintf(backend_path, sizeof(backend_path),
148 + "%s/backend/%s", cups_serverbin, scheme);
149 + if (bytes < 0 || bytes >= sizeof(backend_path))
151 + fprintf(stderr,
152 + "ERROR: beh: Invalid scheme (\"%s\"), could not determing backend path.\n",
153 + scheme);
154 + return (CUPS_BACKEND_FAILED);
158 * Overwrite the device URI and run the actual backend...
159 @@ -253,18 +286,44 @@ call_backend(char *uri, /* I - URI of final destination */
160 setenv("DEVICE_URI", uri, 1);
162 fprintf(stderr,
163 - "DEBUG: beh: Executing backend command line \"%s\"...\n",
164 - cmdline);
165 + "DEBUG: beh: Executing backend command line \"%s '%s' '%s' '%s' '%s' '%s' %s\"...\n",
166 + backend_path, backend_argv[1], backend_argv[2], backend_argv[3],
167 + backend_argv[4], backend_argv[5], backend_argv[6]);
168 fprintf(stderr,
169 "DEBUG: beh: Using device URI: %s\n",
170 uri);
172 - retval = system(cmdline) >> 8;
173 + if ((pid = fork()) == 0) {
174 + /*
175 + * Child comes here...
176 + */
178 + /* Run the backend */
179 + execv(backend_path, backend_argv);
181 - if (retval == -1)
182 fprintf(stderr, "ERROR: Unable to execute backend command line: %s\n",
183 strerror(errno));
185 + exit(1);
186 + } else if (pid < 0) {
187 + /*
188 + * Unable to fork!
189 + */
191 + return (CUPS_BACKEND_FAILED);
194 + while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR);
196 + if (wait_pid >= 0 && wait_status) {
197 + if (WIFEXITED(wait_status))
198 + retval = WEXITSTATUS(wait_status);
199 + else if (WTERMSIG(wait_status) != SIGTERM)
200 + retval = WTERMSIG(wait_status);
201 + else
202 + retval = 0;
205 return (retval);
208 @@ -277,8 +336,10 @@ static void
209 sigterm_handler(int sig) { /* I - Signal number (unused) */
210 (void)sig;
212 - fprintf(stderr,
213 - "DEBUG: beh: Job canceled.\n");
214 + const char * const msg = "DEBUG: beh: Job canceled.\n";
215 + /* The if() is to eliminate the return value and silence the warning
216 + about an unused return value. */
217 + if (write(2, msg, strlen(msg)));
219 if (job_canceled)
220 _exit(CUPS_BACKEND_OK);