1    	/****************************************************************************
2    	 *   Copyright (C) 2006-2010 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3    	 *   jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu              *
4    	 *                                                                          *
5    	 *   This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src).  *
6    	 *                                                                          *
7    	 *  DMTCP:dmtcp/src is free software: you can redistribute it and/or        *
8    	 *  modify it under the terms of the GNU Lesser General Public License as   *
9    	 *  published by the Free Software Foundation, either version 3 of the      *
10   	 *  License, or (at your option) any later version.                         *
11   	 *                                                                          *
12   	 *  DMTCP:dmtcp/src is distributed in the hope that it will be useful,      *
13   	 *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
14   	 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
15   	 *  GNU Lesser General Public License for more details.                     *
16   	 *                                                                          *
17   	 *  You should have received a copy of the GNU Lesser General Public        *
18   	 *  License along with DMTCP:dmtcp/src.  If not, see                        *
19   	 *  <http://www.gnu.org/licenses/>.                                         *
20   	 ****************************************************************************/
21   	
22   	#include <unistd.h>
23   	#include <stdlib.h>
24   	#include <string>
25   	#include <stdio.h>
26   	#include  "../jalib/jassert.h"
27   	#include <ctype.h>
28   	#include  "../jalib/jfilesystem.h"
29   	#include  "../jalib/jconvert.h"
30   	#include "constants.h"
31   	#include "dmtcpworker.h"
32   	#include "dmtcpmessagetypes.h"
33   	#include "syscallwrappers.h"
34   	#include <errno.h>
35   	#include <sys/types.h>
36   	#include <sys/wait.h>
37   	#include <sys/types.h>
38   	#include <sys/stat.h>
39   	#include <fcntl.h>
40   	#include <sys/time.h>
41   	#include <sys/resource.h>
42   	#include <sys/personality.h>
43   	#include <string.h>
44   	#include <dlfcn.h>
45   	
46   	int testMatlab(const char *filename);
47   	void testSetuid(const char *filename);
48   	int testStaticallyLinked(const char *filename);
49   	int testScreen(char **argvPtr[]);
50   	void adjust_rlimit_stack();
51   	int elfType(const char *pathname, bool *isElf, bool *is32bitElf);
52   	int safe_system(const char *command);
53   	
54   	// gcc-4.3.4 -Wformat=2 issues false positives for warnings unless the format
55   	// string has at least one format specifier with corresponding format argument.
56   	// Ubuntu 9.01 uses -Wformat=2 by default.
57   	static const char* theUsage =
58   	  "USAGE: \n"
59   	  "  dmtcp_checkpoint [OPTIONS] <command> [args...]\n\n"
60   	  "OPTIONS:\n"
61   	  "  --host, -h, (environment variable DMTCP_HOST):\n"
62   	  "      Hostname where dmtcp_coordinator is run (default: localhost)\n"
63   	  "  --port, -p, (environment variable DMTCP_PORT):\n"
64   	  "      Port where dmtcp_coordinator is run (default: 7779)\n"
65   	  "  --gzip, --no-gzip, (environment variable DMTCP_GZIP=[01]):\n"
66   	  "      Enable/disable compression of checkpoint images (default: 1)\n"
67   	  "  --ckptdir, -c, (environment variable DMTCP_CHECKPOINT_DIR):\n"
68   	  "      Directory to store checkpoint images (default: ./)\n"
69   	  "  --tmpdir, -t, (environment variable DMTCP_TMPDIR):\n"
70   	  "      Directory to store temporary files \n"
71   	  "        (default: $TMDPIR/dmtcp-$USER@$HOST or /tmp/dmtcp-$USER@$HOST)\n"
72   	  "  --join, -j:\n"
73   	  "      Join an existing coordinator, raise error if one already exists\n"
74   	  "  --new, -n:\n"
75   	  "      Create a new coordinator, raise error if one already exists\n"
76   	  "  --new-coordinator:\n"
77   	  "      Create a new coordinator even if one already exists\n"
78   	  "  --batch, -b:\n"
79   	  "      Enable batch mode i.e. start the coordinator on the same node on\n"
80   	  "        a randomly assigned port (if no port is specified by --port)\n"
81   	  "  --interval, -i, (environment variable DMTCP_CHECKPOINT_INTERVAL):\n"
82   	  "      Time in seconds between automatic checkpoints.\n"
83   	  "      Not allowed if --join is specified\n"
84   	  "      --batch implies -i 3600, unless otherwise specified.\n"
85   	  "  --no-check:\n"
86   	  "      Skip check for valid coordinator and never start one automatically\n"
87   	  "  --checkpoint-open-files:\n"
88   	  "      Checkpoint open files and restore old working dir. (Default: do neither)\n"
89   	  "  --mtcp-checkpoint-signal:\n"
90   	  "      Signal number used internally by MTCP for checkpointing (default: 12)\n"
91   	  "  --quiet, -q, (or set environment variable DMTCP_QUIET = 0, 1, or 2):\n"
92   	  "      Skip banner and NOTE messages; if given twice, also skip WARNINGs\n\n"
93   	  "See http://dmtcp.sf.net/ for more information.\n"
94   	;
95   	
96   	static const char* theBanner =
97   	  "DMTCP/MTCP  Copyright (C) 2006-2010  Jason Ansel, Michael Rieker,\n"
98   	  "                                       Kapil Arya, and Gene Cooperman\n"
99   	  "This program comes with ABSOLUTELY NO WARRANTY.\n"
100  	  "This is free software, and you are welcome to redistribute it\n"
101  	  "under certain conditions; see COPYING file for details.\n"
102  	  "(Use flag \"-q\" to hide this message.)\n\n"
103  	;
104  	
105  	// FIXME:  The warnings below should be collected into a single function,
106  	//          and also called after a user exec(), not just in dmtcp_checkpoint.
107  	static const char* theExecFailedMsg =
108  	  "ERROR: Failed to exec(\"%s\"): %s\n"
109  	  "Perhaps it is not in your $PATH?\n"
110  	  "See `dmtcp_checkpoint --help` for usage.\n"
111  	;
112  	
113  	static dmtcp::string _stderrProcPath()
114  	{
115  	  return "/proc/" + jalib::XToString ( getpid() ) + "/fd/" + jalib::XToString ( fileno ( stderr ) );
116  	}
117  	
118  	static void *get_libc_symbol ( const char* name )
119  	{
120  	  static void* handle = NULL;
121  	  if ( handle==NULL && ( handle=dlopen ( LIBC_FILENAME,RTLD_NOW ) ) == NULL )
122  	  {
123  	    fprintf ( stderr, "dmtcp: get_libc_symbol: ERROR in dlopen: %s \n",
124  	              dlerror() );
125  	    abort();
126  	  }
127  	
128  	  void* tmp = dlsym ( handle, name );
129  	  if ( tmp == NULL )
130  	  {
131  	    fprintf ( stderr, "dmtcp: get_libc_symbol: ERROR finding symbol %s using dlsym: %s \n",
132  	              name, dlerror() );
133  	    abort();
134  	  }
135  	  return tmp;
136  	}
137  	
138  	static void prepareDmtcpWrappers()
139  	{
140  	#ifndef ENABLE_DLOPEN
141  	  unsigned int wrapperOffsetArray[numLibcWrappers];
142  	  char *glibc_base_function_addr = NULL;
143  	
144  	# define _FIRST_BASE_ADDR(name) if (glibc_base_function_addr == NULL) \
145  					  glibc_base_function_addr = (char *)&name;
146  	  FOREACH_GLIBC_BASE_FUNC(_FIRST_BASE_ADDR);
147  	
148  	# define _GET_OFFSET(x) \
149  	    wrapperOffsetArray[enum_ ## x] = ((char*)get_libc_symbol(#x) \
150  					     - glibc_base_function_addr);
151  	  FOREACH_GLIBC_FUNC_WRAPPER(_GET_OFFSET);
152  	
153  	  dmtcp::ostringstream os;
154  	  for (int i = 0; i < numLibcWrappers; i++) {
155  	    os << std::hex << wrapperOffsetArray[i] << ";";
156  	  }
157  	
158  	  setenv(ENV_VAR_LIBC_FUNC_OFFSETS, os.str().c_str(), 1);
159  	#else
160  	  unsetenv(ENV_VAR_LIBC_FUNC_OFFSETS);
161  	#endif
162  	
163  	#ifdef PTRACE
164  	/*  
165  	   * For the sake of dlsym wrapper.  We compute address of _real_dlsym by adding 
166  	   * dlsym_offset to address of dlopen after the exec into the user application.
167  	   */
168  	  void* tmp1 = NULL;
169  	  void* tmp2 = NULL;
170  	  int tmp3;
171  	  static void* handle = NULL;
172  	  if ( handle==NULL && ( handle=dlopen ( "libdl.so",RTLD_NOW ) ) == NULL )
173  	  {
174  	    fprintf ( stderr,"dmtcp: get_libc_symbol: ERROR in dlopen: %s \n",dlerror() );
175  	    abort();
176  	  }
177  	  tmp1 = (void *) &dlopen;
178  	  tmp2 = (void *) &dlsym;
179  	  tmp3 = (char *)tmp2 - (char *) tmp1;
180  	  char str[21] = {0} ;
181  	  sprintf(str,"%d",tmp3);
182  	  setenv(ENV_VAR_DLSYM_OFFSET, str, 0);
183  	  dlclose(handle);
184  	#endif
185  	}
186  	
187  	
188  	//shift args
189  	#define shift argc--,argv++
190  	int main ( int argc, char** argv )
191  	{
192  	  bool isSSHSlave=false;
193  	  bool autoStartCoordinator=true;
194  	  bool checkpointOpenFiles=false;
195  	  int allowedModes = dmtcp::DmtcpWorker::COORD_ANY;
196  	
197  	  if (! getenv(ENV_VAR_QUIET))
198  	    setenv(ENV_VAR_QUIET, "0", 0);
199  	
200  	  //process args
201  	  shift;
202  	  while(true){
203  	    dmtcp::string s = argc>0 ? argv[0] : "--help";
204  	    if(s=="--help" || s=="-h" && argc==1){
205  	      JASSERT_STDERR << theUsage;
206  	      //fprintf(stderr, theUsage, "");
207  	      return 1;
208  	    }else if(s=="--ssh-slave"){
209  	      isSSHSlave = true;
210  	      shift;
211  	    }else if(s == "--no-check"){
212  	      autoStartCoordinator = false;
213  	      shift;
214  	    }else if(s == "-j" || s == "--join"){
215  	      allowedModes = dmtcp::DmtcpWorker::COORD_JOIN;
216  	      shift;
217  	    }else if(s == "--gzip"){
218  	      setenv(ENV_VAR_COMPRESSION, "1", 1);
219  	      shift;
220  	    }else if(s == "--no-gzip"){
221  	      setenv(ENV_VAR_COMPRESSION, "0", 1);
222  	      shift;
223  	    }else if(s == "-n" || s == "--new"){
224  	      allowedModes = dmtcp::DmtcpWorker::COORD_NEW;
225  	      shift;
226  	    }else if(s == "--new-coordinator"){
227  	      allowedModes = dmtcp::DmtcpWorker::COORD_FORCE_NEW;
228  	      shift;
229  	    }else if(s == "-b" || s == "--batch"){
230  	      allowedModes = dmtcp::DmtcpWorker::COORD_BATCH;
231  	      shift;
232  	    }else if(s == "-i" || s == "--interval"){
233  	      setenv(ENV_VAR_CKPT_INTR, argv[1], 1);
234  	      shift; shift;
235  	    }else if(argc>1 && (s == "-h" || s == "--host")){
236  	      setenv(ENV_VAR_NAME_ADDR, argv[1], 1);
237  	      shift; shift;
238  	    }else if(argc>1 && (s == "-p" || s == "--port")){
239  	      setenv(ENV_VAR_NAME_PORT, argv[1], 1);
240  	      shift; shift;
241  	    }else if(argc>1 && (s == "-c" || s == "--ckptdir")){
242  	      setenv(ENV_VAR_CHECKPOINT_DIR, argv[1], 1);
243  	      shift; shift;
244  	    }else if(argc>1 && (s == "-t" || s == "--tmpdir")){
245  	      setenv(ENV_VAR_TMPDIR, argv[1], 1);
246  	      shift; shift;
247  	    }else if(argc>1 && s == "--mtcp-checkpoint-signal"){
248  	      setenv(ENV_VAR_SIGCKPT, argv[1], 1);
249  	      shift; shift;
250  	    }else if(s == "--checkpoint-open-files"){
251  	      checkpointOpenFiles = true;
252  	      shift;
253  	    }else if(s == "-q" || s == "--quiet"){
254  	      *getenv(ENV_VAR_QUIET) = *getenv(ENV_VAR_QUIET) + 1;
255  	      // Just in case a non-standard version of setenv is being used:
256  	      setenv(ENV_VAR_QUIET, getenv(ENV_VAR_QUIET), 1);
257  	      shift;
258  	    }else if( (s.length()>2 && s.substr(0,2)=="--") ||
259  	              (s.length()>1 && s.substr(0,1)=="-" ) ) {
260  	      JASSERT_STDERR << "Invalid Argument\n";
261  	      JASSERT_STDERR << theUsage;
262  	      return 1;
263  	    }else if(argc>1 && s=="--"){
264  	      shift;
265  	      break;
266  	    }else{
267  	      break;
268  	    }
269  	  }
270  	
271  	  dmtcp::UniquePid::setTmpDir(getenv(ENV_VAR_TMPDIR));
272  	
273  	  jassert_quiet = *getenv(ENV_VAR_QUIET) - '0';
274  	
275  	#ifdef FORKED_CHECKPOINTING
276  	  /* When this is robust, add --forked-checkpointing option on command-line,
277  	   * with #ifdef FORKED_CHECKPOINTING around the option, change default of
278  	   * configure.ac, dmtcp/configure.ac, to enable, and change them
279  	   * from enable-forked... to disable-...
280  	   */
281  	  setenv(ENV_VAR_FORKED_CKPT, "1", 1);
282  	#endif
283  	
284  	  if (jassert_quiet == 0)
285  	    JASSERT_STDERR << theBanner;
286  	
287  	  // This code will go away when zero-mapped pages are implemented in MTCP.
288  	  struct rlimit rlim;
289  	  getrlimit(RLIMIT_STACK, &rlim);
290  	  if (rlim.rlim_cur > 256*1024*1024 && rlim.rlim_cur != RLIM_INFINITY)
291  	    JASSERT_STDERR <<
292  	      "*** WARNING:  RLIMIT_STACK > 1/4 GB.  This causes each thread to"
293  	      "\n***  receive a 1/4 GB stack segment.  Checkpoint/restart will be slow,"
294  	      "\n***  and will potentially break if many threads are created."
295  	      "\n*** Suggest setting (sh/bash):  ulimit -s 10000"
296  	      "\n***                (csh/tcsh):  limit stacksize 10000"
297  	      "\n*** prior to using DMTCP.  (This will be fixed in the future, when"
298  	      "\n*** DMTCP supports restoring zero-mapped pages.)\n\n\n" ;
299  	  // Remove this when zero-mapped pages are supported.  For segments with
300  	  // no file backing:  Start with 4096 (page) offset and keep doubling offset
301  	  // until finding region of memory segment with many zeroes.
302  	  // Then mark as CS_ZERO_PAGES in MTCP instead of CS_RESTORE (or mark
303  	  // entire segment as CS_ZERO_PAGES and then overwrite with CS_RESTORE
304  	  // region for portion to be read back fom checkpoint image.
305  	  // For CS_ZERO_PAGES region, mmap // on restart, but don't write in zeroes.
306  	  // Also, after checkpointing segment, munmap zero pages, and mmap them again.
307  	  // Don't try to find all pages.  The above strategy may increase
308  	  // the non-zero-mapped mapped pages to no more than double the actual
309  	  // non-zero region (assuming that the zero-mapped pages are contiguous).
310  	  // - Gene
311  	
312  	  testMatlab(argv[0]);
313  	
314  	  // If dmtcphijack.so is in standard search path and also has setgid access,
315  	  //   then LD_PRELOAD will work.  Otherwise, it will only work if the
316  	  //   application does not use setuid and setgid access.  So, we test
317  	  //   if the application does not use setuid/setgid.  (See 'man ld.so')
318  	  testSetuid(argv[0]);
319  	
320  	  prepareDmtcpWrappers();
321  	
322  	  if(autoStartCoordinator)
323  	     dmtcp::DmtcpWorker::startCoordinatorIfNeeded(allowedModes);
324  	
325  	  dmtcp::string dmtcphjk =
326  	    jalib::Filesystem::FindHelperUtility ( "dmtcphijack.so" );
327  	  dmtcp::string searchDir = jalib::Filesystem::GetProgramDir();
328  	
329  	  // Initialize JASSERT library here
330  	  dmtcp::ostringstream o;
331  	  o << dmtcp::UniquePid::getTmpDir() << "/jassertlog." << dmtcp::UniquePid(getpid());
332  	  JASSERT_INIT(o.str());
333  	
334  	  if (argc > 0)
335  	    JTRACE("dmtcp_checkpoint starting new program:")(argv[0]);
336  	
337  	  //setup CHECKPOINT_DIR
338  	  if(getenv(ENV_VAR_CHECKPOINT_DIR) == NULL){
339  	    const char* ckptDir = get_current_dir_name();
340  	    if(ckptDir != NULL ){
341  	      //copy to private buffer
342  	      static dmtcp::string _buf = ckptDir;
343  	      ckptDir = _buf.c_str();
344  	    }else{
345  	      ckptDir=".";
346  	    }
347  	    setenv ( ENV_VAR_CHECKPOINT_DIR, ckptDir, 0 );
348  	    JTRACE("setting " ENV_VAR_CHECKPOINT_DIR)(ckptDir);
349  	  }
350  	
351  	  dmtcp::string stderrDevice = jalib::Filesystem::ResolveSymlink ( _stderrProcPath() );
352  	
353  	  //TODO:
354  	  // When stderr is a pseudo terminal for IPC between parent/child processes,
355  	  // this logic fails and JASSERT may write data to FD 2 (stderr)
356  	  // this will cause problems in programs that use FD 2 (stderr) for algorithmic things...
357  	  if ( stderrDevice.length() > 0
358  	          && jalib::Filesystem::FileExists ( stderrDevice ) )
359  	    setenv ( ENV_VAR_STDERR_PATH,stderrDevice.c_str(), 0 );
360  	  else// if( isSSHSlave )
361  	    setenv ( ENV_VAR_STDERR_PATH, "/dev/null", 0 );
362  	
363  	  // If dmtcp_checkpoint was called with user LD_PRELOAD, and if
364  	  //   if dmtcp_checkpoint survived the experience, then pass it back to user.
365  	  if (getenv("LD_PRELOAD"))
366  	    dmtcphjk = dmtcphjk + ":" + getenv("LD_PRELOAD");
367  	  setenv ( "LD_PRELOAD", dmtcphjk.c_str(), 1 );
368  	  setenv ( ENV_VAR_HIJACK_LIB, dmtcphjk.c_str(), 0 );
369  	  setenv ( ENV_VAR_UTILITY_DIR, searchDir.c_str(), 0 );
370  	  if ( getenv(ENV_VAR_SIGCKPT) != NULL )
371  	    setenv ( "MTCP_SIGCKPT", getenv(ENV_VAR_SIGCKPT), 1);
372  	  else
373  	    unsetenv("MTCP_SIGCKPT");
374  	
375  	  if ( checkpointOpenFiles )
376  	    setenv( ENV_VAR_CKPT_OPEN_FILES, "1", 0 );
377  	  else
378  	    unsetenv( ENV_VAR_CKPT_OPEN_FILES);
379  	
380  	#ifdef PID_VIRTUALIZATION
381  	  setenv( ENV_VAR_ROOT_PROCESS, "1", 1 );
382  	#endif
383  	
384  	  bool isElf, is32bitElf;
385  	  if  (elfType(argv[0], &isElf, &is32bitElf) == -1) {
386  	    // Couldn't read argv_buf
387  	    // FIXME:  This could have been a symbolic link.  Don't issue an error,
388  	    //         unless we're sure that the executable is not readable.
389  	    JASSERT_STDERR <<
390  	      "*** ERROR:  Executable to run w/ DMTCP appears not to be readable.\n\n"
391  	      << argv[0];
392  	    exit(1);
393  	  } else {
394  	#if defined(__x86_64__) && !defined(CONFIG_M32)
395  	    if (is32bitElf)
396  	      JASSERT_STDERR << "*** ERROR:  You appear to be checkpointing "
397  	        << "a 32-bit target under 64-bit Linux.\n"
398  	        << "***  If this fails, then please try re-configuring DMTCP:\n"
399  	        << "***  configure --enable-m32 ; make clean ; make\n\n";
400  	#endif
401  	
402  	    testStaticallyLinked(argv[0]);
403  	  }
404  	
405  	// FIXME:  Unify this code with code prior to execvp in execwrappers.cpp
406  	//   Can use argument to dmtcpPrepareForExec() or getenv("DMTCP_...")
407  	//   from DmtcpWorker constructor, to distinguish the two cases.
408  	  adjust_rlimit_stack();
409  	
410  	  //run the user program
411  	  char **newArgv = argv;
412  	  if (0 == testScreen(&newArgv))
413  	    execvp ( newArgv[0], newArgv );
414  	  else
415  	    execvp ( argv[0], argv );
416  	
417  	  //should be unreachable
418  	  JASSERT_STDERR <<
419  	    "ERROR: Failed to exec(\"" << argv[0] << "\"): " << JASSERT_ERRNO << "\n"
420  	    << "Perhaps it is not in your $PATH?\n"
421  	    << "See `dmtcp_checkpoint --help` for usage.\n";
422  	  //fprintf(stderr, theExecFailedMsg, argv[0], JASSERT_ERRNO);
423  	
424  	  return -1;
425  	}
426  	
427  	int expandPathname(const char *inpath, char * const outpath, size_t size) {
428  	  bool success = false;
At conditional (1): "*inpath == 47": Taking false branch.
At conditional (2): "strstr(inpath, "/") != NULL": Taking false branch.
429  	  if (*inpath == '/' || strstr(inpath, "/") != NULL) {
430  	    strncpy(outpath, inpath, size);
431  	    success = true;
At conditional (3): "inpath[0] == 126": Taking true branch.
At conditional (4): "inpath[1] == 47": Taking true branch.
432  	  } else if (inpath[0] == '~' && inpath[1] == '/') {
Event tainted_string_return: Function "getenv" returns a tainted string.
Event tainted_data_transitive: "strncpy" taints argument "outpath" because argument "getenv("HOME")" is tainted.
433  	    strncpy(outpath, getenv("HOME"), size);
434  	    strncpy(outpath + strlen(outpath), inpath + 2, size-2);
435  	    success = true;
436  	  } else {
437  	    char *pathVar = getenv("PATH");
438  	    while (*pathVar != '\0') {
439  	      char *nextPtr;
440  	      nextPtr = strstr(pathVar, ":");
441  	      if (nextPtr == NULL)
442  	        nextPtr = pathVar + strlen(pathVar); 
443  	      memcpy(outpath, pathVar, nextPtr - pathVar);
444  	      *(outpath + (nextPtr - pathVar)) = '/';
445  	      strcpy(outpath + (nextPtr - pathVar) + 1, inpath);
446  	      JASSERT (strlen(outpath) < size) (strlen(outpath)) (size)
447  		      (outpath) .Text("Pathname too long; Use larger buffer.");
448  	      if (*nextPtr  == '\0')
449  	        pathVar = nextPtr;
450  	      else // else *nextPtr == ':'
451  	        pathVar = nextPtr + 1; // prepare for next iteration
452  	      if (access(outpath, X_OK) == 0) {
453  		success = true;
454  		break;
455  	      }
456  	    }
457  	  }
458  	  return (success ? 0 : -1);
459  	}
460  	
461  	int elfType(const char *pathname, bool *isElf, bool *is32bitElf) {
462  	  const char *magic_elf = "\177ELF"; // Magic number for ELF
463  	  const char *magic_elf32 = "\177ELF\001"; // Magic number for ELF 32-bit
464  	  // Magic number for ELF 64-bit is "\177ELF\002"
465  	  const int len = strlen(magic_elf32);
466  	  char argv_buf[len];
467  	  char full_path[1024];
468  	  expandPathname(pathname, full_path, sizeof(full_path));
469  	  int fd = open(full_path, O_RDONLY);
470  	  if (fd == -1 || 5 != read(fd, argv_buf, 5))
471  	    return -1;
472  	  else
473  	    close (fd);
474  	  *isElf = (memcmp(magic_elf, argv_buf, strlen(magic_elf)) == 0);
475  	  *is32bitElf = (memcmp(magic_elf32, argv_buf, strlen(magic_elf32)) == 0);
476  	  return 0;
477  	}
478  	
479  	// Doesn't malloc.  Returns pointer to within pathname.
480  	char *dmtcp_basename(char *pathname) {
481  	  char *ptr = pathname;
482  	  while (*ptr++ != '\0')
483  	    if (*ptr == '/')
484  	      pathname = ptr+1;
485  	  return pathname;
486  	}
487  	
488  	// 'screen' requires directory with permissions 0700
489  	int isdir_0700(const char *pathname) {
490  	  struct stat st;
491  	  stat(pathname, &st);
492  	  return (S_ISDIR(st.st_mode) == 1
493  	          && st.st_mode & 0777 == 0700
494  	          && st.st_uid == getuid()
495  	          && access(pathname, R_OK | W_OK | X_OK) == 0
496  	         );
497  	}
498  	int safe_mkdir(const char *pathname, mode_t mode) {
499  	  // If it exists and we can give it the right permissions, do it.
500  	  chmod(pathname, 0700);
501  	  if (isdir_0700(pathname))
502  	    return 0;
503  	  // else start over
504  	  unlink(pathname);
505  	  rmdir(pathname); // Maybe it was an empty directory
506  	  mkdir(pathname, 0700);
507  	  return isdir_0700(pathname);
508  	}
509  	int safe_system(const char *command) {
510  	  char *str = getenv("LD_PRELOAD");
511  	  dmtcp::string dmtcphjk;
At conditional (1): "str != NULL": Taking false branch.
512  	  if (str != NULL)
513  	    dmtcphjk = str;
514  	  unsetenv("LD_PRELOAD");
Event tainted_string_sink_content_lv_call: Passing tainted string "command" to "system", which depends on its content.
515  	  int rc = system(command);
516  	  if (str != NULL)
517  	    setenv( "LD_PRELOAD", dmtcphjk.c_str(), 1 );
518  	  return rc;
519  	}
520  	
521  	int testMatlab(const char *filename) {
522  	#ifdef __GNUC__
523  	# if __GNUC__ == 4 && __GNUC_MINOR__ > 1
524  	  static const char* theMatlabWarning =
525  	    "\n**** WARNING:  Earlier Matlab releases (e.g. release 7.4) use an\n"
526  	    "****  older glibc.  Later releases (e.g. release 7.9) have no problem.\n"
527  	    "****  \n"
528  	    "****  If you are using an _earlier_ Matlab, please re-compile DMTCP/MTCP\n"
529  	    "****  with gcc-4.1 and g++-4.1\n"
530  	    "**** env CC=gcc-4.1 CXX=g++-4.1 ./configure\n"
531  	    "**** [ Also modify mtcp/Makefile to:  CC=gcc-4.1 ]\n"
532  	    "**** [ Next, you may need an alternative Java JVM (see QUICK-START) ]\n"
533  	    "**** [ Finally, run as:   dmtcp_checkpoint matlab -nodisplay ]\n"
534  	    "**** [   (DMTCP does not yet checkpoint X-Windows applications.) ]\n"
535  	    "**** [ You may see \"Not checkpointing libc-2.7.so\".  This is normal. ]\n"
536  	    "****   (Assuming you have done the above, Will now continue"
537  		    " executing.)\n\n" ;
538  	
539  	  // FIXME:  should expand filename and "matlab" before checking
540  	  if ( strcmp(filename, "matlab") == 0 ) {
541  	    JASSERT_STDERR << theMatlabWarning;
542  	    return -1;
543  	  }
544  	# endif
545  	#endif
546  	  return 0;
547  	}
548  	
549  	void testSetuid(const char *filename) {
550  	  static const char* theSetuidWarning =
551  	    "\n**** WARNING:  This process has the setuid or setgid bit set.  This is\n"
552  	    "***  incompatible with the use by DMTCP of LD_PRELOAD.  The process\n"
553  	    "***  will not be checkpointed by DMTCP.  Continuing and hoping\n"
554  	    "***  for the best.  For some programs, you may wish to\n"
555  	    "***  compile your own private copy, without using setuid permission.\n\n" ;
556  	  char pathname[1024];
557  	  if (expandPathname(filename, pathname, sizeof(pathname)) ==  0) {
558  	    struct stat buf;
559  	    int rc = stat(pathname, &buf);
560  	    // screen tested separately.  Exclude it here.
561  	    if (rc == 0 && (buf.st_mode & S_ISUID || buf.st_mode & S_ISGID
562  	        && strcmp(pathname, "screen") != 0
563  	        && strstr(pathname, "/screen") == NULL)) {
564  	      JASSERT_STDERR << theSetuidWarning;
565  	      sleep(3);
566  	    }
567  	  }
568  	}
569  	
570  	int testStaticallyLinked(const char *filename) {
571  	  bool isElf, is32bitElf;
572  	  char pathname[1024];
573  	  expandPathname(filename, pathname, sizeof(pathname));
574  	  elfType(pathname, &isElf, &is32bitElf);
575  	#if defined(__x86_64__) && !defined(CONFIG_M32)
576  	  dmtcp::string cmd = is32bitElf ? "/lib/ld-linux.so.2 --verify "
577  				         : "/lib64/ld-linux-x86-64.so.2 --verify " ;
578  	#else
579  	  dmtcp::string cmd = "/lib/ld-linux.so.2 --verify " ;
580  	#endif
581  	  cmd = cmd + pathname + " > /dev/null";
582  	  // FIXME:  When tested on dmtcp/test/pty.c, 'ld.so -verify' returns
583  	  // nonzero status.  Why is this?  It's dynamically linked.
584  	  if ( isElf && safe_system(cmd.c_str()) ) {
585  	    JASSERT_STDERR <<
586  	      "*** WARNING:  /lib/ld-2.10.1.so --verify " << pathname << " returns\n"
587  	      << "***  nonzero status.  This often means that " << pathname << " is\n"
588  	      << "*** a statically linked target.  If so, you can confirm this with\n"
589  	      << "*** the 'file' command.\n"
590  	      << "***  The standard DMTCP only supports dynamically"
591  	      << " linked executables.\n"
592  	      << "*** If you cannot recompile dynamically, please talk to the"
593  	      << " developers about a\n"
594  	      << "*** custom DMTCP version for statically linked executables.\n"
595  	      << "*** Proceeding for now, and hoping for the best.\n\n";
596  	    return -1;
597  	  } else
598  	    return 0;
599  	}
600  	
601  	void adjust_rlimit_stack() {
602  	#ifdef __i386__
603  	  // This is needed in 32-bit Ubuntu 9.10, to fix bug with test/dmtcp5.c
604  	  // NOTE:  Setting personality() is cleanest way to force legacy_va_layout,
605  	  //   but there's currently a bug on restart in the sequence:
606  	  //   checkpoint -> restart -> checkpoint -> restart
607  	# if 0
608  	  { unsigned long oldPersonality = personality(0xffffffffL);
609  	    if ( ! (oldPersonality & ADDR_COMPAT_LAYOUT) ) {
610  	      // Force ADDR_COMPAT_LAYOUT for libs in high mem, to avoid vdso conflict
611  	      personality(oldPersonality & ADDR_COMPAT_LAYOUT);
612  	      JTRACE( "setting ADDR_COMPAT_LAYOUT" );
613  	      setenv("DMTCP_ADDR_COMPAT_LAYOUT", "temporarily is set", 1);
614  	    }
615  	  }
616  	# else
617  	  { struct rlimit rlim;
618  	    getrlimit(RLIMIT_STACK, &rlim);
619  	    if (rlim.rlim_cur != RLIM_INFINITY) {
620  	      char buf[100];
621  	      sprintf(buf, "%lu", rlim.rlim_cur); // "%llu" for BSD/Mac OS
622  	      JTRACE( "setting rlim_cur for RLIMIT_STACK" ) ( rlim.rlim_cur );
623  	      setenv("DMTCP_RLIMIT_STACK", buf, 1);
624  	      // Force kernel's internal compat_va_layout to 0; Force libs to high mem.
625  	      rlim.rlim_cur = rlim.rlim_max;
626  	      // FIXME: if rlim.rlim_cur != RLIM_INFINITY, then we should warn the user.
627  	      setrlimit(RLIMIT_STACK, &rlim);
628  	      // After exec, process will restore DMTCP_RLIMIT_STACK in DmtcpWorker()
629  	    }
630  	  }
631  	# endif
632  	#endif
633  	}
634  	
635  	// Test for 'screen' program, argvPtr is an in- and out- parameter
636  	int testScreen(char **argvPtr[]) {
637  	  struct stat st;
638  	  // If screen has setuid or segid bits set, ...
639  	  char *pathname_base = dmtcp_basename((*argvPtr)[0]);
640  	  char pathname[1024];
641  	  if ((*argvPtr)[0] == NULL)
642  	    return -1;
643  	  if (expandPathname((*argvPtr)[0], pathname, sizeof(pathname)) != 0)
644  	    return -1;
645  	  if ( strcmp(pathname_base, "screen") == 0
646  	       && stat(pathname, &st) == 0
647  	       && (st.st_mode & S_ISUID || st.st_mode & S_ISGID) ) {
648  	    dmtcp::string tmpdir = dmtcp::UniquePid::getTmpDir() + "/" + "uscreens";
649  	    safe_mkdir(tmpdir.c_str(), 0700);
650  	    setenv("SCREENDIR", tmpdir.c_str(), 1);
651  	
652  	    static char cmdBuf[1024];
653  	    bool isElf, is32bitElf;
654  	    char ** oldArgv = *argvPtr; // Initialize oldArgv with argument passed here
655  	    *(char **)(cmdBuf+sizeof(cmdBuf)-sizeof(char *)) = NULL;
Event tainted_string_argument: "expandPathname(char const *, char *, unsigned long)" taints variable "cmdBuf". [details]
Also see events: [var_assign_var][var_assign_var][tainted_string]
656  	    expandPathname(oldArgv[0], cmdBuf, sizeof(cmdBuf));
657  	#define COPY_SCREEN
658  	#ifdef COPY_SCREEN
659  	    // cp /usr/bin/screen /tmp/dmtcp-USER@HOST/screen
Event var_assign_var: Assigning: "newArgv0" = "&cmdBuf[strlen(cmdBuf)] + 1". Both are now tainted.
Also see events: [tainted_string_argument][var_assign_var][tainted_string]
660  	    char *newArgv0 = cmdBuf + strlen(cmdBuf) + 1;
661  	    snprintf(newArgv0, sizeof(cmdBuf)-(newArgv0-cmdBuf), "%s/%s",
662  		    dmtcp::UniquePid::getTmpDir().c_str(), pathname_base);
663  	    unlink(newArgv0);  // Remove any stale copy, just in case it's not right.
Event var_assign_var: Assigning: "cpCmd" = "newArgv0 + strlen(newArgv0) + 1". Both are now tainted.
Also see events: [tainted_string_argument][var_assign_var][tainted_string]
664  	    char *cpCmd = newArgv0 + strlen(newArgv0) + 1;
665  	    snprintf(cpCmd, sizeof(cmdBuf)-(cpCmd-cmdBuf), "cp %s %s",
666  		     pathname, newArgv0);
Event tainted_string: Passing tainted string "cpCmd" to a function that cannot accept tainted data. [details]
Also see events: [tainted_string_argument][var_assign_var][var_assign_var]
667  	    safe_system(cpCmd);
668  	    JASSERT (access(newArgv0, X_OK) == 0) (newArgv0) (JASSERT_ERRNO);
669  	    (*argvPtr)[0] = newArgv0;
670  	    return 0;
671  	#else
672  	    // Translate: screen   to: /lib/ld-linux.so /usr/bin/screen
673  	    // This version is more general, but has a bug on restart:
674  	    //    memory layout is altered on restart, and so brk() doesn't match.
675  	    // Switch argvPtr from ptr to input to ptr to output now.
676  	    *argvPtr = (char **)(cmdBuf + strlen(cmdBuf) + 1); // ... + 1 for '\0'
677  	    // Use /lib64 if 64-bit O/S and not 32-bit app:
678  	# if defined(__x86_64__) && !defined(CONFIG_M32)
679  	    elfType(cmdBuf, &isElf, &is32bitElf);
680  	    if (is32bitElf)
681  	      (*argvPtr)[0] = (char *)"/lib/ld-linux.so.2";
682  	    else
683  	      (*argvPtr)[0] = (char *)"/lib64/ld-linux-x86-64.so.2";
684  	# else
685  	    (*argvPtr)[0] = (char *)"/lib/ld-linux.so.2";
686  	# endif
687  	    (*argvPtr)[1] = cmdBuf;
688  	    for (int i = 1; oldArgv[i] != NULL; i++)
689  	      *argvPtr[i+1] = oldArgv[i];
690  	    JASSERT ((char *)cmdBuf[sizeof(cmdBuf)-sizeof(char *)] == NULL)
691  	      (sizeof(cmdBuf)) .Text("Expanded command longer than sizeof(cmdBuf");
692  	    return 0;
693  	#endif
694  	  } else
695  	    return -1;
696  	}