diff --git a/tests/fuzzing/meson.build b/tests/fuzzing/meson.build index ffc367759..b0622298e 100644 --- a/tests/fuzzing/meson.build +++ b/tests/fuzzing/meson.build @@ -29,6 +29,8 @@ nas_5gs_message_source = files('nas-5gs-message-fuzz.c') sbi_nf_profile_source = files('sbi-nf-profile-fuzz.c') sbi_sm_context_source = files('sbi-sm-context-fuzz.c') ipfw_rule_source = files('ipfw-rule-fuzz.c') +sbi_openapi_model_source = files('sbi-openapi-model-fuzz.c') +sbi_request_source = files('sbi-request-fuzz.c') # Build all executable executable( @@ -87,6 +89,22 @@ executable( link_args: lib_fuzzing_engine ) +executable( + 'sbi_openapi_model_fuzz', + sources : sbi_openapi_model_source, + c_args : [testunit_core_cc_flags, sbi_cc_flags], + dependencies : [libsbi_dep, libcore_dep], + link_args: lib_fuzzing_engine +) + +executable( + 'sbi_request_fuzz', + sources : sbi_request_source, + c_args : [testunit_core_cc_flags, sbi_cc_flags], + dependencies : [libsbi_dep, libcore_dep], + link_args: lib_fuzzing_engine +) + executable( 'sbi_sm_context_fuzz', sources : sbi_sm_context_source, diff --git a/tests/fuzzing/sbi-openapi-model-fuzz.c b/tests/fuzzing/sbi-openapi-model-fuzz.c new file mode 100644 index 000000000..4d9e7585a --- /dev/null +++ b/tests/fuzzing/sbi-openapi-model-fuzz.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019-2026 by Arthur SC Chan + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "fuzzing.h" +#include "ogs-sbi.h" + +#include "model/access_and_mobility_subscription_data.h" +#include "model/dnn_configuration.h" +#include "model/event_notification.h" +#include "model/event_subscription.h" +#include "model/events_notification.h" +#include "model/hsmf_update_data.h" +#include "model/mdt_configuration.h" +#include "model/media_component.h" +#include "model/media_component_rm.h" +#include "model/pcc_rule.h" +#include "model/pdu_session_create_data.h" +#include "model/pdu_session_created_data.h" +#include "model/policy_association_request.h" +#include "model/sm_context_update_data.h" +#include "model/sm_policy_context_data.h" +#include "model/sm_policy_decision.h" +#include "model/subscr_cond.h" +#include "model/ue_context.h" +#include "model/vsmf_update_data.h" + +#define kMinInputLength 2 +#define kMaxInputLength 16384 + +#define TRY_MODEL(name) \ + do { \ + cJSON *json = cJSON_Parse(text); \ + if (json) { \ + OpenAPI_##name##_t *model = \ + OpenAPI_##name##_parseFromJSON(json); \ + if (model) { \ + OpenAPI_##name##_free(model); \ + } \ + cJSON_Delete(json); \ + } \ + } while (0) + +extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) +{ + char *text; + + if (Size < kMinInputLength || Size > kMaxInputLength) { + return 1; + } + + if (!initialized) { + initialize(); + ogs_log_install_domain(&__ogs_sbi_domain, "sbi", OGS_LOG_NONE); + } + + /* cJSON_Parse needs a NUL-terminated string, as the HTTP layer provides. */ + text = ogs_malloc(Size + 1); + if (text == NULL) { + return 0; + } + memcpy(text, Data, Size); + text[Size] = '\0'; + + /* AMF and SMF context transfer */ + TRY_MODEL(ue_context); + TRY_MODEL(sm_context_update_data); + TRY_MODEL(pdu_session_create_data); + TRY_MODEL(pdu_session_created_data); + TRY_MODEL(hsmf_update_data); + TRY_MODEL(vsmf_update_data); + + /* Subscription and event exposure */ + TRY_MODEL(event_subscription); + TRY_MODEL(events_notification); + TRY_MODEL(event_notification); + TRY_MODEL(subscr_cond); + + /* Subscriber data from UDM/UDR */ + TRY_MODEL(access_and_mobility_subscription_data); + TRY_MODEL(dnn_configuration); + TRY_MODEL(mdt_configuration); + + /* Policy control */ + TRY_MODEL(sm_policy_context_data); + TRY_MODEL(sm_policy_decision); + TRY_MODEL(policy_association_request); + TRY_MODEL(pcc_rule); + TRY_MODEL(media_component); + TRY_MODEL(media_component_rm); + + ogs_free(text); + + return 0; +} diff --git a/tests/fuzzing/sbi-request-fuzz.c b/tests/fuzzing/sbi-request-fuzz.c new file mode 100644 index 000000000..396ca0ce8 --- /dev/null +++ b/tests/fuzzing/sbi-request-fuzz.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019-2026 by Arthur SC Chan + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "fuzzing.h" +#include "ogs-sbi.h" + +#define kMinInputLength 4 +#define kMaxInputLength 16384 + +extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) +{ + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + const uint8_t *nl = NULL; + size_t line_len = 0, body_len = 0; + char *line = NULL, *sp = NULL; + + if (Size < kMinInputLength || Size > kMaxInputLength) { + return 0; + } + + if (!initialized) { + initialize(); + ogs_log_install_domain(&__ogs_sbi_domain, "sbi", OGS_LOG_NONE); + ogs_sbi_message_init(8, 8); + } + + /* Split " \n" */ + nl = (const uint8_t *)memchr(Data, '\n', Size); + line_len = nl ? (size_t)(nl - Data) : Size; + body_len = nl ? Size - line_len - 1 : 0; + + line = ogs_malloc(line_len + 1); + if (line == NULL) { + return 0; + } + memcpy(line, Data, line_len); + line[line_len] = '\0'; + + request = ogs_sbi_request_new(); + if (request == NULL) { + ogs_free(line); + return 0; + } + + sp = strchr(line, ' '); + if (sp) { + *sp = '\0'; + request->h.method = ogs_strdup(line); + request->h.uri = ogs_strdup(sp + 1); + } else { + request->h.method = ogs_strdup(line); + request->h.uri = ogs_strdup(""); + } + + /* The HTTP layer always hands open5gs a NUL-terminated body */ + if (body_len) { + request->http.content = ogs_malloc(body_len + 1); + if (request->http.content) { + memcpy(request->http.content, nl + 1, body_len); + request->http.content[body_len] = '\0'; + request->http.content_length = body_len; + } + } + + memset(&message, 0, sizeof(message)); + if (ogs_sbi_parse_request(&message, request) == OGS_OK) { + ogs_sbi_message_free(&message); + } + + ogs_sbi_request_free(request); + ogs_free(line); + + return 0; +}