From eaf49dcd87a3417c50803867e0ae6844c5748622 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 3 Sep 2009 11:07:03 +0200 Subject: [PATCH] Commit patch for: Fix bug #1355 Director crashes with double free in Accurate SQL query --- bacula/patches/3.0.2-accurate.patch | 341 ++++++++++++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 bacula/patches/3.0.2-accurate.patch diff --git a/bacula/patches/3.0.2-accurate.patch b/bacula/patches/3.0.2-accurate.patch new file mode 100644 index 0000000000..18225ad04b --- /dev/null +++ b/bacula/patches/3.0.2-accurate.patch @@ -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 + patch -p2 <3.0.2-accurate.patch + ./configure + 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; jargc; 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; -- 2.39.5