[stunnel-users] fix resource leaks and potential null

Arthur Mesh arthurmesh at gmail.com
Mon Feb 4 19:17:10 CET 2013


dereferences in 4.54
Reply-To: 
In-Reply-To: <mailman.1.1359889202.25775.stunnel-users at stunnel.org>

On Sun, Feb 03, 2013 at 12:00:02PM +0100, stunnel-users-request at stunnel.org wrote:
> > -    char line_text[CONFLINELEN], *errstr;
> > +    char line_text[CONFLINELEN], *errstr = NULL;
> Were you able to identify a case where it's used without
> initialization?  This is interesting.
> It would be a good idea to fix it there instead of implementing a
> workaround here.

Hi,

I will provide the output of coverity run for these defect:

int parse_conf(char *name, CONF_TYPE type) {
1997    DISK_FILE *df;
At (1): Declaring variable "errstr" without initializer.
1998    char line_text[CONFLINELEN], *errstr;
1999    char config_line[CONFLINELEN], *config_opt, *config_arg;
2000    int line_number, i;
2001    SERVICE_OPTIONS *section, *new_section;
2002    static char *filename=NULL; /* a copy of config file name for reloading */
2003#ifndef USE_WIN32
2004    int fd;
2005    char *tmpstr;
2006#endif
2007
At (2): Condition "name", taking true branch
2008    if(name) /* not reload */
2009        filename=str_dup(name);
2010
At (3): Condition "type == 2U", taking true branch
2011    s_log(LOG_NOTICE, "Reading configuration from %s %s",
2012        type==CONF_FD ? "descriptor" : "file", filename);
2013#ifndef USE_WIN32
At (4): Condition "type == 2U", taking true branch
2014    if(type==CONF_FD) { /* file descriptor */
2015        fd=strtol(filename, &tmpstr, 10);
At (5): Condition "tmpstr == filename", taking false branch
At (6): Condition "*tmpstr", taking false branch
2016        if(tmpstr==filename || *tmpstr) { /* not a number */
2017            s_log(LOG_ERR, "Invalid file descriptor number");
2018            print_syntax();
2019            return 1;
2020        }
2021        df=file_fdopen(fd);
At (7): Falling through to end of if statement
2022    } else
2023#endif
2024        df=file_open(filename, 0);
At (8): Condition "!df", taking false branch
2025    if(!df) {
2026        s_log(LOG_ERR, "Cannot read configuration");
2027        if(type!=CONF_RELOAD)
2028            print_syntax();
2029        return 1;
2030    }
2031
2032    memset(&new_global_options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */
2033    memset(&new_service_options, 0, sizeof(SERVICE_OPTIONS)); /* reset local options */
2034    new_service_options.next=NULL;
2035    section=&new_service_options;
2036    parse_global_option(CMD_BEGIN, NULL, NULL);
2037    parse_service_option(CMD_BEGIN, section, NULL, NULL);
At (9): Condition "type != 0U", taking true branch
2038    if(type!=CONF_RELOAD) { /* provide defaults for gui.c */
2039        memcpy(&global_options, &new_global_options, sizeof(GLOBAL_OPTIONS));
2040        memcpy(&service_options, &new_service_options, sizeof(SERVICE_OPTIONS));
2041    }
2042
2043    line_number=0;
At (10): Condition "file_getline(df, line_text, 16384) >= 0", taking true branch
At (19): Condition "file_getline(df, line_text, 16384) >= 0", taking false branch
2044    while(file_getline(df, line_text, CONFLINELEN)>=0) {
2045        memcpy(config_line, line_text, CONFLINELEN);
2046        ++line_number;
2047        config_opt=config_line;
At (11): Condition "__istype((unsigned char)*config_opt, 16384UL)", taking true branch
At (12): Condition "__istype((unsigned char)*config_opt, 16384UL)", taking false branch
2048        while(isspace((unsigned char)*config_opt))
2049            ++config_opt; /* remove initial whitespaces */
At (13): Condition "i >= 0", taking true branch
At (14): Condition "__istype((unsigned char)config_opt[i], 16384UL)", taking true branch
At (15): Condition "i >= 0", taking true branch
At (16): Condition "__istype((unsigned char)config_opt[i], 16384UL)", taking false branch
2050        for(i=strlen(config_opt)-1; i>=0 && isspace((unsigned char)config_opt[i]); --i)
2051            config_opt[i]='\0'; /* remove trailing whitespaces */
At (17): Condition "config_opt[0] == 0", taking true branch
2052        if(config_opt[0]=='\0' || config_opt[0]=='#' || config_opt[0]==';') /* empty or comment */
At (18): Continuing loop
2053            continue;
2054        if(config_opt[0]=='[' && config_opt[strlen(config_opt)-1]==']') { /* new section */
2055            if(!new_service_options.next) {
2056                errstr=parse_global_option(CMD_END, NULL, NULL);
2057                if(errstr) {
2058                    s_log(LOG_ERR, "Line %d: \"%s\": %s", line_number, line_text, errstr);
2059                    file_close(df);
2060                    return 1;
2061                }
2062            }
2063            ++config_opt;
2064            config_opt[strlen(config_opt)-1]='\0';
2065            new_section=str_alloc(sizeof(SERVICE_OPTIONS));
2066            memcpy(new_section, &new_service_options, sizeof(SERVICE_OPTIONS));
2067            new_section->servname=str_dup(config_opt);
2068            new_section->session=NULL;
2069            new_section->next=NULL;
2070            section->next=new_section;
2071            section=new_section;
2072            continue;
2073        }
2074        config_arg=strchr(config_line, '=');
2075        if(!config_arg) {
2076            s_log(LOG_ERR, "Line %d: \"%s\": No '=' found", line_number, line_text);
2077            file_close(df);
2078            return 1;
2079        }
2080        *config_arg++='\0'; /* split into option name and argument value */
2081        for(i=strlen(config_opt)-1; i>=0 && isspace((unsigned char)config_opt[i]); --i)
2082            config_opt[i]='\0'; /* remove trailing whitespaces */
2083        while(isspace((unsigned char)*config_arg))
2084            ++config_arg; /* remove initial whitespaces */
2085        errstr=parse_service_option(CMD_EXEC, section, config_opt, config_arg);
2086        if(!new_service_options.next && errstr==option_not_found)
2087            errstr=parse_global_option(CMD_EXEC, config_opt, config_arg);
2088        if(errstr) {
2089            s_log(LOG_ERR, "Line %d: \"%s\": %s", line_number, line_text, errstr);
2090            file_close(df);
2091            return 1;
2092        }
2093    }
2094    file_close(df);
2095
At (20): Condition "new_service_options.next", taking true branch
2096    if(new_service_options.next) { /* daemon mode: initialize sections */
At (21): Condition "section", taking false branch
2097        for(section=new_service_options.next; section; section=section->next) {
2098            s_log(LOG_INFO, "Initializing service [%s]", section->servname);
2099            errstr=parse_service_option(CMD_END, section, NULL, NULL);
2100            if(errstr)
2101                break;
2102        }
At (22): Falling through to end of if statement
2103    } else { /* inetd mode: need to initialize global options */
2104        errstr=parse_global_option(CMD_END, NULL, NULL);
2105        if(errstr) {
2106            s_log(LOG_ERR, "Global options: %s", errstr);
2107            return 1;
2108        }
2109        s_log(LOG_INFO, "Initializing inetd mode configuration");
2110        section=&new_service_options;
2111        errstr=parse_service_option(CMD_END, section, NULL, NULL);
2112    }
CID 32706: Uninitialized pointer read (UNINIT)At (23): Using uninitialized value "errstr".
2113    if(errstr) {
CID 32693: Dereference after null check (FORWARD_NULL) [select defect]
2114        s_log(LOG_ERR, "Service [%s]: %s", section->servname, errstr);
2115        return 1;
2116    }

> > -        s_log(LOG_ERR, "Service [%s]: %s", section->servname, errstr);
> > +        s_log(LOG_ERR, "Service [%s]: %s", section ? section->servname : "",
> > +              errstr);
> Again it would be useful to fix the root cause instead of implementing a
> workaround.


Coverity output:

At (1): Condition "name", taking true branch
2008    if(name) /* not reload */
2009        filename=str_dup(name);
2010
At (2): Condition "type == 2U", taking true branch
2011    s_log(LOG_NOTICE, "Reading configuration from %s %s",
2012        type==CONF_FD ? "descriptor" : "file", filename);
2013#ifndef USE_WIN32
At (3): Condition "type == 2U", taking true branch
2014    if(type==CONF_FD) { /* file descriptor */
2015        fd=strtol(filename, &tmpstr, 10);
At (4): Condition "tmpstr == filename", taking false branch
At (5): Condition "*tmpstr", taking false branch
2016        if(tmpstr==filename || *tmpstr) { /* not a number */
2017            s_log(LOG_ERR, "Invalid file descriptor number");
2018            print_syntax();
2019            return 1;
2020        }
2021        df=file_fdopen(fd);
At (6): Falling through to end of if statement
2022    } else
2023#endif
2024        df=file_open(filename, 0);
At (7): Condition "!df", taking false branch
2025    if(!df) {
2026        s_log(LOG_ERR, "Cannot read configuration");
2027        if(type!=CONF_RELOAD)
2028            print_syntax();
2029        return 1;
2030    }
2031
2032    memset(&new_global_options, 0, sizeof(GLOBAL_OPTIONS)); /* reset global options */
2033    memset(&new_service_options, 0, sizeof(SERVICE_OPTIONS)); /* reset local options */
2034    new_service_options.next=NULL;
2035    section=&new_service_options;
2036    parse_global_option(CMD_BEGIN, NULL, NULL);
2037    parse_service_option(CMD_BEGIN, section, NULL, NULL);
At (8): Condition "type != 0U", taking true branch
2038    if(type!=CONF_RELOAD) { /* provide defaults for gui.c */
2039        memcpy(&global_options, &new_global_options, sizeof(GLOBAL_OPTIONS));
2040        memcpy(&service_options, &new_service_options, sizeof(SERVICE_OPTIONS));
2041    }
2042
2043    line_number=0;
At (9): Condition "file_getline(df, line_text, 16384) >= 0", taking true branch
At (18): Condition "file_getline(df, line_text, 16384) >= 0", taking false branch
2044    while(file_getline(df, line_text, CONFLINELEN)>=0) {
2045        memcpy(config_line, line_text, CONFLINELEN);
2046        ++line_number;
2047        config_opt=config_line;
At (10): Condition "__istype((unsigned char)*config_opt, 16384UL)", taking true branch
At (11): Condition "__istype((unsigned char)*config_opt, 16384UL)", taking false branch
2048        while(isspace((unsigned char)*config_opt))
2049            ++config_opt; /* remove initial whitespaces */
At (12): Condition "i >= 0", taking true branch
At (13): Condition "__istype((unsigned char)config_opt[i], 16384UL)", taking true branch
At (14): Condition "i >= 0", taking true branch
At (15): Condition "__istype((unsigned char)config_opt[i], 16384UL)", taking false branch
2050        for(i=strlen(config_opt)-1; i>=0 && isspace((unsigned char)config_opt[i]); --i)
2051            config_opt[i]='\0'; /* remove trailing whitespaces */
At (16): Condition "config_opt[0] == 0", taking true branch
2052        if(config_opt[0]=='\0' || config_opt[0]=='#' || config_opt[0]==';') /* empty or comment */
At (17): Continuing loop
2053            continue;
2054        if(config_opt[0]=='[' && config_opt[strlen(config_opt)-1]==']') { /* new section */
2055            if(!new_service_options.next) {
2056                errstr=parse_global_option(CMD_END, NULL, NULL);
2057                if(errstr) {
2058                    s_log(LOG_ERR, "Line %d: \"%s\": %s", line_number, line_text, errstr);
2059                    file_close(df);
2060                    return 1;
2061                }
2062            }
2063            ++config_opt;
2064            config_opt[strlen(config_opt)-1]='\0';
2065            new_section=str_alloc(sizeof(SERVICE_OPTIONS));
2066            memcpy(new_section, &new_service_options, sizeof(SERVICE_OPTIONS));
2067            new_section->servname=str_dup(config_opt);
2068            new_section->session=NULL;
2069            new_section->next=NULL;
2070            section->next=new_section;
2071            section=new_section;
2072            continue;
2073        }
2074        config_arg=strchr(config_line, '=');
2075        if(!config_arg) {
2076            s_log(LOG_ERR, "Line %d: \"%s\": No '=' found", line_number, line_text);
2077            file_close(df);
2078            return 1;
2079        }
2080        *config_arg++='\0'; /* split into option name and argument value */
2081        for(i=strlen(config_opt)-1; i>=0 && isspace((unsigned char)config_opt[i]); --i)
2082            config_opt[i]='\0'; /* remove trailing whitespaces */
2083        while(isspace((unsigned char)*config_arg))
2084            ++config_arg; /* remove initial whitespaces */
2085        errstr=parse_service_option(CMD_EXEC, section, config_opt, config_arg);
2086        if(!new_service_options.next && errstr==option_not_found)
2087            errstr=parse_global_option(CMD_EXEC, config_opt, config_arg);
2088        if(errstr) {
2089            s_log(LOG_ERR, "Line %d: \"%s\": %s", line_number, line_text, errstr);
2090            file_close(df);
2091            return 1;
2092        }
2093    }
2094    file_close(df);
2095
At (19): Condition "new_service_options.next", taking true branch
2096    if(new_service_options.next) { /* daemon mode: initialize sections */
At (20): Comparing "section" to null implies that "section" might be null.
At (21): Condition "section", taking false branch
2097        for(section=new_service_options.next; section; section=section->next) {
2098            s_log(LOG_INFO, "Initializing service [%s]", section->servname);
2099            errstr=parse_service_option(CMD_END, section, NULL, NULL);
2100            if(errstr)
2101                break;
2102        }
At (22): Falling through to end of if statement
2103    } else { /* inetd mode: need to initialize global options */
2104        errstr=parse_global_option(CMD_END, NULL, NULL);
2105        if(errstr) {
2106            s_log(LOG_ERR, "Global options: %s", errstr);
2107            return 1;
2108        }
2109        s_log(LOG_INFO, "Initializing inetd mode configuration");
2110        section=&new_service_options;
2111        errstr=parse_service_option(CMD_END, section, NULL, NULL);
2112    }
CID 32706: Uninitialized pointer read (UNINIT) [select defect]
At (23): Condition "errstr", taking true branch
2113    if(errstr) {
CID 32693: Dereference after null check (FORWARD_NULL)At (24): Dereferencing null pointer "section".
2114        s_log(LOG_ERR, "Service [%s]: %s", section->servname, errstr);
2115        return 1;
2116    }

> > -        if(!strcasecmp(fl->name, string)) {
> > +        if(string && !strcasecmp(fl->name, string)) {
> Could you give an example parameter where "string" may be NULL here?


2238/* facilities only make sense on Unix */
2239#if !defined (USE_WIN32) && !defined (__vms)
At (1): Condition "strchr(string, 46)", taking true branch
2240    if(strchr(string, '.')) { /* we have a facility specified */
2241        new_global_options.facility=-1;
2242        string=strtok(arg_copy, "."); /* break it up */
2243
At (2): Condition "fl->name", taking true branch
2244        for(fl=facilities; fl->name; ++fl) {
At (3): Condition "!strcasecmp(fl->name, string)", taking true branch
2245            if(!strcasecmp(fl->name, string)) {
2246                new_global_options.facility=fl->value;
At (4): Breaking from loop
2247                break;
2248            }
2249        }
At (5): Condition "new_global_options.facility == -1", taking false branch
2250        if(new_global_options.facility==-1)
2251            return 1; /* FAILED */
2252        string=strtok(NULL, ".");    /* set to the remainder */
2253    }
2254#endif /* USE_WIN32, __vms */
2255
2256    /* time to check the syslog level */
At (6): Comparing "string" to null implies that "string" might be null.
At (7): Condition "string", taking false branch
2257    if(string && strlen(string)==1 && *string>='0' && *string<='7') {
2258        new_global_options.debug_level=*string-'0';
2259        return 0; /* OK */
2260    }
2261    new_global_options.debug_level=8;    /* illegal level */
At (8): Condition "fl->name", taking true branch
2262    for(fl=levels; fl->name; ++fl) {
CID 11183: Dereference after null check (FORWARD_NULL)At (9): Passing null pointer "string" to function "strcasecmp(char const *, char const *)", which dereferences it.
2263        if(!strcasecmp(fl->name, string)) {
2264            new_global_options.debug_level=fl->value;
2265            break;
2266        }
2267    }
2268    if(new_global_options.debug_level==8)
2269        return 1; /* FAILED */
2270    return 0; /* OK */
2271}

Let me know if more info is required.

Thanks



More information about the stunnel-users mailing list