Vulnerability: An arbitrary memory overwrite vulnerability in Asylo versions up to 0.6.0 allows an attacker to make a host call to FromkLinuxSockAddr with attacker controlled content and size of klinux_addr which allows an attacker to write memory values from within the enclave. We recommend upgrading past commit a37fb6a0e7daf30134dbbf357c9a518a1026aa02
Vulnerability ID: CVE-2020-8938
CWE: CWE-787
Severity score: 2.9
Project: https://github.com/google/asylo
Published: 2020-12-15
File: asylo/platform/system_call/type_conversions/manual_types_functions.cc
Commit message: Check input length in FromLinuxSockAddr

PiperOrigin-RevId: 333785506
Change-Id: I1d68fb8954665eebc1018d80ff995cbe9e7ed6a9
Commit author: Chong Cai

Vulnerable version (before fix):
 bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,    int16_t klinux_family = input->klinux_sa_family;   if (klinux_family == kLinux_AF_UNIX) {     struct klinux_sockaddr_un *klinux_sockaddr_un_in =         const_cast<struct klinux_sockaddr_un *>(             reinterpret_cast<const struct klinux_sockaddr_un *>(input)); bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,                  sizeof(klinux_sockaddr_un_in->klinux_sun_path)));     CopySockaddr(&sockaddr_un_out, sizeof(sockaddr_un_out), output, output_len);   } else if (klinux_family == kLinux_AF_INET) {     struct klinux_sockaddr_in *klinux_sockaddr_in_in =         const_cast<struct klinux_sockaddr_in *>(             reinterpret_cast<const struct klinux_sockaddr_in *>(input)); bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,                          klinux_sockaddr_in_in->klinux_sin_zero);     CopySockaddr(&sockaddr_in_out, sizeof(sockaddr_in_out), output, output_len);   } else if (klinux_family == kLinux_AF_INET6) {     struct klinux_sockaddr_in6 *klinux_sockaddr_in6_in =         const_cast<struct klinux_sockaddr_in6 *>(             reinterpret_cast<const struct klinux_sockaddr_in6 *>(input));

Fixed version (after fix):
 bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,    int16_t klinux_family = input->klinux_sa_family;   if (klinux_family == kLinux_AF_UNIX) {     if (input_len < sizeof(struct klinux_sockaddr_un)) {       return false;     }      struct klinux_sockaddr_un *klinux_sockaddr_un_in =         const_cast<struct klinux_sockaddr_un *>(             reinterpret_cast<const struct klinux_sockaddr_un *>(input)); bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,                  sizeof(klinux_sockaddr_un_in->klinux_sun_path)));     CopySockaddr(&sockaddr_un_out, sizeof(sockaddr_un_out), output, output_len);   } else if (klinux_family == kLinux_AF_INET) {     if (input_len < sizeof(struct klinux_sockaddr_in)) {       return false;     }     struct klinux_sockaddr_in *klinux_sockaddr_in_in =         const_cast<struct klinux_sockaddr_in *>(             reinterpret_cast<const struct klinux_sockaddr_in *>(input)); bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,                          klinux_sockaddr_in_in->klinux_sin_zero);     CopySockaddr(&sockaddr_in_out, sizeof(sockaddr_in_out), output, output_len);   } else if (klinux_family == kLinux_AF_INET6) {     if (input_len < sizeof(struct klinux_sockaddr_in6)) {       return false;     }      struct klinux_sockaddr_in6 *klinux_sockaddr_in6_in =         const_cast<struct klinux_sockaddr_in6 *>(             reinterpret_cast<const struct klinux_sockaddr_in6 *>(input));

Patch:
patch: @@ -429,6 +429,10 @@ bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,
 
   int16_t klinux_family = input->klinux_sa_family;
   if (klinux_family == kLinux_AF_UNIX) {
+    if (input_len < sizeof(struct klinux_sockaddr_un)) {
+      return false;
+    }
+
     struct klinux_sockaddr_un *klinux_sockaddr_un_in =
         const_cast<struct klinux_sockaddr_un *>(
             reinterpret_cast<const struct klinux_sockaddr_un *>(input));
@@ -442,6 +446,9 @@ bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,
                  sizeof(klinux_sockaddr_un_in->klinux_sun_path)));
     CopySockaddr(&sockaddr_un_out, sizeof(sockaddr_un_out), output, output_len);
   } else if (klinux_family == kLinux_AF_INET) {
+    if (input_len < sizeof(struct klinux_sockaddr_in)) {
+      return false;
+    }
     struct klinux_sockaddr_in *klinux_sockaddr_in_in =
         const_cast<struct klinux_sockaddr_in *>(
             reinterpret_cast<const struct klinux_sockaddr_in *>(input));
@@ -457,6 +464,10 @@ bool FromkLinuxSockAddr(const struct klinux_sockaddr *input,
                          klinux_sockaddr_in_in->klinux_sin_zero);
     CopySockaddr(&sockaddr_in_out, sizeof(sockaddr_in_out), output, output_len);
   } else if (klinux_family == kLinux_AF_INET6) {
+    if (input_len < sizeof(struct klinux_sockaddr_in6)) {
+      return false;
+    }
+
     struct klinux_sockaddr_in6 *klinux_sockaddr_in6_in =
         const_cast<struct klinux_sockaddr_in6 *>(
             reinterpret_cast<const struct klinux_sockaddr_in6 *>(input));
path: asylo/platform/system_call/type_conversions/manual_types_functions.cc