diff --git a/fuzz/libpsl_fuzzer.c b/fuzz/libpsl_fuzzer.c index ef6a6ef..786da3d 100644 --- a/fuzz/libpsl_fuzzer.c +++ b/fuzz/libpsl_fuzzer.c @@ -40,9 +40,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { static int first_run = 1; psl_ctx_t *psl; - char *domain = (char *) malloc(size + 1), *res; + char *domain, *res; int rc; + if (size > 64 * 1024 - 1) + return 0; + + domain = (char *) malloc(size + 1); assert(domain != NULL); /* 0 terminate */ diff --git a/src/psl.c b/src/psl.c index 1691d5c..323409c 100644 --- a/src/psl.c +++ b/src/psl.c @@ -1048,6 +1048,19 @@ const char *psl_unregistrable_domain(const psl_ctx_t *psl, const char *domain) if (!psl || !domain) return NULL; + /* + * In the main loop we introduce a O(N^2) behavior to avoid code duplication. + * To avoid nasty CPU hogging, we limit the lookup to max. 8 domain labels to the right. + */ + + int nlabels = 0; + for (const char *p = domain + strlen(domain) - 1; p >= domain; p--) { + if (*p == '.' && ++nlabels > 8) { + domain = p + 1; + break; + } + } + /* * We check from left to right to catch special PSL entries like 'forgot.his.name': * 'forgot.his.name' and 'name' are in the PSL while 'his.name' is not. @@ -1090,6 +1103,19 @@ const char *psl_registrable_domain(const psl_ctx_t *psl, const char *domain) if (!psl || !domain || *domain == '.') return NULL; + /* + * In the main loop we introduce a O(N^2) behavior to avoid code duplication. + * To avoid nasty CPU hogging, we limit the lookup to max. 8 domain labels to the right. + */ + + int nlabels = 0; + for (p = domain + strlen(domain) - 1; p >= domain; p--) { + if (*p == '.' && ++nlabels > 8) { + domain = p + 1; + break; + } + } + /* * We check from left to right to catch special PSL entries like 'forgot.his.name': * 'forgot.his.name' and 'name' are in the PSL while 'his.name' is not.