1    	/*****************************************************************************
2    	 *   Copyright (C) 2006-2008 by Michael Rieker, Jason Ansel, Kapil Arya, and *
3    	 *                                                            Gene Cooperman *
4    	 *   mrieker@nii.net, jansel@csail.mit.edu, kapil@ccs.neu.edu, and           *
5    	 *                                                          gene@ccs.neu.edu *
6    	 *                                                                           *
7    	 *   This file is part of the MTCP module of DMTCP (DMTCP:mtcp).             *
8    	 *                                                                           *
9    	 *  DMTCP:mtcp is free software: you can redistribute it and/or              *
10   	 *  modify it under the terms of the GNU Lesser General Public License as    *
11   	 *  published by the Free Software Foundation, either version 3 of the       *
12   	 *  License, or (at your option) any later version.                          *
13   	 *                                                                           *
14   	 *  DMTCP:dmtcp/src is distributed in the hope that it will be useful,       *
15   	 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
16   	 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
17   	 *  GNU Lesser General Public License for more details.                      *
18   	 *                                                                           *
19   	 *  You should have received a copy of the GNU Lesser General Public         *
20   	 *  License along with DMTCP:dmtcp/src.  If not, see                         *
21   	 *  <http://www.gnu.org/licenses/>.                                          *
22   	 *****************************************************************************/
23   	
24   	/********************************************************************************************************************************/
25   	/*																*/
26   	/*  This command-line utility is what a user uses to perform a restore								*/
27   	/*  It reads the given checkpoint file into memory then jumps to it, thus being just like the original program was restarted 	*/
28   	/*  from the last checkpoint.													*/
29   	/*																*/
30   	/*  It is also used by the checkpoint verification to perform a restore while the original application program is running, to 	*/
31   	/*  make sure the restore works.  The --verify option tells it to rename the checkpoint file, removing the .temp from the end.	*/
32   	/*																*/
33   	/********************************************************************************************************************************/
34   	
35   	#include <unistd.h>
36   	#include <sys/types.h>
37   	#include <sys/stat.h>
38   	#include <errno.h>
39   	#include <fcntl.h>
40   	#include <stdio.h>
41   	#include <stdlib.h>
42   	#include <sys/mman.h>
43   	#include <string.h>
44   	#include <sys/resource.h>
45   	#include <sys/types.h>
46   	
47   	#include "mtcp_internal.h"
48   	
49   	#include <sys/personality.h>
50   	
51   	static char first_char(char *filename);
52   	static int open_ckpt_to_read(char *filename);
53   	static void readcs (int fd, char cs);
54   	static void readfile (int fd, void *buf, size_t size);
55   	
56   	static pid_t gzip_child_pid = -1;
57   	
58   	extern int dmtcp_info_stderr_fd;
59   	
60   	//shift args
61   	#define shift argc--,argv++
62   	
63   	static const char* theUsage =
64   	  "USAGE:\n"
65   	  "mtcp_restart [--verify] <ckeckpointfile>\n\n"
66   	  "mtcp_restart [--offset <offset-in-bytes>] [--stderr-fd <fd>] [--] <ckeckpointfile>\n\n"
67   	  "mtcp_restart [--fd <ckpt-fd>] [--gzip-child-pid <pid>] [--rename-ckpt <newname>] [--stderr-fd <fd>]\n\n"
68   	;
69   	
70   	int main (int argc, char *argv[], char *envp[])
71   	{
72   	  char magicbuf[MAGIC_LEN], *restorename;
73   	  int fd, verify;
74   	  size_t restore_size, offset=0;
75   	  void *restore_begin, *restore_mmap;
76   	  void (*restore_start) (int fd, int verify, pid_t gzip_child_pid,
77   	                         char *ckpt_newname, char *cmd_file,
78   	                         char *argv[], char *envp[]);
79   	  char cmd_file[MAXPATHLEN+1];
80   	  char ckpt_newname[MAXPATHLEN+1] = "";
Event var_assign_var: Assigning: "orig_argv" = "argv". Both are now tainted.
Also see events: [tainted_data_transitive][var_assign_var][vararg_transitive][tainted_string]
81   	  char **orig_argv = argv;
82   	
At conditional (1): "getuid() == 0U": Taking true branch.
83   	  if (getuid() == 0 || geteuid() == 0) {
84   	    mtcp_printf("Running mtcp_restart as root is dangerous.  Aborting.\n" \
85   		   "If you still want to do this (at your own risk)," \
86   		   "  then modify mtcp/%s:%d and re-compile.\n",
87   		   __FILE__, __LINE__ - 4);
88   	    abort();
89   	  }
90   	
91   	  /* Turn off randomize_va (by re-exec'ing) or warn user if vdso_enabled is on. */
92   	  mtcp_check_vdso_enabled();
93   	
94   	/* DELETE THE "#else" CASE AND MAKE THIS PERMANENT, ONCE IT'S BEEN USED A LOT.
95   	 * IT WAS ADDED IN rev. 458.
96   	 */
97   	#if 1
98   	  fd = gzip_child_pid = -1;
99   	  verify = 0;
100  	
101  	  shift;
At conditional (2): "1": Taking true branch.
At conditional (10): "1": Taking true branch.
102  	  while (1) {
At conditional (3): "argc == 0": Taking false branch.
At conditional (4): "strcasecmp(argv[0], "--help") == 0": Taking true branch.
At conditional (5): "argc == 1": Taking false branch.
At conditional (11): "argc == 0": Taking false branch.
At conditional (12): "strcasecmp(argv[0], "--help") == 0": Taking true branch.
At conditional (13): "argc == 1": Taking false branch.
103  	    if (argc == 0 || (strcasecmp(argv[0], "--help") == 0 && argc == 1)) {
104  	      mtcp_printf("%s", theUsage);
105  	      return (-1);
At conditional (6): "strcasecmp(argv[0], "--verify") == 0": Taking true branch.
At conditional (7): "argc == 2": Taking false branch.
At conditional (14): "strcasecmp(argv[0], "--verify") == 0": Taking true branch.
At conditional (15): "argc == 2": Taking true branch.
106  	    } else if (strcasecmp (argv[0], "--verify") == 0 && argc == 2) {
107  	      verify = 1;
Event var_assign_var: Assigning: "restorename" = "argv[1]". Both are now tainted.
Also see events: [var_assign_var][tainted_data_transitive][vararg_transitive][tainted_string]
108  	      restorename = argv[1];
109  	      break;
At conditional (8): "strcasecmp(argv[0], "--offset") == 0": Taking true branch.
At conditional (9): "argc >= 3": Taking true branch.
110  	    } else if (strcasecmp (argv[0], "--offset") == 0 && argc >= 3) {
Event tainted_data_transitive: Call to function "atoi" with tainted argument "argv[1]" returns tainted data.
Also see events: [var_assign_var][var_assign_var][vararg_transitive][tainted_string]
111  	      offset = atoi(argv[1]);
112  	      shift; shift;
113  	    } else if (strcasecmp (argv[0], "--fd") == 0 && argc >= 2) {
114  	      fd = atoi(argv[1]);
115  	      shift; shift;
116  	    } else if (strcasecmp (argv[0], "--gzip-child-pid") == 0 && argc >= 2) {
117  	      gzip_child_pid = atoi(argv[1]);
118  	      shift; shift;
119  	    } else if (strcasecmp (argv[0], "--rename-ckpt") == 0 && argc >= 2) {
120  	      strncpy(ckpt_newname, argv[1], MAXPATHLEN);
121  	      shift; shift;
122  	    } else if (strcasecmp (argv[0], "--stderr-fd") == 0 && argc >= 2) {
123  	      dmtcp_info_stderr_fd = atoi(argv[1]);
124  	      shift; shift;
125  	    } else if (strcasecmp (argv[0], "--") == 0 && argc == 2) {
126  	      restorename = argv[1];
127  	      break;
128  	    } else if (argc == 1) {
129  	      restorename = argv[0];
130  	      break;
131  	    } else {
132  	      mtcp_printf("%s", theUsage);
133  	      return (-1);
134  	    }
135  	  }
136  	
137  	  /* XXX XXX XXX:
138  	   *    DO NOT USE mtcp_printf OR DPRINTF BEFORE THIS BLOCK, IT'S DANGEROUS AND
139  	   *    CAN MESS UP YOUR PROCESSES BY WRITING GARBAGE TO THEIR STDERR FD,
140  	   *    IF THEY ARE NOT USING IT AS STDERR.
141  	   *                                                                   --Kapil
142  	   */
143  	
At conditional (16): "fd != -1": Taking false branch.
144  	  if (fd != -1 && gzip_child_pid != -1) {
145  	    restorename = NULL;
At conditional (17): "fd == -1": Taking true branch.
At conditional (18): "gzip_child_pid != -1": Taking false branch.
At conditional (19): "offset != 0UL": Taking true branch.
At conditional (20): "fd != -1": Taking false branch.
146  	  } else if ((fd == -1 && gzip_child_pid != -1) ||
147  	             (offset != 0 && fd != -1)) {
148  	    mtcp_printf("%s", theUsage);
149  	    return (-1);
150  	  }
151  	
At conditional (21): "restorename": Taking true branch.
152  	  if (restorename) {
153  	    struct stat buf;
154  	    int rc = stat(restorename, &buf);
At conditional (22): "rc == -1": Taking true branch.
155  	    if (rc == -1) {
156  	      char error_msg[MAXPATHLEN+35];
Event vararg_transitive: Call to "sprintf" with tainted argument "restorename" taints "error_msg".
Also see events: [var_assign_var][tainted_data_transitive][var_assign_var][tainted_string]
157  	      sprintf(error_msg, "\nmtcp_restart: ckpt image %s", restorename);
158  	      perror(error_msg);
159  	      abort();
160  	    } else if (buf.st_uid != getuid()) { /*Could also run if geteuid() matches*/
161  	      mtcp_printf("\nProcess uid (%d) doesn't match uid (%d) of\n" \
162  		          "checkpoint image (%s).\n" \
163  			  "This is dangerous.  Aborting for security reasons.\n" \
164  		   "If you still want to do this, modify mtcp/%s:%d and re-compile.\n",
165  		   getuid(), buf.st_uid, restorename, __FILE__, __LINE__ - 5);
166  	      abort();
167  	    }
168  	  }
169  	
At conditional (23): "strlen(ckpt_newname) == 0UL": Taking false branch.
170  	  if (strlen(ckpt_newname) == 0 && restorename != NULL && offset != 0) {
171  	    strncpy(ckpt_newname, restorename, MAXPATHLEN);
172  	  }
173  	
174  	#else
175  	
176  	  if (argc == 2) {
177  	    verify = 0;
178  	    restorename = argv[1];
179  	  } else if ((argc == 3) && (strcasecmp (argv[1], "--verify") == 0)) {
180  	    verify = 1;
181  	    restorename = argv[2];
182  	  } else if ((argc == 4) && (strcasecmp (argv[1], "--offset") == 0)) {
183  	    verify = 0;
184  	    offset = atoi(argv[2]);
185  	    restorename = argv[3];
186  		strncpy(ckpt_newname,restorename,MAXPATHLEN);
187  	  } else if ((argc == 3) && (strcasecmp (argv[1], "--fd") == 0)) {
188  	    /* This case used only when dmtcp_restart exec's to mtcp_restart. */
189  	    verify = 0;
190  	    restorename = NULL;
191  	    fd = atoi(argv[2]);
192  	  } else if ((argc == 5) && (strcasecmp (argv[1], "--fd") == 0)
193  		     && (strcasecmp (argv[3], "--gzip-child-pid") == 0)) {
194  	    /* This case used only when dmtcp_restart exec's to mtcp_restart. */
195  	    verify = 0;
196  	    restorename = NULL;
197  	    fd = atoi(argv[2]);
198  	    gzip_child_pid = atoi(argv[4]);
199  	  } else if ((argc == 7) && (strcasecmp (argv[1], "--fd") == 0)
200  		     && (strcasecmp (argv[3], "--gzip-child-pid") == 0)
201  			 && (strcasecmp (argv[5], "--rename-ckpt") == 0)) {
202  	    /* This case used only when dmtcp_restart exec's to mtcp_restart. & wants to rename checkpoint filename */
203  	    verify = 0;
204  	    restorename = NULL;
205  	    fd = atoi(argv[2]);
206  	    gzip_child_pid = atoi(argv[4]);
207  		strncpy(ckpt_newname,argv[6],MAXPATHLEN);
208  	  } else {
209  	    mtcp_printf("%s", theUsage);
210  	    return (-1);
211  	  }
212  	
213  	#endif
214  	
Event tainted_string: Passing tainted string "restorename" to a function that cannot accept tainted data. [details]
Also see events: [var_assign_var][tainted_data_transitive][var_assign_var][vararg_transitive]
At conditional (24): "restorename != NULL": Taking true branch.
215  	  if(restorename!=NULL) fd = open_ckpt_to_read(restorename);
216  	  if(offset>0){
217  	    //skip into the file a bit
218  	    char* tmp = malloc(offset);
219  	    readfile(fd, tmp, offset);
220  	    free(tmp);
221  	  }
222  	  memset(magicbuf, 0, sizeof magicbuf);
223  	  readfile (fd, magicbuf, MAGIC_LEN);
224  	  if (memcmp (magicbuf, MAGIC, MAGIC_LEN) != 0) {
225  	    mtcp_printf("mtcp_restart: '%s' is '%s', but this restore is '%s' (fd=%d)\n", restorename, magicbuf, MAGIC, fd);
226  	    return (-1);
227  	  }
228  	
229  	  /* Set the resourse limits for stack from saved values */
230  	  struct rlimit stack_rlimit;
231  	  readcs (fd, CS_STACKRLIMIT); /* resource limit for stack */
232  	  readfile (fd, &stack_rlimit, sizeof stack_rlimit);
233  	#ifdef DEBUG
234  	  mtcp_printf("mtcp_restart: saved stack resource limit: soft_lim:%p, hard_lim:%p\n", stack_rlimit.rlim_cur, stack_rlimit.rlim_max);
235  	#endif
236  	  setrlimit(RLIMIT_STACK, &stack_rlimit);
237  	
238  	  /* Find where the restore image goes */
239  	  readcs (fd, CS_RESTOREBEGIN); /* beginning of checkpointed libmtcp.so image */
240  	  readfile (fd, &restore_begin, sizeof restore_begin);
241  	  readcs (fd, CS_RESTORESIZE); /* size of checkpointed libmtcp.so image */
242  	  readfile (fd, &restore_size, sizeof restore_size);
243  	  readcs (fd, CS_RESTORESTART);
244  	  readfile (fd, &restore_start, sizeof restore_start);
245  	
246  	  /* Read in the restore image to same address where it was loaded at time
247  	   *  of checkpoint.  This is libmtcp.so, including both text and data sections
248  	   *  as a single section.  Hence, we need both write and exec permission,
249  	   *  and MAP_ANONYMOUS, since the data could have changed.
250  	   */
251  	
252  	#ifdef DEBUG
253  	  mtcp_printf("mtcp_restart.c: main*: restoring anonymous area %p at %p\n",
254  	              restore_size, restore_begin);
255  	#endif
256  	  if (munmap(restore_begin, restore_size) < 0) {
257  	    mtcp_printf("mtcp_restart.c: failed to unmap region at %p\n", restore_begin);
258  	    abort ();
259  	  }
260  	  restore_mmap = mtcp_safemmap (restore_begin, restore_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0);
261  	  if (restore_mmap == MAP_FAILED) {
262  	#ifndef _XOPEN_UNIX
263  	    mtcp_printf("mtcp_restart: Does mmap here support MAP_FIXED?\n");
264  	#endif
265  	    if (mtcp_sys_errno != EBUSY) {
266  	      mtcp_printf("mtcp_restart: error creating %p byte restore region at %p: %s\n", restore_size, restore_begin, strerror(mtcp_sys_errno));
267  	      abort ();
268  	    } else {
269  	      mtcp_printf("mtcp_restart: info: restarting due to address conflict...\n");
270  	      close (fd);
271  	      argv = orig_argv;
272  	      execvp (argv[0], argv);
273  	    }
274  	  }
275  	  if (restore_mmap != restore_begin) {
276  	    mtcp_printf("mtcp_restart: %p byte restore region at %p got mapped at %p\n", restore_size, restore_begin, restore_mmap);
277  	    abort ();
278  	  }
279  	  readcs (fd, CS_RESTOREIMAGE);
280  	  readfile (fd, restore_begin, restore_size);
281  	
282  	#ifndef __x86_64__
283  	  // Copy command line to libmtcp.so, so that we can re-exec if randomized vdso
284  	  //   steps on us.  This won't be needed when we use the linker to map areas.
285  	  cmd_file[0] = '\0';
286  	  { int cmd_len = readlink("/proc/self/exe", cmd_file, MAXPATHLEN);
287  	    if (cmd_len == -1)
288  	      mtcp_printf("WARNING:  Couldn't find /proc/self/exe."
289  			  "  Trying to continue anyway.\n");
290  	    else
291  	      cmd_file[cmd_len] = '\0';
292  	  }
293  	#endif
294  	
295  	#if defined(DEBUG) && ! DMTCP_DEBUG
296  	    char *p, symbolbuff[256];
297  	    FILE *symbolfile;
298  	    VA textbase;
299  	
300  	    mtcp_printf("mtcp_restart*: restore_begin=%p, restore_start=%p\n", restore_begin, restore_start);
301  	    textbase = 0;
302  	
303  	    symbolfile = popen ("readelf -S libmtcp.so", "r");
304  	    if (symbolfile != NULL) {
305  	      while (fgets (symbolbuff, sizeof symbolbuff, symbolfile) != NULL) {
306  	        if (memcmp (symbolbuff + 5, "] .text ", 8) == 0) {
307  	          textbase = strtoul (symbolbuff + 41, &p, 16);
308  	        }
309  	      }
310  	      pclose (symbolfile);
311  	      if (textbase != 0) {
312  		mtcp_printf("\n**********\nmtcp_restart*: The symbol table of the"
313  			 " checkpointed file can be\nmade available to gdb."
314  			 "  Just type the command below in gdb:\n");
315  	        mtcp_printf("     add-symbol-file libmtcp.so %p\n",
316  	                 restore_begin + textbase);
317  	        mtcp_printf("Then type \"continue\" to continue debugging.\n");
318  		mtcp_printf("**********\n");
319  	      }
320  	    }
321  	    mtcp_maybebpt ();
322  	#endif
323  	
324  	  /* Now call it - it shouldn't return */
325  	  (*restore_start) (fd, verify, gzip_child_pid, ckpt_newname, cmd_file, argv, envp);
326  	  mtcp_printf("mtcp_restart: restore routine returned (it should never do this!)\n");
327  	  abort ();
328  	  return (0);
329  	}
330  	
331  	/**
332  	 * This function will return the first character of the given file.  If the
333  	 * file is not readable, we will abort.
334  	 *
335  	 * @param filename the name of the file to read
336  	 * @return the first character of the given file
337  	 */
338  	static char first_char(char *filename)
339  	{
340  	    int fd, rc;
341  	    char c;
342  	
Event tainted_string_sink_content_lv_call: Passing tainted string "filename" to "open", which depends on its content.
343  	    fd = open(filename, O_RDONLY);
344  	    if(fd < 0)
345  	    {
346  	        mtcp_printf("ERROR: Cannot open file %s\n", filename);
347  	        abort();
348  	    }
349  	
350  	    rc = read(fd, &c, 1);
351  	    if(rc != 1)
352  	    {
353  	        mtcp_printf("ERROR: Error reading from file %s\n", filename);
354  	        abort();
355  	    }
356  	
357  	    close(fd);
358  	    return c;
359  	}
360  	
361  	/**
362  	 * This function will open the checkpoint file stored at the given filename.
363  	 * It will check the magic number and take the appropriate action.  If the
364  	 * magic number is unknown, we will abort.  The fd returned points to the
365  	 * beginning of the uncompressed data.
366  	 * NOTE: related code in ../dmtcp/src/connectionmanager.cpp:open_ckpt_to_read()
367  	 *
368  	 * @param filename the name of the checkpoint file
369  	 * @return the fd to use
370  	 */
371  	static int open_ckpt_to_read(char *filename) {
372  	    int fd;
373  	    int fds[2];
374  	    char fc;
375  	    char *gzip_cmd = "gzip";
376  	    char gzip_path[MTCP_MAX_PATH];
377  	    static char *gzip_args[] = { "gzip", "-d", "-", NULL };
378  	    pid_t cpid;
379  	
Event tainted_string_sink_content_lv_call: Passing tainted string "filename" to "first_char", which depends on its content. [details]
380  	    fc = first_char(filename);
381  	    fd = open(filename, O_RDONLY);
382  	    if(fd < 0) {
383  	        mtcp_printf("ERROR: Cannot open checkpoint file %s\n", filename);
384  	        abort();
385  	    }
386  	
387  	    if (fc == MAGIC_FIRST || fc == 'D') /* no compression ('D' from DMTCP) */
388  	        return fd;
389  	    else if (fc == GZIP_FIRST) /* gzip : Set gzip_path */ {
390  	        if (mtcp_find_executable(gzip_cmd, gzip_path) == NULL) {
391  	            fputs("ERROR: Cannot find gunzip to decompress checkpoint file!\n", stderr);
392  	            abort();
393  	        }
394  	
395  	        if (pipe(fds) == -1) {
396  	            fputs("ERROR: Cannot create pipe to execute gunzip to decompress checkpoint file!\n", stderr);
397  	            abort();
398  	        }
399  	
400  	        cpid = fork();
401  	
402  	        if(cpid == -1) {
403  	            fputs("ERROR: Cannot fork to execute gunzip to decompress checkpoint file!\n", stderr);
404  	            abort();
405  	        }
406  	        else if(cpid > 0) /* parent process */ {
407  	            gzip_child_pid = cpid;
408  	            close(fd);
409  	            close(fds[1]);
410  	            return fds[0];
411  	        }
412  	        else /* child process */ {
413  	            fd = dup(dup(dup(fd)));
414  	            if (fd == -1) {
415  	            fputs("ERROR: dup() failed!  No restoration will be performed!  Cancel now!\n", stderr);
416  	              mtcp_abort();
417  	            }
418  	            fds[1] = dup(fds[1]);
419  	            close(fds[0]);
420  	            if (dup2(fd, STDIN_FILENO) != STDIN_FILENO) {
421  	            fputs("ERROR: dup2() failed!  No restoration will be performed!  Cancel now!\n", stderr);
422  	              mtcp_abort();
423  	            }
424  	            close(fd);
425  	            dup2(fds[1], STDOUT_FILENO);
426  	            close(fds[1]);
427  	            execvp(gzip_path, gzip_args);
428  	            /* should not get here */
429  	            fputs("ERROR: Decompression failed!  No restoration will be performed!  Cancel now!\n", stderr);
430  	            abort();
431  	        }
432  	    }
433  	    else /* invalid magic number */ {
434  	        fputs("ERROR: Invalid magic number in this checkpoint file!\n", stderr);
435  	        abort();
436  	    }
437  	}
438  	
439  	static void readcs (int fd, char cs)
440  	
441  	{
442  	  char xcs;
443  	
444  	  readfile (fd, &xcs, sizeof xcs);
445  	  if (xcs != cs) {
446  	    mtcp_printf("mtcp_restart readcs: checkpoint section %d next, expected %d\n", xcs, cs);
447  	    abort ();
448  	  }
449  	}
450  	
451  	static void readfile(int fd, void *buf, size_t size)
452  	{
453  	    int rc, ar;
454  	
455  	    ar = 0;
456  	
457  	    while(ar != size)
458  	    {
459  	        rc = read(fd, buf + ar, size - ar);
460  	        if(rc < 0)
461  	        {
462  	            mtcp_printf("mtcp_restart readfile: error reading checkpoint file: %s\n", strerror(errno));
463  	            abort();
464  	        }
465  	        else if(rc == 0)
466  	        {
467  	            mtcp_printf("mtcp_restart readfile: only read %d bytes instead of %d from checkpoint file\n", ar, size);
468  	            abort();
469  	        }
470  	
471  	        ar += rc;
472  	    }
473  	}