avdtp: Fix accepting invalid/malformed capabilities
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 30 Apr 2021 00:10:50 +0000 (17:10 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 11 Mar 2022 13:38:35 +0000 (19:08 +0530)
Check if capabilities are valid before attempting to copy them.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
profiles/audio/avdtp.c

index 9da2f9f..d1f8440 100644 (file)
@@ -1748,43 +1748,53 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
        return NULL;
 }
 
-static GSList *caps_to_list(uint8_t *data, int size,
+static GSList *caps_to_list(uint8_t *data, size_t size,
                                struct avdtp_service_capability **codec,
                                gboolean *delay_reporting)
 {
+       struct avdtp_service_capability *cap;
        GSList *caps;
-       int processed;
 
        if (delay_reporting)
                *delay_reporting = FALSE;
 
-       for (processed = 0, caps = NULL; processed + 2 <= size;) {
-               struct avdtp_service_capability *cap;
-               uint8_t length, category;
+       if (size < sizeof(*cap))
+               return NULL;
+
+       for (caps = NULL; size >= sizeof(*cap);) {
+               struct avdtp_service_capability *cpy;
 
-               category = data[0];
-               length = data[1];
+               cap = (struct avdtp_service_capability *)data;
 
-               if (processed + 2 + length > size) {
+               if (sizeof(*cap) + cap->length >= size) {
                        error("Invalid capability data in getcap resp");
                        break;
                }
 
-               cap = g_malloc(sizeof(struct avdtp_service_capability) +
-                                       length);
-               memcpy(cap, data, 2 + length);
+               if (cap->category == AVDTP_MEDIA_CODEC &&
+                                       cap->length < sizeof(**codec)) {
+                       error("Invalid codec data in getcap resp");
+                       break;
+               }
+
+               cpy = btd_malloc(sizeof(*cpy) + cap->length);
+               memcpy(cpy, cap, sizeof(*cap) + cap->length);
 
-               processed += 2 + length;
-               data += 2 + length;
+               size -= sizeof(*cap) + cap->length;
+               data += sizeof(*cap) + cap->length;
 
-               caps = g_slist_append(caps, cap);
+               caps = g_slist_append(caps, cpy);
 
-               if (category == AVDTP_MEDIA_CODEC &&
-                               length >=
-                               sizeof(struct avdtp_media_codec_capability))
-                       *codec = cap;
-               else if (category == AVDTP_DELAY_REPORTING && delay_reporting)
-                       *delay_reporting = TRUE;
+               switch (cap->category) {
+               case AVDTP_MEDIA_CODEC:
+                       if (codec)
+                               *codec = cap;
+                       break;
+               case AVDTP_DELAY_REPORTING:
+                       if (delay_reporting)
+                               *delay_reporting = TRUE;
+                       break;
+               }
        }
 
        return caps;
@@ -1981,6 +1991,12 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
                                        &stream->codec,
                                        &stream->delay_reporting);
 
+       if (!stream->caps || !stream->codec) {
+               err = AVDTP_UNSUPPORTED_CONFIGURATION;
+               category = 0x00;
+               goto failed_stream;
+       }
+
        /* Verify that the Media Transport capability's length = 0. Reject otherwise */
        for (l = stream->caps; l != NULL; l = g_slist_next(l)) {
                struct avdtp_service_capability *cap = l->data;