rgw: reject control characters in response-header actions
authorRobin H. Johnson <rjohnson@digitalocean.com>
Fri, 27 Mar 2020 19:48:13 +0000 (20:48 +0100)
committerBastien Roucariès <rouca@debian.org>
Sat, 21 Oct 2023 16:42:26 +0000 (17:42 +0100)
S3 GetObject permits overriding response header values, but those inputs
need to be validated to insure only characters that are valid in an HTTP
header value are present.

Credit: Initial vulnerability discovery by William Bowling (@wcbowling)
Credit: Further vulnerability discovery by Robin H. Johnson <rjohnson@digitalocean.com>
Signed-off-by: Robin H. Johnson <rjohnson@digitalocean.com>
Origin: upstream, https://github.com/ceph/ceph/pull/34504/commits/9ca5b3628245e2878426602bb24f1a4e45edc850

Gbp-Pq: Name CVE-2020-1760-3.patch

src/rgw/rgw_rest_s3.cc

index 2edf586163901616cf87bb0fe66b2aae64f124d4..eb51e7536f3f0e495b949268875368d40f42104f 100644 (file)
@@ -166,6 +166,15 @@ int decode_attr_bl_single_value(map<string, bufferlist>& attrs, const char *attr
   return 0;
 }
 
+inline bool str_has_cntrl(const std::string s) {
+  return std::any_of(s.begin(), s.end(), ::iscntrl);
+}
+
+inline bool str_has_cntrl(const char* s) {
+  std::string _s(s);
+  return str_has_cntrl(_s);
+}
+
 int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs,
                                              off_t bl_len)
 {
@@ -273,6 +282,19 @@ int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs,
        if (s->auth.identity->is_anonymous()) {
          return -ERR_INVALID_REQUEST;
        }
+        /* HTTP specification says no control characters should be present in
+         * header values: https://tools.ietf.org/html/rfc7230#section-3.2
+         *      field-vchar    = VCHAR / obs-text
+         *
+         * Failure to validate this permits a CRLF injection in HTTP headers,
+         * whereas S3 GetObject only permits specific headers.
+         */
+        if(str_has_cntrl(val)) {
+          /* TODO: return a more distinct error in future;
+           * stating what the problem is */
+          return -ERR_INVALID_REQUEST;
+        }
+
        if (strcmp(p->param, "response-content-type") != 0) {
          response_attrs[p->http_attr] = val;
        } else {