Beispiel #1
0
/**
 * Build supermin appliance from C<supermin_path> to
 * F<$TMPDIR/.guestfs-$UID>.
 *
 * Returns: C<0> = built or C<-1> = error (aborts launch).
 */
static int
build_supermin_appliance (guestfs_h *g,
                          const char *supermin_path,
                          char **kernel, char **initrd,
                          char **appliance)
{
  CLEANUP_FREE char *cachedir = NULL, *lockfile = NULL, *appliancedir = NULL;

  cachedir = guestfs_int_lazy_make_supermin_appliance_dir (g);
  if (cachedir == NULL)
    return -1;

  appliancedir = safe_asprintf (g, "%s/appliance.d", cachedir);
  lockfile = safe_asprintf (g, "%s/lock", cachedir);

  debug (g, "begin building supermin appliance");

  /* Build the appliance if it needs to be built. */
  debug (g, "run supermin");

  if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1)
    return -1;

  debug (g, "finished building supermin appliance");

  /* Return the appliance filenames. */
  *kernel = safe_asprintf (g, "%s/kernel", appliancedir);
  *initrd = safe_asprintf (g, "%s/initrd", appliancedir);
  *appliance = safe_asprintf (g, "%s/root", appliancedir);

  /* Touch the files so they don't get deleted (as they are in /var/tmp). */
  (void) utimes (*kernel, NULL);
  (void) utimes (*initrd, NULL);

  /* Checking backend != "uml" is a big hack.  UML encodes the mtime
   * of the original backing file (in this case, the appliance) in the
   * COW file, and checks it when adding it to the VM.  If there are
   * multiple threads running and one touches the appliance here, it
   * will disturb the mtime and UML will give an error.
   *
   * We can get rid of this hack as soon as UML fixes the
   * ubdN=cow,original parsing bug, since we won't need to run
   * uml_mkcow separately, so there is no possible race.
   *
   * XXX
   */
  if (STRNEQ (g->backend, "uml"))
    (void) utimes (*appliance, NULL);

  return 0;
}
Beispiel #2
0
/* Build supermin appliance from supermin_path to $TMPDIR/.guestfs-$UID.
 *
 * Returns:
 * 0 = built
 * -1 = error (aborts launch)
 */
static int
build_supermin_appliance (guestfs_h *g,
                          const char *supermin_path,
                          uid_t uid,
                          char **kernel, char **dtb,
			  char **initrd, char **appliance)
{
  CLEANUP_FREE char *tmpdir = guestfs_get_cachedir (g);
  struct stat statbuf;
  size_t len;

  /* len must be longer than the length of any pathname we can
   * generate in this function.
   */
  len = strlen (tmpdir) + 128;
  char cachedir[len];
  snprintf (cachedir, len, "%s/.guestfs-%ju", tmpdir, (uintmax_t) uid);
  char lockfile[len];
  snprintf (lockfile, len, "%s/lock", cachedir);
  char appliancedir[len];
  snprintf (appliancedir, len, "%s/appliance.d", cachedir);

  ignore_value (mkdir (cachedir, 0755));
  ignore_value (chmod (cachedir, 0755)); /* RHBZ#921292 */

  /* See if the cache directory exists and passes some simple checks
   * to make sure it has not been tampered with.
   */
  if (lstat (cachedir, &statbuf) == -1)
    return 0;
  if (statbuf.st_uid != uid) {
    error (g, _("security: cached appliance %s is not owned by UID %ju"),
           cachedir, (uintmax_t) uid);
    return -1;
  }
  if (!S_ISDIR (statbuf.st_mode)) {
    error (g, _("security: cached appliance %s is not a directory (mode %o)"),
           cachedir, statbuf.st_mode);
    return -1;
  }
  if ((statbuf.st_mode & 0022) != 0) {
    error (g, _("security: cached appliance %s is writable by group or other (mode %o)"),
           cachedir, statbuf.st_mode);
    return -1;
  }

  (void) utimes (cachedir, NULL);
  if (g->verbose)
    guestfs_int_print_timestamped_message (g, "begin building supermin appliance");

  /* Build the appliance if it needs to be built. */
  if (g->verbose)
    guestfs_int_print_timestamped_message (g, "run supermin");

  if (run_supermin_build (g, lockfile, appliancedir, supermin_path) == -1)
    return -1;

  if (g->verbose)
    guestfs_int_print_timestamped_message (g, "finished building supermin appliance");

  /* Return the appliance filenames. */
  *kernel = safe_malloc (g, len);
#ifdef DTB_WILDCARD
  *dtb = safe_malloc (g, len);
#else
  *dtb = NULL;
#endif
  *initrd = safe_malloc (g, len);
  *appliance = safe_malloc (g, len);
  snprintf (*kernel, len, "%s/kernel", appliancedir);
#ifdef DTB_WILDCARD
  snprintf (*dtb, len, "%s/dtb", appliancedir);
#endif
  snprintf (*initrd, len, "%s/initrd", appliancedir);
  snprintf (*appliance, len, "%s/root", appliancedir);

  /* Touch the files so they don't get deleted (as they are in /var/tmp). */
  (void) utimes (*kernel, NULL);
#ifdef DTB_WILDCARD
  (void) utimes (*dtb, NULL);
#endif
  (void) utimes (*initrd, NULL);

  /* Checking backend != "uml" is a big hack.  UML encodes the mtime
   * of the original backing file (in this case, the appliance) in the
   * COW file, and checks it when adding it to the VM.  If there are
   * multiple threads running and one touches the appliance here, it
   * will disturb the mtime and UML will give an error.
   *
   * We can get rid of this hack as soon as UML fixes the
   * ubdN=cow,original parsing bug, since we won't need to run
   * uml_mkcow separately, so there is no possible race.
   *
   * XXX
   */
  if (STRNEQ (g->backend, "uml"))
    (void) utimes (*appliance, NULL);

  return 0;
}