/* "sb.path_exists", to be called from lua code
 * returns true if file or directory exists at the specified real path,
 * false if not.
*/
static int lua_sb_path_exists(lua_State *l)
{
	int n;

	n = lua_gettop(l);
	if (n != 1) {
		lua_pushboolean(l, 0);
	} else {
		char	*path = strdup(lua_tostring(l, 1));
		int	result = 0;
		SB_LOG(SB_LOGLEVEL_DEBUG, "lua_sb_path_exists testing '%s'",
			path);
		if (access_nomap_nolog(path, F_OK) == 0) {
			/* target exists */
			lua_pushboolean(l, 1);
			result=1;
		} else {
			lua_pushboolean(l, 0);
			result=0;
		}
		SB_LOG(SB_LOGLEVEL_DEBUG, "lua_sb_path_exists got %d",
			result);
		free(path);
	}
	return 1;
}
Beispiel #2
0
static enum binary_type inspect_binary(const char *filename,
	int check_x_permission,
	int *modep,
	uid_t *uidp,
	gid_t *gidp)
{
	static const char *target_cpu = NULL;
	enum binary_type retval;
	int fd, j;
	struct stat status;
	char *region;
	unsigned int ei_data;
	uint16_t e_machine;

	SB_LOG(SB_LOGLEVEL_DEBUG, "%s(%s)", __func__, filename);

	retval = BIN_NONE; /* assume it doesn't exist, until proven otherwise */
	if (check_x_permission && access_nomap_nolog(filename, X_OK) < 0) {
		int saved_errno = errno;
		const char *sb1_bug_emulation_mode =
			ruletree_catalog_get_string("config",
				"sbox_emulate_sb1_bugs");

		if (access_nomap_nolog(filename, F_OK) < 0) {
			/* file is missing completely, or can't be accessed
			 * at all.
			 * errno has been set */
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"%s: access F_OK failed (1) => out", __func__);
			goto _out;
		}

		if (sb1_bug_emulation_mode && 
		    strchr(sb1_bug_emulation_mode,'x')) {
			/* the old scratchbox didn't have the x-bit check, so 
			 * having R-bit set was enough to exec a file. That is 
			 * of course wrong, but unfortunately there are now 
			 * lots of packages out there that have various scripts 
			 * with wrong permissions.
			 * We'll provide a compatibility mode, so that broken 
			 * packages can be built.
			 *
			 * an 'x' in the env.var. means that we should not 
			 * worry about x-bits when checking exec parmissions
			*/
			if (access_nomap_nolog(filename, R_OK) < 0) {
				saved_errno = errno;
				SB_LOG(SB_LOGLEVEL_DEBUG, "no X or R "
					"permission for '%s'", filename);
				retval = BIN_INVALID;
				errno = saved_errno;
				goto _out;
			}
			SB_LOG(SB_LOGLEVEL_WARNING, 
				"X permission missing, but exec enabled by"
				" SB1 bug emulation mode ('%s')", filename);
		} else {
			/* The normal case:
			 * can't execute it. Possible errno codes from access() 
			 * are all possible from execve(), too, so there is no
			 * need to convert errno.
			*/
			SB_LOG(SB_LOGLEVEL_DEBUG, "no X permission for '%s'",
				filename);
			retval = BIN_INVALID;
			errno = saved_errno;
			goto _out;
		}
	} else if(!check_x_permission) {
		if (access_nomap_nolog(filename, F_OK) < 0) {
			/* file is missing completely, or can't be accessed
			 * at all.
			 * errno has been set */
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"%s: access F_OK failed (2) => out", __func__);
			goto _out;
		}
	}

	fd = open_nomap_nolog(filename, O_RDONLY, 0);
	if (fd < 0) {
		retval = BIN_HOST_DYNAMIC; /* can't peek in to look, assume dynamic */
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: can't open for reading => out", __func__);
		goto _out;
	}

	retval = BIN_UNKNOWN;

	if (sb2_fstat(fd, &status) < 0) {
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: fstat failed => out", __func__);
		goto _out_close;
	}
	if (modep) *modep = status.st_mode;
	if (uidp) *uidp = status.st_uid;
	if (gidp) *gidp = status.st_gid;

	if (!S_ISREG(status.st_mode) && !S_ISLNK(status.st_mode)) {
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: not REG/LNK => out", __func__);
		goto _out_close;
	}

	if (status.st_size < 4) {
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"File size is too small, can't exec (%s)", filename);
		errno = ENOEXEC;
		retval = BIN_NONE;
		goto _out_close;
	}

	region = mmap(0, status.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
	if (!region) {
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: mmap failed => out", __func__);
		goto _out_close;
	}

	retval = inspect_elf_binary(region);
	switch (retval) {
	case BIN_HASHBANG:
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: script => out", __func__);
		goto _out_munmap;
	case BIN_HOST_STATIC:
	case BIN_HOST_DYNAMIC:
		/* host binary, lets go out of here */
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: host binary => out", __func__);
		goto _out_munmap;

	default:
		break;
	}

	/*
	 * Target binary.  Find out whether it is supported
	 * by scratchbox2.
	 */
	if (!target_cpu) {
		SB_LOG(SB_LOGLEVEL_DEBUG, "Lookin up target_cpu..");
		target_cpu = ruletree_catalog_get_string("config", "sbox_cpu");
		if (!target_cpu) {
			target_cpu = "arm";
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"no target_cpu in config, set to %s", target_cpu);
		} else  {
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"target_cpu found, %s", target_cpu);
		}
	}

	ei_data = ELFDATANONE;
	e_machine = EM_NONE;

	for (j = 0; (size_t) j < ARRAY_SIZE(target_table); j++) {
		const struct target_info *ti = &target_table[j];

		if (strncmp(target_cpu, ti->name, strlen(ti->name)))
			continue;

		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: try target '%s'", __func__, target_cpu);

		ei_data = ti->default_byteorder;
		e_machine = ti->machine;

		if (ti->multi_byteorder &&
		    strlen(target_cpu) >= strlen(ti->name) + 2) {
			size_t len = strlen(target_cpu);
			const char *tail = target_cpu + len - 2;

			if (strcmp(tail, "eb") == 0)
				ei_data = ELFDATA2MSB;
			else if (strcmp(tail, "el") == 0)
				ei_data = ELFDATA2LSB;
		}

		break;
	}

	if (elf_hdr_match(region, e_machine, ei_data)) {
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"%s: BIN_TARGET", __func__);
		retval = BIN_TARGET;
	}

_out_munmap:
	munmap(region, status.st_size);
_out_close:
	close_nomap_nolog(fd);
_out:
	return retval;
}