From e03b1722377f6212dd4c74a86edc3b9f591a6df9 Mon Sep 17 00:00:00 2001 From: wk333 <13474090681@163.com> Date: Mon, 8 Nov 2021 15:13:43 +0800 Subject: [PATCH] fix CVE-2021-37147 CVE-2021-37149 CVE-2021-41585 CVE-2021-43082 (cherry picked from commit 1560580ab1c9905cc2654299d57f4773ff05a50f) --- CVE-2021-37147.patch | 33 +++ CVE-2021-37149.patch | 467 +++++++++++++++++++++++++++++++++++++++++++ CVE-2021-41585.patch | 77 +++++++ CVE-2021-43082.patch | 43 ++++ trafficserver.spec | 13 +- 5 files changed, 630 insertions(+), 3 deletions(-) create mode 100644 CVE-2021-37147.patch create mode 100644 CVE-2021-37149.patch create mode 100644 CVE-2021-41585.patch create mode 100644 CVE-2021-43082.patch diff --git a/CVE-2021-37147.patch b/CVE-2021-37147.patch new file mode 100644 index 0000000..1e1ae69 --- /dev/null +++ b/CVE-2021-37147.patch @@ -0,0 +1,33 @@ +From 64f25678bfbbd1433cce703e3c43bcc49a53de56 Mon Sep 17 00:00:00 2001 +From: Brian Neradt +Date: Wed, 27 Oct 2021 13:35:41 -0500 +Subject: [PATCH] Fix output '\n' HTTP field line endings (#8455) + +This is another attempt to fix what was initially addressed in #8096 but +got backed out via #8305. That more extensive patch was considered too +invasive and potentially risky. This more targeted patch will fix +clients that only send the \n endings but it will force the \r\n line +ending on output. + +This was mostly in place except for header lines that get +m_n_v_raw_printable set, which seems to be most header lines. The +addition checks to see if the header line ends in \r\n. If it does not +the m_n_v_raw_printable flag gets cleared and the logic that explicitly +adds the line endings while be invoked on output. +--- + proxy/hdrs/MIME.cc | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/proxy/hdrs/MIME.cc b/proxy/hdrs/MIME.cc +index 14e7ce352a6..729ec9da977 100644 +--- a/proxy/hdrs/MIME.cc ++++ b/proxy/hdrs/MIME.cc +@@ -2580,6 +2580,8 @@ mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char + } + field_name.rtrim_if(&ParseRules::is_ws); + raw_print_field = false; ++ } else if (parsed.suffix(2) != "\r\n") { ++ raw_print_field = false; + } + + // find value first diff --git a/CVE-2021-37149.patch b/CVE-2021-37149.patch new file mode 100644 index 0000000..9d998f6 --- /dev/null +++ b/CVE-2021-37149.patch @@ -0,0 +1,467 @@ +From 83c89f3d217d473ecb000b68c910c0f183c3a355 Mon Sep 17 00:00:00 2001 +From: Brian Neradt +Date: Wed, 27 Oct 2021 11:30:54 -0500 +Subject: [PATCH] Detect and handle chunk header size truncation (#8452) + +This detects if a chunk header size is too large and, if so, closes the +connection. +--- + include/tscore/ink_memory.h | 19 +++ + proxy/http/HttpTunnel.cc | 11 +- + src/tscore/Makefile.am | 1 + + src/tscore/unit_tests/test_ink_memory.cc | 141 ++++++++++++++++++ + .../bad_chunked_encoding.test.py | 86 ++++++++++- + .../malformed_chunked_header.replay.yaml | 109 ++++++++++++++ + 6 files changed, 364 insertions(+), 3 deletions(-) + create mode 100644 src/tscore/unit_tests/test_ink_memory.cc + create mode 100644 tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml + +diff --git a/include/tscore/ink_memory.h b/include/tscore/ink_memory.h +index fdaaa27c21b..7fd8de1f347 100644 +--- a/include/tscore/ink_memory.h ++++ b/include/tscore/ink_memory.h +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -205,6 +206,24 @@ ink_zero(T &t) + memset(static_cast(&t), 0, sizeof(t)); + } + ++/** Verify that we can safely shift value num_places places left. ++ * ++ * This checks that the shift will not cause the variable to overflow and that ++ * the value will not become negative. ++ * ++ * @param[in] value The value against which to check whether the shift is safe. ++ * ++ * @param[in] num_places The number of places to check that shifting left is safe. ++ * ++ */ ++template ++inline constexpr bool ++can_safely_shift_left(T value, int num_places) ++{ ++ constexpr auto max_value = std::numeric_limits::max(); ++ return value >= 0 && value <= (max_value >> num_places); ++} ++ + /** Scoped resources. + + An instance of this class is used to hold a contingent resource. When this object goes out of scope +diff --git a/proxy/http/HttpTunnel.cc b/proxy/http/HttpTunnel.cc +index 08837c6290e..564adc23bf6 100644 +--- a/proxy/http/HttpTunnel.cc ++++ b/proxy/http/HttpTunnel.cc +@@ -36,6 +36,7 @@ + #include "HttpSM.h" + #include "HttpDebugNames.h" + #include "tscore/ParseRules.h" ++#include "tscore/ink_memory.h" + + static const int min_block_transfer_bytes = 256; + static const char *const CHUNK_HEADER_FMT = "%" PRIx64 "\r\n"; +@@ -134,8 +135,16 @@ ChunkedHandler::read_size() + if (state == CHUNK_READ_SIZE) { + // The http spec says the chunked size is always in hex + if (ParseRules::is_hex(*tmp)) { ++ // Make sure we will not overflow running_sum with our shift. ++ if (!can_safely_shift_left(running_sum, 4)) { ++ // We have no more space in our variable for the shift. ++ state = CHUNK_READ_ERROR; ++ done = true; ++ break; ++ } + num_digits++; +- running_sum *= 16; ++ // Shift over one hex value. ++ running_sum <<= 4; + + if (ParseRules::is_digit(*tmp)) { + running_sum += *tmp - '0'; +diff --git a/src/tscore/Makefile.am b/src/tscore/Makefile.am +index 43750b2a739..c0ca76c670e 100644 +--- a/src/tscore/Makefile.am ++++ b/src/tscore/Makefile.am +@@ -174,6 +174,7 @@ test_tscore_SOURCES = \ + unit_tests/test_Extendible.cc \ + unit_tests/test_History.cc \ + unit_tests/test_ink_inet.cc \ ++ unit_tests/test_ink_memory.cc \ + unit_tests/test_IntrusiveHashMap.cc \ + unit_tests/test_IntrusivePtr.cc \ + unit_tests/test_IpMap.cc \ +diff --git a/src/tscore/unit_tests/test_ink_memory.cc b/src/tscore/unit_tests/test_ink_memory.cc +new file mode 100644 +index 00000000000..fa6725b84ca +--- /dev/null ++++ b/src/tscore/unit_tests/test_ink_memory.cc +@@ -0,0 +1,141 @@ ++/** @file ++ ++ ink_memory unit tests. ++ ++ @section license License ++ ++ Licensed to the Apache Software Foundation (ASF) under one ++ or more contributor license agreements. See the NOTICE file ++ distributed with this work for additional information ++ regarding copyright ownership. The ASF licenses this file ++ to you under the Apache License, Version 2.0 (the ++ "License"); you may not use this file except in compliance ++ with the License. You may obtain a copy of the License at ++ ++ http://www.apache.org/licenses/LICENSE-2.0 ++ ++ Unless required by applicable law or agreed to in writing, software ++ distributed under the License is distributed on an "AS IS" BASIS, ++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ See the License for the specific language governing permissions and ++ limitations under the License. ++*/ ++ ++#include ++#include ++#include "tscore/ink_memory.h" ++ ++constexpr void ++test_can_safely_shift_int8_t() ++{ ++ constexpr int8_t a = 0; ++ static_assert(can_safely_shift_left(a, 0) == true, "shifting 0 is safe"); ++ static_assert(can_safely_shift_left(a, 4) == true, "shifting 0 is safe"); ++ static_assert(can_safely_shift_left(a, 8) == true, "shifting 0 is safe"); ++ ++ constexpr int8_t b = 1; ++ static_assert(can_safely_shift_left(b, 0) == true, "shifting int8_t 1 0 places is safe"); ++ static_assert(can_safely_shift_left(b, 1) == true, "shifting int8_t 1 1 places is safe"); ++ static_assert(can_safely_shift_left(b, 6) == true, "shifting int8_t 1 6 places is safe"); ++ static_assert(can_safely_shift_left(b, 7) == false, "shifting int8_t 1 7 places becomes negative"); ++ static_assert(can_safely_shift_left(b, 8) == false, "shifting int8_t 1 8 places overflows"); ++ ++ constexpr int8_t c = 0xff; ++ static_assert(can_safely_shift_left(c, 0) == false, "int8_t 0xff is already negative"); ++ static_assert(can_safely_shift_left(c, 1) == false, "shifting int8_t 0xff 1 place overflows"); ++} ++ ++constexpr void ++test_can_safely_shift_uint8_t() ++{ ++ constexpr uint8_t a = 0; ++ static_assert(can_safely_shift_left(a, 0) == true, "shifting 0 is safe"); ++ static_assert(can_safely_shift_left(a, 4) == true, "shifting 0 is safe"); ++ static_assert(can_safely_shift_left(a, 8) == true, "shifting 0 is safe"); ++ ++ constexpr uint8_t b = 1; ++ static_assert(can_safely_shift_left(b, 0) == true, "shifting uint8_t 1 0 places is safe"); ++ static_assert(can_safely_shift_left(b, 1) == true, "shifting uint8_t 1 1 places is safe"); ++ static_assert(can_safely_shift_left(b, 6) == true, "shifting uint8_t 1 6 places is safe"); ++ static_assert(can_safely_shift_left(b, 7) == true, "shifting uint8_t 1 7 is safe"); ++ static_assert(can_safely_shift_left(b, 8) == false, "shifting uint8_t 1 8 places overflows"); ++ ++ constexpr uint8_t c = 0xff; ++ static_assert(can_safely_shift_left(c, 0) == true, "shifting int8_t 0xff 0 places is safe"); ++ static_assert(can_safely_shift_left(c, 1) == false, "shifting int8_t 0xff 1 place overflows"); ++} ++ ++constexpr void ++test_can_safely_shift_int32_t() ++{ ++ constexpr int32_t a = 0; ++ static_assert(can_safely_shift_left(a, 4) == true, "shifting 0 is safe"); ++ ++ constexpr int32_t b = 1; ++ static_assert(can_safely_shift_left(b, 4) == true, "shifting 1 is safe"); ++ ++ constexpr int32_t c = 0x00ff'ffff; ++ static_assert(can_safely_shift_left(c, 4) == true, "shifting 0x00ff'ffff is safe"); ++ ++ constexpr int32_t d = 0x07ff'ffff; ++ static_assert(can_safely_shift_left(d, 4) == true, "shifting 0x07ff'ffff is safe"); ++ ++ constexpr int32_t e = -1; ++ static_assert(can_safely_shift_left(e, 4) == false, "shifting -1 will result in truncation"); ++ ++ constexpr int32_t f = 0x0800'0000; ++ static_assert(can_safely_shift_left(f, 4) == false, "shifting 0x0801'0000 will become negative"); ++ ++ constexpr int32_t g = 0x0fff'ffff; ++ static_assert(can_safely_shift_left(g, 4) == false, "shifting 0x0fff'ffff will become negative"); ++ ++ constexpr int32_t h = 0x1000'0000; ++ static_assert(can_safely_shift_left(h, 4) == false, "shifting 0x1000'0000 will overflow"); ++ ++ constexpr int32_t i = 0xf000'0000; ++ static_assert(can_safely_shift_left(i, 4) == false, "shifting 0xf000'0000 will overflow"); ++ ++ constexpr int32_t j = 0xf800'0000; ++ static_assert(can_safely_shift_left(j, 4) == false, "shifting 0xf800'0000 will become negative"); ++} ++ ++constexpr void ++test_can_safely_shift_uint32_t() ++{ ++ constexpr uint32_t a = 0; ++ static_assert(can_safely_shift_left(a, 4) == true, "shifting 0 is safe"); ++ ++ constexpr uint32_t b = 1; ++ static_assert(can_safely_shift_left(b, 4) == true, "shifting 1 is safe"); ++ ++ constexpr uint32_t c = 0x00ff'ffff; ++ static_assert(can_safely_shift_left(c, 4) == true, "shifting 0x00ff'ffff is safe"); ++ ++ constexpr uint32_t d = 0x07ff'ffff; ++ static_assert(can_safely_shift_left(d, 4) == true, "shifting 0x07ff'ffff is safe"); ++ ++ constexpr uint32_t e = 0x0800'0000; ++ static_assert(can_safely_shift_left(e, 4) == true, "shifting unisgned 0x0800'0000 is safe"); ++ ++ constexpr uint32_t f = 0x0fff'ffff; ++ static_assert(can_safely_shift_left(f, 4) == true, "shifting unsigned 0x0fff'ffff is safe"); ++ ++ constexpr uint32_t g = 0x1000'0000; ++ static_assert(can_safely_shift_left(g, 4) == false, "shifting 0x1000'0000 will overflow"); ++ ++ constexpr uint32_t h = 0xf000'0000; ++ static_assert(can_safely_shift_left(h, 4) == false, "shifting 0xf000'0000 will overflow"); ++ ++ constexpr uint32_t i = 0xf800'0000; ++ static_assert(can_safely_shift_left(i, 4) == false, "shifting 0xf800'0000 will become negative"); ++} ++ ++TEST_CASE("can_safely_shift", "[libts][ink_inet][memory]") ++{ ++ // can_safely_shift_left is a constexpr function, therefore all these checks are ++ // done at compile time and REQUIRES calls are not necessary. ++ test_can_safely_shift_int8_t(); ++ test_can_safely_shift_uint8_t(); ++ test_can_safely_shift_int32_t(); ++ test_can_safely_shift_uint32_t(); ++} +diff --git a/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py b/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py +index cdfc0bf9cd2..38e4206687b 100644 +--- a/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py ++++ b/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py +@@ -25,7 +25,7 @@ + Test.ContinueOnFail = True + + # Define default ATS +-ts = Test.MakeATSProcess("ts", select_ports=True, enable_tls=False) ++ts = Test.MakeATSProcess("ts1", select_ports=True, enable_tls=False) + server = Test.MakeOriginServer("server") + + testName = "" +@@ -53,7 +53,7 @@ + ts.Variables.port) + tr.Processes.Default.ReturnCode = 0 + tr.Processes.Default.StartBefore(server) +-tr.Processes.Default.StartBefore(Test.Processes.ts) ++tr.Processes.Default.StartBefore(ts) + tr.Processes.Default.Streams.All = Testers.ContainsExpression("501 Field not implemented", "Should fail") + tr.Processes.Default.Streams.All = Testers.ExcludesExpression("200 OK", "Should not succeed") + tr.StillRunningAfter = server +@@ -69,3 +69,85 @@ + tr.Processes.Default.Streams.All = Testers.ExcludesExpression("200 OK", "Should not succeed") + tr.StillRunningAfter = server + tr.StillRunningAfter = ts ++ ++ ++class MalformedChunkHeaderTest: ++ chunkedReplayFile = "replays/malformed_chunked_header.replay.yaml" ++ ++ def __init__(self): ++ self.setupOriginServer() ++ self.setupTS() ++ ++ def setupOriginServer(self): ++ self.server = Test.MakeVerifierServerProcess("verifier-server", self.chunkedReplayFile) ++ ++ # The server's responses will fail the first two transactions ++ # because ATS will close the connection due to the malformed ++ # chunk headers. ++ self.server.Streams.stdout += Testers.ContainsExpression( ++ "Header write for key 1 failed", ++ "Verify that writing the first response failed.") ++ self.server.Streams.stdout += Testers.ContainsExpression( ++ "Header write for key 2 failed", ++ "Verify that writing the second response failed.") ++ ++ # ATS should close the connection before any body gets through. ++ # "abc" is the body sent for each of these chunked cases. ++ self.server.Streams.stdout += Testers.ExcludesExpression( ++ "abc", ++ "Verify that the body never got through.") ++ ++ def setupTS(self): ++ self.ts = Test.MakeATSProcess("ts2", enable_tls=True, enable_cache=False) ++ self.ts.addDefaultSSLFiles() ++ self.ts.Disk.records_config.update({ ++ "proxy.config.diags.debug.enabled": 1, ++ "proxy.config.diags.debug.tags": "http", ++ "proxy.config.ssl.server.cert.path": f'{self.ts.Variables.SSLDir}', ++ "proxy.config.ssl.server.private_key.path": f'{self.ts.Variables.SSLDir}', ++ "proxy.config.ssl.client.verify.server.policy": 'PERMISSIVE', ++ }) ++ self.ts.Disk.ssl_multicert_config.AddLine( ++ 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key' ++ ) ++ self.ts.Disk.remap_config.AddLine( ++ f"map / http://127.0.0.1:{self.server.Variables.http_port}/", ++ ) ++ self.ts.Streams.stderr += Testers.ContainsExpression( ++ "user agent post chunk decoding error", ++ "Verify that ATS detected a problem parsing a chunk.") ++ ++ def runChunkedTraffic(self): ++ tr = Test.AddTestRun() ++ tr.AddVerifierClientProcess( ++ "client", ++ self.chunkedReplayFile, ++ http_ports=[self.ts.Variables.port], ++ https_ports=[self.ts.Variables.ssl_port], ++ other_args='--thread-limit 1') ++ tr.Processes.Default.StartBefore(self.server) ++ tr.Processes.Default.StartBefore(self.ts) ++ tr.StillRunningAfter = self.server ++ tr.StillRunningAfter = self.ts ++ ++ # The aborted connections will result in errors and a non-zero return ++ # code from the verifier client. ++ tr.Processes.Default.ReturnCode = 1 ++ tr.Processes.Default.Streams.stdout += Testers.ContainsExpression( ++ "Failed HTTP/1 transaction with key=3", ++ "Verify that ATS closed the third transaction.") ++ tr.Processes.Default.Streams.stdout += Testers.ContainsExpression( ++ "Failed HTTP/1 transaction with key=4", ++ "Verify that ATS closed the fourth transaction.") ++ ++ # ATS should close the connection before any body gets through. ++ # "abc" is the body sent for each of these chunked cases. ++ tr.Processes.Default.Streams.stdout += Testers.ExcludesExpression( ++ "abc", ++ "Verify that the body never got through.") ++ ++ def run(self): ++ self.runChunkedTraffic() ++ ++ ++MalformedChunkHeaderTest().run() +diff --git a/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml b/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml +new file mode 100644 +index 00000000000..c6091ab4ee1 +--- /dev/null ++++ b/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml +@@ -0,0 +1,109 @@ ++# Licensed to the Apache Software Foundation (ASF) under one ++# or more contributor license agreements. See the NOTICE file ++# distributed with this work for additional information ++# regarding copyright ownership. The ASF licenses this file ++# to you under the Apache License, Version 2.0 (the ++# "License"); you may not use this file except in compliance ++# with the License. You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++ ++meta: ++ version: "1.0" ++ ++sessions: ++- transactions: ++ - client-request: ++ method: "POST" ++ version: "1.1" ++ url: /malformed/chunk/header ++ headers: ++ fields: ++ - [ Host, example.com ] ++ - [ Transfer-Encoding, chunked ] ++ - [ uuid, 1 ] ++ content: ++ transfer: plain ++ encoding: uri ++ # Chunk header sizes are in hex, so a size of `z` is malformed. ++ data: z%0D%0Aabc%0D%0A0%0D%0A%0D%0A ++ ++ # The connection will be dropped and this response will not go out. ++ server-response: ++ status: 200 ++ ++- transactions: ++ - client-request: ++ method: "POST" ++ version: "1.1" ++ url: /large/chunk/size/header ++ headers: ++ fields: ++ - [ Host, example.com ] ++ - [ Transfer-Encoding, chunked ] ++ - [ uuid, 2 ] ++ content: ++ transfer: plain ++ encoding: uri ++ # Super large chunk header, larger than will fit in an int. ++ data: 111111113%0D%0Aabc%0D%0A0%0D%0A%0D%0A ++ ++ # The connection will be dropped and this response will not go out. ++ server-response: ++ status: 200 ++ ++ # ++ # Now repeat the above two malformed chunk header tests, but on the server ++ # side. ++ # ++- transactions: ++ - client-request: ++ method: "GET" ++ version: "1.1" ++ url: /response/malformed/chunk/size ++ headers: ++ fields: ++ - [ Host, example.com ] ++ - [ uuid, 3 ] ++ ++ # The connection will be dropped and this response will not go out. ++ server-response: ++ status: 200 ++ reason: OK ++ headers: ++ fields: ++ - [ Transfer-Encoding, chunked ] ++ content: ++ transfer: plain ++ encoding: uri ++ # Chunk header sizes are in hex, so a size of `z` is malformed. ++ data: z%0D%0Aabc%0D%0A0%0D%0A%0D%0A ++ ++- transactions: ++ - client-request: ++ method: "GET" ++ version: "1.1" ++ url: /response/large/chunk/size ++ headers: ++ fields: ++ - [ Host, example.com ] ++ - [ uuid, 4 ] ++ ++ # The connection will be dropped and this response will not go out. ++ server-response: ++ status: 200 ++ reason: OK ++ headers: ++ fields: ++ - [ Transfer-Encoding, chunked ] ++ content: ++ transfer: plain ++ encoding: uri ++ # Super large chunk header, larger than will fit in an int. ++ data: 111111113%0D%0Aabc%0D%0A0%0D%0A%0D%0A diff --git a/CVE-2021-41585.patch b/CVE-2021-41585.patch new file mode 100644 index 0000000..cb453eb --- /dev/null +++ b/CVE-2021-41585.patch @@ -0,0 +1,77 @@ +From 268b540edae0b3e51d033795a4dd7404a5756a93 Mon Sep 17 00:00:00 2001 +From: Masaori Koshiba +Date: Thu, 28 Oct 2021 01:53:14 +0900 +Subject: [PATCH] Ignore ECONNABORTED on blocking accept (#8453) + +--- + iocore/net/P_UnixNet.h | 4 +++- + iocore/net/UnixNetAccept.cc | 30 ++++++++++++++++++++---------- + 2 files changed, 23 insertions(+), 11 deletions(-) + +diff --git a/iocore/net/P_UnixNet.h b/iocore/net/P_UnixNet.h +index 0043e1d763c..cff9439e9a4 100644 +--- a/iocore/net/P_UnixNet.h ++++ b/iocore/net/P_UnixNet.h +@@ -480,6 +480,7 @@ change_net_connections_throttle(const char *token, RecDataT data_type, RecData v + return 0; + } + ++// 2 - ignore + // 1 - transient + // 0 - report as warning + // -1 - fatal +@@ -487,8 +488,9 @@ TS_INLINE int + accept_error_seriousness(int res) + { + switch (res) { +- case -EAGAIN: + case -ECONNABORTED: ++ return 2; ++ case -EAGAIN: + case -ECONNRESET: // for Linux + case -EPIPE: // also for Linux + return 1; +diff --git a/iocore/net/UnixNetAccept.cc b/iocore/net/UnixNetAccept.cc +index d1ecc22d185..1ce5923b8ff 100644 +--- a/iocore/net/UnixNetAccept.cc ++++ b/iocore/net/UnixNetAccept.cc +@@ -295,19 +295,29 @@ NetAccept::do_blocking_accept(EThread *t) + do { + if ((res = server.accept(&con)) < 0) { + int seriousness = accept_error_seriousness(res); +- if (seriousness >= 0) { // not so bad +- if (!seriousness) { // bad enough to warn about +- check_transient_accept_error(res); +- } ++ switch (seriousness) { ++ case 0: ++ // bad enough to warn about ++ check_transient_accept_error(res); + safe_delay(net_throttle_delay); + return 0; ++ case 1: ++ // not so bad but needs delay ++ safe_delay(net_throttle_delay); ++ return 0; ++ case 2: ++ // ignore ++ return 0; ++ case -1: ++ [[fallthrough]]; ++ default: ++ if (!action_->cancelled) { ++ SCOPED_MUTEX_LOCK(lock, action_->mutex ? action_->mutex : t->mutex, t); ++ action_->continuation->handleEvent(EVENT_ERROR, (void *)static_cast(res)); ++ Warning("accept thread received fatal error: errno = %d", errno); ++ } ++ return -1; + } +- if (!action_->cancelled) { +- SCOPED_MUTEX_LOCK(lock, action_->mutex ? action_->mutex : t->mutex, t); +- action_->continuation->handleEvent(EVENT_ERROR, (void *)static_cast(res)); +- Warning("accept thread received fatal error: errno = %d", errno); +- } +- return -1; + } + // check for throttle + if (!opt.backdoor && check_net_throttle(ACCEPT)) { diff --git a/CVE-2021-43082.patch b/CVE-2021-43082.patch new file mode 100644 index 0000000..5552e28 --- /dev/null +++ b/CVE-2021-43082.patch @@ -0,0 +1,43 @@ +From 02b17dbe3cff71ffd31577d872e077531124d207 Mon Sep 17 00:00:00 2001 +From: Masaori Koshiba +Date: Fri, 29 Oct 2021 09:34:12 +0900 +Subject: [PATCH] Check length before search accept-encoding header (#8475) + +--- + plugins/stats_over_http/stats_over_http.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/plugins/stats_over_http/stats_over_http.c b/plugins/stats_over_http/stats_over_http.c +index b78575d5cf5..bb75fe791b5 100644 +--- a/plugins/stats_over_http/stats_over_http.c ++++ b/plugins/stats_over_http/stats_over_http.c +@@ -61,6 +61,10 @@ + /* global holding the path used for access to this JSON data */ + #define DEFAULT_URL_PATH "_stats" + ++// TODO: replace with TS_HTTP_* when BROTLI is supported ++#define HTTP_VALUE_BR "BR" ++#define HTTP_LEN_BR 2 ++ + // from mod_deflate: + // ZLIB's compression algorithm uses a + // 0-9 based scale that GZIP does where '1' is 'Best speed' +@@ -618,15 +622,15 @@ stats_origin(TSCont contp ATS_UNUSED, TSEvent event ATS_UNUSED, void *edata) + if (accept_encoding_field != TS_NULL_MLOC) { + int len = -1; + const char *str = TSMimeHdrFieldValueStringGet(reqp, hdr_loc, accept_encoding_field, -1, &len); +- if (strstr(str, "deflate") != NULL) { ++ if (len >= TS_HTTP_LEN_DEFLATE && strstr(str, TS_HTTP_VALUE_DEFLATE) != NULL) { + TSDebug(PLUGIN_NAME, "Saw deflate in accept encoding"); + my_state->encoding = init_gzip(my_state, DEFLATE_MODE); +- } else if (strstr(str, "gzip") != NULL) { ++ } else if (len >= TS_HTTP_LEN_GZIP && strstr(str, TS_HTTP_VALUE_GZIP) != NULL) { + TSDebug(PLUGIN_NAME, "Saw gzip in accept encoding"); + my_state->encoding = init_gzip(my_state, GZIP_MODE); + } + #if HAVE_BROTLI_ENCODE_H +- else if (strstr(str, "br") != NULL) { ++ else if (len >= HTTP_LEN_BR && strstr(str, HTTP_VALUE_BR) != NULL) { + TSDebug(PLUGIN_NAME, "Saw br in accept encoding"); + my_state->encoding = init_br(my_state); + } diff --git a/trafficserver.spec b/trafficserver.spec index 64a5813..6c36338 100644 --- a/trafficserver.spec +++ b/trafficserver.spec @@ -1,16 +1,20 @@ %define _hardened_build 1 -%{!?release: %define release 1} +%{!?release: %define release 2} Name: trafficserver Version: 9.1.0 -Release: 1 +Release: 2 Summary: Apache Traffic Server, a reverse, forward and transparent HTTP proxy cache License: Apache-2.0 URL: https://trafficserver.apache.org/ Source0: http://www.apache.org/dist/%{name}/%{name}-%{version}.tar.bz2 Patch0000: Add-openeuler-support.patch +Patch0001: CVE-2021-37147.patch +Patch0002: CVE-2021-37149.patch +Patch0003: CVE-2021-41585.patch +Patch0004: CVE-2021-43082.patch BuildRequires: expat-devel hwloc-devel openssl-devel pcre-devel zlib-devel xz-devel BuildRequires: libcurl-devel ncurses-devel gcc gcc-c++ perl-ExtUtils-MakeMaker -BuildRequires: libcap-devel cmake libunwind-devel +BuildRequires: libcap-devel cmake libunwind-devel automake Requires: expat hwloc openssl pcre zlib xz libcurl Requires: systemd ncurses pkgconfig libcap initscripts Requires(postun): systemd @@ -110,5 +114,8 @@ getent passwd ats >/dev/null || useradd -r -u 176 -g ats -d / -s /sbin/nologin - %{_datadir}/pkgconfig/trafficserver.pc %changelog +* Mon Nov 08 2021 wangkai - 9.1.0-2 +- fix CVE-2021-37147 CVE-2021-37149 CVE-2021-41585 CVE-2021-43082 + * Tue Aug 31 2021 liyanan - 9.1.0-1 - package init -- Gitee