Skip to content

Commit 2bf684c

Browse files
committed
lbbs: Fix various code defects.
Fixes various defects throughout the codebase, in particular: * resource leaks * locking issues * unchecked return values * assignments instead of comparisons * possible NULL dereferences * uninitialized variables
1 parent 581f51e commit 2bf684c

27 files changed

+89
-45
lines changed

bbs/bbs.c

+2
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ static void *monitor_sig_flags(void *unused)
740740
break;
741741
} else {
742742
/* Shouldn't ever happen... */
743+
pthread_mutex_unlock(&sig_lock);
743744
bbs_warning("Received unactionable activity on sig alert pipe?\n");
744745
}
745746
}
@@ -776,6 +777,7 @@ static long bbs_is_running(void)
776777
}
777778
if (fscanf(f, "%ld", &file_pid) == EOF) {
778779
bbs_debug(5, "PID file %s does not contain a PID\n", BBS_PID_FILE);
780+
fclose(f);
779781
return 0;
780782
}
781783
fclose(f);

bbs/curl.c

+12-3
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ static int curl_common_setup(CURL **curl_ptr, const char *url)
135135
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
136136
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20); /* Max 20 seconds */
137137

138-
curl_easy_setopt(curl, CURLOPT_URL, url);
138+
if (curl_easy_setopt(curl, CURLOPT_URL, url)) {
139+
bbs_warning("Failed to set cURL option CURLOPT_URL\n");
140+
return -1;
141+
}
139142
return 0;
140143
}
141144

@@ -187,7 +190,10 @@ static int curl_common_run(CURL *curl, struct bbs_curl *c, FILE *fp)
187190
if (fp) {
188191
/* Write response body to a file */
189192
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
190-
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
193+
if (curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp)) {
194+
bbs_warning("Failed to set cURL opt CURLOPT_WRITEDATA\n");
195+
return -1;
196+
}
191197
} else {
192198
/* Write response body to an allocated string */
193199
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
@@ -304,7 +310,10 @@ int bbs_curl_post(struct bbs_curl *c)
304310
if (curl_common_setup(&curl, c->url)) {
305311
return -1;
306312
}
307-
curl_easy_setopt(curl, CURLOPT_POST, 1);
313+
if (curl_easy_setopt(curl, CURLOPT_POST, 1)) {
314+
bbs_warning("Failed to set cURL option CURLOPT_POST\n");
315+
return -1;
316+
}
308317
if (c->postfields) {
309318
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, c->postfields);
310319
} else {

bbs/fd.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ int __fdleak_socket(int domain, int type, int protocol, const char *file, int li
222222
}
223223

224224
if (sproto) {
225-
STORE_COMMON(res, "socket", "%s,%s,\"%s\"", sdomain, stype, sproto);
225+
STORE_COMMON_HELPER(res, "socket", "%s,%s,\"%s\"", sdomain, stype, sproto);
226226
} else {
227-
STORE_COMMON(res, "socket", "%s,%s,\"%d\"", sdomain, stype, protocol);
227+
STORE_COMMON_HELPER(res, "socket", "%s,%s,\"%d\"", sdomain, stype, protocol);
228228
}
229229
return res;
230230
}

bbs/module.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ static int unload_dependencies(struct bbs_module *mod, struct stringlist *restri
627627
int usecount;
628628
/* The module MAY have already been unloaded, in which case m is no longer valid memory.
629629
* Check to see if it's in the list. */
630-
if (stringlist_contains(removed, r->name)) {
630+
if (removed && stringlist_contains(removed, r->name)) {
631631
free(r);
632632
continue;
633633
}

bbs/range.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ int uintlist_append2(unsigned int **a, unsigned int **b, int *lengths, int *allo
143143
newb = realloc(*b, (size_t) newallocsize * sizeof(unsigned int));
144144
if (ALLOC_FAILURE(newb)) {
145145
/* This is tricky. We expanded a but failed to expand b. Keep the smaller size for our records. */
146+
free(newa);
146147
return -1;
147148
}
148149
*allocsizes = newallocsize;
@@ -282,4 +283,4 @@ int range_to_uintlist(char *s, unsigned int **list, int *length)
282283
}
283284
}
284285
return 0;
285-
}
286+
}

bbs/socket.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,12 @@ int bbs_resolve_hostname(const char *hostname, char *buf, size_t len)
300300
if (ai->ai_family == AF_INET) {
301301
saddr_in = (struct sockaddr_in *) ai->ai_addr;
302302
inet_ntop(ai->ai_family, &saddr_in->sin_addr, buf, (socklen_t) len); /* Print IPv4*/
303+
break; /* Use the 1st one that works */
303304
} else if (ai->ai_family == AF_INET6) {
304305
saddr_in6 = (struct sockaddr_in6 *) ai->ai_addr;
305306
inet_ntop(ai->ai_family, &saddr_in6->sin6_addr, buf, (socklen_t) len); /* Print IPv6 */
307+
break; /* Use the 1st one that works */
306308
}
307-
break; /* Use the 1st one that works */
308309
}
309310

310311
freeaddrinfo(res);
@@ -357,7 +358,12 @@ int bbs_tcp_connect(const char *hostname, int port)
357358
* Using SO_SNDTIMEO works on Linux and is easier than doing bbs_unblock_fd before and bbs_block_fd after. */
358359
timeout.tv_sec = 4; /* Wait up to 4 seconds to connect */
359360
timeout.tv_usec = 0;
360-
setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
361+
if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout))) {
362+
bbs_error("setsockopt failed: %s\n", strerror(errno));
363+
close(sfd);
364+
sfd = -1;
365+
continue;
366+
}
361367
if (connect(sfd, ai->ai_addr, ai->ai_addrlen)) {
362368
bbs_error("connect: %s\n", strerror(errno));
363369
close(sfd);

bbs/utils.c

+4-13
Original file line numberDiff line numberDiff line change
@@ -561,12 +561,6 @@ int bbs_dir_has_file_prefix(const char *path, const char *prefix)
561561
}
562562

563563
closedir(dir);
564-
565-
if (res < 0 && errno) {
566-
bbs_error("Error while reading directories (%d) - %s: %s\n", res, path, strerror(errno));
567-
res = -1;
568-
}
569-
570564
return res;
571565
}
572566

@@ -598,12 +592,6 @@ int bbs_dir_has_subdirs(const char *path)
598592
}
599593

600594
closedir(dir);
601-
602-
if (res < 0 && errno) {
603-
bbs_error("Error while reading directories (%d) - %s: %s\n", res, path, strerror(errno));
604-
res = -1;
605-
}
606-
607595
return res;
608596
}
609597

@@ -682,6 +670,7 @@ static int __bbs_dir_size(const char *path, long *size, int max_depth)
682670
/* Don't use alloca or allocate on the stack, because we're in a loop */
683671
full_path = malloc(strlen(path) + strlen(entry->d_name) + 2);
684672
if (!full_path) {
673+
closedir(dir);
685674
return -1;
686675
}
687676
sprintf(full_path, "%s/%s", isroot ? "" : path, entry->d_name); /* Safe */
@@ -829,7 +818,9 @@ FILE *bbs_mkftemp(char *template, mode_t mode)
829818
int pfd;
830819

831820
pfd = mkstemp(template); /* template will get updated to contain the actual filename */
832-
chmod(template, mode);
821+
if (chmod(template, mode)) {
822+
bbs_warning("Failed to set permissions for %s: %s\n", template, strerror(errno));
823+
}
833824

834825
if (pfd == -1) {
835826
/* It's not specified if mkstemp sets errno, but check it anyways */

bbs/variables.c

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ int bbs_node_var_set(struct bbs_node *node, const char *key, const char *value)
228228
if (!node->vars) {
229229
vars = calloc(1, sizeof(*vars));
230230
if (ALLOC_FAILURE(vars)) {
231+
bbs_node_unlock(node);
231232
return -1;
232233
}
233234
bbs_debug(5, "Allocated variable list for node %d\n", node->id);

doors/door_irc.c

+2
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ static int load_config(void)
190190
ircl = irc_client_new(hostname, port, username, password);
191191
if (!ircl) {
192192
free(client);
193+
free_if(msgscript);
193194
continue;
194195
}
195196
irc_client_autojoin(ircl, autojoin);
@@ -306,6 +307,7 @@ static struct participant *join_client(struct bbs_node *node, const char *name)
306307
}
307308
if (!client) {
308309
bbs_error("IRC client %s doesn't exist\n", name);
310+
RWLIST_UNLOCK(&clients);
309311
return NULL;
310312
}
311313
/* Okay, we have the client. Add the newcomer to it. */

include/version.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515

1616
#define BBS_MAJOR_VERSION 0
1717
#define BBS_MINOR_VERSION 4
18-
#define BBS_PATCH_VERSION 4
18+
#define BBS_PATCH_VERSION 5

modules/mod_auth_static.c

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ static struct bbs_user **get_users(void)
120120
RWLIST_RDLOCK(&users);
121121
userlist = malloc((size_t) (RWLIST_SIZE(&users, u, entry) + 1) * sizeof(*user)); /* The list will be NULL terminated, so add 1 */
122122
if (ALLOC_FAILURE(userlist)) {
123+
RWLIST_UNLOCK(&users);
123124
return NULL;
124125
}
125126
/* Keep list locked here so count can't change on us */

modules/mod_mail.c

+4
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,9 @@ unsigned long mailbox_quota(struct mailbox *mbox)
778778
fclose(fp);
779779
} else {
780780
mbox->quota = (unsigned int) maxquota;
781+
if (fp) {
782+
fclose(fp);
783+
}
781784
}
782785
return mbox->quota;
783786
}
@@ -1221,6 +1224,7 @@ static unsigned long __maildir_modseq(struct mailbox *mbox, const char *director
12211224
if (res != 1) {
12221225
bbs_error("Error reading HIGHESTMODSEQ from %s\n", modseqfile);
12231226
/* No sane thing we can do here either */
1227+
fclose(fp);
12241228
return 0;
12251229
}
12261230

modules/mod_mysql.c

+2
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,11 @@ int sql_fetch_columns(int bind_ints[], long long bind_longs[], char *bind_string
594594
break;
595595
case 'b': /* Blob */
596596
bbs_warning("Blobs are currently unsupported\n");
597+
va_end(ap);
597598
return -1;
598599
default:
599600
bbs_warning("Unknown SQL format type specifier: %c\n", *cur);
601+
va_end(ap);
600602
return -1;
601603
}
602604
}

modules/mod_relay_irc.c

+8-9
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ static int wait_response(struct bbs_node *node, int fd, const char *requsername,
254254
numericclient = clientname;
255255
if (pipe(nickpipe)) {
256256
bbs_error("pipe failed: %s\n", strerror(errno));
257+
pthread_mutex_unlock(&nicklock);
257258
return -1;
258259
}
259260
switch (numeric) {
@@ -860,16 +861,14 @@ static void doormsg_cb(const char *clientname, const char *channel, const char *
860861
if (*msg == '<') {
861862
safe_strncpy(msgbuf, msg, sizeof(msgbuf));
862863
tmp = strchr(msgbuf, '>');
863-
if (msg) {
864-
*tmp++ = '\0';
865-
msg = tmp;
866-
sendnick = msgbuf + 1;
867-
/* Okay, now the message is just the message, and we have extracted the real sender name */
868-
snprintf(nativenick, sizeof(nativenick), "%s/%s", clientname, sendnick);
864+
*tmp++ = '\0';
865+
msg = tmp;
866+
sendnick = msgbuf + 1;
867+
/* Okay, now the message is just the message, and we have extracted the real sender name */
868+
snprintf(nativenick, sizeof(nativenick), "%s/%s", clientname, sendnick);
869869
#pragma GCC diagnostic pop /* -Wformat-truncation */
870-
sendnick = nativenick;
871-
/* Now we have a unique nick that doesn't conflict with this same nick on our local IRC server */
872-
}
870+
sendnick = nativenick;
871+
/* Now we have a unique nick that doesn't conflict with this same nick on our local IRC server */
873872
}
874873
irc_relay_send(cp->channel1, CHANNEL_USER_MODE_NONE, S_OR(cp->client2, clientname), sendnick, NULL, msg, cp->ircuser);
875874
}

modules/mod_sieve.c

+1
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ static int my_getheader(sieve2_context_t *s, void *varg)
388388
fp = fopen(sieve->mproc->datafile, "r");
389389
if (!fp) {
390390
bbs_error("Failed to open %s: %s\n", sieve->mproc->datafile, strerror(errno));
391+
free(headers);
391392
return SIEVE2_ERROR_FAIL;
392393
}
393394

modules/mod_slack.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ static int on_message(struct slack_event *event, const char *channel, const char
606606
pthread_mutex_lock(&u->lock);
607607
if (!strcmp(u->lastmsg, text)) {
608608
pthread_mutex_unlock(&cp->lock);
609+
pthread_mutex_unlock(&u->lock);
609610
bbs_debug(4, "Not echoing our own direct message post...\n");
610611
return 0;
611612
}
@@ -967,7 +968,9 @@ static int start_clients(void)
967968
struct slack_relay *relay;
968969
RWLIST_RDLOCK(&relays);
969970
RWLIST_TRAVERSE(&relays, relay, entry) {
970-
bbs_pthread_create(&relay->thread, NULL, slack_relay, relay);
971+
if (bbs_pthread_create(&relay->thread, NULL, slack_relay, relay)) {
972+
bbs_warning("Failed to start Slack relay %s\n", relay->name);
973+
}
971974
}
972975
RWLIST_UNLOCK(&relays);
973976
return 0;

modules/mod_smtp_delivery_external.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ static int try_send(struct smtp_session *smtp, struct smtp_tx_data *tx, const ch
352352
off_t send_offset = offset;
353353
int caps = 0, maxsendsize = 0;
354354
char sendercopy[64];
355-
char *user, *domain;
355+
char *user, *domain, *saslstr = NULL;
356356

357357
bbs_assert(datafd != -1);
358358
bbs_assert(writelen > 0);
@@ -483,7 +483,7 @@ static int try_send(struct smtp_session *smtp, struct smtp_tx_data *tx, const ch
483483
}
484484
}
485485
} else if (caps & SMTP_CAPABILITY_AUTH_LOGIN) {
486-
char *saslstr = bbs_sasl_encode(username, username, password);
486+
saslstr = bbs_sasl_encode(username, username, password);
487487
if (!saslstr) {
488488
res = -1;
489489
goto cleanup;
@@ -554,6 +554,7 @@ static int try_send(struct smtp_session *smtp, struct smtp_tx_data *tx, const ch
554554
res = 0;
555555

556556
cleanup:
557+
free_if(saslstr);
557558
if (res > 0) {
558559
smtp_client_send(&client, "QUIT\r\n");
559560
}

modules/mod_smtp_mailing_lists.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static int listify(struct mailing_list *l, struct smtp_response *resp, FILE *fp,
273273
firstword = strsep(&subjectcopy, " ");
274274
/* Ignore Re:, Fwd:, Fw:, and such prefixes. In fact, just ignore all prefixes. */
275275
tmp = strchr(firstword, ':');
276-
if (tmp && !++tmp) { /* Ends in : */
276+
if (tmp && !*++tmp) { /* Ends in : */
277277
has_prefix = 1;
278278
} else if (!strcmp(l->tag, firstword)) {
279279
has_prefix = 1;

modules/mod_test_range.c

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ static int test_range_generation(void)
6767
return 0;
6868

6969
cleanup:
70+
free_if(ranges);
7071
return -1;
7172
}
7273

modules/mod_webmail.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,10 @@ static void append_header_meta(json_t *restrict json, char *headers, int fetchli
12361236

12371237
if (isspace(header[0])) {
12381238
/* Continuation of previous header */
1239+
if (!prevval) {
1240+
bbs_warning("No previous header to continue?\n");
1241+
continue;
1242+
}
12391243
dyn_str_append(&dynstr, prevval, strlen(prevval));
12401244
prevval = header;
12411245
} else {
@@ -2266,7 +2270,7 @@ static int fetch_mime_recurse(json_t *root, json_t *attachments, struct mailmime
22662270
case MAILIMF_FIELD_SUBJECT:
22672271
subject = f->fld_data.fld_subject;
22682272
decoded = subject ? mime_header_decode(subject->sbj_value) : NULL;
2269-
name = decoded ? decoded : subject->sbj_value;
2273+
name = decoded ? decoded : subject ? subject->sbj_value : NULL;
22702274
bbs_debug(5, "Subject: %s\n", name);
22712275
json_set_header(root, "subject", json_string(name));
22722276
free_if(decoded);

nets/net_imap.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -2040,7 +2040,7 @@ static int handle_move(struct imap_session *imap, const char *sequences, const c
20402040
unsigned int *olduids = NULL, *newuids = NULL, *expunged = NULL, *expungedseqs = NULL;
20412041
int lengths = 0, allocsizes = 0;
20422042
int exp_lengths = 0, exp_allocsizes = 0;
2043-
unsigned int uidvalidity, uidnext, uidres;
2043+
unsigned int uidvalidity = 0, uidnext, uidres;
20442044
char *olduidstr = NULL, *newuidstr = NULL;
20452045
int destacl;
20462046
int error = 0;
@@ -2062,6 +2062,7 @@ static int handle_move(struct imap_session *imap, const char *sequences, const c
20622062
files = scandir(imap->curdir, &entries, NULL, imap_uidsort);
20632063
if (files < 0) {
20642064
bbs_error("scandir(%s) failed: %s\n", imap->curdir, strerror(errno));
2065+
mailbox_unlock(imap->mbox);
20652066
return -1;
20662067
}
20672068
while (fno < files && (entry = entries[fno++])) {
@@ -2770,6 +2771,7 @@ static int handle_remote_move(struct imap_session *imap, char *dest, const char
27702771
}
27712772
if (items_received < 3) {
27722773
bbs_warning("Incomplete download, only got %d/3 items\n", items_received);
2774+
close_if(destfd);
27732775
goto cleanup;
27742776
}
27752777
/* Finish processing */

nets/net_imap/imap_server_search.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,7 @@ static int thread_references_step1(struct thread_messageid *tmsgids, struct thre
20792079
#endif
20802080
childmsg = push_threadmsgid(tmsgids, ref, 1);
20812081
if (ALLOC_FAILURE(childmsg)) {
2082+
free(refdup);
20822083
return -1;
20832084
}
20842085
}
@@ -2222,7 +2223,6 @@ static int thread_references_step3(struct thread_messageid *msgids, unsigned int
22222223
#endif
22232224

22242225
/* Prune dummy messages */
2225-
t = msgids;
22262226
t = msgids->llnext; /* Skip the dummy root */
22272227
while (t) {
22282228
struct thread_messageid *next = t->llnext; /* Since we could free t within the loop */

nets/net_irc.c

+1
Original file line numberDiff line numberDiff line change
@@ -3324,6 +3324,7 @@ static void irc_handler(struct bbs_node *node, int secure)
33243324
ssl = ssl_node_new_accept(node, &rfd, &wfd);
33253325
if (!ssl) {
33263326
bbs_error("Failed to create SSL\n");
3327+
free(user);
33273328
return;
33283329
}
33293330
} else {

0 commit comments

Comments
 (0)