Coverage Report

Created: 2026-08-31 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/test/fuzz/fuzz_url.c
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  Licensed under the Apache License,
4
 * Version 2.0 (the "License"); you may not use this file except in
5
 * compliance with the License.  You may obtain a copy of the License at
6
 *
7
 *   http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Copyright (C) 2017-2026 ZmartZone Holding BV - hans.zandbelt@openidc.com
10
 *
11
 * Fuzz target for oidc_validate_redirect_url(): the open-redirect guard that
12
 * vets attacker-supplied return-to / post_logout_redirect / target_link_uri
13
 * values before the module redirects to them. Seed corpus:
14
 * test/open-redirect-payload-list.txt (replayed line by line).
15
 *
16
 * Every input is validated three times, against the three configurations the
17
 * guard distinguishes: same-host scope (the logout/return-to case), any-host
18
 * scope (the target_link_uri case once it has passed the configured-URL
19
 * match), and same-host scope with an OIDCRedirectURLsAllowed list -- which
20
 * switches the guard from hostname comparison to regex matching, a branch the
21
 * fixture's plain configuration never takes. The allow-list copy of the
22
 * fixture config is made once at startup; the fixture itself is not changed.
23
 */
24
25
#include "cfg/cfg_int.h" /* oidc_cfg_t members, for the allow-list */
26
#include "fuzz.h"
27
#include "mod_auth_openidc.h" /* oidc_validate_redirect_url */
28
#include "util.h"       /* test fixture */
29
30
#include <apr_hash.h>
31
#include <apr_pools.h>
32
#include <apr_strings.h>
33
34
static int g_ready = 0;
35
static oidc_cfg_t *g_cfg_allowed = NULL;
36
37
/* engine-called one-time init, pre-forkserver on AFL++: see fuzz.h */
38
34
int LLVMFuzzerInitialize(int *argc, char ***argv) {
39
34
  (void)argc;
40
34
  (void)argv;
41
34
  if (!g_ready) {
42
34
    oidc_test_setup();
43
    /* a second server config carrying an allow-list: one anchored host
44
     * pattern and one deliberately loose one, so both the match and the
45
     * no-match legs of the regex loop see traffic. Allocated by the library
46
     * rather than declared here by value: sizeof(oidc_cfg_t) depends on the
47
     * USE_* feature macros, so a by-value instance in this TU is only as big
48
     * as the harness build flags make it, not as big as the library expects. */
49
34
    apr_pool_t *pool = oidc_test_pool_get();
50
34
    g_cfg_allowed = oidc_cfg_server_create(pool, oidc_test_request_get()->server);
51
34
    g_cfg_allowed->redirect_urls_allowed = apr_hash_make(pool);
52
34
    const char *anchored = "^https://www\\.example\\.com/";
53
34
    const char *loose = "example\\.org/.*callback";
54
34
    apr_hash_set(g_cfg_allowed->redirect_urls_allowed, anchored, APR_HASH_KEY_STRING, anchored);
55
34
    apr_hash_set(g_cfg_allowed->redirect_urls_allowed, loose, APR_HASH_KEY_STRING, loose);
56
34
    g_ready = 1;
57
34
  }
58
34
  return 0;
59
34
}
60
61
6.63k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
62
6.63k
  if (!g_ready)
63
0
    LLVMFuzzerInitialize(NULL, NULL);
64
65
6.63k
  apr_pool_t *pool = NULL;
66
6.63k
  apr_pool_create(&pool, oidc_test_pool_get());
67
68
  /* shallow-copy the fixture request and give it a per-input pool so all
69
   * allocations made while validating are reclaimed each iteration */
70
6.63k
  request_rec r = *oidc_test_request_get();
71
6.63k
  r.pool = pool;
72
6.63k
  oidc_cfg_t *cfg = oidc_test_cfg_get();
73
74
6.63k
  char *url = apr_pstrmemdup(pool, (const char *)data, size);
75
6.63k
  char *err_str = NULL;
76
6.63k
  char *err_desc = NULL;
77
6.63k
  oidc_validate_redirect_url(&r, cfg, url, OIDC_REDIRECT_URL_SAME_HOST, &err_str, &err_desc);
78
6.63k
  oidc_validate_redirect_url(&r, cfg, url, OIDC_REDIRECT_URL_ANY_HOST, &err_str, &err_desc);
79
6.63k
  oidc_validate_redirect_url(&r, g_cfg_allowed, url, OIDC_REDIRECT_URL_SAME_HOST, &err_str, &err_desc);
80
81
6.63k
  apr_pool_destroy(pool);
82
6.63k
  return 0;
83
6.63k
}