Re: clamd: Keep scanning while reloading database

Steven Morgan <[email protected]>
Newsgroups gmane.comp.security.virus.clamav.devel
Message-ID <CAH-jhOCV8QnYU7=TuJ2O31ShMqjJR0qVvQuP0h_F4NuoWP8MGQ@mail.gmail.com>
Thanks for sending a patch, we will look at integrating it with ClamAV.

I have opened bug # 10979 at bugzilla.clamav.net for tracking.


On Mon, Apr 28, 2014 at 10:29 AM, Julius Plenz <[email protected]>wrote:

> Hi,
>
> * Julius Plenz <[email protected]> [2014-04-07 20:43]:
> > > 1) Start reload_db() in a background thread, resume scanning, and call
> > >    back once the new engine is in place; then exchange the pointers
> > >    from old to new engine and free the old one.
> >
> > FWIW, I have implemented this option, and it seems to work just
> > fine.
>
> We have been running ClamAV on all incoming mail for the past week
> while periodically reloading a fresh definition database, and it works
> very well. Any chance of getting this included into upstream?
>
> Current patch against Git tag clamav-0.98.1 pasted below.
>
> Cheers,
>
> Julius
> --
>  clamd/server-th.c | 145
> ++++++++++++++++++++++++++++++++----------------------
>  clamd/server.h    |   7 +++
>  2 files changed, 94 insertions(+), 58 deletions(-)
>
> diff --git a/clamd/server-th.c b/clamd/server-th.c
> index 86a3a48..3df5c9c 100644
> --- a/clamd/server-th.c
> +++ b/clamd/server-th.c
> @@ -64,6 +64,8 @@
>  int progexit = 0;
>  pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
>  int reload = 0;
> +volatile int reload_in_progress = 0;
> +struct cl_engine *reload_engine = NULL;
>  time_t reloaded_time = 0;
>  pthread_mutex_t reload_mutex = PTHREAD_MUTEX_INITIALIZER;
>  int sighup = 0;
> @@ -158,40 +160,27 @@ void sighandler_th(int sig)
>             logg("$Failed to write to syncpipe\n");
>  }
>
> -static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int
> dboptions, const struct optstruct *opts, int do_check, int *ret)
> +static void *reload_db(void *argp)
>  {
> -       const char *dbdir;
> -       int retval;
> -       unsigned int sigs = 0;
> -       struct cl_settings *settings = NULL;
> -
> -    *ret = 0;
> -    if(do_check) {
> -       if(!dbstat.entries) {
> -           logg("No stats for Database check - forcing reload\n");
> -           return engine;
> -       }
> -
> -       if(cl_statchkdir(&dbstat) == 1) {
> -           logg("SelfCheck: Database modification detected. Forcing
> reload.\n");
> -           return engine;
> -       } else {
> -           logg("SelfCheck: Database status OK.\n");
> -           return NULL;
> -       }
> -    }
> -
> -    /* release old structure */
> -    if(engine) {
> +    const char *dbdir;
> +    int retval;
> +    unsigned int sigs = 0;
> +    struct cl_settings *settings = NULL;
> +    struct cl_engine *engine = NULL;
> +
> +    struct reload_db_args *args = (struct reload_db_args *)argp;
> +    struct cl_engine *oldengine = args->engine;
> +    unsigned int dboptions = args->dboptions;
> +    const struct optstruct *opts = args->opts;
> +
> +    if(oldengine) {
>         /* copy current settings */
> -       settings = cl_engine_settings_copy(engine);
> +       settings = cl_engine_settings_copy(oldengine);
>         if(!settings)
>             logg("^Can't make a copy of the current engine settings\n");
> -
> -       thrmgr_setactiveengine(NULL);
> -       cl_engine_free(engine);
>      }
>
> +
>      dbdir = optget(opts, "DatabaseDirectory")->strarg;
>      logg("Reading databases from %s\n", dbdir);
>
> @@ -201,18 +190,12 @@ static struct cl_engine *reload_db(struct cl_engine
> *engine, unsigned int dbopti
>      memset(&dbstat, 0, sizeof(struct cl_stat));
>      if((retval = cl_statinidir(dbdir, &dbstat))) {
>         logg("!cl_statinidir() failed: %s\n", cl_strerror(retval));
> -       *ret = 1;
> -       if(settings)
> -           cl_engine_settings_free(settings);
> -       return NULL;
> +       goto err;
>      }
>
>      if(!(engine = cl_engine_new())) {
>         logg("!Can't initialize antivirus engine\n");
> -       *ret = 1;
> -       if(settings)
> -           cl_engine_settings_free(settings);
> -       return NULL;
> +       goto err;
>      }
>
>      if(settings) {
> @@ -222,25 +205,38 @@ static struct cl_engine *reload_db(struct cl_engine
> *engine, unsigned int dbopti
>             logg("^Using default engine settings\n");
>         }
>         cl_engine_settings_free(settings);
> +       settings = NULL;
>      }
>
>      if((retval = cl_load(dbdir, engine, &sigs, dboptions))) {
>         logg("!reload db failed: %s\n", cl_strerror(retval));
> -       cl_engine_free(engine);
> -       *ret = 1;
> -       return NULL;
> +       goto err;
>      }
>
>      if((retval = cl_engine_compile(engine)) != 0) {
>         logg("!Database initialization error: can't compile engine: %s\n",
> cl_strerror(retval));
> -       cl_engine_free(engine);
> -       *ret = 1;
> -       return NULL;
> +       goto err;
>      }
>      logg("Database correctly reloaded (%u signatures)\n", sigs);
>
> -    thrmgr_setactiveengine(engine);
> -    return engine;
> +    pthread_mutex_lock(&reload_mutex);
> +    time(&reloaded_time);
> +    reload_engine = engine;
> +    goto end;
> +
> +err:
> +    if(settings)
> +       cl_engine_settings_free(settings);
> +    if(engine)
> +       cl_engine_free(engine);
> +
> +    pthread_mutex_lock(&reload_mutex);
> +
> +end:
> +    reload_in_progress = 0;
> +    pthread_mutex_unlock(&reload_mutex);
> +
> +    free(args);
>  }
>
>  /*
> @@ -713,6 +709,7 @@ int recvloop_th(int *socketds, unsigned nsockets,
> struct cl_engine *engine, unsi
>         unsigned long long val;
>         size_t i, j, rr_last = 0;
>         pthread_t accept_th;
> +       pthread_t reload_th;
>         pthread_mutex_t fds_mutex = PTHREAD_MUTEX_INITIALIZER;
>         pthread_mutex_t recvfds_mutex = PTHREAD_MUTEX_INITIALIZER;
>         struct acceptdata acceptdata = ACCEPTDATA_INIT(&fds_mutex,
> &recvfds_mutex);
> @@ -1347,10 +1344,19 @@ int recvloop_th(int *socketds, unsigned nsockets,
> struct cl_engine *engine, unsi
>         if(selfchk) {
>             time(&current_time);
>             if((current_time - start_time) >= (time_t)selfchk) {
> -               if(reload_db(engine, dboptions, opts, TRUE, &ret)) {
> +               if(!dbstat.entries) {
> +                   logg("No stats for Database check - forcing reload\n");
> +                   pthread_mutex_lock(&reload_mutex);
> +                   reload = 1;
> +                   pthread_mutex_unlock(&reload_mutex);
> +               }
> +               else if(cl_statchkdir(&dbstat) == 1) {
> +                   logg("SelfCheck: Database modification detected.
> Forcing reload.\n");
>                     pthread_mutex_lock(&reload_mutex);
>                     reload = 1;
>                     pthread_mutex_unlock(&reload_mutex);
> +               } else {
> +                   logg("SelfCheck: Database status OK.\n");
>                 }
>                 time(&start_time);
>             }
> @@ -1358,34 +1364,57 @@ int recvloop_th(int *socketds, unsigned nsockets,
> struct cl_engine *engine, unsi
>
>         /* DB reload */
>         pthread_mutex_lock(&reload_mutex);
> -       if(reload) {
> +       if(reload && reload_in_progress) {
> +           logg("Database reload already in progress; ignoring reload
> request.\n");
> +           reload = 0;
> +           pthread_mutex_unlock(&reload_mutex);
> +       } else if(reload) {
>             pthread_mutex_unlock(&reload_mutex);
> +           struct reload_db_args *reload_db_args;
> +           reload_db_args = (struct reload_db_args *)
> malloc(sizeof(struct reload_db_args));
> +           if (reload_db_args)
> +           {
> +               reload_db_args->engine = engine;
> +               reload_db_args->dboptions = dboptions;
> +               reload_db_args->opts = opts;
> +
> +               pthread_mutex_lock(&reload_mutex);
> +               reload = 0;
> +               reload_in_progress = 1;
> +
> +               if (pthread_create(&reload_th, NULL, reload_db,
> reload_db_args) != 0) {
> +                   logg("*Error dispatching DB reload thread!\n");
> +                   reload_in_progress = 0;
> +                   free(reload_db_args);
> +               }
> +               pthread_mutex_unlock(&reload_mutex);
> +           }
> +       } else if(reload_engine != NULL) {
>  #if defined(FANOTIFY) || defined(CLAMAUTH)
> +           pthread_mutex_unlock(&reload_mutex);
>             if(optget(opts, "ScanOnAccess")->enabled && tharg) {
>                 logg("Restarting on-access scan\n");
>                 pthread_kill(fan_pid, SIGUSR1);
>                 pthread_join(fan_pid, NULL);
>             }
> -#endif
> -           engine = reload_db(engine, dboptions, opts, FALSE, &ret);
> -           if(ret) {
> -               logg("Terminating because of a fatal error.\n");
> -               if(new_sd >= 0)
> -                   closesocket(new_sd);
> -               break;
> -           }
> -
>             pthread_mutex_lock(&reload_mutex);
> -           reload = 0;
> -           time(&reloaded_time);
> +#endif
> +           static struct cl_engine *tmp;
> +           tmp = engine;
> +           engine = reload_engine;
> +           thrmgr_setactiveengine(engine);
> +           time(&start_time);
> +           reload_engine = NULL;
>             pthread_mutex_unlock(&reload_mutex);
> +
> +           cl_engine_free(tmp);
> +
>  #if defined(FANOTIFY) || defined(CLAMAUTH)
>             if(optget(opts, "ScanOnAccess")->enabled && tharg) {
>                 tharg->engine = engine;
>                 pthread_create(&fan_pid, &fan_attr, fan_th, tharg);
>             }
>  #endif
> -           time(&start_time);
>         } else {
>             pthread_mutex_unlock(&reload_mutex);
>         }
> diff --git a/clamd/server.h b/clamd/server.h
> index bc2a296..e171ea9 100644
> --- a/clamd/server.h
> +++ b/clamd/server.h
> @@ -46,6 +46,13 @@ struct thrwarg {
>      unsigned int options;
>  };
>
> +/* reload_db arguments */
> +struct reload_db_args {
> +    struct cl_engine *engine;
> +    unsigned int dboptions;
> +    const struct optstruct *opts;
> +};
> +
>  int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine
> *engine, unsigned int dboptions, const struct optstruct *opts);
>  void sighandler(int sig);
>  void sighandler_th(int sig);
> --
> 1.9.0-zedat
>
> _______________________________________________
> http://lurker.clamav.net/list/clamav-devel.html
> Please submit your patches to our Bugzilla: http://bugs.clamav.net
>
_______________________________________________
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.