Skip to content

[SAST] Several potential handle leaks #2762

Description

@Canned-pineapple-8

Running static analysis on UWSGi identified several potential handle leaks that I believe are confirmed. They are quite minor, but still could be fixed.

The findings are:

  1. Handle leak in create_server_socket
    File: /core/socket.c

Problem:
Socket desciptor serverfd is acquired on line 82:

int serverfd = socket(domain, type, 0);

On certain error paths (e.g. lines 94-98) uwsgi_nuclear_blast is called:

uwsgi/core/socket.c

Lines 94 to 98 in 8d116f7

if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
uwsgi_error("SO_REUSEADDR setsockopt()");
uwsgi_nuclear_blast();
return -1;
}

Which terminates the process with exit in most cases, however, it may simply return in some scenarios (e.g. when running as Emperor):

uwsgi/core/uwsgi.c

Lines 1455 to 1458 in 8d116f7

void uwsgi_nuclear_blast() {
// the Emperor (as an example) cannot nuke itself
if (uwsgi.disable_nuclear_blast) return;

If the process survives, the function returns without closing serverfd, resulting in a handle leak.

Suggested patch:
Close serverfd before returning if the process survived nuclear blast:

if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) {
	uwsgi_error("SO_REUSEADDR setsockopt()");
	uwsgi_nuclear_blast();
	close(serverfd);
	return -1;
}
  1. Handle leak in uwsgi_load_plugin
    File: /core/plugins.c

Problem:
Plugin handle plugin_handle is acquired via dlopen (e.g. on line 157):

plugin_handle = dlopen(plugin_filename, RTLD_NOW | RTLD_GLOBAL);

Then, under the success label, the first dlsym call on line 175 may fail:

up = dlsym(plugin_handle, plugin_entry_symbol);

And the subsequent dlsym call on line 197 may also fail:

up = dlsym(plugin_handle, plugin_entry_symbol);

(Seems like an unlikely scenario, but I believe it is still possible if the user provided a regular .so file instead of a valid uwsgi plugin. Please correct me if I'm wrong though).

If both dlsym calls fail, the function reaches the end block at lines 268–275 and returns without closing plugin_handle:

uwsgi/core/plugins.c

Lines 268 to 275 in 8d116f7

end:
if (need_free)
free(plugin_name);
if (plugin_filename)
free(plugin_filename);
return NULL;
}

This results in a handle leak.

Suggested patch:
Close plugin_handle in the end block if needed:

end:
	if (need_free)
		free(plugin_name);
	if (plugin_filename)
		free(plugin_filename);
    if (plugin_handle && dlclose(plugin_handle)) {
        uwsgi_error("dlclose()");
    }

	return NULL;
}

Please feel free to get back to me and reject any of the findings described above if you believe they are false positives, or discuss any of my suggested patches. I will adjust the linked PR accordingly.

Thank you for your time and consideration.

Found by Linux Verification Center with SVACE

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions