Exemple #1
0
/// This finalizer is called automatically as the auditor library
/// is being unmapped, but only if interception is on (aka active)
/// and only on "normal" exit as described in Interposer/exit.h.
/*static*/ void
interposed_finalize(void)
{
    if (_auditor_isActiveByRequest()) {
	pid_t pid;

	// This is a really cute trick I got from a guy named Nate Eldredge.
	// The exit status is not given to the library finalizer but we
	// need it, so what can we do? This is the answer: do a meaningless
	// fork. The child just returns so that the parent can wait for
	// it and gets its exit status. There's a slight chance that
	// the extra fork will cause non-beneficial side effects but
	// that should be quite rare.
	// IDEA Would it be better to use vfork() here? A big IDE
	// like Eclipse might have a large memory footprint and forking
	// it only to exit might be costly and/or have an OOM failure.
	// Answer, no, vfork is not allowed to return. There could be
	// an answer within posix_spawn but I haven't looked into it.
	if ((pid = fork_real()) == -1) {
	    putil_syserr(0, "fork");
	} else if (pid == 0) {
	    // The child just returns so the parent can wait for it.
	} else {
	    int wstat, status = 7;

	    if (waitpid(pid, &wstat, 0) == pid) {
		if (WIFEXITED(wstat)) {
		    status = WEXITSTATUS(wstat);
		}
	    } else {
		putil_syserr(0, "waitpid");
	    }

	    _audit_end("exit", EXITING, status);

	    // Do an explicit _exit( to abort any remaining library
	    // finalizers since they will have run in the child. I.e.
	    // any *previous* finalizers will have run in the
	    // original (now parent) copy and any *subsequent*
	    // ones will have run in the child, so continuing with
	    // exit processing here would run the latter set twice.
	    _exit_real(status);
	}
    } else if (_auditor_isActiveByDefault()) {
	_audit_end("exit", EXITING, 0);
    }

    /*
     * The cleanups below would be done by exit anyway but we try to
     * free things explicitly so that leak detectors such as valgrind
     * can more easily pinpoint real leaks. Perhaps we could have an
     * optimized "production mode" which skips the explicit cleanup.
     */
    code_fini();
    prop_fini();
    vb_fini();
}
Exemple #2
0
/// Interposes over the vfork() function.
/// It's nearly impossible to wrap vfork() since the docs say:
/// "The procedure that called vfork() should not
/// return while running in the child's context ...". Any
/// wrapper function would have to return to reach the exec().
/// So we convert vfork to fork. There may be a few corner
/// cases where this affects behavior but generally use of
/// vfork is an anachronism, and SUS does contain verbiage to
/// the effect that vfork may be equivalent to fork.
/// Better ideas solicited. In particular it appears that
/// we could hack in some assembler code to play with the
/// stack. See a response by Jonathan Adams in comp.unix.solaris
/// from 2004-09-17, subject 'how to "wrap" vfork?'
/// @return same as the wrapped function
/*static*/ pid_t
vfork(void)
{
    const char *call = "vfork";
    interposer_late_init(call);
    WRAPPER_DEBUG("ENTERING vfork_wrapper() => %p\n", fork_real);

    if (interposer_get_active()) {
	return fork_wrapper(call, fork_real);
    } else {
	return fork_real();
    }
}
Exemple #3
0
/*
 * hildon-desktop is typically running with higher priority and
 * runs protected against out-of-memory killing from the kernel.
 * Spawned children however should not be given these priviledges.
 */
pid_t
fork (void)
{
  static pid_t (*fork_real) () = NULL;
  pid_t         pid;

  if (fork_real == NULL)
    fork_real = dlsym (RTLD_NEXT, "fork");

  pid = fork_real ();

  if (pid == 0)
  {
    pid_t       child_pid;
    int         priority;
    int         fd;

    errno = 0;

    child_pid = getpid ();

    /* If the child process inherited desktop's high priority,
     * give child default priority */
    priority = getpriority (PRIO_PROCESS, child_pid);

    if (!errno && priority < 0)
    {
      setpriority (PRIO_PROCESS, child_pid, 0);
    }

    /* Unprotect from OOM */
    fd = g_open ("/proc/self/oom_adj", O_WRONLY, 0);

    if (fd >= 0)
    {
      write (fd, "0", sizeof (char));
      close (fd);
    }

  }

  return pid;
}
Exemple #4
0
pid_t fork(void) {
  static int loaded=0;
  static pid_t (*fork_real)(void);
  pid_t rv;
  
  if(!loaded) {
    fork_real=0;
    
    fork_real = (pid_t (*)(void))
      dlsym(RTLD_NEXT, "fork");
    
    if(!dlerror()) loaded=1;
    else {
      IPMERR("Intercepting fork(): load failed\n");
    }
  }

#if defined(HAVE_POSIXIO_TRACE) || defined(HAVE_MPI_TRACE)
  if( task.tracefile ) {
    fprintf(task.tracefile, "Before fork(), pid=%d\n", getpid());
  }
#endif
  
  rv = fork_real();
  
  if(!rv) {
    ipm_init(0);
#if defined(HAVE_POSIXIO_TRACE) || defined(HAVE_MPI_TRACE)
    task.tracefile=stderr;
#endif
  }

#if defined(HAVE_POSIXIO_TRACE) || defined(HAVE_MPI_TRACE)
  if( task.tracefile ) {
    fprintf(task.tracefile, "After fork(), pid=%d\n", getpid());
  }
#endif

  return rv;
}