Skip to content

Commit 9ac54f0

Browse files
committed
[daap] Fix null pointer deref in parse_meta()
Description NULL Pointer Dereference in daap_reply_playlists (src/httpd_daap.c:1483). Analysis When the meta parameter contains consecutive commas (e.g. "abc,,def"), The function parse_meta does not increment nmeta correctly and may leave NULL values in the meta array. After calling parse_meta, The function daap_reply_playlists accesses the member dfm of meta[i], causing a NULL Pointer Dereference. Steps to reproduce Sending the following request (followed by two CRLFs): GET /databases/1/containers?meta=abc,,def HTTP/1.1 Thanks @archersec for finding and reporting. Fixes #1961.
1 parent 3d1652d commit 9ac54f0

File tree

3 files changed

+42
-42
lines changed

3 files changed

+42
-42
lines changed

src/dmap_common.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ dmap_get_fields_table(int *nfields)
4343

4444
// This wrapper is so callers don't need to include dmap_fields_hash.h
4545
const struct dmap_field *
46-
dmap_find_field_wrapper(const char *str, int len)
46+
dmap_find_field_wrapper(const char *str)
4747
{
48-
return dmap_find_field(str, len);
48+
if (!str)
49+
return NULL;
50+
51+
return dmap_find_field(str, strlen(str));
4952
}
5053

5154
void

src/dmap_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const struct dmap_field *
4545
dmap_get_fields_table(int *nfields);
4646

4747
const struct dmap_field *
48-
dmap_find_field_wrapper(const char *str, int len);
48+
dmap_find_field_wrapper(const char *str);
4949

5050

5151
void

src/httpd_daap.c

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -592,64 +592,61 @@ query_params_set(struct query_params *qp, int *sort_headers, struct httpd_reques
592592
user_agent_filter(qp, hreq);
593593
}
594594

595+
#define NMETA_MAX 128
595596
static int
596597
parse_meta(const struct dmap_field ***out_meta, const char *param)
597598
{
598-
const struct dmap_field **meta;
599-
char *ptr;
599+
const struct dmap_field *meta[NMETA_MAX];
600+
const struct dmap_field *dfield;
601+
size_t out_size;
602+
char *saveptr;
600603
char *field;
601-
char *metastr;
604+
char *param_copy;
605+
bool is_duplicate;
602606
int nmeta;
603607
int i;
604-
int n;
605-
606-
CHECK_NULL(L_DAAP, metastr = strdup(param));
607-
608-
nmeta = 1;
609-
ptr = metastr;
610-
while ((ptr = strchr(ptr + 1, ',')) && (strlen(ptr) > 1))
611-
nmeta++;
612-
613-
DPRINTF(E_DBG, L_DAAP, "Asking for %d meta tags\n", nmeta);
614-
615-
CHECK_NULL(L_DAAP, meta = calloc(nmeta, sizeof(const struct dmap_field *)));
616608

617-
field = strtok_r(metastr, ",", &ptr);
618-
for (i = 0; field != NULL && i < nmeta; i++)
609+
CHECK_NULL(L_DAAP, param_copy = strdup(param));
610+
field = strtok_r(param_copy, ",", &saveptr);
611+
nmeta = 0;
612+
for (; field && nmeta < NMETA_MAX; field = strtok_r(NULL, ",", &saveptr))
619613
{
620-
for (n = 0; (n < i) && (strcmp(field, meta[n]->desc) != 0); n++);
621-
622-
if (n == i)
614+
dfield = dmap_find_field_wrapper(field);
615+
if (!dfield)
623616
{
624-
meta[i] = dmap_find_field_wrapper(field, strlen(field));
625-
626-
if (!meta[i])
627-
{
628-
DPRINTF(E_WARN, L_DAAP, "Could not find requested meta field '%s'\n", field);
629-
630-
i--;
631-
nmeta--;
632-
}
617+
DPRINTF(E_DBG, L_DAAP, "Could not find requested meta field '%s' in '%s'\n", field, param);
618+
continue;
633619
}
634-
else
635-
{
636-
DPRINTF(E_WARN, L_DAAP, "Parser will ignore duplicate occurrence of meta field '%s'\n", field);
637620

638-
i--;
639-
nmeta--;
621+
is_duplicate = false;
622+
for (i = 0; i < nmeta && !is_duplicate; i++)
623+
is_duplicate = (dfield == meta[i]);
624+
if (is_duplicate)
625+
{
626+
DPRINTF(E_SPAM, L_DAAP, "Parser will ignore duplicate occurrence of meta field '%s'\n", field);
627+
continue;
640628
}
641629

642-
field = strtok_r(NULL, ",", &ptr);
630+
meta[nmeta] = dfield;
631+
nmeta++;
643632
}
644633

645-
free(metastr);
646-
647-
DPRINTF(E_DBG, L_DAAP, "Found %d meta tags\n", nmeta);
634+
if (nmeta == 0)
635+
{
636+
printf("No known metadata fields found in input '%s'\n", param);
637+
goto out;
638+
}
648639

649-
*out_meta = meta;
640+
// meta is a list of pointers to dmf entries, here we copy it to the heap
641+
out_size = nmeta * sizeof(struct dmap_field *);
642+
CHECK_NULL(L_DAAP, *out_meta = malloc(out_size));
643+
memcpy(*out_meta, meta, out_size);
650644

645+
out:
646+
free(param_copy);
651647
return nmeta;
652648
}
649+
#undef NMETA_MAX
653650

654651
static void
655652
daap_reply_send(struct httpd_request *hreq, enum daap_reply_result result)

0 commit comments

Comments
 (0)