diff options
| author | Catalin Enache <catalin.enache@windriver.com> | 2021-03-23 19:37:57 -0400 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2021-04-06 22:45:36 +0100 |
| commit | 4ea2ccd7e9f74df8346e35022dea107f4e00ef86 (patch) | |
| tree | 5f4597766bd5fbbd35e1749aac8f7d58d7496ed8 | |
| parent | 5568e334d70213d611fd34910bdf4e4b00f09e99 (diff) | |
| download | poky-4ea2ccd7e9f74df8346e35022dea107f4e00ef86.tar.gz | |
connman: fix CVE-2021-26675, CVE-2021-26676
A stack-based buffer overflow in dnsproxy in ConnMan before 1.39
could be used by network adjacent attackers to execute code.
gdhcp in ConnMan before 1.39 could be used by network-adjacent.
attackers to leak sensitive stack information, allowing further
exploitation of bugs in gdhcp.
References:
https://nvd.nist.gov/vuln/detail/CVE-2021-26675
https://nvd.nist.gov/vuln/detail/CVE-2021-26676
Upstream patches:
https://git.kernel.org/pub/scm/network/connman/connman.git/commit/?id=e4079a20f617a4b076af503f6e4e8b0304c9f2cb
https://git.kernel.org/pub/scm/network/connman/connman.git/commit/?id=58d397ba74873384aee449690a9070bacd5676fa
https://git.kernel.org/pub/scm/network/connman/connman.git/commit/?id=a74524b3e3fad81b0fd1084ffdf9f2ea469cd9b1
(From OE-Core rev: 3c78000aaf8e4ee8ffb7674f5c286e2c110f167b)
Signed-off-by: Catalin Enache <catalin.enache@windriver.com>
Signed-off-by: Randy MacLeod <Randy.MacLeod@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
4 files changed, 329 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/connman/connman/CVE-2021-26675.patch b/meta/recipes-connectivity/connman/connman/CVE-2021-26675.patch new file mode 100644 index 0000000000..2648a832ca --- /dev/null +++ b/meta/recipes-connectivity/connman/connman/CVE-2021-26675.patch | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | From e4079a20f617a4b076af503f6e4e8b0304c9f2cb Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Colin Wee <cwee@tesla.com> | ||
| 3 | Date: Thu, 28 Jan 2021 19:41:53 +0100 | ||
| 4 | Subject: [PATCH] dnsproxy: Add length checks to prevent buffer overflow | ||
| 5 | |||
| 6 | Fixes: CVE-2021-26675 | ||
| 7 | |||
| 8 | Upstream-Status: Backport | ||
| 9 | CVE: CVE-2021-26675 | ||
| 10 | |||
| 11 | Reference to upstream patch: | ||
| 12 | https://git.kernel.org/pub/scm/network/connman/connman.git/commit/?id=e4079a20f617a4b076af503f6e4e8b0304c9f2cb | ||
| 13 | |||
| 14 | Signed-off-by: Catalin Enache <catalin.enache@windriver.com> | ||
| 15 | --- | ||
| 16 | src/dnsproxy.c | 14 +++++++++++--- | ||
| 17 | 1 file changed, 11 insertions(+), 3 deletions(-) | ||
| 18 | |||
| 19 | diff --git a/src/dnsproxy.c b/src/dnsproxy.c | ||
| 20 | index a7bf87a1..4f5c897f 100644 | ||
| 21 | --- a/src/dnsproxy.c | ||
| 22 | +++ b/src/dnsproxy.c | ||
| 23 | @@ -1767,6 +1767,7 @@ static char *uncompress(int16_t field_count, char *start, char *end, | ||
| 24 | char **uncompressed_ptr) | ||
| 25 | { | ||
| 26 | char *uptr = *uncompressed_ptr; /* position in result buffer */ | ||
| 27 | + char * const uncomp_end = uncompressed + uncomp_len - 1; | ||
| 28 | |||
| 29 | debug("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr); | ||
| 30 | |||
| 31 | @@ -1787,12 +1788,15 @@ static char *uncompress(int16_t field_count, char *start, char *end, | ||
| 32 | * tmp buffer. | ||
| 33 | */ | ||
| 34 | |||
| 35 | - ulen = strlen(name); | ||
| 36 | - strncpy(uptr, name, uncomp_len - (uptr - uncompressed)); | ||
| 37 | - | ||
| 38 | debug("pos %d ulen %d left %d name %s", pos, ulen, | ||
| 39 | (int)(uncomp_len - (uptr - uncompressed)), uptr); | ||
| 40 | |||
| 41 | + ulen = strlen(name); | ||
| 42 | + if ((uptr + ulen + 1) > uncomp_end) { | ||
| 43 | + goto out; | ||
| 44 | + } | ||
| 45 | + strncpy(uptr, name, uncomp_len - (uptr - uncompressed)); | ||
| 46 | + | ||
| 47 | uptr += ulen; | ||
| 48 | *uptr++ = '\0'; | ||
| 49 | |||
| 50 | @@ -1802,6 +1806,10 @@ static char *uncompress(int16_t field_count, char *start, char *end, | ||
| 51 | * We copy also the fixed portion of the result (type, class, | ||
| 52 | * ttl, address length and the address) | ||
| 53 | */ | ||
| 54 | + if ((uptr + NS_RRFIXEDSZ) > uncomp_end) { | ||
| 55 | + debug("uncompressed data too large for buffer"); | ||
| 56 | + goto out; | ||
| 57 | + } | ||
| 58 | memcpy(uptr, ptr, NS_RRFIXEDSZ); | ||
| 59 | |||
| 60 | dns_type = uptr[0] << 8 | uptr[1]; | ||
| 61 | -- | ||
| 62 | 2.17.1 | ||
diff --git a/meta/recipes-connectivity/connman/connman/CVE-2021-26676-0001.patch b/meta/recipes-connectivity/connman/connman/CVE-2021-26676-0001.patch new file mode 100644 index 0000000000..4104e4bfc6 --- /dev/null +++ b/meta/recipes-connectivity/connman/connman/CVE-2021-26676-0001.patch | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | From 58d397ba74873384aee449690a9070bacd5676fa Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Colin Wee <cwee@tesla.com> | ||
| 3 | Date: Thu, 28 Jan 2021 19:39:14 +0100 | ||
| 4 | Subject: [PATCH] gdhcp: Avoid reading invalid data in dhcp_get_option | ||
| 5 | |||
| 6 | Upstream-Status: Backport | ||
| 7 | CVE: CVE-2021-26676 | ||
| 8 | |||
| 9 | Reference to upstream patch: | ||
| 10 | https://git.kernel.org/pub/scm/network/connman/connman.git/commit/?id=58d397ba74873384aee449690a9070bacd5676fa | ||
| 11 | |||
| 12 | Signed-off-by: Catalin Enache <catalin.enache@windriver.com> | ||
| 13 | --- | ||
| 14 | gdhcp/client.c | 20 +++++++++++--------- | ||
| 15 | gdhcp/common.c | 24 +++++++++++++++++++----- | ||
| 16 | gdhcp/common.h | 2 +- | ||
| 17 | gdhcp/server.c | 12 +++++++----- | ||
| 18 | 4 files changed, 38 insertions(+), 20 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/gdhcp/client.c b/gdhcp/client.c | ||
| 21 | index 09dfe5ec..6a5613e7 100644 | ||
| 22 | --- a/gdhcp/client.c | ||
| 23 | +++ b/gdhcp/client.c | ||
| 24 | @@ -1629,12 +1629,12 @@ static void start_request(GDHCPClient *dhcp_client) | ||
| 25 | NULL); | ||
| 26 | } | ||
| 27 | |||
| 28 | -static uint32_t get_lease(struct dhcp_packet *packet) | ||
| 29 | +static uint32_t get_lease(struct dhcp_packet *packet, uint16_t packet_len) | ||
| 30 | { | ||
| 31 | uint8_t *option; | ||
| 32 | uint32_t lease_seconds; | ||
| 33 | |||
| 34 | - option = dhcp_get_option(packet, DHCP_LEASE_TIME); | ||
| 35 | + option = dhcp_get_option(packet, packet_len, DHCP_LEASE_TIME); | ||
| 36 | if (!option) | ||
| 37 | return 3600; | ||
| 38 | |||
| 39 | @@ -2226,7 +2226,8 @@ static void get_dhcpv6_request(GDHCPClient *dhcp_client, | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | -static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet) | ||
| 44 | +static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet, | ||
| 45 | + uint16_t packet_len) | ||
| 46 | { | ||
| 47 | GDHCPOptionType type; | ||
| 48 | GList *list, *value_list; | ||
| 49 | @@ -2237,7 +2238,7 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet) | ||
| 50 | for (list = dhcp_client->request_list; list; list = list->next) { | ||
| 51 | code = (uint8_t) GPOINTER_TO_INT(list->data); | ||
| 52 | |||
| 53 | - option = dhcp_get_option(packet, code); | ||
| 54 | + option = dhcp_get_option(packet, packet_len, code); | ||
| 55 | if (!option) { | ||
| 56 | g_hash_table_remove(dhcp_client->code_value_hash, | ||
| 57 | GINT_TO_POINTER((int) code)); | ||
| 58 | @@ -2297,6 +2298,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 59 | re = dhcp_recv_l2_packet(&packet, | ||
| 60 | dhcp_client->listener_sockfd, | ||
| 61 | &dst_addr); | ||
| 62 | + pkt_len = (uint16_t)(unsigned int)re; | ||
| 63 | xid = packet.xid; | ||
| 64 | } else if (dhcp_client->listen_mode == L3) { | ||
| 65 | if (dhcp_client->type == G_DHCP_IPV6) { | ||
| 66 | @@ -2361,7 +2363,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 67 | dhcp_client->status_code = status; | ||
| 68 | } | ||
| 69 | } else { | ||
| 70 | - message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE); | ||
| 71 | + message_type = dhcp_get_option(&packet, pkt_len, DHCP_MESSAGE_TYPE); | ||
| 72 | if (!message_type) | ||
| 73 | return TRUE; | ||
| 74 | } | ||
| 75 | @@ -2378,7 +2380,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 76 | dhcp_client->timeout = 0; | ||
| 77 | dhcp_client->retry_times = 0; | ||
| 78 | |||
| 79 | - option = dhcp_get_option(&packet, DHCP_SERVER_ID); | ||
| 80 | + option = dhcp_get_option(&packet, pkt_len, DHCP_SERVER_ID); | ||
| 81 | dhcp_client->server_ip = get_be32(option); | ||
| 82 | dhcp_client->requested_ip = ntohl(packet.yiaddr); | ||
| 83 | |||
| 84 | @@ -2428,9 +2430,9 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 85 | |||
| 86 | remove_timeouts(dhcp_client); | ||
| 87 | |||
| 88 | - dhcp_client->lease_seconds = get_lease(&packet); | ||
| 89 | + dhcp_client->lease_seconds = get_lease(&packet, pkt_len); | ||
| 90 | |||
| 91 | - get_request(dhcp_client, &packet); | ||
| 92 | + get_request(dhcp_client, &packet, pkt_len); | ||
| 93 | |||
| 94 | switch_listening_mode(dhcp_client, L_NONE); | ||
| 95 | |||
| 96 | @@ -2438,7 +2440,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 97 | dhcp_client->assigned_ip = get_ip(packet.yiaddr); | ||
| 98 | |||
| 99 | if (dhcp_client->state == REBOOTING) { | ||
| 100 | - option = dhcp_get_option(&packet, | ||
| 101 | + option = dhcp_get_option(&packet, pkt_len, | ||
| 102 | DHCP_SERVER_ID); | ||
| 103 | dhcp_client->server_ip = get_be32(option); | ||
| 104 | } | ||
| 105 | diff --git a/gdhcp/common.c b/gdhcp/common.c | ||
| 106 | index 1d667d17..c8916aa8 100644 | ||
| 107 | --- a/gdhcp/common.c | ||
| 108 | +++ b/gdhcp/common.c | ||
| 109 | @@ -73,18 +73,21 @@ GDHCPOptionType dhcp_get_code_type(uint8_t code) | ||
| 110 | return OPTION_UNKNOWN; | ||
| 111 | } | ||
| 112 | |||
| 113 | -uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code) | ||
| 114 | +uint8_t *dhcp_get_option(struct dhcp_packet *packet, uint16_t packet_len, int code) | ||
| 115 | { | ||
| 116 | int len, rem; | ||
| 117 | - uint8_t *optionptr; | ||
| 118 | + uint8_t *optionptr, *options_end; | ||
| 119 | + size_t options_len; | ||
| 120 | uint8_t overload = 0; | ||
| 121 | |||
| 122 | /* option bytes: [code][len][data1][data2]..[dataLEN] */ | ||
| 123 | optionptr = packet->options; | ||
| 124 | rem = sizeof(packet->options); | ||
| 125 | + options_len = packet_len - (sizeof(*packet) - sizeof(packet->options)); | ||
| 126 | + options_end = optionptr + options_len - 1; | ||
| 127 | |||
| 128 | while (1) { | ||
| 129 | - if (rem <= 0) | ||
| 130 | + if ((rem <= 0) && (optionptr + OPT_CODE > options_end)) | ||
| 131 | /* Bad packet, malformed option field */ | ||
| 132 | return NULL; | ||
| 133 | |||
| 134 | @@ -115,14 +118,25 @@ uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code) | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | + if (optionptr + OPT_LEN > options_end) { | ||
| 139 | + /* bad packet, would read length field from OOB */ | ||
| 140 | + return NULL; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | len = 2 + optionptr[OPT_LEN]; | ||
| 144 | |||
| 145 | rem -= len; | ||
| 146 | if (rem < 0) | ||
| 147 | continue; /* complain and return NULL */ | ||
| 148 | |||
| 149 | - if (optionptr[OPT_CODE] == code) | ||
| 150 | - return optionptr + OPT_DATA; | ||
| 151 | + if (optionptr[OPT_CODE] == code) { | ||
| 152 | + if (optionptr + len > options_end) { | ||
| 153 | + /* bad packet, option length points OOB */ | ||
| 154 | + return NULL; | ||
| 155 | + } else { | ||
| 156 | + return optionptr + OPT_DATA; | ||
| 157 | + } | ||
| 158 | + } | ||
| 159 | |||
| 160 | if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) | ||
| 161 | overload |= optionptr[OPT_DATA]; | ||
| 162 | diff --git a/gdhcp/common.h b/gdhcp/common.h | ||
| 163 | index 9660231c..8f63fd75 100644 | ||
| 164 | --- a/gdhcp/common.h | ||
| 165 | +++ b/gdhcp/common.h | ||
| 166 | @@ -179,7 +179,7 @@ struct in6_pktinfo { | ||
| 167 | }; | ||
| 168 | #endif | ||
| 169 | |||
| 170 | -uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code); | ||
| 171 | +uint8_t *dhcp_get_option(struct dhcp_packet *packet, uint16_t packet_len, int code); | ||
| 172 | uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len, | ||
| 173 | int code, uint16_t *option_len, int *option_count); | ||
| 174 | uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len, | ||
| 175 | diff --git a/gdhcp/server.c b/gdhcp/server.c | ||
| 176 | index 85405f19..52ea2a55 100644 | ||
| 177 | --- a/gdhcp/server.c | ||
| 178 | +++ b/gdhcp/server.c | ||
| 179 | @@ -413,7 +413,7 @@ error: | ||
| 180 | } | ||
| 181 | |||
| 182 | |||
| 183 | -static uint8_t check_packet_type(struct dhcp_packet *packet) | ||
| 184 | +static uint8_t check_packet_type(struct dhcp_packet *packet, uint16_t packet_len) | ||
| 185 | { | ||
| 186 | uint8_t *type; | ||
| 187 | |||
| 188 | @@ -423,7 +423,7 @@ static uint8_t check_packet_type(struct dhcp_packet *packet) | ||
| 189 | if (packet->op != BOOTREQUEST) | ||
| 190 | return 0; | ||
| 191 | |||
| 192 | - type = dhcp_get_option(packet, DHCP_MESSAGE_TYPE); | ||
| 193 | + type = dhcp_get_option(packet, packet_len, DHCP_MESSAGE_TYPE); | ||
| 194 | |||
| 195 | if (!type) | ||
| 196 | return 0; | ||
| 197 | @@ -651,6 +651,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 198 | struct dhcp_lease *lease; | ||
| 199 | uint32_t requested_nip = 0; | ||
| 200 | uint8_t type, *server_id_option, *request_ip_option; | ||
| 201 | + uint16_t packet_len; | ||
| 202 | int re; | ||
| 203 | |||
| 204 | if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { | ||
| 205 | @@ -661,12 +662,13 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 206 | re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd); | ||
| 207 | if (re < 0) | ||
| 208 | return TRUE; | ||
| 209 | + packet_len = (uint16_t)(unsigned int)re; | ||
| 210 | |||
| 211 | - type = check_packet_type(&packet); | ||
| 212 | + type = check_packet_type(&packet, packet_len); | ||
| 213 | if (type == 0) | ||
| 214 | return TRUE; | ||
| 215 | |||
| 216 | - server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID); | ||
| 217 | + server_id_option = dhcp_get_option(&packet, packet_len, DHCP_SERVER_ID); | ||
| 218 | if (server_id_option) { | ||
| 219 | uint32_t server_nid = | ||
| 220 | get_unaligned((const uint32_t *) server_id_option); | ||
| 221 | @@ -675,7 +677,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 222 | return TRUE; | ||
| 223 | } | ||
| 224 | |||
| 225 | - request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP); | ||
| 226 | + request_ip_option = dhcp_get_option(&packet, packet_len, DHCP_REQUESTED_IP); | ||
| 227 | if (request_ip_option) | ||
| 228 | requested_nip = get_be32(request_ip_option); | ||
| 229 | |||
| 230 | -- | ||
| 231 | 2.17.1 | ||
diff --git a/meta/recipes-connectivity/connman/connman/CVE-2021-26676-0002.patch b/meta/recipes-connectivity/connman/connman/CVE-2021-26676-0002.patch new file mode 100644 index 0000000000..ce909ec293 --- /dev/null +++ b/meta/recipes-connectivity/connman/connman/CVE-2021-26676-0002.patch | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | From a74524b3e3fad81b0fd1084ffdf9f2ea469cd9b1 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Colin Wee <cwee@tesla.com> | ||
| 3 | Date: Thu, 28 Jan 2021 19:41:09 +0100 | ||
| 4 | Subject: [PATCH] gdhcp: Avoid leaking stack data via unitiialized variable | ||
| 5 | |||
| 6 | Fixes: CVE-2021-26676 | ||
| 7 | |||
| 8 | Upstream-Status: Backport | ||
| 9 | CVE: CVE-2021-26676 | ||
| 10 | |||
| 11 | Reference to upstream patch: | ||
| 12 | https://git.kernel.org/pub/scm/network/connman/connman.git/commit/?id=a74524b3e3fad81b0fd1084ffdf9f2ea469cd9b1 | ||
| 13 | |||
| 14 | Signed-off-by: Catalin Enache <catalin.enache@windriver.com> | ||
| 15 | --- | ||
| 16 | gdhcp/client.c | 2 +- | ||
| 17 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 18 | |||
| 19 | diff --git a/gdhcp/client.c b/gdhcp/client.c | ||
| 20 | index 6a5613e7..c7b85e58 100644 | ||
| 21 | --- a/gdhcp/client.c | ||
| 22 | +++ b/gdhcp/client.c | ||
| 23 | @@ -2270,7 +2270,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, | ||
| 24 | { | ||
| 25 | GDHCPClient *dhcp_client = user_data; | ||
| 26 | struct sockaddr_in dst_addr = { 0 }; | ||
| 27 | - struct dhcp_packet packet; | ||
| 28 | + struct dhcp_packet packet = { 0 }; | ||
| 29 | struct dhcpv6_packet *packet6 = NULL; | ||
| 30 | uint8_t *message_type = NULL, *client_id = NULL, *option, | ||
| 31 | *server_id = NULL; | ||
| 32 | -- | ||
| 33 | 2.17.1 | ||
diff --git a/meta/recipes-connectivity/connman/connman_1.37.bb b/meta/recipes-connectivity/connman/connman_1.37.bb index 00852bf0d6..bdab4c4f18 100644 --- a/meta/recipes-connectivity/connman/connman_1.37.bb +++ b/meta/recipes-connectivity/connman/connman_1.37.bb | |||
| @@ -6,6 +6,9 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/network/${BPN}/${BP}.tar.xz \ | |||
| 6 | file://0001-gweb-fix-segfault-with-musl-v1.1.21.patch \ | 6 | file://0001-gweb-fix-segfault-with-musl-v1.1.21.patch \ |
| 7 | file://connman \ | 7 | file://connman \ |
| 8 | file://no-version-scripts.patch \ | 8 | file://no-version-scripts.patch \ |
| 9 | file://CVE-2021-26675.patch \ | ||
| 10 | file://CVE-2021-26676-0001.patch \ | ||
| 11 | file://CVE-2021-26676-0002.patch \ | ||
| 9 | " | 12 | " |
| 10 | 13 | ||
| 11 | SRC_URI_append_libc-musl = " file://0002-resolve-musl-does-not-implement-res_ninit.patch" | 14 | SRC_URI_append_libc-musl = " file://0002-resolve-musl-does-not-implement-res_ninit.patch" |
