From 5f21094a6862c65eb96dc10112a2a516f7275c59 Mon Sep 17 00:00:00 2001 From: dmiller Date: Tue, 13 Sep 2022 21:09:38 +0000 Subject: [PATCH] Fix a memory leak of port service name (strdup but not freed) --- portlist.cc | 77 ++++++++++++++++++++++++++++++----------------------- portlist.h | 6 +++-- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/portlist.cc b/portlist.cc index 01aa8fb0c..4feafb37a 100644 --- a/portlist.cc +++ b/portlist.cc @@ -84,33 +84,39 @@ Port::Port() { state_reason_init(&reason); } -void Port::freeService(bool del_service) { - if (service != NULL) { - std::vector::iterator it; +void serviceDeductions::erase() { + std::vector::iterator it; - if (service->name) - free(service->name); - if (service->product) - free(service->product); - if (service->version) - free(service->version); - if (service->extrainfo) - free(service->extrainfo); - if (service->hostname) - free(service->hostname); - if (service->ostype) - free(service->ostype); - if (service->devicetype) - free(service->devicetype); - if (service->service_fp) - free(service->service_fp); - for (it = service->cpe.begin(); it != service->cpe.end(); it++) - free(*it); - service->cpe.clear(); + if (this->product) + free(this->product); + if (this->version) + free(this->version); + if (this->extrainfo) + free(this->extrainfo); + if (this->hostname) + free(this->hostname); + if (this->ostype) + free(this->ostype); + if (this->devicetype) + free(this->devicetype); + if (this->service_fp) + free(this->service_fp); + // For now, always free CPE strings + for (it = this->cpe.begin(); it != this->cpe.end(); it++) + free(*it); + this->cpe.clear(); - if (del_service) - delete service; - } + this->name = NULL; + this->name_confidence = 0; + this->product = NULL; + this->version = NULL; + this->extrainfo = NULL; + this->hostname = NULL; + this->ostype = NULL; + this->devicetype = NULL; + this->service_tunnel = SERVICE_TUNNEL_NONE; + this->service_fp = NULL; + this->dtype = SERVICE_DETECTION_TABLE; } void Port::freeScriptResults(void) @@ -253,7 +259,6 @@ void serviceDeductions::populateFullVersionString(char *buf, size_t n) const { // pass in an allocated struct serviceDeductions (don't worry about // initializing, and you don't have to free any internal ptrs. See the // serviceDeductions definition for the fields that are populated. -// Returns 0 if at least a name is available. void PortList::getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const { const Port *port; @@ -265,7 +270,7 @@ void PortList::getServiceDeductions(u16 portno, int protocol, struct serviceDedu *sd = serviceDeductions(); service = nmap_getservbyport(portno, IPPROTO2STR(protocol)); if (service != NULL) - sd->name = strdup(service->s_name); + sd->name = service->s_name; else sd->name = NULL; sd->name_confidence = 3; @@ -315,6 +320,8 @@ void PortList::setServiceProbeResults(u16 portno, int protocol, port = createPort(portno, protocol); if (port->service == NULL) port->service = new serviceDeductions; + else + port->service->erase(); if (sres == PROBESTATE_FINISHED_HARDMATCHED || sres == PROBESTATE_FINISHED_SOFTMATCHED) { @@ -341,10 +348,8 @@ void PortList::setServiceProbeResults(u16 portno, int protocol, // port->serviceprobe_results = sres; port->service->service_tunnel = tunnel; - port->freeService(false); - if (sname) - port->service->name = strdup(sname); + port->service->name = sname; else port->service->name = NULL; @@ -426,10 +431,14 @@ PortList::~PortList() { for(proto=0; proto < PORTLIST_PROTO_MAX; proto++) { // for every protocol if(port_list[proto]) { for(i=0; i < port_list_count[proto]; i++) { // free every Port - if(port_list[proto][i]) { - port_list[proto][i]->freeService(true); - port_list[proto][i]->freeScriptResults(); - delete port_list[proto][i]; + Port *port = port_list[proto][i]; + if(port) { + if (port->service) { + port->service->erase(); + delete port->service; + } + port->freeScriptResults(); + delete port; } } free(port_list[proto]); diff --git a/portlist.h b/portlist.h index 73cf664af..7d31eceac 100644 --- a/portlist.h +++ b/portlist.h @@ -115,9 +115,11 @@ void random_port_cheat(u16 *ports, int portcount); struct serviceDeductions { serviceDeductions(); + // Free any strings that need to be freed and set all pointers to null. + void erase(); void populateFullVersionString(char *buf, size_t n) const; - char *name; // will be NULL if can't determine + const char *name; // will be NULL if can't determine // Confidence is a number from 0 (least confident) to 10 (most // confident) expressing how accurate the service detection is // likely to be. @@ -236,7 +238,7 @@ class PortList { // pass in an allocated struct serviceDeductions (don't worry about initializing, and // you don't have to free any internal ptrs. See the serviceDeductions definition for - // the fields that are populated. Returns 0 if at least a name is available. + // the fields that are populated. void getServiceDeductions(u16 portno, int protocol, struct serviceDeductions *sd) const; #ifndef NOLUA