]> git.sur5r.net Git - bacula/bacula/commitdiff
Commit patch for: Fix bug #1355 Director crashes with double free in Accurate SQL...
authorKern Sibbald <kern@sibbald.com>
Thu, 3 Sep 2009 09:07:03 +0000 (11:07 +0200)
committerKern Sibbald <kern@sibbald.com>
Thu, 3 Sep 2009 09:07:03 +0000 (11:07 +0200)
bacula/patches/3.0.2-accurate.patch [new file with mode: 0644]

diff --git a/bacula/patches/3.0.2-accurate.patch b/bacula/patches/3.0.2-accurate.patch
new file mode 100644 (file)
index 0000000..18225ad
--- /dev/null
@@ -0,0 +1,341 @@
+
+ This patch can be applied to version 3.0.2 and fixes
+ bug #1355 'bacula director crashes with double free
+ in Accurate SQL query'
+
+ Apply it to version 3.0.2 with:
+
+ cd <bacula-source>
+ patch -p2 <3.0.2-accurate.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h
+index 2ff803f..be07e84 100644
+--- a/bacula/src/cats/cats.h
++++ b/bacula/src/cats/cats.h
+@@ -1037,6 +1037,16 @@ struct db_int64_ctx {
+    int count;                         /* number of values seen */
+ };
++/* Call back context for getting a list of comma separated strings from the database */
++class db_list_ctx {
++public:
++   POOLMEM *list;                     /* list */
++   int count;                         /* number of values seen */
++
++   db_list_ctx() { list = get_pool_memory(PM_FNAME); *list = 0; count = 0; }
++   ~db_list_ctx() { free_pool_memory(list); list = NULL; }
++};
++
+ #include "protos.h"
+ #include "jcr.h"
+diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h
+index ea03a3c..565526a 100644
+--- a/bacula/src/cats/protos.h
++++ b/bacula/src/cats/protos.h
+@@ -1,7 +1,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
++   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+    The main author of Bacula is Kern Sibbald, with contributions from
+    many others, a complete list can be found in the file AUTHORS.
+@@ -57,6 +57,7 @@ bool db_sql_query(B_DB *mdb, const char *cmd, DB_RESULT_HANDLER *result_handler,
+ void db_start_transaction(JCR *jcr, B_DB *mdb);
+ void db_end_transaction(JCR *jcr, B_DB *mdb);
+ int db_int64_handler(void *ctx, int num_fields, char **row);
++int db_list_handler(void *ctx, int num_fields, char **row);
+ void db_thread_cleanup();
+ void _dbg_print_db(JCR *jcr, FILE *fp);
+@@ -106,8 +107,8 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr);
+ int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
+ bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids);
+ bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids, DB_RESULT_HANDLER *result_handler, void *ctx);
+-bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *jobids);
+-int db_get_int_handler(void *ctx, int num_fields, char **row);
++bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, JOB_DBR *jr, db_list_ctx *jobids);
++int db_get_int_handler(void *list, int num_fields, char **row);
+ /* sql_list.c */
+diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c
+index 324d017..e698b5a 100644
+--- a/bacula/src/cats/sql.c
++++ b/bacula/src/cats/sql.c
+@@ -144,7 +144,21 @@ int db_int64_handler(void *ctx, int num_fields, char **row)
+    return 0;
+ }
+-
++/*
++ * Use to build a comma separated list of values from a query. "10,20,30"
++ */
++int db_list_handler(void *ctx, int num_fields, char **row)
++{
++   db_list_ctx *lctx = (db_list_ctx *)ctx;
++   if (num_fields == 1 && row[0]) {
++      if (lctx->list[0]) {
++         pm_strcat(lctx->list, ",");
++      }
++      pm_strcat(lctx->list, row[0]);
++      lctx->count++;
++   }
++   return 0;
++}
+ /* NOTE!!! The following routines expect that the
+  *  calling subroutine sets and clears the mutex
+diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c
+index b9d25bb..62cd07c 100644
+--- a/bacula/src/cats/sql_get.c
++++ b/bacula/src/cats/sql_get.c
+@@ -1,7 +1,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
++   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+    The main author of Bacula is Kern Sibbald, with contributions from
+    many others, a complete list can be found in the file AUTHORS.
+@@ -1100,7 +1100,7 @@ bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
+  * TODO: look and merge from ua_restore.c
+  */
+ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, 
+-                            JOB_DBR *jr, POOLMEM *jobids)
++                            JOB_DBR *jr, db_list_ctx *jobids)
+ {
+    bool ret=false;
+    char clientid[50], jobid[50], filesetid[50];
+@@ -1111,7 +1111,8 @@ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
+    time_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
+    bstrutime(date, sizeof(date),  StartTime + 1);
+-   jobids[0]='\0';
++   jobids->list[0] = 0;
++   jobids->count = 0;
+    /* First, find the last good Full backup for this job/client/fileset */
+    Mmsg(query, 
+@@ -1177,8 +1178,8 @@ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
+    /* build a jobid list ie: 1,2,3,4 */
+    Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
+-   db_sql_query(mdb, query.c_str(), db_get_int_handler, jobids);
+-   Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids);
++   db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
++   Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
+    ret = true;
+ bail_out:
+@@ -1188,19 +1189,4 @@ bail_out:
+    return ret;
+ }
+-/*
+- * Use to build a string of int list from a query. "10,20,30"
+- */
+-int db_get_int_handler(void *ctx, int num_fields, char **row)
+-{
+-   POOLMEM *ret = (POOLMEM *)ctx;
+-   if (num_fields == 1) {
+-      if (ret[0]) {
+-         pm_strcat(ret, ",");
+-      }
+-      pm_strcat(ret, row[0]);
+-   }
+-   return 0;
+-}
+-
+ #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
+diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c
+index 029dfa0..1837a6b 100644
+--- a/bacula/src/dird/backup.c
++++ b/bacula/src/dird/backup.c
+@@ -131,42 +131,37 @@ static int accurate_list_handler(void *ctx, int num_fields, char **row)
+ bool send_accurate_current_files(JCR *jcr)
+ {
+    POOL_MEM buf;
++   db_list_ctx jobids;
++   db_list_ctx nb;
+    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
+       return true;
+    }
+-   POOLMEM *jobids = get_pool_memory(PM_FNAME);
+-   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
+-
+-   if (*jobids == 0) {
+-      free_pool_memory(jobids);
++   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
++   if (jobids.count == 0) {
+       Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
+       return false;
+    }
++
+    if (jcr->JobId) {            /* display the message only for real jobs */
+       Jmsg(jcr, M_INFO, 0, _("Sending Accurate information.\n"));
+    }
+    /* to be able to allocate the right size for htable */
+-   POOLMEM *nb = get_pool_memory(PM_FNAME);
+-   *nb = 0;                           /* clear buffer */
+-   Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids);
+-   db_sql_query(jcr->db, buf.c_str(), db_get_int_handler, nb);
+-   Dmsg2(200, "jobids=%s nb=%s\n", jobids, nb);
+-   jcr->file_bsock->fsend("accurate files=%s\n", nb); 
++   Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids.list);
++   db_sql_query(jcr->db, buf.c_str(), db_list_handler, &nb);
++   Dmsg2(200, "jobids=%s nb=%s\n", jobids.list, nb.list);
++   jcr->file_bsock->fsend("accurate files=%s\n", nb.list); 
+    if (!db_open_batch_connexion(jcr, jcr->db)) {
+       Jmsg0(jcr, M_FATAL, 0, "Can't get dedicate sql connexion");
+       return false;
+    }
+-   db_get_file_list(jcr, jcr->db_batch, jobids, accurate_list_handler, (void *)jcr);
++   db_get_file_list(jcr, jcr->db_batch, jobids.list, accurate_list_handler, (void *)jcr);
+    /* TODO: close the batch connexion ? (can be used very soon) */
+-   free_pool_memory(jobids);
+-   free_pool_memory(nb);
+-
+    jcr->file_bsock->signal(BNET_EOD);
+    return true;
+diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c
+index 3d5fc1d..028be52 100644
+--- a/bacula/src/dird/ua_output.c
++++ b/bacula/src/dird/ua_output.c
+@@ -456,7 +456,7 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
+          }
+          list_nextvol(ua, n);
+       } else if (strcasecmp(ua->argk[i], NT_("copies")) == 0) {
+-         char *jobids=NULL;
++         char *jobids = NULL;
+          uint32_t limit=0;
+          for (j=i+1; j<ua->argc; j++) {
+             if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
+diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c
+index 366d9ed..16f5215 100644
+--- a/bacula/src/dird/ua_restore.c
++++ b/bacula/src/dird/ua_restore.c
+@@ -1,7 +1,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
++   Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
+    The main author of Bacula is Kern Sibbald, with contributions from
+    many others, a complete list can be found in the file AUTHORS.
+@@ -556,6 +556,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
+       char *fname;
+       int len;
+       bool gui_save;
++      db_list_ctx jobids;
+       start_prompt(ua, _("To select the JobIds, you have the following choices:\n"));
+       for (int i=0; list[i]; i++) {
+@@ -752,9 +753,10 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
+             return 0;
+          }
+          jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
+-         if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, rx->JobIds)) {
++         if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &jobids)) {
+             return 0;
+          }
++         pm_strcpy(rx->JobIds, jobids.list);
+          Dmsg1(30, "Item 12: jobids = %s\n", rx->JobIds);
+          break;
+       case 12:                        /* Cancel or quit */
+diff --git a/bacula/src/dird/vbackup.c b/bacula/src/dird/vbackup.c
+index 45a1f7e..e75d08d 100644
+--- a/bacula/src/dird/vbackup.c
++++ b/bacula/src/dird/vbackup.c
+@@ -50,7 +50,7 @@
+ static const int dbglevel = 10;
+-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids);
++static bool create_bootstrap_file(JCR *jcr, char *jobids);
+ void vbackup_cleanup(JCR *jcr, int TermCode);
+ /* 
+@@ -135,6 +135,7 @@ bool do_vbackup(JCR *jcr)
+    char ed1[100];
+    BSOCK *sd;
+    char *p;
++   db_list_ctx jobids;
+    Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->rstorage, jcr->wstorage);
+    Dmsg2(100, "Read store=%s, write store=%s\n", 
+@@ -157,28 +158,27 @@ bool do_vbackup(JCR *jcr)
+ _("This Job is not an Accurate backup so is not equivalent to a Full backup.\n"));
+    }
+-   POOLMEM *jobids = get_pool_memory(PM_FNAME);
+    jcr->jr.JobLevel = L_VIRTUAL_FULL;
+-   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
+-   jcr->jr.JobLevel = L_FULL;
+-   Dmsg1(10, "Accurate jobids=%s\n", jobids);
+-   if (*jobids == 0) {
+-      free_pool_memory(jobids);
++   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
++   Dmsg1(10, "Accurate jobids=%s\n", jobids.list);
++   if (jobids.count == 0) {
+       Jmsg(jcr, M_FATAL, 0, _("No previous Jobs found.\n"));
+       return false;
+    }
++   jcr->jr.JobLevel = L_FULL;
++
+    /*
+     * Now we find the last job that ran and store it's info in
+     *  the previous_jr record.  We will set our times to the
+     *  values from that job so that anything changed after that
+     *  time will be picked up on the next backup.
+     */
+-   p = strrchr(jobids, ',');              /* find last jobid */
++   p = strrchr(jobids.list, ',');           /* find last jobid */
+    if (p != NULL) {
+       p++;
+    } else {
+-      p = jobids;
++      p = jobids.list;
+    }
+    memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr));
+    jcr->previous_jr.JobId = str_to_int64(p);
+@@ -189,12 +189,10 @@ _("This Job is not an Accurate backup so is not equivalent to a Full backup.\n")
+       return false;
+    }
+-   if (!create_bootstrap_file(jcr, jobids)) {
++   if (!create_bootstrap_file(jcr, jobids.list)) {
+       Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
+-      free_pool_memory(jobids);
+       return false;
+    }
+-   free_pool_memory(jobids);
+    /*
+     * Open a message channel connection with the Storage
+@@ -476,7 +474,7 @@ int insert_bootstrap_handler(void *ctx, int num_fields, char **row)
+ }
+-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
++static bool create_bootstrap_file(JCR *jcr, char *jobids)
+ {
+    RESTORE_CTX rx;
+    UAContext *ua;