Skip to content

Commit

Permalink
mod_mail: Avoid soft assertion caused by trying to stat nonexistent m…
Browse files Browse the repository at this point in the history
…ailbox.

The SUBSCRIBE and UNSUBSCRIBE commands do not require that the referenced
mailbox actually exists. In fact, it is common for them not to, in the
case of a DELETE (mailbox delete) followed by an UNSUBSCRIBE, which is
a common client command sequence. In this case, the mailbox no longer
exists by the time of the UNSUBSCRIBE. Rather than trying to retrieve
UIDNEXT and UIDVALIDITY for a mailbox that may no longer exists,
which will trigger a soft assert since we can't, just don't attempt to
at all, which will avoid these invalid accesses in such cases. Even in
the case where the mailbox does exist, it's probably not super vital to
include this info in the event.

A test has been added to capture this, since backtraces cause tests
to fail when run with the -e flag (under valgrind) since backtraces
leak memory.
  • Loading branch information
InterLinked1 committed Jan 10, 2025
1 parent 2eb03de commit 5211134
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 10 deletions.
30 changes: 20 additions & 10 deletions modules/mod_mail.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,28 @@ void mailbox_notify_quota_exceeded(struct bbs_node *node, struct mailbox *mbox)
mailbox_dispatch_event(&e);
}

static int use_mailbox_for_event(struct mailbox_event *e)
{
if (!e->mbox || !e->maildir) {
bbs_error("No mailbox and/or maildir\n");
return 0;
} else if (e->type == EVENT_MAILBOX_DELETE) {
bbs_debug(3, "Mailbox has been deleted\n");
return 0;
}
/* Certain types of mailbox events don't require that the mailbox actually needs to exist.
* In particular, SUBSCRIBE and UNSUBSCRIBE could be for arbitrary mailboxes,
* and those mailboxes may or may not exist. */
if (e->type == EVENT_MAILBOX_SUBSCRIBE || e->type == EVENT_MAILBOX_UNSUBSCRIBE) {
return 0;
}
return 1;
}

unsigned int mailbox_event_uidvalidity(struct mailbox_event *e)
{
if (!e->uidvalidity) {
if (!e->mbox || !e->maildir) {
bbs_error("No mailbox and/or maildir\n");
return 0;
} else if (e->type == EVENT_MAILBOX_DELETE) {
bbs_debug(3, "Mailbox has been deleted\n");
if (!use_mailbox_for_event(e)) {
return 0;
}
mailbox_get_next_uid(e->mbox, e->node, e->maildir, 0, &e->uidvalidity, &e->uidnext);
Expand All @@ -341,11 +355,7 @@ unsigned int mailbox_event_uidvalidity(struct mailbox_event *e)
unsigned int mailbox_event_uidnext(struct mailbox_event *e)
{
if (!e->uidnext) {
if (!e->mbox || !e->maildir) {
bbs_error("No mailbox and/or maildir\n");
return 0;
} else if (e->type == EVENT_MAILBOX_DELETE) {
bbs_debug(3, "Mailbox has been deleted\n");
if (!use_mailbox_for_event(e)) {
return 0;
}
mailbox_get_next_uid(e->mbox, e->node, e->maildir, 0, &e->uidvalidity, &e->uidnext);
Expand Down
4 changes: 4 additions & 0 deletions tests/test_imap.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ static int run(void)
SWRITE(client1, "a9 SUBSCRIBE foobar" ENDL); /* Doesn't matter whether or not it exists */
CLIENT_EXPECT(client1, "a9 OK SUBSCRIBE");

/* UNSUBSCRIBE from nonexistent */
SWRITE(client1, "a9b UNSUBSCRIBE foobar" ENDL);
CLIENT_EXPECT(client1, "a9b OK UNSUBSCRIBE");

/* NAMESPACE */
SWRITE(client1, "a10 NAMESPACE" ENDL);
CLIENT_EXPECT(client1, "* NAMESPACE");
Expand Down

0 comments on commit 5211134

Please sign in to comment.