xorl %eax, %eax

spamd do_changes() Memory Leak

with one comment

This is known at least since February 2009 when Artis Caune reported it. SPAMd is a popular daemon against spam emails developed by the OpenBSD project. Here is the buggy code from spamd 4.1.2 release:

1 /*      $OpenBSD: grey.c,v 1.39 2007/03/18 18:38:57 beck Exp $  */
2
3 /*
4  * Copyright (c) 2004-2006 Bob Beck.  All rights reserved.
        ...
565 static int
566 do_changes(DB *db)
567 {
568         DBT                     dbk, dbd;
569         struct db_change        *dbc;
570         int ret = 0;
571
572         while (!SLIST_EMPTY(&db_changes)) {
573                 dbc = SLIST_FIRST(&db_changes);
574                 switch (dbc->act) {
575                 case DBC_ADD:
        ...
605                 free(dbc->key);
606                 dbc->key = NULL;
607                 free(dbc->data);
608                 dbc->data = NULL;
609                 dbc->act = 0;
610                 dbc->dsiz = 0;
611                 SLIST_REMOVE_HEAD(&db_changes, entry);
612
613         }
614         return(ret);
615 }

The above code is part of spamd/grey.c and the bug is fairly simple. At line 573 it initializes dbc using SLIST_FIRST(). Then it traverses through db_changes SLIST linked list using a while loop (line 572). As you can see at the clean up part (lines 605-611). It performs the following operations:
1) Free the allocated space for dbc->key. Line 605
2) Update dbc->key to point to NULL. Line 606
3) Free the allocated space for dbc->data. Line 607
4) Update dbc->data to point to NULL. Line 608
5) Set dbc->act to zero. Line 609
6) Set dbc->dsiz to zero. Line 610
7) Remove entry from db_changes SLIST‘s head. Line 611
It is obvious that dbc never gets freed even though the record that it points to is removed from the linked list. This was later reported on openbsd-bugs on 25 Februrary 2009 by Artis Caune and he also provided a patch that fixes this problem. The patch was:

         SLIST_REMOVE_HEAD(&db_changes, entry);
-
+        free(dbc);
+        dbc = NULL;
     }


Which adds the missing free(3) call. This function is called by greyscan() which is the gray-listing scanner routine of SPAMd. Specifically, it uses do_changes() to update the db_changes SLIST. So, I think that it won’t be that hard to trigger it and consume a lot of memory. In the original report, Artis Caune talks about some notable memory leaks during normal operation in a week. I believe that this can be accelarated and eventually might lead to a DoS situation. However, I haven’t test this assumption.

Written by xorl

May 26, 2009 at 13:42

Posted in bugs

One Response

Subscribe to comments with RSS.

  1. thanks a lot

    arbto

    September 1, 2009 at 14:06


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s