summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Marko <peter.marko@siemens.com>2026-01-01 13:14:57 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2026-01-26 09:49:25 +0000
commit3f703ca1c41cb488cc31282c3c135e2cb1e4a029 (patch)
tree1f04d23b1743407a1ecf0e4f347d8a5d15b141a3
parent15ea9a3dcbcbce4dc1c0e61f299ebff01f8b6e5d (diff)
downloadpoky-3f703ca1c41cb488cc31282c3c135e2cb1e4a029.tar.gz
cups: patch CVE-2025-58436
Pick patch from branch 2.4.x corresponding to patch mentioned in [1]. [1] https://nvd.nist.gov/vuln/detail/CVE-2025-58436 (From OE-Core rev: f1014ff6d886312afd55473497934590bc9c78ac) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-extended/cups/cups.inc1
-rw-r--r--meta/recipes-extended/cups/cups/CVE-2025-58436.patch630
2 files changed, 631 insertions, 0 deletions
diff --git a/meta/recipes-extended/cups/cups.inc b/meta/recipes-extended/cups/cups.inc
index cba4406720..c808eef9a7 100644
--- a/meta/recipes-extended/cups/cups.inc
+++ b/meta/recipes-extended/cups/cups.inc
@@ -27,6 +27,7 @@ SRC_URI = "https://github.com/OpenPrinting/cups/releases/download/v${PV}/cups-${
27 file://CVE-2024-47175-5.patch \ 27 file://CVE-2024-47175-5.patch \
28 file://CVE-2025-58060.patch \ 28 file://CVE-2025-58060.patch \
29 file://CVE-2025-58364.patch \ 29 file://CVE-2025-58364.patch \
30 file://CVE-2025-58436.patch \
30 " 31 "
31 32
32UPSTREAM_CHECK_URI = "https://github.com/OpenPrinting/cups/releases" 33UPSTREAM_CHECK_URI = "https://github.com/OpenPrinting/cups/releases"
diff --git a/meta/recipes-extended/cups/cups/CVE-2025-58436.patch b/meta/recipes-extended/cups/cups/CVE-2025-58436.patch
new file mode 100644
index 0000000000..388c5e57b5
--- /dev/null
+++ b/meta/recipes-extended/cups/cups/CVE-2025-58436.patch
@@ -0,0 +1,630 @@
1From 5d414f1f91bdca118413301b148f0b188eb1cdc6 Mon Sep 17 00:00:00 2001
2From: Zdenek Dohnal <zdohnal@redhat.com>
3Date: Mon, 13 Oct 2025 10:16:48 +0200
4Subject: [PATCH] Fix unresponsive cupsd process caused by a slow client
5
6If client is very slow, it will slow cupsd process for other clients.
7The fix is the best effort without turning scheduler cupsd into
8multithreaded process which would be too complex and error-prone when
9backporting to 2.4.x series.
10
11The fix for unencrypted communication is to follow up on communication
12only if there is the whole line on input, and the waiting time is
13guarded by timeout.
14
15Encrypted communication now starts after we have the whole client hello
16packet, which conflicts with optional upgrade support to HTTPS via
17methods other than method OPTIONS, so this optional support defined in
18RFC 2817, section 3.1 is removed. Too slow or incomplete requests are
19handled by connection timeout.
20
21Fixes CVE-2025-58436
22
23CVE: CVE-2025-58436
24Upstream-Status: Backport [https://github.com/OpenPrinting/cups/commit/5d414f1f91bdca118413301b148f0b188eb1cdc6]
25Signed-off-by: Peter Marko <peter.marko@siemens.com>
26---
27 cups/http-private.h | 7 +-
28 cups/http.c | 80 +++++++++++++-------
29 cups/tls-openssl.c | 15 +++-
30 scheduler/client.c | 178 ++++++++++++++++++++++++++++----------------
31 scheduler/client.h | 3 +
32 scheduler/select.c | 12 +++
33 6 files changed, 198 insertions(+), 97 deletions(-)
34
35diff --git a/cups/http-private.h b/cups/http-private.h
36index d9854faed..2d9035032 100644
37--- a/cups/http-private.h
38+++ b/cups/http-private.h
39@@ -120,6 +120,7 @@ extern "C" {
40 * Constants...
41 */
42
43+# define _HTTP_MAX_BUFFER 32768 /* Size of read buffer */
44 # define _HTTP_MAX_SBUFFER 65536 /* Size of (de)compression buffer */
45 # define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */
46 # define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */
47@@ -231,8 +232,8 @@ struct _http_s /**** HTTP connection structure ****/
48 http_encoding_t data_encoding; /* Chunked or not */
49 int _data_remaining;/* Number of bytes left (deprecated) */
50 int used; /* Number of bytes used in buffer */
51- char buffer[HTTP_MAX_BUFFER];
52- /* Buffer for incoming data */
53+ char _buffer[HTTP_MAX_BUFFER];
54+ /* Old read buffer (deprecated) */
55 int _auth_type; /* Authentication in use (deprecated) */
56 unsigned char _md5_state[88]; /* MD5 state (deprecated) */
57 char nonce[HTTP_MAX_VALUE];
58@@ -306,6 +307,8 @@ struct _http_s /**** HTTP connection structure ****/
59 /* Allocated field values */
60 *default_fields[HTTP_FIELD_MAX];
61 /* Default field values, if any */
62+ char buffer[_HTTP_MAX_BUFFER];
63+ /* Read buffer */
64 };
65 # endif /* !_HTTP_NO_PRIVATE */
66
67diff --git a/cups/http.c b/cups/http.c
68index 7a42cb3d6..214e45158 100644
69--- a/cups/http.c
70+++ b/cups/http.c
71@@ -53,7 +53,7 @@ static http_t *http_create(const char *host, int port,
72 static void http_debug_hex(const char *prefix, const char *buffer,
73 int bytes);
74 #endif /* DEBUG */
75-static ssize_t http_read(http_t *http, char *buffer, size_t length);
76+static ssize_t http_read(http_t *http, char *buffer, size_t length, int timeout);
77 static ssize_t http_read_buffered(http_t *http, char *buffer, size_t length);
78 static ssize_t http_read_chunk(http_t *http, char *buffer, size_t length);
79 static int http_send(http_t *http, http_state_t request,
80@@ -1188,7 +1188,7 @@ httpGets(char *line, /* I - Line to read into */
81 return (NULL);
82 }
83
84- bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used));
85+ bytes = http_read(http, http->buffer + http->used, (size_t)(_HTTP_MAX_BUFFER - http->used), http->wait_value);
86
87 DEBUG_printf(("4httpGets: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes));
88
89@@ -1706,24 +1706,13 @@ httpPeek(http_t *http, /* I - HTTP connection */
90
91 ssize_t buflen; /* Length of read for buffer */
92
93- if (!http->blocking)
94- {
95- while (!httpWait(http, http->wait_value))
96- {
97- if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
98- continue;
99-
100- return (0);
101- }
102- }
103-
104 if ((size_t)http->data_remaining > sizeof(http->buffer))
105 buflen = sizeof(http->buffer);
106 else
107 buflen = (ssize_t)http->data_remaining;
108
109 DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen));
110- bytes = http_read(http, http->buffer, (size_t)buflen);
111+ bytes = http_read(http, http->buffer, (size_t)buflen, http->wait_value);
112
113 DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.",
114 CUPS_LLCAST bytes));
115@@ -1744,9 +1733,9 @@ httpPeek(http_t *http, /* I - HTTP connection */
116 int zerr; /* Decompressor error */
117 z_stream stream; /* Copy of decompressor stream */
118
119- if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER)
120+ if (http->used > 0 && ((z_stream *)http->stream)->avail_in < _HTTP_MAX_BUFFER)
121 {
122- size_t buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in;
123+ size_t buflen = _HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in;
124 /* Number of bytes to copy */
125
126 if (((z_stream *)http->stream)->avail_in > 0 &&
127@@ -2004,7 +1993,7 @@ httpRead2(http_t *http, /* I - HTTP connection */
128
129 if (bytes == 0)
130 {
131- ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in;
132+ ssize_t buflen = _HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in;
133 /* Additional bytes for buffer */
134
135 if (buflen > 0)
136@@ -2754,7 +2743,7 @@ int /* O - 1 to continue, 0 to stop */
137 _httpUpdate(http_t *http, /* I - HTTP connection */
138 http_status_t *status) /* O - Current HTTP status */
139 {
140- char line[32768], /* Line from connection... */
141+ char line[_HTTP_MAX_BUFFER], /* Line from connection... */
142 *value; /* Pointer to value on line */
143 http_field_t field; /* Field index */
144 int major, minor; /* HTTP version numbers */
145@@ -2762,12 +2751,46 @@ _httpUpdate(http_t *http, /* I - HTTP connection */
146
147 DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
148
149+ /* When doing non-blocking I/O, make sure we have a whole line... */
150+ if (!http->blocking)
151+ {
152+ ssize_t bytes; /* Bytes "peeked" from connection */
153+
154+ /* See whether our read buffer is full... */
155+ DEBUG_printf(("2_httpUpdate: used=%d", http->used));
156+
157+ if (http->used > 0 && !memchr(http->buffer, '\n', (size_t)http->used) && (size_t)http->used < sizeof(http->buffer))
158+ {
159+ /* No, try filling in more data... */
160+ if ((bytes = http_read(http, http->buffer + http->used, sizeof(http->buffer) - (size_t)http->used, /*timeout*/0)) > 0)
161+ {
162+ DEBUG_printf(("2_httpUpdate: Read %d bytes.", (int)bytes));
163+ http->used += (int)bytes;
164+ }
165+ }
166+
167+ /* Peek at the incoming data... */
168+ if (!http->used || !memchr(http->buffer, '\n', (size_t)http->used))
169+ {
170+ /* Don't have a full line, tell the reader to try again when there is more data... */
171+ DEBUG_puts("1_htttpUpdate: No newline in buffer yet.");
172+ if ((size_t)http->used == sizeof(http->buffer))
173+ *status = HTTP_STATUS_ERROR;
174+ else
175+ *status = HTTP_STATUS_CONTINUE;
176+ return (0);
177+ }
178+
179+ DEBUG_puts("2_httpUpdate: Found newline in buffer.");
180+ }
181+
182 /*
183 * Grab a single line from the connection...
184 */
185
186 if (!httpGets(line, sizeof(line), http))
187 {
188+ DEBUG_puts("1_httpUpdate: Error reading request line.");
189 *status = HTTP_STATUS_ERROR;
190 return (0);
191 }
192@@ -4089,7 +4112,8 @@ http_debug_hex(const char *prefix, /* I - Prefix for line */
193 static ssize_t /* O - Number of bytes read or -1 on error */
194 http_read(http_t *http, /* I - HTTP connection */
195 char *buffer, /* I - Buffer */
196- size_t length) /* I - Maximum bytes to read */
197+ size_t length, /* I - Maximum bytes to read */
198+ int timeout) /* I - Wait timeout */
199 {
200 ssize_t bytes; /* Bytes read */
201
202@@ -4098,7 +4122,7 @@ http_read(http_t *http, /* I - HTTP connection */
203
204 if (!http->blocking || http->timeout_value > 0.0)
205 {
206- while (!httpWait(http, http->wait_value))
207+ while (!_httpWait(http, timeout, 1))
208 {
209 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
210 continue;
211@@ -4201,7 +4225,7 @@ http_read_buffered(http_t *http, /* I - HTTP connection */
212 else
213 bytes = (ssize_t)length;
214
215- DEBUG_printf(("8http_read: Grabbing %d bytes from input buffer.",
216+ DEBUG_printf(("8http_read_buffered: Grabbing %d bytes from input buffer.",
217 (int)bytes));
218
219 memcpy(buffer, http->buffer, (size_t)bytes);
220@@ -4211,7 +4235,7 @@ http_read_buffered(http_t *http, /* I - HTTP connection */
221 memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
222 }
223 else
224- bytes = http_read(http, buffer, length);
225+ bytes = http_read(http, buffer, length, http->wait_value);
226
227 return (bytes);
228 }
229@@ -4557,15 +4581,15 @@ http_set_timeout(int fd, /* I - File descriptor */
230 static void
231 http_set_wait(http_t *http) /* I - HTTP connection */
232 {
233- if (http->blocking)
234- {
235- http->wait_value = (int)(http->timeout_value * 1000);
236+ http->wait_value = (int)(http->timeout_value * 1000);
237
238- if (http->wait_value <= 0)
239+ if (http->wait_value <= 0)
240+ {
241+ if (http->blocking)
242 http->wait_value = 60000;
243+ else
244+ http->wait_value = 1000;
245 }
246- else
247- http->wait_value = 10000;
248 }
249
250
251diff --git a/cups/tls-openssl.c b/cups/tls-openssl.c
252index 9fcbe0af3..f746f4cba 100644
253--- a/cups/tls-openssl.c
254+++ b/cups/tls-openssl.c
255@@ -180,12 +180,14 @@ cupsMakeServerCredentials(
256 // Save them...
257 if ((bio = BIO_new_file(keyfile, "wb")) == NULL)
258 {
259+ DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file '%s': %s", keyfile, strerror(errno)));
260 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
261 goto done;
262 }
263
264 if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL))
265 {
266+ DEBUG_puts("1cupsMakeServerCredentials: PEM_write_bio_PrivateKey failed.");
267 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write private key."), 1);
268 BIO_free(bio);
269 goto done;
270@@ -195,12 +197,14 @@ cupsMakeServerCredentials(
271
272 if ((bio = BIO_new_file(crtfile, "wb")) == NULL)
273 {
274+ DEBUG_printf(("1cupsMakeServerCredentials: Unable to create certificate file '%s': %s", crtfile, strerror(errno)));
275 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
276 goto done;
277 }
278
279 if (!PEM_write_bio_X509(bio, cert))
280 {
281+ DEBUG_puts("1cupsMakeServerCredentials: PEM_write_bio_X509 failed.");
282 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write X.509 certificate."), 1);
283 BIO_free(bio);
284 goto done;
285@@ -1044,10 +1048,10 @@ _httpTLSStart(http_t *http) // I - Connection to server
286
287 if (!cupsMakeServerCredentials(tls_keypath, cn, 0, NULL, time(NULL) + 365 * 86400))
288 {
289- DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed.");
290+ DEBUG_printf(("4_httpTLSStart: cupsMakeServerCredentials failed: %s", cupsLastErrorString()));
291 http->error = errno = EINVAL;
292 http->status = HTTP_STATUS_ERROR;
293- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
294+// _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1);
295 SSL_CTX_free(context);
296
297 return (-1);
298@@ -1272,14 +1276,17 @@ http_bio_read(BIO *h, // I - BIO data
299
300 http = (http_t *)BIO_get_data(h);
301
302- if (!http->blocking)
303+ if (!http->blocking || http->timeout_value > 0.0)
304 {
305 /*
306 * Make sure we have data before we read...
307 */
308
309- if (!_httpWait(http, 10000, 0))
310+ while (!_httpWait(http, http->wait_value, 0))
311 {
312+ if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
313+ continue;
314+
315 #ifdef WIN32
316 http->error = WSAETIMEDOUT;
317 #else
318diff --git a/scheduler/client.c b/scheduler/client.c
319index f0349a6c9..9593c9138 100644
320--- a/scheduler/client.c
321+++ b/scheduler/client.c
322@@ -34,11 +34,11 @@
323
324 static int check_if_modified(cupsd_client_t *con,
325 struct stat *filestats);
326+#ifdef HAVE_TLS
327+static int check_start_tls(cupsd_client_t *con);
328+#endif /* HAVE_TLS */
329 static int compare_clients(cupsd_client_t *a, cupsd_client_t *b,
330 void *data);
331-#ifdef HAVE_TLS
332-static int cupsd_start_tls(cupsd_client_t *con, http_encryption_t e);
333-#endif /* HAVE_TLS */
334 static char *get_file(cupsd_client_t *con, struct stat *filestats,
335 char *filename, size_t len);
336 static http_status_t install_cupsd_conf(cupsd_client_t *con);
337@@ -360,14 +360,20 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
338 if (lis->encryption == HTTP_ENCRYPTION_ALWAYS)
339 {
340 /*
341- * https connection; go secure...
342+ * HTTPS connection, force TLS negotiation...
343 */
344
345- if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS))
346- cupsdCloseClient(con);
347+ con->tls_start = time(NULL);
348+ con->encryption = HTTP_ENCRYPTION_ALWAYS;
349 }
350 else
351+ {
352+ /*
353+ * HTTP connection, but check for HTTPS negotiation on first data...
354+ */
355+
356 con->auto_ssl = 1;
357+ }
358 #endif /* HAVE_TLS */
359 }
360
361@@ -597,17 +603,46 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */
362
363 con->auto_ssl = 0;
364
365- if (recv(httpGetFd(con->http), buf, 1, MSG_PEEK) == 1 &&
366- (!buf[0] || !strchr("DGHOPT", buf[0])))
367+ if (recv(httpGetFd(con->http), buf, 5, MSG_PEEK) == 5 && buf[0] == 0x16 && buf[1] == 3 && buf[2])
368 {
369 /*
370- * Encrypt this connection...
371+ * Client hello record, encrypt this connection...
372 */
373
374- cupsdLogClient(con, CUPSD_LOG_DEBUG2, "Saw first byte %02X, auto-negotiating SSL/TLS session.", buf[0] & 255);
375+ cupsdLogClient(con, CUPSD_LOG_DEBUG2, "Saw client hello record, auto-negotiating TLS session.");
376+ con->tls_start = time(NULL);
377+ con->encryption = HTTP_ENCRYPTION_ALWAYS;
378+ }
379+ }
380
381- if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS))
382- cupsdCloseClient(con);
383+ if (con->tls_start)
384+ {
385+ /*
386+ * Try negotiating TLS...
387+ */
388+
389+ int tls_status = check_start_tls(con);
390+
391+ if (tls_status < 0)
392+ {
393+ /*
394+ * TLS negotiation failed, close the connection.
395+ */
396+
397+ cupsdCloseClient(con);
398+ return;
399+ }
400+ else if (tls_status == 0)
401+ {
402+ /*
403+ * Nothing to do yet...
404+ */
405+
406+ if ((time(NULL) - con->tls_start) > 5)
407+ {
408+ // Timeout, close the connection...
409+ cupsdCloseClient(con);
410+ }
411
412 return;
413 }
414@@ -771,9 +806,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */
415 * Parse incoming parameters until the status changes...
416 */
417
418- while ((status = httpUpdate(con->http)) == HTTP_STATUS_CONTINUE)
419- if (!httpGetReady(con->http))
420- break;
421+ status = httpUpdate(con->http);
422
423 if (status != HTTP_STATUS_OK && status != HTTP_STATUS_CONTINUE)
424 {
425@@ -935,11 +968,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */
426 return;
427 }
428
429- if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED))
430- {
431- cupsdCloseClient(con);
432- return;
433- }
434+ con->tls_start = time(NULL);
435+ con->tls_upgrade = 1;
436+ con->encryption = HTTP_ENCRYPTION_REQUIRED;
437+ return;
438 #else
439 if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
440 {
441@@ -978,32 +1010,11 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */
442 if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION),
443 "Upgrade") && !httpIsEncrypted(con->http))
444 {
445-#ifdef HAVE_TLS
446- /*
447- * Do encryption stuff...
448- */
449-
450- httpClearFields(con->http);
451-
452- if (!cupsdSendHeader(con, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL,
453- CUPSD_AUTH_NONE))
454- {
455- cupsdCloseClient(con);
456- return;
457- }
458-
459- if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED))
460- {
461- cupsdCloseClient(con);
462- return;
463- }
464-#else
465 if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE))
466 {
467 cupsdCloseClient(con);
468 return;
469 }
470-#endif /* HAVE_TLS */
471 }
472
473 if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_STATUS_OK)
474@@ -2631,6 +2642,69 @@ check_if_modified(
475 }
476
477
478+#ifdef HAVE_TLS
479+/*
480+ * 'check_start_tls()' - Start encryption on a connection.
481+ */
482+
483+static int /* O - 0 to continue, 1 on success, -1 on error */
484+check_start_tls(cupsd_client_t *con) /* I - Client connection */
485+{
486+ unsigned char chello[4096]; /* Client hello record */
487+ ssize_t chello_bytes; /* Bytes read/peeked */
488+ int chello_len; /* Length of record */
489+
490+
491+ /*
492+ * See if we have a good and complete client hello record...
493+ */
494+
495+ if ((chello_bytes = recv(httpGetFd(con->http), (char *)chello, sizeof(chello), MSG_PEEK)) < 5)
496+ return (0); /* Not enough bytes (yet) */
497+
498+ if (chello[0] != 0x016 || chello[1] != 3 || chello[2] == 0)
499+ return (-1); /* Not a TLS Client Hello record */
500+
501+ chello_len = (chello[3] << 8) | chello[4];
502+
503+ if ((chello_len + 5) > chello_bytes)
504+ return (0); /* Not enough bytes yet */
505+
506+ /*
507+ * OK, we do, try negotiating...
508+ */
509+
510+ con->tls_start = 0;
511+
512+ if (httpEncryption(con->http, con->encryption))
513+ {
514+ cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to encrypt connection: %s", cupsLastErrorString());
515+ return (-1);
516+ }
517+
518+ cupsdLogClient(con, CUPSD_LOG_DEBUG, "Connection now encrypted.");
519+
520+ if (con->tls_upgrade)
521+ {
522+ // Respond to the original OPTIONS command...
523+ con->tls_upgrade = 0;
524+
525+ httpClearFields(con->http);
526+ httpClearCookie(con->http);
527+ httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0");
528+
529+ if (!cupsdSendHeader(con, HTTP_STATUS_OK, NULL, CUPSD_AUTH_NONE))
530+ {
531+ cupsdCloseClient(con);
532+ return (-1);
533+ }
534+ }
535+
536+ return (1);
537+}
538+#endif /* HAVE_TLS */
539+
540+
541 /*
542 * 'compare_clients()' - Compare two client connections.
543 */
544@@ -2651,28 +2725,6 @@ compare_clients(cupsd_client_t *a, /* I - First client */
545 }
546
547
548-#ifdef HAVE_TLS
549-/*
550- * 'cupsd_start_tls()' - Start encryption on a connection.
551- */
552-
553-static int /* O - 0 on success, -1 on error */
554-cupsd_start_tls(cupsd_client_t *con, /* I - Client connection */
555- http_encryption_t e) /* I - Encryption mode */
556-{
557- if (httpEncryption(con->http, e))
558- {
559- cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to encrypt connection: %s",
560- cupsLastErrorString());
561- return (-1);
562- }
563-
564- cupsdLogClient(con, CUPSD_LOG_DEBUG, "Connection now encrypted.");
565- return (0);
566-}
567-#endif /* HAVE_TLS */
568-
569-
570 /*
571 * 'get_file()' - Get a filename and state info.
572 */
573diff --git a/scheduler/client.h b/scheduler/client.h
574index 9fe4e2ea6..2939ce997 100644
575--- a/scheduler/client.h
576+++ b/scheduler/client.h
577@@ -51,6 +51,9 @@ struct cupsd_client_s
578 cups_lang_t *language; /* Language to use */
579 #ifdef HAVE_TLS
580 int auto_ssl; /* Automatic test for SSL/TLS */
581+ time_t tls_start; /* Do TLS negotiation? */
582+ int tls_upgrade; /* Doing TLS upgrade via OPTIONS? */
583+ http_encryption_t encryption; /* Type of TLS negotiation */
584 #endif /* HAVE_TLS */
585 http_addr_t clientaddr; /* Client's server address */
586 char clientname[256];/* Client's server name for connection */
587diff --git a/scheduler/select.c b/scheduler/select.c
588index 2e64f2a7e..ac6205c51 100644
589--- a/scheduler/select.c
590+++ b/scheduler/select.c
591@@ -408,6 +408,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */
592
593 cupsd_in_select = 1;
594
595+ // Prevent 100% CPU by releasing control before the kevent call...
596+ usleep(1);
597+
598 if (timeout >= 0 && timeout < 86400)
599 {
600 ktimeout.tv_sec = timeout;
601@@ -454,6 +457,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */
602 struct epoll_event *event; /* Current event */
603
604
605+ // Prevent 100% CPU by releasing control before the epoll_wait call...
606+ usleep(1);
607+
608 if (timeout >= 0 && timeout < 86400)
609 nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs,
610 timeout * 1000);
611@@ -546,6 +552,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */
612 }
613 }
614
615+ // Prevent 100% CPU by releasing control before the poll call...
616+ usleep(1);
617+
618 if (timeout >= 0 && timeout < 86400)
619 nfds = poll(cupsd_pollfds, (nfds_t)count, timeout * 1000);
620 else
621@@ -599,6 +608,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */
622 cupsd_current_input = cupsd_global_input;
623 cupsd_current_output = cupsd_global_output;
624
625+ // Prevent 100% CPU by releasing control before the select call...
626+ usleep(1);
627+
628 if (timeout >= 0 && timeout < 86400)
629 {
630 stimeout.tv_sec = timeout;