Re: Benchmarked tcpserver dlopen() -> qmail_smtpd() VS tcpserver --> fork() --> exec qmail-smtpd

Manvendra Bhangui <[email protected]> Wed, 5 Apr 2017 01:36:10 +0530
Newsgroups gmane.mail.qmail.general
Message-ID <CAOqj+1PoJP2B7ZdZFkqFj9=w3bTtiL27rJ9cLgwKovp3D0=iOw@mail.gmail.com>
On 5 April 2017 at 00:39, Erwin Hoffmann <[email protected]> wrote:
> Absolutely ACK. And -- according to your list of control files -- at least some of them can be replaced by environment variables and can be merged into one control file (badmail*). This is the way Spamcontrol did it and s/qmail does it.

That's how indimail does it too :). Environment variable BADMAILFROM
and BLACKHOLEDSENDERS. In addition, it looks at the file extension. If
it is .cdb, it uses cdb search. If it has .sql extension, then it
connects to mysql as per database name, tablename, user, socket, etc
stored in badmail.sql file. So no issues here.

> PS: Apart from that: a 25K badmail file is ridiculous. Something is wrong with your mail architecture.
>

No. I don't use a 25 Mib badmail file. That example was to make
apparent the penalty imposed in the current architecture where every
invocation of qmail-smtpd reads this file. I just load the badmail
file in tcpserver and the data is available to each and every child
without the need to again open it. The disadvantage - If the file
changes, I have to send tcpserver SIGHUP. Even for small control
files, I have been able to see small performance improvement by
loading the control files just once. David who replied in an earlier
post suggested using inotify and also suggested using a control file
server using UNIX Domain sockets. One of these days I am gonna use TCP
IP socket. With so many relay servers, one will have to maintain this
control file at just one location and also cache the file locally in
case the control file server is not available. But that's for another
day.

My dlopen() architecture was completed months ago but I did not
succeed in making the tcpserver symbols private to just the tcpserver
executable. If the symbols can be private how can that be less secure
then using exec() ?

So yesterday I discovered dlmopen() which allows you to create a
private namespace but I have been struggling to make it work with
tcpserver. Had a painful session completed few mins ago with gdb. The
moment I use dlmopen(), tcpserver goes at the top, consuming 100% cpu.
gdb showed that it never returned from the function prot_gid() defined
in prot.c. I figured out that due to NPTL, Native Posix Thread
Library, setgroups, setgid, setuid, etc are all wrappers which are
supposed to set the gid, uid of all threads in case of multi-threaded
processes. The setgroups() and setgid() implementation on linux
definitely has a bug. setgroups(), setgid() hang in all cases if
dlmopen has been called. setuid() hangs only if it is passed int
instead of uid_t. The original prot.c uses int instead of uid_t. Since
tcpserver is not a multi-threaded application I have fixed the file
prot.c in the ucsp-tcp-0.88 as following to bypass the NPTL wrappers
in glibc. WIth this change, it is bliss/nirvana for me at the moment
:)

#include "hasshsgr.h"
#include "prot.h"
#include <unistd.h>
#include <grp.h>

#include <syscall.h>
#define SYS_SETGROUPS(NGRUP,MYGIDSET) syscall(SYS_setgroups, NGRUP, MYGIDSET)
#define SYS_SETGID(MYGID) syscall(SYS_setgid, MYGID)
#define SYS_SETUID(MYUID) syscall(SYS_setuid, MYUID)

int
prot_gid(gid_t gid)
{
#ifdef HASSHORTSETGROUPS
    short           x[2];
    x[0] = gid;
    x[1] = 73; /*- catch errors */
    if (SYS_SETGROUPS(1, x) == -1)
        return -1;
#else
    if (SYS_SETGROUPS(1, &gid) == -1)
        return -1;
#endif
    return SYS_SETGID(gid); /*- _should_ be redundant, but on some
systems it isn't */
}

int
prot_uid(uid_t uid)
{
    return SYS_SETUID(uid);
}



-- 
Regards Manvendra - http://www.indimail.org
GPG Pub Key
http://pgp.mit.edu:11371/pks/lookup?op=get&search=0xC7CBC760014D250C