Copilot commented on code in PR #12864:
URL: https://github.com/apache/trafficserver/pull/12864#discussion_r2784954952


##########
src/iocore/net/ProxyProtocol.cc:
##########
@@ -547,6 +547,80 @@ ProxyProtocol::get_tlv(const uint8_t tlvCode) const
   return std::nullopt;
 }
 
+/*
+ * PP2_TYPE_SSL
+ * struct pp2_tlv_ssl {
+ *   uint8_t  client;
+ *   uint32_t verify;
+ *   struct pp2_tlv sub_tlv[0];
+ * };
+ */
+
+std::optional<std::string_view>
+ProxyProtocol::_get_tlv_ssl_subtype(int subtype) const
+{
+  if (auto v = tlv.find(PP2_TYPE_SSL); v != tlv.end() && v->second.length() != 
0) {
+    auto ssl = v->second;
+
+    // Is the client connected over TLS
+    if ((ssl.data()[0] & 0x01) == 0) {
+      // Not over TLS
+      return std::nullopt;
+    }
+
+    // Find the given subtype
+    uint16_t    len = ssl.length();
+    const char *p   = ssl.data() + 5; // Skip client (uint8_t) + verify 
(uint32_t)
+    const char *end = p + len + 1;
+    while (p != end) {

Review Comment:
   _get_tlv_ssl_subtype() computes the end pointer incorrectly (it uses `end = 
p + len + 1` after already advancing `p` by 5). This makes the loop read past 
the end of the PP2_TYPE_SSL TLV value and can cause out-of-bounds 
reads/undefined behavior. Compute `end` from the start of the SSL value (e.g., 
`ssl.data() + ssl.size()`) and iterate while `p < end` (not `p != end`).
   ```suggestion
       // The SSL TLV must contain at least the client (uint8_t) and verify 
(uint32_t) fields.
       if (ssl.length() < 5) {
         Dbg(dbg_ctl_proxyprotocol_v2, "SSL TLV too short: %zu bytes (expected 
at least 5)", static_cast<size_t>(ssl.length()));
         return std::nullopt;
       }
   
       // Find the given subtype
       uint16_t    len = ssl.length();
       const char *p   = ssl.data() + 5;           // Skip client (uint8_t) + 
verify (uint32_t)
       const char *end = ssl.data() + len;         // End of the SSL TLV value
       while (p < end) {
   ```



##########
doc/admin-guide/logging/formatting.en.rst:
##########
@@ -532,6 +532,10 @@ ppd   Proxy Protocol Destination IP received via Proxy 
Protocol context from the
       Dest IP        to the |TS|
 ppa   Proxy Protocol The Authority TLV from Proxy Protocol context from the LB
       Authority      to the |TS|
+pptc  Proxy Protocol The TLS cipher from Proxy Protocol context from the LB
+      Authority      to the |TS|
+pptv  Proxy Protocol The TLS version from Proxy Protocol context from the LB
+      Authority      to the |TS|

Review Comment:
   The new log field table entries for `pptc`/`pptv` look like copy/paste from 
`ppa`: the second column label is "Authority" for both, which doesn't match the 
TLS cipher/version descriptions. Update the field name in the middle column to 
something like "TLS Cipher" and "TLS Version" so the table is internally 
consistent.
   ```suggestion
         TLS Cipher     to the |TS|
   pptv  Proxy Protocol The TLS version from Proxy Protocol context from the LB
         TLS Version    to the |TS|
   ```



##########
src/iocore/net/ProxyProtocol.cc:
##########
@@ -547,6 +547,80 @@ ProxyProtocol::get_tlv(const uint8_t tlvCode) const
   return std::nullopt;
 }
 
+/*
+ * PP2_TYPE_SSL
+ * struct pp2_tlv_ssl {
+ *   uint8_t  client;
+ *   uint32_t verify;
+ *   struct pp2_tlv sub_tlv[0];
+ * };
+ */
+
+std::optional<std::string_view>
+ProxyProtocol::_get_tlv_ssl_subtype(int subtype) const
+{
+  if (auto v = tlv.find(PP2_TYPE_SSL); v != tlv.end() && v->second.length() != 
0) {
+    auto ssl = v->second;
+
+    // Is the client connected over TLS
+    if ((ssl.data()[0] & 0x01) == 0) {
+      // Not over TLS
+      return std::nullopt;
+    }
+
+    // Find the given subtype
+    uint16_t    len = ssl.length();
+    const char *p   = ssl.data() + 5; // Skip client (uint8_t) + verify 
(uint32_t)

Review Comment:
   _get_tlv_ssl_subtype() reads `ssl.data()[0]` and skips 5 bytes without 
verifying the TLV value is at least 5 bytes long. If PP2_TYPE_SSL is present 
but truncated/malformed, this will access beyond the string_view. Add a 
`ssl.size() >= 5` (and preferably `>= 5 + 3` before parsing sub-TLVs) guard 
before dereferencing and parsing.



##########
include/iocore/net/ProxyProtocol.h:
##########
@@ -134,6 +136,8 @@ class ProxyProtocol
 
 private:
   std::string additional_data;
+
+  std::optional<std::string_view> _get_tlv_ssl_subtype(int subtype) const;

Review Comment:
   ProxyProtocol::_get_tlv_ssl_subtype takes `int subtype`, but subtype IDs are 
8-bit values on the wire (and `get_tlv()` uses `uint8_t`). Using `uint8_t` here 
avoids accidental sign/width issues and better communicates the expected range.
   ```suggestion
     std::optional<std::string_view> _get_tlv_ssl_subtype(uint8_t subtype) 
const;
   ```



##########
src/proxy/logging/LogAccess.cc:
##########
@@ -1660,6 +1660,40 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
   return 0;
 }
 
+int
+LogAccess::marshal_proxy_protocol_tls_cipher(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto cipher = m_http_sm->t_state.pp_info.get_tlv_ssl_cipher(); cipher) 
{
+      len = padded_length(cipher->size() + 1);
+      if (buf) {
+        marshal_str(buf, cipher->data(), len);
+        buf[cipher->size()] = '\0';
+      }
+    }
+  }
+  return len;
+}
+
+int
+LogAccess::marshal_proxy_protocol_tls_version(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto version = m_http_sm->t_state.pp_info.get_tlv_ssl_version(); 
version) {
+      len = padded_length(version->size() + 1);
+      if (buf) {
+        marshal_str(buf, version->data(), len);
+        buf[version->size()] = '\0';
+      }
+    }
+  }

Review Comment:
   marshal_proxy_protocol_tls_cipher() returns `INK_MIN_ALIGN` when no cipher 
is available but does not write anything into `buf` in that case. This can 
leave uninitialized bytes in the log buffer. Consider always marshalling a 
default string (e.g., "-") when `buf` is non-null, and return the padded length 
that matches what was written.
   ```suggestion
     int len        = INK_MIN_ALIGN;
     bool have_data = false;
   
     if (m_http_sm) {
       if (auto cipher = m_http_sm->t_state.pp_info.get_tlv_ssl_cipher(); 
cipher) {
         have_data = true;
         len       = padded_length(cipher->size() + 1);
         if (buf) {
           marshal_str(buf, cipher->data(), len);
           buf[cipher->size()] = '\0';
         }
       }
     }
   
     // When no cipher is available, ensure the buffer is initialized with a 
default value.
     if (buf && !have_data) {
       buf[0] = '-';
       // NUL-terminate and pad the remaining bytes in the field.
       for (int i = 1; i < len; ++i) {
         buf[i] = '\0';
       }
     }
   
     return len;
   }
   
   int
   LogAccess::marshal_proxy_protocol_tls_version(char *buf)
   {
     int len        = INK_MIN_ALIGN;
     bool have_data = false;
   
     if (m_http_sm) {
       if (auto version = m_http_sm->t_state.pp_info.get_tlv_ssl_version(); 
version) {
         have_data = true;
         len       = padded_length(version->size() + 1);
         if (buf) {
           marshal_str(buf, version->data(), len);
           buf[version->size()] = '\0';
         }
       }
     }
   
     // When no TLS version is available, ensure the buffer is initialized with 
a default value.
     if (buf && !have_data) {
       buf[0] = '-';
       // NUL-terminate and pad the remaining bytes in the field.
       for (int i = 1; i < len; ++i) {
         buf[i] = '\0';
       }
     }
   ```



##########
src/proxy/logging/LogAccess.cc:
##########
@@ -1660,6 +1660,40 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
   return 0;
 }
 
+int
+LogAccess::marshal_proxy_protocol_tls_cipher(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto cipher = m_http_sm->t_state.pp_info.get_tlv_ssl_cipher(); cipher) 
{
+      len = padded_length(cipher->size() + 1);
+      if (buf) {
+        marshal_str(buf, cipher->data(), len);
+        buf[cipher->size()] = '\0';
+      }
+    }
+  }
+  return len;
+}
+
+int
+LogAccess::marshal_proxy_protocol_tls_version(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto version = m_http_sm->t_state.pp_info.get_tlv_ssl_version(); 
version) {
+      len = padded_length(version->size() + 1);
+      if (buf) {
+        marshal_str(buf, version->data(), len);
+        buf[version->size()] = '\0';
+      }
+    }
+  }
+  return len;

Review Comment:
   marshal_proxy_protocol_tls_version() returns `INK_MIN_ALIGN` when the TLS 
version TLV isn't present, but does not marshal any default value into `buf` in 
that case. This can result in uninitialized log output for the field. Align the 
behavior with other string marshalers by always writing a default string when 
`buf` is provided and returning the corresponding padded length.



##########
src/proxy/logging/LogAccess.cc:
##########
@@ -1660,6 +1660,40 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
   return 0;
 }
 
+int
+LogAccess::marshal_proxy_protocol_tls_cipher(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto cipher = m_http_sm->t_state.pp_info.get_tlv_ssl_cipher(); cipher) 
{
+      len = padded_length(cipher->size() + 1);
+      if (buf) {
+        marshal_str(buf, cipher->data(), len);
+        buf[cipher->size()] = '\0';
+      }
+    }
+  }
+  return len;
+}
+
+int
+LogAccess::marshal_proxy_protocol_tls_version(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto version = m_http_sm->t_state.pp_info.get_tlv_ssl_version(); 
version) {
+      len = padded_length(version->size() + 1);
+      if (buf) {
+        marshal_str(buf, version->data(), len);
+        buf[version->size()] = '\0';
+      }

Review Comment:
   LogAccess::marshal_proxy_protocol_tls_version() has the same issue as the 
cipher field: `version->data()` is a `std::string_view` that is not guaranteed 
NUL-terminated, but marshal_str() will read until it finds a terminator. Use 
marshal_mem() with the view length and padded length (or ensure NUL 
termination) to avoid out-of-bounds reads.



##########
src/proxy/logging/LogAccess.cc:
##########
@@ -1660,6 +1660,40 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
   return 0;
 }
 
+int
+LogAccess::marshal_proxy_protocol_tls_cipher(char *buf)
+{
+  int len = INK_MIN_ALIGN;
+
+  if (m_http_sm) {
+    if (auto cipher = m_http_sm->t_state.pp_info.get_tlv_ssl_cipher(); cipher) 
{
+      len = padded_length(cipher->size() + 1);
+      if (buf) {
+        marshal_str(buf, cipher->data(), len);
+        buf[cipher->size()] = '\0';
+      }

Review Comment:
   LogAccess::marshal_proxy_protocol_tls_cipher() passes a non-NUL-terminated 
`std::string_view` buffer (`cipher->data()`) into marshal_str(), which uses 
`ink_strlcpy` and will read past the end of the view looking for a terminator. 
Use marshal_mem() with the actual length (cipher->size()) and the padded 
length, or otherwise ensure the input is NUL-terminated before calling 
marshal_str().



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to