int get_default_context_with_rolelevel(const char *user,
				       const char *role,
				       const char *level,
				       security_context_t fromcon,
				       security_context_t * newcon)
{

	int rc = 0;
	int freefrom = 0;
	context_t con;
	char *newfromcon;
	if (!level)
		return get_default_context_with_role(user, role, fromcon,
						     newcon);

	if (!fromcon) {
		rc = getcon(&fromcon);
		if (rc < 0)
			return rc;
		freefrom = 1;
	}

	rc = -1;
	con = context_new(fromcon);
	if (!con)
		goto out;

	if (context_range_set(con, level))
		goto out;

	newfromcon = context_str(con);
	if (!newfromcon)
		goto out;

	rc = get_default_context_with_role(user, role, newfromcon, newcon);

      out:
	context_free(con);
	if (freefrom)
		freecon(fromcon);
	return rc;

}
Example #2
0
int fgetfilecon(int fd, security_context_t * context)
{
	security_context_t rcontext;
	int ret;

	*context = NULL;

	ret = fgetfilecon_raw(fd, &rcontext);

	if (ret > 0) {
		ret = selinux_raw_to_trans_context(rcontext, context);
		freecon(rcontext);
	}

	if (ret >= 0 && *context)
		return strlen(*context) + 1;

	return ret;
}
Example #3
0
int selinux_util_label(const char *path)
{
    int retval = 0;
    int enforce;
    struct stat st;
    security_context_t con;

    enforce = security_getenforce();
    if (retval < 0)
        return retval;

    if (!hnd)
        return (enforce) ? -1 : 0;

    retval = lstat(path, &st);
    if (retval < 0) {
        if (errno == ENOENT)
            return 0;
        return (enforce) ? -1 : 0;
    }

    /* lookup the context */
    retval = selabel_lookup_raw(hnd, &con, path, st.st_mode);
    if (retval < 0) {
        if (errno == ENOENT)
            return 0;
        return (enforce) ? -1 : 0;
    }

    /* apply the context */
    retval = lsetfilecon(path, con);
    freecon(con);
    if (retval < 0) {
        if (errno == ENOENT)
            return 0;
        if (errno == ENOTSUP)
            return 0;
        return (enforce) ? -1 : 0;
    }

    return 0;
}
Example #4
0
static void check_selinux_update_passwd(const char *username)
{
	security_context_t context;
	char *seuser;

	if (getuid() != (uid_t)0 || is_selinux_enabled() == 0)
		return;  /* No need to check */

	if (getprevcon_raw(&context) < 0)
		bb_perror_msg_and_die("getprevcon failed");
	seuser = strtok(context, ":");
	if (!seuser)
		bb_error_msg_and_die("invalid context '%s'", context);
	if (strcmp(seuser, username) != 0) {
		if (checkPasswdAccess(PASSWD__PASSWD) != 0)
			bb_error_msg_and_die("SELinux: access denied");
	}
	if (ENABLE_FEATURE_CLEAN_UP)
		freecon(context);
}
Example #5
0
void 
setup_selinux_exec_context(char *name)
{

  if (is_selinux_enabled() > 0) {
    security_context_t user_context=selinux_get_user_context(name);
    if (setexeccon(user_context)) {
      if (security_getenforce() > 0)
        fatal("Failed to set exec security context %s for %s.",
              user_context, name);
      else
        error("Failed to set exec security context %s for %s. "
              "Continuing in permissive mode",
              user_context, name);
    }
    if (user_context) {
      freecon(user_context);
    }
  }
}
Example #6
0
int label_fix(const char *path, bool ignore_enoent) {
        int r = 0;

#ifdef HAVE_SELINUX
        struct stat st;
        security_context_t fcon;

        if (!use_selinux() || !label_hnd)
                return 0;

        r = lstat(path, &st);
        if (r == 0) {
                r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);

                /* If there's no label to set, then exit without warning */
                if (r < 0 && errno == ENOENT)
                        return 0;

                if (r == 0) {
                        r = setfilecon(path, fcon);
                        freecon(fcon);

                        /* If the FS doesn't support labels, then exit without warning */
                        if (r < 0 && errno == ENOTSUP)
                                return 0;
                }
        }

        if (r < 0) {
                /* Ignore ENOENT in some cases */
                if (ignore_enoent && errno == ENOENT)
                        return 0;

                log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG,
                         "Unable to fix label of %s: %m", path);
                r = security_getenforce() == 1 ? -errno : 0;
        }
#endif

        return r;
}
Example #7
0
static char *get_selinux_label(int pid) {
#ifdef HAVE_SELINUX_SELINUX_H
	char *selinux_label;
	security_context_t pid_context;
	context_t context;

	if (getpidcon(pid, &pid_context) == -1) {
		/* error getting pid selinux context */
		dW("Can't get selinux context for process %d\n", pid);
		return NULL;
	}
	context = context_new(pid_context);
	selinux_label = strdup(context_type_get(context));
	context_free(context);
	freecon(pid_context);
	return selinux_label;

#else
	return NULL;
#endif /* HAVE_SELINUX_SELINUX_H */
}
Example #8
0
static int printmatchpathcon(const char *path, int header, int mode)
{
	char *buf;
	int rc = matchpathcon(path, mode, &buf);
	if (rc < 0) {
		if (errno == ENOENT) {
			buf = strdup("<<none>>");
		} else {
			fprintf(stderr, "matchpathcon(%s) failed: %s\n", path,
				strerror(errno));
			return 1;
		}
	}
	if (header)
		printf("%s\t%s\n", path, buf);
	else
		printf("%s\n", buf);

	freecon(buf);
	return 0;
}
int get_ordered_context_list_with_level(const char *user,
					const char *level,
					security_context_t fromcon,
					security_context_t ** list)
{
	int rc;
	int freefrom = 0;
	context_t con;
	char *newfromcon;

	if (!level)
		return get_ordered_context_list(user, fromcon, list);

	if (!fromcon) {
		rc = getcon(&fromcon);
		if (rc < 0)
			return rc;
		freefrom = 1;
	}

	rc = -1;
	con = context_new(fromcon);
	if (!con)
		goto out;

	if (context_range_set(con, level))
		goto out;

	newfromcon = context_str(con);
	if (!newfromcon)
		goto out;

	rc = get_ordered_context_list(user, newfromcon, list);

      out:
	context_free(con);
	if (freefrom)
		freecon(fromcon);
	return rc;
}
static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
    char *sctx = NULL;
    const char *class = "service_manager";
    bool allowed;
    struct audit_data ad;

    if (getpidcon(spid, &sctx) < 0) {
        ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
        return false;
    }

    ad.pid = spid;
    ad.uid = uid;
    ad.name = name;

    int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
    allowed = (result == 0);

    freecon(sctx);
    return allowed;
}
Example #11
0
/*
 * selinux_file_context - Set the security context before any file or
 *                        directory creation.
 *
 *  selinux_file_context () should be called before any creation of file,
 *  symlink, directory, ...
 *
 *  Callers may have to Reset SELinux to create files with default
 *  contexts:
 *      reset_selinux_file_context();
 */
int selinux_file_context(const char *dst_name)
{
    security_context_t scontext = NULL;

    if (is_selinux_enabled() == 1) {
        /* Get the default security context for this file */
        if (matchpathcon(dst_name, 0, &scontext) < 0) {
            if (security_getenforce () != 0) {
                return 1;
            }
        }
        /* Set the security context for the next created file */
        if (setfscreatecon(scontext) < 0) {
            if (security_getenforce() != 0) {
                return 1;
            }
        }
        freecon(scontext);
    }

    return 0;
}
Example #12
0
int make_dir(const char *path, mode_t mode)
{
    int rc;

    char *secontext = NULL;

    if (sehandle) {
        selabel_lookup(sehandle, &secontext, path, mode);
        setfscreatecon(secontext);
    }

    rc = mkdir(path, mode);

    if (secontext) {
        int save_errno = errno;
        freecon(secontext);
        setfscreatecon(NULL);
        errno = save_errno;
    }

    return rc;
}
Example #13
0
static void mkswap_selinux_setcontext(int fd, const char *path)
{
	struct stat stbuf;

	if (!is_selinux_enabled())
		return;

	if (fstat(fd, &stbuf) < 0)
		bb_perror_msg_and_die("fstat failed");
	if (S_ISREG(stbuf.st_mode)) {
		security_context_t newcon;
		security_context_t oldcon = NULL;
		context_t context;

		if (fgetfilecon(fd, &oldcon) < 0) {
			if (errno != ENODATA)
				goto error;
			if (matchpathcon(path, stbuf.st_mode, &oldcon) < 0)
				goto error;
		}
		context = context_new(oldcon);
		if (!context || context_type_set(context, "swapfile_t"))
			goto error;
		newcon = context_str(context);
		if (!newcon)
			goto error;
		/* fsetfilecon_raw is hidden */
		if (strcmp(oldcon, newcon) != 0 && fsetfilecon(fd, newcon) < 0)
			goto error;
		if (ENABLE_FEATURE_CLEAN_UP) {
			context_free(context);
			freecon(oldcon);
		}
	}
	return;
 error:
	bb_perror_msg_and_die("SELinux relabeling failed");
}
Example #14
0
static void
set_selinux_path_context(const char *matchpath, const char *path, mode_t mode)
{
#ifdef WITH_SELINUX
  static int selinux_enabled = -1;
  security_context_t scontext = NULL;
  int ret;

  /* If there's no file type, just give up. */
  if ((mode & S_IFMT) == 0)
    return;

  /* Set selinux_enabled if it is not already set (singleton). */
  if (selinux_enabled < 0)
    selinux_enabled = (is_selinux_enabled() > 0);

  /* If SE Linux is not enabled just do nothing. */
  if (!selinux_enabled)
    return;

  /* XXX: Well, we could use set_matchpathcon_printf() to redirect the
   * errors from the following bit, but that seems too much effort. */

  /* Do nothing if we can't figure out what the context is, or if it has
   * no context; in which case the default context shall be applied. */
  ret = matchpathcon(matchpath, mode & S_IFMT, &scontext);
  if (ret == -1 || (ret == 0 && scontext == NULL))
    return;

  if (strcmp(scontext, "<<none>>") != 0) {
    if (lsetfilecon(path, scontext) < 0)
      /* XXX: This might need to be fatal instead!? */
      perror("Error setting security context for next file object:");
  }

  freecon(scontext);
#endif /* WITH_SELINUX */
}
static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
{
    bool allowed;
    char *tctx = NULL;

    if (selinux_enabled <= 0) {
        return true;
    }

    if (!sehandle) {
        ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
        abort();
    }

    if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
        ALOGE("SELinux: No match for %s in service_contexts.\n", name);
        return false;
    }

    allowed = check_mac_perms(spid, uid, tctx, perm, name);
    freecon(tctx);
    return allowed;
}
Example #16
0
static int set_context( security_context_t cntx )
{
   const char *func = "set_context" ;

   int retval = setexeccon(cntx);

   if (debug.on)
   {
      security_context_t current_exec_context;
      if ( getexeccon( &current_exec_context ) == 0 ) {

         msg( LOG_DEBUG, func, 
	   "current security exec context now: %s", 
	   current_exec_context ? current_exec_context : "unknown" );

         freecon( current_exec_context );
      } 
      else
         msg( LOG_DEBUG, func, "Error calling getexeccon: %m" );
   }

   return retval;
}
Example #17
0
static int
SELinuxReserveSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                            virDomainDefPtr def,
                            pid_t pid)
{
    security_context_t pctx;
    context_t ctx = NULL;
    const char *mcs;

    if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

    if (getpidcon(pid, &pctx) == -1) {
        virReportSystemError(errno,
                             _("unable to get PID %d security context"), pid);
        return -1;
    }

    ctx = context_new(pctx);
    freecon(pctx);
    if (!ctx)
        goto err;

    mcs = context_range_get(ctx);
    if (!mcs)
        goto err;

    mcsAdd(mcs);

    context_free(ctx);

    return 0;

err:
    context_free(ctx);
    return -1;
}
Example #18
0
/* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL.
 * If COMMAND is nonzero, pass it to the shell with the -c option.
 * If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
 * arguments.  */
void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args)
{
	const char **args;
	int argno;
	int additional_args_cnt = 0;

	for (args = additional_args; args && *args; args++)
		additional_args_cnt++;

	args = xmalloc(sizeof(char*) * (4 + additional_args_cnt));

	if (!shell || !shell[0])
		shell = DEFAULT_SHELL;

	args[0] = bb_get_last_path_component_nostrip(shell);
	if (loginshell)
		args[0] = xasprintf("-%s", args[0]);
	argno = 1;
	if (command) {
		args[argno++] = "-c";
		args[argno++] = command;
	}
	if (additional_args) {
		for (; *additional_args; ++additional_args)
			args[argno++] = *additional_args;
	}
	args[argno] = NULL;

#if ENABLE_SELINUX
	if (current_sid)
		setexeccon(current_sid);
	if (ENABLE_FEATURE_CLEAN_UP)
		freecon(current_sid);
#endif
	execv(shell, (char **) args);
	bb_perror_msg_and_die("can't execute '%s'", shell);
}
static int check_mac_perms(const char *name, char *sctx)
{
    if (is_selinux_enabled() <= 0)
        return 1;

    char *tctx = NULL;
    int result = 0;

    if (!sctx)
        goto err;

    if (!sehandle_prop)
        goto err;

    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
        goto err;

    if (selinux_check_access(sctx, tctx, "property_service", "set", (void*) name) == 0)
        result = 1;

    freecon(tctx);
 err:
    return result;
}
  /*
   * Function: getPeerCon
   * Purpose: retrieves security context of peer socket
   * Parameters:
   *        fileDescriptor: peer socket file as a FileDescriptor object
   * Returns: jstring representing the security_context of socket or NULL if error
   * Exceptions: NullPointerException if fileDescriptor object is NULL
   */
  static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
#ifdef HAVE_SELINUX
    if (isSELinuxDisabled)
      return NULL;

    if (fileDescriptor == NULL) {
      throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
      return NULL;
    }

    security_context_t context = NULL;
    jstring securityString = NULL;

    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);

    if (env->ExceptionOccurred() != NULL) {
      ALOGE("There was an issue with retrieving the file descriptor");
      goto bail;
    }

    if (getpeercon(fd, &context) == -1)
      goto bail;

    ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);

    securityString = env->NewStringUTF(context);

  bail:
    if (context != NULL)
      freecon(context);

    return securityString;
#else
    return NULL;
#endif
  }
  /*
   * Function: getCon
   * Purpose: Get the context of the current process.
   * Parameters: none
   * Returns: a jstring representing the security context of the process,
   *          the jstring may be NULL if there was an error
   * Exceptions: none
   */
  static jstring getCon(JNIEnv *env, jobject clazz) {
#ifdef HAVE_SELINUX
    if (isSELinuxDisabled)
      return NULL;

    security_context_t context = NULL;
    jstring securityString = NULL;

    if (getcon(&context) == -1)
      goto bail;

    ALOGV("getCon: Successfully retrieved context '%s'", context);

    securityString = env->NewStringUTF(context);

  bail:
    if (context != NULL)
      freecon(context);

    return securityString;
#else
    return NULL;
#endif
  }
Example #22
0
int label_symlinkfile_set(const char *path) {
        int r = 0;

#ifdef HAVE_SELINUX
        security_context_t filecon = NULL;

        if (!use_selinux() || !label_hnd)
                return 0;

        if ((r = selabel_lookup_raw(label_hnd, &filecon, path, S_IFLNK)) == 0) {
                if ((r = setfscreatecon(filecon)) < 0) {
                        log_error("Failed to set SELinux file context on %s: %m", path);
                        r = -errno;
                }

                freecon(filecon);
        }

        if (r < 0 && security_getenforce() == 0)
                r = 0;
#endif

        return r;
}
Example #23
0
const char * rpmsxLgetfilecon(rpmsx sx, const char *fn)
{
    const char * scon = NULL;

    if (sx == NULL) sx = rpmsxI();

if (_rpmsx_debug)
fprintf(stderr, "--> %s(%p,%s) sxfn %s\n", __FUNCTION__, sx, fn, sx->fn);

#if defined(WITH_SELINUX)
    if (sx->fn && fn) {
	security_context_t _con = NULL;
	int rc = lgetfilecon(fn, &_con);
	if (rc > 0 && _con != NULL)
	    scon = (const char *) _con;
	else
	    freecon(_con);
    }
#endif

if (_rpmsx_debug)
fprintf(stderr, "<-- %s(%p,%s) scon %s\n", __FUNCTION__, sx, fn, scon);
    return scon;
}
Example #24
0
static void pw_write(void)
{
	char tmp[FILENAMELEN + 4];

	sprintf(tmp, "%s%s", orig_file, ".OLD");
	unlink(tmp);

	if (link(orig_file, tmp))
		warn(_("%s: create a link to %s failed"), orig_file, tmp);

#ifdef HAVE_LIBSELINUX
	if (is_selinux_enabled() > 0) {
		security_context_t passwd_context = NULL;
		int ret = 0;
		if (getfilecon(orig_file, &passwd_context) < 0) {
			warnx(_("Can't get context for %s"), orig_file);
			pw_error(orig_file, 1, 1);
		}
		ret = setfilecon(tmp_file, passwd_context);
		freecon(passwd_context);
		if (ret != 0) {
			warnx(_("Can't set context for %s"), tmp_file);
			pw_error(tmp_file, 1, 1);
		}
	}
#endif

	if (rename(tmp_file, orig_file) == -1) {
		int errsv = errno;
		errx(EXIT_FAILURE,
		     ("cannot write %s: %s (your changes are still in %s)"),
		     orig_file, strerror(errsv), tmp_file);
	}
	unlink(tmp_file);
	free(tmp_file);
}
Example #25
0
/* Return:
 * -1 error, copy not made
 *  0 copy is made or user answered "no" in interactive mode
 *    (failures to preserve mode/owner/times are not reported in exit code)
 */
int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
{
	/* This is a recursive function, try to minimize stack usage */
	/* NB: each struct stat is ~100 bytes */
	struct stat source_stat;
	struct stat dest_stat;
	smallint retval = 0;
	smallint dest_exists = 0;
	smallint ovr;

/* Inverse of cp -d ("cp without -d") */
#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))

	if ((FLAGS_DEREF ? stat : lstat)(source, &source_stat) < 0) {
		/* This may be a dangling symlink.
		 * Making [sym]links to dangling symlinks works, so... */
		if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK))
			goto make_links;
		bb_perror_msg("can't stat '%s'", source);
		return -1;
	}

	if (lstat(dest, &dest_stat) < 0) {
		if (errno != ENOENT) {
			bb_perror_msg("can't stat '%s'", dest);
			return -1;
		}
	} else {
		if (source_stat.st_dev == dest_stat.st_dev
		 && source_stat.st_ino == dest_stat.st_ino
		) {
			bb_error_msg("'%s' and '%s' are the same file", source, dest);
			return -1;
		}
		dest_exists = 1;
	}

#if ENABLE_SELINUX
	if ((flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) && is_selinux_enabled() > 0) {
		security_context_t con;
		if (lgetfilecon(source, &con) >= 0) {
			if (setfscreatecon(con) < 0) {
				bb_perror_msg("can't set setfscreatecon %s", con);
				freecon(con);
				return -1;
			}
		} else if (errno == ENOTSUP || errno == ENODATA) {
			setfscreatecon_or_die(NULL);
		} else {
			bb_perror_msg("can't lgetfilecon %s", source);
			return -1;
		}
	}
#endif

	if (S_ISDIR(source_stat.st_mode)) {
		DIR *dp;
		const char *tp;
		struct dirent *d;
		mode_t saved_umask = 0;

		if (!(flags & FILEUTILS_RECUR)) {
			bb_error_msg("omitting directory '%s'", source);
			return -1;
		}

		/* Did we ever create source ourself before? */
		tp = is_in_ino_dev_hashtable(&source_stat);
		if (tp) {
			/* We did! it's a recursion! man the lifeboats... */
			bb_error_msg("recursion detected, omitting directory '%s'",
					source);
			return -1;
		}

		if (dest_exists) {
			if (!S_ISDIR(dest_stat.st_mode)) {
				bb_error_msg("target '%s' is not a directory", dest);
				return -1;
			}
			/* race here: user can substitute a symlink between
			 * this check and actual creation of files inside dest */
		} else {
			/* Create DEST */
			mode_t mode;
			saved_umask = umask(0);

			mode = source_stat.st_mode;
			if (!(flags & FILEUTILS_PRESERVE_STATUS))
				mode = source_stat.st_mode & ~saved_umask;
			/* Allow owner to access new dir (at least for now) */
			mode |= S_IRWXU;
			if (mkdir(dest, mode) < 0) {
				umask(saved_umask);
				bb_perror_msg("can't create directory '%s'", dest);
				return -1;
			}
			umask(saved_umask);
			/* need stat info for add_to_ino_dev_hashtable */
			if (lstat(dest, &dest_stat) < 0) {
				bb_perror_msg("can't stat '%s'", dest);
				return -1;
			}
		}
		/* remember (dev,inode) of each created dir.
		 * NULL: name is not remembered */
		add_to_ino_dev_hashtable(&dest_stat, NULL);

		/* Recursively copy files in SOURCE */
		dp = opendir(source);
		if (dp == NULL) {
			retval = -1;
			goto preserve_mode_ugid_time;
		}

		while ((d = readdir(dp)) != NULL) {
			char *new_source, *new_dest;

			new_source = concat_subpath_file(source, d->d_name);
			if (new_source == NULL)
				continue;
			new_dest = concat_path_file(dest, d->d_name);
			if (copy_file(new_source, new_dest, flags & ~FILEUTILS_DEREFERENCE_L0) < 0)
				retval = -1;
			free(new_source);
			free(new_dest);
		}
		closedir(dp);

		if (!dest_exists
		 && chmod(dest, source_stat.st_mode & ~saved_umask) < 0
		) {
			bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
			/* retval = -1; - WRONG! copy *WAS* made */
		}
		goto preserve_mode_ugid_time;
	}

	if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
		int (*lf)(const char *oldpath, const char *newpath);
 make_links:
		/* Hmm... maybe
		 * if (DEREF && MAKE_SOFTLINK) source = realpath(source) ?
		 * (but realpath returns NULL on dangling symlinks...) */
		lf = (flags & FILEUTILS_MAKE_SOFTLINK) ? symlink : link;
		if (lf(source, dest) < 0) {
			ovr = ask_and_unlink(dest, flags);
			if (ovr <= 0)
				return ovr;
			if (lf(source, dest) < 0) {
				bb_perror_msg("can't create link '%s'", dest);
				return -1;
			}
		}
		/* _Not_ jumping to preserve_mode_ugid_time:
		 * (sym)links don't have those */
		return 0;
	}

	if (/* "cp thing1 thing2" without -R: just open and read() from thing1 */
	    !(flags & FILEUTILS_RECUR)
	    /* "cp [-opts] regular_file thing2" */
	 || S_ISREG(source_stat.st_mode)
	 /* DEREF uses stat, which never returns S_ISLNK() == true.
	  * So the below is never true: */
	 /* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
	) {
		int src_fd;
		int dst_fd;
		mode_t new_mode;

		if (!FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) {
			/* "cp -d symlink dst": create a link */
			goto dont_cat;
		}

		if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
			const char *link_target;
			link_target = is_in_ino_dev_hashtable(&source_stat);
			if (link_target) {
				if (link(link_target, dest) < 0) {
					ovr = ask_and_unlink(dest, flags);
					if (ovr <= 0)
						return ovr;
					if (link(link_target, dest) < 0) {
						bb_perror_msg("can't create link '%s'", dest);
						return -1;
					}
				}
				return 0;
			}
			add_to_ino_dev_hashtable(&source_stat, dest);
		}

		src_fd = open_or_warn(source, O_RDONLY);
		if (src_fd < 0)
			return -1;

		/* Do not try to open with weird mode fields */
		new_mode = source_stat.st_mode;
		if (!S_ISREG(source_stat.st_mode))
			new_mode = 0666;

		// POSIX way is a security problem versus (sym)link attacks
		if (!ENABLE_FEATURE_NON_POSIX_CP) {
			dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
		} else { /* safe way: */
			dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
		}
		if (dst_fd == -1) {
			ovr = ask_and_unlink(dest, flags);
			if (ovr <= 0) {
				close(src_fd);
				return ovr;
			}
			/* It shouldn't exist. If it exists, do not open (symlink attack?) */
			dst_fd = open3_or_warn(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
			if (dst_fd < 0) {
				close(src_fd);
				return -1;
			}
		}

#if ENABLE_SELINUX
		if ((flags & (FILEUTILS_PRESERVE_SECURITY_CONTEXT|FILEUTILS_SET_SECURITY_CONTEXT))
		 && is_selinux_enabled() > 0
		) {
			security_context_t con;
			if (getfscreatecon(&con) == -1) {
				bb_perror_msg("getfscreatecon");
				return -1;
			}
			if (con) {
				if (setfilecon(dest, con) == -1) {
					bb_perror_msg("setfilecon:%s,%s", dest, con);
					freecon(con);
					return -1;
				}
				freecon(con);
			}
		}
#endif

		if (bb_copyfd_eof(src_fd, dst_fd) == -1)
			retval = -1;
		/* Careful with writing... */
		if (close(dst_fd) < 0) {
			bb_perror_msg("error writing to '%s'", dest);
			retval = -1;
		}
		/* ...but read size is already checked by bb_copyfd_eof */
		close(src_fd);
		/* "cp /dev/something new_file" should not
		 * copy mode of /dev/something */
		if (!S_ISREG(source_stat.st_mode))
			return retval;
		goto preserve_mode_ugid_time;
	}
 dont_cat:

	/* Source is a symlink or a special file */
	/* We are lazy here, a bit lax with races... */
	if (dest_exists) {
		errno = EEXIST;
		ovr = ask_and_unlink(dest, flags);
		if (ovr <= 0)
			return ovr;
	}
	if (S_ISLNK(source_stat.st_mode)) {
		char *lpath = xmalloc_readlink_or_warn(source);
		if (lpath) {
			int r = symlink(lpath, dest);
			free(lpath);
			if (r < 0) {
				bb_perror_msg("can't create symlink '%s'", dest);
				return -1;
			}
			if (flags & FILEUTILS_PRESERVE_STATUS)
				if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
					bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
		}
		/* _Not_ jumping to preserve_mode_ugid_time:
		 * symlinks don't have those */
		return 0;
	}
	if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
	 || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
	) {
		if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
			bb_perror_msg("can't create '%s'", dest);
			return -1;
		}
	} else {
		bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode);
		return -1;
	}

 preserve_mode_ugid_time:

	if (flags & FILEUTILS_PRESERVE_STATUS
	/* Cannot happen: */
	/* && !(flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) */
	) {
		struct timeval times[2];

		times[1].tv_sec = times[0].tv_sec = source_stat.st_mtime;
		times[1].tv_usec = times[0].tv_usec = 0;
		/* BTW, utimes sets usec-precision time - just FYI */
		if (utimes(dest, times) < 0)
			bb_perror_msg("can't preserve %s of '%s'", "times", dest);
		if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) {
			source_stat.st_mode &= ~(S_ISUID | S_ISGID);
			bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
		}
#if ENABLE_XATTR
		/* Preserve extended attributes. We must copy it after chown()
		 * because it resets capabilities. */
		if (copy_file_attr(source, dest) == -1)
			bb_perror_msg("can't preserve %s of '%s'",
				      "extended attributes", dest);
#endif
		if (chmod(dest, source_stat.st_mode) < 0)
			bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
	}

	return retval;
}
int make_ext4fs_internal(int fd, const char *directory,
                         char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse,
                         int crc, int wipe, int init_itabs, struct selabel_handle *sehnd)
{
	u32 root_inode_num;
	u16 root_mode;

	if (setjmp(setjmp_env))
		return EXIT_FAILURE; /* Handle a call to longjmp() */

	if (info.len <= 0)
		info.len = get_file_size(fd);

	if (info.len <= 0) {
		fprintf(stderr, "Need size of filesystem\n");
		return EXIT_FAILURE;
	}

	if (info.block_size <= 0)
		info.block_size = compute_block_size();

	/* Round down the filesystem length to be a multiple of the block size */
	info.len &= ~((u64)info.block_size - 1);

	if (info.journal_blocks == 0)
		info.journal_blocks = compute_journal_blocks();

	if (info.no_journal == 0)
		info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
	else
		info.journal_blocks = 0;

	if (info.blocks_per_group <= 0)
		info.blocks_per_group = compute_blocks_per_group();

	if (info.inodes <= 0)
		info.inodes = compute_inodes();

	if (info.inode_size <= 0)
		info.inode_size = 256;

	if (info.label == NULL)
		info.label = "";

	info.inodes_per_group = compute_inodes_per_group();

	info.feat_compat |=
			EXT4_FEATURE_COMPAT_RESIZE_INODE;

	info.feat_ro_compat |=
			EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
			EXT4_FEATURE_RO_COMPAT_LARGE_FILE;

	info.feat_incompat |=
			EXT4_FEATURE_INCOMPAT_EXTENTS |
			EXT4_FEATURE_INCOMPAT_FILETYPE;


	info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();

	printf("Creating filesystem with parameters:\n");
	printf("    Size: %llu\n", info.len);
	printf("    Block size: %d\n", info.block_size);
	printf("    Blocks per group: %d\n", info.blocks_per_group);
	printf("    Inodes per group: %d\n", info.inodes_per_group);
	printf("    Inode size: %d\n", info.inode_size);
	printf("    Journal blocks: %d\n", info.journal_blocks);
	printf("    Label: %s\n", info.label);

	ext4_create_fs_aux_info();

	printf("    Blocks: %llu\n", aux_info.len_blocks);
	printf("    Block groups: %d\n", aux_info.groups);
	printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);

	info.sparse_file = sparse_file_new(info.block_size, info.len);

	block_allocator_init();

	ext4_fill_in_sb();
	MTK_add_mountpoint(aux_info.sb,mountpoint);

	if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
		error("failed to reserve first 10 inodes");

	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
		ext4_create_journal_inode();

	if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
		ext4_create_resize_inode();

#ifdef USE_MINGW
	// Windows needs only 'create an empty fs image' functionality
	assert(!directory);
	root_inode_num = build_default_directory_structure();
#else
	if (directory)
		root_inode_num = build_directory_structure(directory, mountpoint, 0,
                        fs_config_func, sehnd);
	else
		root_inode_num = build_default_directory_structure();
#endif

	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
	inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);

#ifdef HAVE_SELINUX
	if (sehnd) {
		char *sepath = NULL;
		char *secontext = NULL;

		if (mountpoint[0] == '/')
			sepath = strdup(mountpoint);
		else
			asprintf(&sepath, "/%s", mountpoint);
		if (!sepath)
			critical_error_errno("malloc");
		if (selabel_lookup(sehnd, &secontext, sepath, S_IFDIR) < 0) {
			error("cannot lookup security context for %s", sepath);
		}
		if (secontext) {
			printf("Labeling %s as %s\n", sepath, secontext);
			inode_set_selinux(root_inode_num, secontext);
		}
		free(sepath);
		freecon(secontext);
	}
#endif

	ext4_update_free();

	if (init_itabs)
		init_unused_inode_tables();

	ext4_queue_sb();

	printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
			aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
			aux_info.sb->s_inodes_count,
			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
			aux_info.sb->s_blocks_count_lo);

	if (wipe)
		wipe_block_device(fd, info.len);

	write_ext4_image(fd, gzip, sparse, crc);

	sparse_file_destroy(info.sparse_file);
	info.sparse_file = NULL;

	return 0;
}
Example #27
0
int
dirCreateHierarchy(const char *path, int mode,
        const struct utimbuf *timestamp, bool stripFileName,
        struct selabel_handle *sehnd)
{
    DirStatus ds;

    /* Check for an empty string before we bother
     * making any syscalls.
     */
    if (path[0] == '\0') {
        errno = ENOENT;
        return -1;
    }

    /* Allocate a path that we can modify; stick a slash on
     * the end to make things easier.
     */
    size_t pathLen = strlen(path);
    char *cpath = (char *)malloc(pathLen + 2);
    if (cpath == NULL) {
        errno = ENOMEM;
        return -1;
    }
    memcpy(cpath, path, pathLen);
    if (stripFileName) {
        /* Strip everything after the last slash.
         */
        char *c = cpath + pathLen - 1;
        while (c != cpath && *c != '/') {
            c--;
        }
        if (c == cpath) {
//xxx test this path
            /* No directory component.  Act like the path was empty.
             */
            errno = ENOENT;
            free(cpath);
            return -1;
        }
        c[1] = '\0';    // Terminate after the slash we found.
    } else {
        /* Make sure that the path ends in a slash.
         */
        cpath[pathLen] = '/';
        cpath[pathLen + 1] = '\0';
    }

    /* See if it already exists.
     */
    ds = getPathDirStatus(cpath);
    if (ds == DDIR) {
        return 0;
    } else if (ds == DILLEGAL) {
        return -1;
    }

    /* Walk up the path from the root and make each level.
     * If a directory already exists, no big deal.
     */
    char *p = cpath;
    while (*p != '\0') {
        /* Skip any slashes, watching out for the end of the string.
         */
        while (*p != '\0' && *p == '/') {
            p++;
        }
        if (*p == '\0') {
            break;
        }

        /* Find the end of the next path component.
         * We know that we'll see a slash before the NUL,
         * because we added it, above.
         */
        while (*p != '/') {
            p++;
        }
        *p = '\0';

        /* Check this part of the path and make a new directory
         * if necessary.
         */
        ds = getPathDirStatus(cpath);
        if (ds == DILLEGAL) {
            /* Could happen if some other process/thread is
             * messing with the filesystem.
             */
            free(cpath);
            return -1;
        } else if (ds == DMISSING) {
            int err;

#ifdef HAVE_SELINUX
            char *secontext = NULL;

            if (sehnd) {
                selabel_lookup(sehnd, &secontext, cpath, mode);
                setfscreatecon(secontext);
            }
#endif

            err = mkdir(cpath, mode);

#ifdef HAVE_SELINUX

            if (secontext) {
                freecon(secontext);
                setfscreatecon(NULL);
            }
#endif

            if (err != 0) {
                free(cpath);
                return -1;
            }
            if (timestamp != NULL && utime(cpath, timestamp)) {
                free(cpath);
                return -1;
            }
        }
        // else, this directory already exists.
        
        /* Repair the path and continue.
         */
        *p = '/';
    }
    free(cpath);

    return 0;
}
 void operator()(security_context_t p) const {
     freecon(p);
 }
Example #29
0
void handle_property_set_fd()
{
    prop_msg msg;
    int s;
    int r;
    int res;
    struct ucred cr;
    struct sockaddr_un addr;
    socklen_t addr_size = sizeof(addr);
    socklen_t cr_size = sizeof(cr);
    char * source_ctx = NULL;

    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
        return;
    }

    /* Check socket options here */
    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
        close(s);
        ERROR("Unable to receive socket options\n");
        return;
    }

    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
    if(r != sizeof(prop_msg)) {
        ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
              r, sizeof(prop_msg), errno);
        close(s);
        return;
    }

    switch(msg.cmd) {
    case PROP_MSG_SETPROP:
        msg.name[PROP_NAME_MAX-1] = 0;
        msg.value[PROP_VALUE_MAX-1] = 0;

        if (!is_legal_property_name(msg.name, strlen(msg.name))) {
            ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
            close(s);
            return;
        }

        getpeercon(s, &source_ctx);

        if(memcmp(msg.name,"ctl.",4) == 0) {
            // Keep the old close-socket-early behavior when handling
            // ctl.* properties.
            close(s);
            if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
                handle_control_message((char*) msg.name + 4, (char*) msg.value);
            } else {
                ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
                        msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
            }
        } else {
            if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
                property_set((char*) msg.name, (char*) msg.value);
            } else {
                ERROR("sys_prop: permission denied uid:%d  name:%s\n",
                      cr.uid, msg.name);
            }

            // Note: bionic's property client code assumes that the
            // property server will not close the socket until *AFTER*
            // the property is written to memory.
            close(s);
        }
        freecon(source_ctx);
        break;

    default:
        close(s);
        break;
    }
}
Example #30
0
/* appends a file to the tar archive */
int
tar_append_file(TAR *t, char *realname, char *savename)
{
	struct stat s;
	int i;
	libtar_hashptr_t hp;
	tar_dev_t *td = NULL;
	tar_ino_t *ti = NULL;
	char path[MAXPATHLEN];

#ifdef DEBUG
	printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
	       "savename=\"%s\")\n", t, t->pathname, realname,
	       (savename ? savename : "[NULL]"));
#endif

	if (lstat(realname, &s) != 0)
	{
#ifdef DEBUG
		perror("lstat()");
#endif
		return -1;
	}

	/* set header block */
#ifdef DEBUG
	puts("    tar_append_file(): setting header block...");
#endif
	memset(&(t->th_buf), 0, sizeof(struct tar_header));
	th_set_from_stat(t, &s);

	/* set the header path */
#ifdef DEBUG
	puts("    tar_append_file(): setting header path...");
#endif
	th_set_path(t, (savename ? savename : realname));

#ifdef HAVE_SELINUX
	/* get selinux context */
	if(t->options & TAR_STORE_SELINUX) {
		if(t->th_buf.selinux_context != NULL) {
			free(t->th_buf.selinux_context);
			t->th_buf.selinux_context = NULL;
		}

		security_context_t selinux_context = NULL;
		if (lgetfilecon(realname, &selinux_context) >= 0) {
			t->th_buf.selinux_context = strdup(selinux_context);
			printf("setting selinux context: %s\n", selinux_context);
			freecon(selinux_context);
		}
		else
			perror("Failed to get selinux context");
	}
#endif
	/* check if it's a hardlink */
#ifdef DEBUG
	puts("    tar_append_file(): checking inode cache for hardlink...");
#endif
	libtar_hashptr_reset(&hp);
	if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
			       (libtar_matchfunc_t)dev_match) != 0)
		td = (tar_dev_t *)libtar_hashptr_data(&hp);
	else
	{
#ifdef DEBUG
		printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
		       major(s.st_dev), minor(s.st_dev));
#endif
		td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
		td->td_dev = s.st_dev;
		td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
		if (td->td_h == NULL)
			return -1;
		if (libtar_hash_add(t->h, td) == -1)
			return -1;
	}
	libtar_hashptr_reset(&hp);
	if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
			       (libtar_matchfunc_t)ino_match) != 0)
	{
		ti = (tar_ino_t *)libtar_hashptr_data(&hp);
#ifdef DEBUG
		printf("    tar_append_file(): encoding hard link \"%s\" "
		       "to \"%s\"...\n", realname, ti->ti_name);
#endif
		t->th_buf.typeflag = LNKTYPE;
		th_set_link(t, ti->ti_name);
	}
	else
	{
#ifdef DEBUG
		printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
		       "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
		       s.st_ino, realname);
#endif
		ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
		if (ti == NULL)
			return -1;
		ti->ti_ino = s.st_ino;
		snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
			 savename ? savename : realname);
		libtar_hash_add(td->td_h, ti);
	}

	/* check if it's a symlink */
	if (TH_ISSYM(t))
	{
		i = readlink(realname, path, sizeof(path));
		if (i == -1)
			return -1;
		if (i >= MAXPATHLEN)
			i = MAXPATHLEN - 1;
		path[i] = '\0';
#ifdef DEBUG
		printf("    tar_append_file(): encoding symlink \"%s\" -> "
		       "\"%s\"...\n", realname, path);
#endif
		th_set_link(t, path);
	}

	/* print file info */
	if (t->options & TAR_VERBOSE)
		th_print_long_ls(t);

#ifdef DEBUG
	puts("    tar_append_file(): writing header");
#endif
	/* write header */
	if (th_write(t) != 0)
	{
#ifdef DEBUG
		printf("t->fd = %d\n", t->fd);
#endif
		return -1;
	}
#ifdef DEBUG
	puts("    tar_append_file(): back from th_write()");
#endif

	/* if it's a regular file, write the contents as well */
	if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
		return -1;

	return 0;
}