On 19 March 2011 20:04, Jonny Mosco <[email protected]> wrote:
> I'm using smtpd as a smtp relay for around 50+ systems.  It will run for a
> few days and eat up memory before crashing.  The patch provided is by Jared
> Yanovich.  After a good amount of testing, we discovered the memory leak.
>
> Index: asr.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/asr.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 asr.c
> --- asr.c       3 Dec 2010 23:29:08 -0000       1.2
> +++ asr.c       19 Mar 2011 19:48:33 -0000
> @@ -774,8 +774,7 @@ asr_ctx_query(struct asr_ctx *ac, int ty
>  void
>  asr_done(struct asr *asr)
>  {
> -       if (asr_ctx_unref(asr->a_ctx))
> -               return;
> +       asr_ctx_unref(asr->a_ctx);
>        if (asr->a_path)
>                free(asr->a_path);
>        free(asr);
> Index: client.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/client.c,v
> retrieving revision 1.33
> diff -u -p -r1.33 client.c
> --- client.c    28 Nov 2010 13:56:43 -0000      1.33
> +++ client.c    19 Mar 2011 19:48:33 -0000
> @@ -573,6 +573,7 @@ client_close(struct smtp_client *sp)
>                SSL_free(sp->ssl);
>  #endif
>        close(sp->w.fd);
> +       fclose(sp->body);
>        free(sp);
>  }

Client API's caller manages the message body descriptor so close()
belongs there.  I believe the caller has been releasing this
descriptor correctly before this diff.

The problem is that, roughly speaking, fclose does free+close, while
what is needed here is just free.  The solution is to use something
else than stdio, or to change the API so that caller no longer manages
the descriptor.

>
> @@ -690,6 +691,7 @@ client_getln(struct smtp_client *sp, int
>
>                if (ln[3] == ' ')
>                        break;
> +               free(ln);
>        }

There are uses of ln after this free.  I cannot see a case where ln
would not be freed.


>
>        /* validate reply code */
> Index: queue_shared.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/queue_shared.c,v
> retrieving revision 1.35
> diff -u -p -r1.35 queue_shared.c
> --- queue_shared.c      28 Nov 2010 14:35:58 -0000      1.35
> +++ queue_shared.c      19 Mar 2011 19:48:33 -0000
> @@ -124,6 +124,8 @@ queue_record_layout_envelope(char *queue
>        FILE *fp;
>        int fd;
>
> +       fp = NULL;
> +
>  again:
>        if (! bsnprintf(evpname, sizeof(evpname), "%s/%s%s/%s.%qu",
> queuepath,
>                message->message_id, PATH_ENVELOPES, message->message_id,
> @@ -154,14 +156,20 @@ again:
>                fatal("queue_record_incoming_envelope: write");
>        }
>
> -       if (! safe_fclose(fp))
> +       if (! safe_fclose(fp)) {
> +               fp = NULL;
> +               fd = -1;
>                goto tempfail;
> +       }
>
>        return 1;
>
>  tempfail:
>        unlink(evpname);
> -       close(fd);
> +       if (fp)
> +               fclose(fp);
> +       else if (fd != -1)
> +               close(fd);
>        message->creation = 0;
>        message->message_uid[0] = '\0';

Reply via email to