Пример #1
0
	ScriptObject* TypeDescriber::describeMetadataInfo(PoolObject* pool, uint32_t metadata_index)
	{
		AvmCore* core = m_toplevel->core();
		const uint8_t* metadata_pos = pool->metadata_infos[metadata_index];

		const uint32_t name_index = (metadata_pos) ? AvmCore::readU30(metadata_pos) : 0;
		// A bit of a hack: if the pool is builtin, always omit metadata chunks with names of "Version"
		// or "native", since these are used for reserved purposes internally.
		Stringp name = poolstr(pool, name_index);
		AvmAssert(name->isInterned() && core->kVersion->isInterned() && str(kstrid_native)->isInterned());
		if (pool->isBuiltin && (name == core->kVersion || name == str(kstrid_native))) 
			return NULL;

		const uint32_t val_count = (metadata_pos) ? AvmCore::readU30(metadata_pos) : 0;

		ScriptObject* o = new_object();
		ArrayObject* a = new_array();

		if (val_count > 0)
		{
			GC* gc = core->GetGC();
			List<uint32_t> key_indexes(gc);
			List<uint32_t> val_indexes(gc);
			
			read_u30_list(key_indexes, val_count, metadata_pos);
			read_u30_list(val_indexes, val_count, metadata_pos);

			for (uint32_t i = 0; i < val_count; ++i)
			{
				ScriptObject* v = new_object();
				const KVPair props[] = {
					{ kstrid_key, strAtom(poolstr(pool, key_indexes.get(i))) },
					{ kstrid_value, strAtom(poolstr(pool, val_indexes.get(i))) },
				};
				setpropmulti(v, props, elem_count(props));
				pushobj(a, v);
			}
		}

		const KVPair props[] = {
			{ kstrid_name, strAtom(name) },
			{ kstrid_value, objAtom(a) },
		};
		setpropmulti(o, props, elem_count(props));

		return o;
	}
Пример #2
0
	ArrayObject* TypeDescriber::describeParams(const AbstractFunction* af)
	{
		ArrayObject* a = new_array();
		const int requiredParamCount = af->requiredParamCount();
		for (int i = 1; i <= af->param_count; ++i) 
		{
			ScriptObject* v = new_object();
			const KVPair props[] = {
				{ kstrid_type, strAtom(describeClassName(af->paramTraits(i))) },
				{ kstrid_optional, boolAtom(i > requiredParamCount) },
			};
			setpropmulti(v, props, elem_count(props));
			pushobj(a, v);
		}
		return a;
	}
Пример #3
0
static int prepare_hashbang(
	char **mapped_file,	/* In: script, out: mapped script interpreter */
	char *orig_file,
	char ***argvp,
	char ***envpp,
	const char *exec_policy_name)
{
	int argc, fd, c, i, j, n;
	char ch;
	char *mapped_interpreter = NULL;
	char **new_argv = NULL;
	char hashbang[SBOX_MAXPATH]; /* only 60 needed on linux, just be safe */
	char interpreter[SBOX_MAXPATH];
	char *interp_arg = NULL;
	char *tmp = NULL, *mapped_binaryname = NULL;
	int result = 0;

	if ((fd = open_nomap(*mapped_file, O_RDONLY)) < 0) {
		/* unexpected error, just run it */
		return 0;
	}

	if ((c = read(fd, &hashbang[0], SBOX_MAXPATH - 1)) < 2) {
		/* again unexpected error, close fd and run it */
		close_nomap_nolog(fd);
		return 0;
	}

	argc = elem_count(*argvp);

	/* extra element for hashbang argument */
	new_argv = calloc(argc + 3, sizeof(char *));

	/* skip any initial whitespace following "#!" */
	for (i = 2; (hashbang[i] == ' ' 
			|| hashbang[i] == '\t') && i < c; i++)
		;

	for (n = 0, j = i; i < c; i++) {
		ch = hashbang[i];
		if (hashbang[i] == 0
			|| hashbang[i] == ' '
			|| hashbang[i] == '\t'
			|| hashbang[i] == '\n') {
			hashbang[i] = 0;
			if (i > j) {
				if (n == 0) {
					char *ptr = &hashbang[j];
					strcpy(interpreter, ptr);
					new_argv[n++] = strdup(interpreter);
				} else {
					/* this was the one and only
					 * allowed argument for the
					 * interpreter
					 */
					interp_arg = strdup(&hashbang[j]);
					new_argv[n++] = interp_arg;
					break;
				}
			}
			j = i + 1;
		}
		if (ch == '\n' || ch == 0) break;
	}

	new_argv[n++] = strdup(orig_file); /* the unmapped script path */
	for (i = 1; (*argvp)[i] != NULL && i < argc; ) {
		new_argv[n++] = (*argvp)[i++];
	}
	new_argv[n] = NULL;

	/* Now we need to update __SB2_ORIG_BINARYNAME to point to 
	 * the unmapped script interpreter (exec_map_script_interpreter
	 * may change it again (not currently, but in the future)
	*/
	change_environment_variable(
		*envpp, "__SB2_ORIG_BINARYNAME=", interpreter);

	/* script interpreter mapping in C */
	exec_policy_handle_t     eph = find_exec_policy_handle(exec_policy_name);
	int c_mapping_result_code;
	const char *c_new_exec_policy_name = NULL;
	
	c_mapping_result_code = exec_map_script_interpreter(eph, exec_policy_name,
		interpreter, interp_arg, *mapped_file,
		orig_file, new_argv, &c_new_exec_policy_name, &mapped_interpreter);
	SB_LOG(SB_LOGLEVEL_DEBUG,
		"back from exec_map_script_interpreter => %d (%s)",
		c_mapping_result_code, (mapped_interpreter ? mapped_interpreter : "<NULL>"));

	switch (c_mapping_result_code) {
	case 0:
                /* exec arguments were modified, argv has been modified */
                SB_LOG(SB_LOGLEVEL_DEBUG,
                        "%s: <0> argv has been updated", __func__);
		break;
	case 1:
                SB_LOG(SB_LOGLEVEL_DEBUG,
                        "%s: <1> argv was not modified", __func__);
		break;
	case 2:
                SB_LOG(SB_LOGLEVEL_DEBUG,
                        "%s: <2> Use ordinary path mapping", __func__);
		if (mapped_interpreter) free(mapped_interpreter);
                mapped_interpreter = NULL;
                {
                        mapping_results_t       mapping_result;

                        clear_mapping_results_struct(&mapping_result);
                        sbox_map_path_for_exec("script_interp",
                                interpreter, &mapping_result);
                        if (mapping_result.mres_result_buf) {
                                mapped_interpreter =
                                        strdup(mapping_result.mres_result_buf);
                        }
                        if (mapping_result.mres_exec_policy_name)
				c_new_exec_policy_name = strdup(mapping_result.mres_exec_policy_name);
			else
				c_new_exec_policy_name = NULL;
                        free_mapping_results(&mapping_result);
                }
                SB_LOG(SB_LOGLEVEL_DEBUG, "%s: "
                        "interpreter=%s mapped_interpreter=%s policy=%s",
                        __func__, interpreter, mapped_interpreter,
                        c_new_exec_policy_name ? c_new_exec_policy_name : "NULL");
		break;
	case -1:
		SB_LOG(SB_LOGLEVEL_DEBUG, "%s: <-1> exec denied", __func__);
		if (mapped_interpreter) free(mapped_interpreter);
		mapped_interpreter = NULL;
		return(-1);
	default:
                SB_LOG(SB_LOGLEVEL_ERROR,
                        "%s: Unsupported result %d", __func__, c_mapping_result_code);
		return(-1);
	}
	exec_policy_name = c_new_exec_policy_name;

	if (!mapped_interpreter) {
		SB_LOG(SB_LOGLEVEL_ERROR,
			"failed to map script interpreter=%s", interpreter);
		return(-1);
	}

	/*
	 * Binaryname (the one expected by the rules) comes still from
	 * the interpreter name so we set it here.  Note that it is now
	 * basename of the mapped interpreter (not the original one)!
	 */
	tmp = strdup(mapped_interpreter);
	mapped_binaryname = strdup(basename(tmp));
	change_environment_variable(*envpp, "__SB2_BINARYNAME=",
	    mapped_binaryname);
	free(mapped_binaryname);
	free(tmp);
	
	SB_LOG(SB_LOGLEVEL_DEBUG, "prepare_hashbang(): interpreter=%s,"
			"mapped_interpreter=%s", interpreter,
			mapped_interpreter);

	/* feed this through prepare_exec to let it deal with
	 * cpu transparency etc.
	 */
	result = prepare_exec("run_hashbang",
		exec_policy_name,
		mapped_interpreter,
		1/*file_has_been_mapped, and rue&policy exist*/,
		new_argv, *envpp,
		(enum binary_type*)NULL,
		mapped_file, argvp, envpp);

	SB_LOG(SB_LOGLEVEL_DEBUG, "prepare_hashbang done: mapped_file='%s'",
			*mapped_file);

	return(result);
}
Пример #4
0
	ScriptObject* TypeDescriber::describeTraits(Traitsp traits, uint32_t flags)
	{
		if (!(flags & INCLUDE_TRAITS))
			return NULL;
			
		AvmCore* core = m_toplevel->core();
		GC* gc = core->GetGC();
		TraitsBindingsp tb = traits->getTraitsBindings();
		TraitsMetadatap tm = traits->getTraitsMetadata();

		ScriptObject* o = new_object();

		ArrayObject* bases = NULL;
		ArrayObject* metadata = NULL;
		ArrayObject* interfaces = NULL;
		ArrayObject* methods = NULL;
		ArrayObject* accessors = NULL;
		ArrayObject* variables = NULL;
		ScriptObject* constructor = NULL;

		if (flags & INCLUDE_BASES)
		{
			metadata = new_array();
			PoolObject* class_mdpool;
			const uint8_t* class_md = tm->getMetadataPos(class_mdpool);
			if (class_md)
				addDescribeMetadata(metadata, class_mdpool, class_md);
		}
		
		if (flags & INCLUDE_BASES)
		{
			bases = new_array();
			for (Traitsp b = traits->base; b; b = b->base) 
				pushstr(bases, describeClassName(b));
		}
		
		if (flags & INCLUDE_INTERFACES)
		{
			interfaces = new_array();
			// our TraitsBindings only includes our own interfaces, not any we might have inherited, 
			// so walk the tree. there might be redundant interfaces listed in the inheritance, 
			// so use a list to remove dupes
			List<Traitsp> unique(gc);
			for (Traitsp b = traits; b; b = b->base) 
			{
				TraitsBindingsp tbi = b->getTraitsBindings();
				for (uint32_t i = 0; i < tbi->interfaceCapacity; ++i)
				{
					Traitsp ti = tbi->getInterface(i);
					if (ti && ti->isInterface && unique.indexOf(ti) < 0)
					{
						unique.add(ti);
						pushstr(interfaces, describeClassName(ti));
					}
				}
			}
		}

		// constructor
		if (flags & INCLUDE_CONSTRUCTOR)
		{
			AbstractFunction* initMethod = traits->init;
			if (initMethod && initMethod->param_count)
			{
				constructor = describeParams(initMethod);
			}
		}
		
		if (flags & (INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_VARIABLES))
		{
			// recover slot/method metadata and method-declarer information.
			
			// make a flattened set of bindings so we don't have to check for overrides as we go.
			// This is not terribly efficient, but doesn't need to be.
			MultinameHashtable* mybind = new (gc) MultinameHashtable();
			addBindings(mybind, tb, flags);

			// Don't want interface methods, so post-process and wipe out any
			// bindings that were added
			for (uint32_t i = 0; i < tb->interfaceCapacity; ++i)
			{
				Traitsp ti = tb->getInterface(i);
				if (ti && ti->isInterface)
				{
					TraitsBindingsp tbi = ti->getTraitsBindings();
					for (int32_t index = 0; (index = tbi->next(index)) != 0; )
					{
						Stringp name = tbi->keyAt(index);
						Namespacep ns = tbi->nsAt(index);
						mybind->add(name, ns, BIND_NONE);
					}
				}
			}
			
			// yuck, replicate buggy behavior in FP9/10
			List<Namespacep> nsremoval(gc);
			if (flags & HIDE_NSURI_METHODS)
			{
				for (uint32_t i = 0; i < tb->interfaceCapacity; ++i)
				{
					Traitsp ti = tb->getInterface(i);
					// already did interfaces, don't need to do them again
					if (ti && !ti->isInterface)
					{
						TraitsBindingsp tbi = ti->getTraitsBindings();
						for (int32_t index = 0; (index = tbi->next(index)) != 0; )
						{
							Namespacep ns = tbi->nsAt(index);
							if (ns->getURI()->length() > 0 && nsremoval.indexOf(ns) < 0)
								nsremoval.add(ns);
						}
					}
				}
			}

			for (int32_t index = 0; (index = mybind->next(index)) != 0; )
			{
				Binding binding = mybind->valueAt(index);
				Stringp name = mybind->keyAt(index);
				Namespacep ns = mybind->nsAt(index);
				Stringp nsuri = ns->getURI();
				TraitsMetadata::MetadataPtr md1 = NULL;
				TraitsMetadata::MetadataPtr md2 = NULL;
				PoolObject* md1pool = NULL;
				PoolObject* md2pool = NULL;

				// We only display public members -- exposing private namespaces could compromise security.
				if (ns->getType() != Namespace::NS_Public) 
					continue;
				
				if ((flags & HIDE_NSURI_METHODS) && nsremoval.indexOf(ns) >= 0)
					continue;
			
				ScriptObject* v = new_object();

				const BindingKind bk = AvmCore::bindingKind(binding);
				switch (bk)
				{
					case BKIND_CONST:
					case BKIND_VAR:
					{
						if (!(flags & INCLUDE_VARIABLES))
							continue;

						const uint32_t slotID = AvmCore::bindingToSlotId(binding);
						const KVPair props[] = {
							{ kstrid_access, strAtom(str(bk == BKIND_CONST ? kstrid_readonly : kstrid_readwrite)) },
							{ kstrid_type, strAtom(describeClassName(tb->getSlotTraits(slotID))) },
						};
						setpropmulti(v, props, elem_count(props));
						if (!variables) variables = new_array();
						pushobj(variables, v);
						md1 = tm->getSlotMetadataPos(slotID, md1pool);
						break;
					}

					case BKIND_METHOD:
					{
						if (!(flags & INCLUDE_METHODS))
							continue;

						const uint32_t methodID = AvmCore::bindingToMethodId(binding);
						const AbstractFunction* af = tb->getMethod(methodID);

						Traitsp declaringTraits = af->declaringTraits;

						const KVPair props[] = {
							{ kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) },
							{ kstrid_returnType, strAtom(describeClassName(af->returnTraits())) },
							{ kstrid_parameters, objAtom(describeParams(af)) },
						};
						setpropmulti(v, props, elem_count(props));
						if (!methods) methods = new_array();
						pushobj(methods, v);
						md1 = tm->getMethodMetadataPos(methodID, md1pool);
						break;
					}
					
					case BKIND_GET:
					case BKIND_SET:
					case BKIND_GETSET:
					{
						if (!(flags & INCLUDE_ACCESSORS))
							continue;
							
						const uint32_t methodID = AvmCore::hasGetterBinding(binding) ?
													AvmCore::bindingToGetterId(binding) :
													AvmCore::bindingToSetterId(binding);

						const AbstractFunction* af = tb->getMethod(methodID);

						Traitsp declaringTraits = af->declaringTraits;

						Traitsp accessorType = AvmCore::hasGetterBinding(binding) ?
													af->returnTraits() :
													af->paramTraits(1);

						static const uint8_t bk2str[8] = 
						{
							uint8_t(kstrid_emptyString),	// BKIND_NONE
							uint8_t(kstrid_emptyString),	// BKIND_METHOD
							uint8_t(kstrid_emptyString),	// BKIND_VAR
							uint8_t(kstrid_emptyString),	// BKIND_CONST
							uint8_t(kstrid_emptyString),	// BKIND_ITRAMP
							uint8_t(kstrid_readonly),		// BKIND_GET
							uint8_t(kstrid_writeonly),		// BKIND_SET
							uint8_t(kstrid_readwrite)		// BKIND_GETSET
						};
						const KVPair props[] = {
							{ kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) },
							{ kstrid_access, strAtom(str(StringId(bk2str[bk]))) },
							{ kstrid_type, strAtom(describeClassName(accessorType)) },
						};
						setpropmulti(v, props, elem_count(props));
						if (AvmCore::hasGetterBinding(binding))
							md1 = tm->getMethodMetadataPos(AvmCore::bindingToGetterId(binding), md1pool);
						if (AvmCore::hasSetterBinding(binding))
							md2 = tm->getMethodMetadataPos(AvmCore::bindingToSetterId(binding), md2pool);
						if (!accessors) accessors = new_array();
						pushobj(accessors, v);
						break;
					}
					case BKIND_NONE:
						break;
				}

				ArrayObject* vm = NULL;
				if ((flags & INCLUDE_METADATA) && (md1 || md2))
				{
					vm = new_array();
					addDescribeMetadata(vm, md1pool, md1);
					addDescribeMetadata(vm, md2pool, md2);
				}
				const KVPair props[] = {
					{ kstrid_name, strAtom(name) },
					{ kstrid_uri, strAtom(nsuri->length() == 0 ? NULL : nsuri) },
					{ kstrid_metadata, objAtom(vm) },
				};
				setpropmulti(v, props, elem_count(props));
			}
		}

		const KVPair props[] = {
			{ kstrid_bases, objAtom(bases) },
			{ kstrid_interfaces, objAtom(interfaces) },
			{ kstrid_metadata, objAtom(metadata) },
			{ kstrid_accessors, objAtom(accessors) },
			{ kstrid_methods, objAtom(methods) },
			{ kstrid_variables, objAtom(variables) },
			{ kstrid_constructor, objAtom(constructor) },
		};
		setpropmulti(o, props, elem_count(props));

		return o;
	}