Exemple #1
0
/* write callback */
static ssize_t kplugs_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
	kplugs_command_t *cmd = NULL;
	context_t *file_cont = NULL;
	context_t *cont = NULL;
	bytecode_t *code = NULL;
	function_t *func = NULL;
	exception_t excep;
	stack_t stack;
	word iter, arg;
	word args;
	byte little_endian;
	byte func_name[MAX_FUNC_NAME + 1];
	int err = 0;

#ifdef __LITTLE_ENDIAN
	little_endian = 1;
#else
	little_endian = 0;
#endif
	/* get the user's command */
	cmd = (kplugs_command_t *)buf;
	file_cont = (context_t *)filp->private_data;

	if (count < sizeof(byte) * 3) { /* three bytes of header */
		return create_error(file_cont, -ERROR_PARAM);
	}

	if (cmd->word_size != sizeof(word) || cmd->l_endian != little_endian) {
		return create_error(file_cont, -ERROR_ARCH);
	}

	if (cmd->version_major != VERSION_MAJOR || cmd->version_minor != VERSION_MINOR) {
		return create_error(file_cont, -ERROR_VERSION);
	}

	if (count != sizeof(kplugs_command_t)) {
		return create_error(file_cont, -ERROR_PARAM);
	}

	cont = cmd->is_global ? GLOBAL_CONTEXT : file_cont;

	switch (cmd->type) {
	case KPLUGS_LOAD:
		/* load a new function */

		if (cmd->len2 != 0 || cmd->ptr2 != NULL) {
			return create_error(file_cont, -ERROR_PARAM);
		}

		code = memory_alloc(cmd->len1);
		if (NULL == code) {
			ERROR(create_error(file_cont, -ERROR_MEM));
		}

		err = memory_copy_from_outside(code, cmd->uptr1, cmd->len1);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		/* create the function */
		err = function_create(code, cmd->len1, &func);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		err = context_add_function(cont, func);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		/* return the function's address */
		context_create_reply(file_cont, (word)&func->func_code, NULL);

		return count;

	case KPLUGS_UNLOAD:
		/* unload a function with a name */
		if (NULL != cmd->uptr2) {
			return create_error(file_cont, -ERROR_PARAM);
		}
	case KPLUGS_EXECUTE:
		/* execute (and unload) a function with a name */
		if (cmd->len1 > MAX_FUNC_NAME || (cmd->len2 % sizeof(word)) != 0) {
			return create_error(file_cont, -ERROR_PARAM);
		}

		err = memory_copy_from_outside(func_name, cmd->uptr1, cmd->len1);
		if (err < 0) {
			return create_error(file_cont, err);
		}

		func_name[cmd->len1] = '\0';

		/* find the function */

		if (cmd->type == KPLUGS_UNLOAD) {
			func = context_find_function(cont, func_name);
			if (NULL == func) {
				return create_error(file_cont, -ERROR_UFUNC);
			}
			/* delete the function */
			context_free_function(func);
			err = (int)count;

			goto clean;
		}

		if (!cmd->is_global) {
			func = context_find_function(file_cont, func_name);
		}
		if (NULL == func) {
			func = context_find_function(GLOBAL_CONTEXT, func_name);
			if (NULL == func) {
				return create_error(file_cont, -ERROR_UFUNC);
			}
		}

		goto execute_func;

	case KPLUGS_UNLOAD_ANONYMOUS:
		/* unload an anonymous function */
		if (NULL != cmd->uptr2 || cmd->len1 || cmd->len2) {
			return create_error(file_cont, -ERROR_PARAM);
		}
		func = context_find_anonymous(cont, cmd->ptr1);
		if (NULL == func) {
			return create_error(file_cont, -ERROR_UFUNC);
		}

		/* delete the function */
		context_free_function(func);

		err = (int)count;
		goto clean;
	break;

	case KPLUGS_EXECUTE_ANONYMOUS:
		/* execute (and unload) an anonymous function */
		if (cmd->len1 || (cmd->len2 % sizeof(word)) != 0) {
			return create_error(file_cont, -ERROR_PARAM);
		}

		/* find the function */
		if (!cmd->is_global) {
			func = context_find_anonymous(file_cont, cmd->ptr1);
		}
		if (NULL == func) {
			func = context_find_anonymous(GLOBAL_CONTEXT, cmd->ptr1);
			if (NULL == func) {
				return create_error(file_cont, -ERROR_UFUNC);
			}
		}

execute_func:
		/* do the execution of a function: */

		args = cmd->len2 / sizeof(word);
		if (args > func->num_maxargs || args < func->num_minargs) {
			ERROR_CLEAN(create_error(file_cont, -ERROR_ARGS));
		}

		err = stack_alloc(&stack, sizeof(word), CALL_STACK_SIZE);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		/* push the arguments to a stack */
		for (iter = 0; iter < args; ++iter) {
			err = memory_copy_from_outside(&arg, cmd->ptr2 + (iter * sizeof(word)), sizeof(arg));
			if (err < 0) {
				stack_free(&stack);
				err = create_error(file_cont, err);
				goto clean;
			}

			if (NULL == stack_push(&stack, &arg)) {
				stack_free(&stack);
				ERROR_CLEAN(create_error(file_cont, -ERROR_MEM));
			}
		}

		/* execute the function and create an answer */
		arg = vm_run_function(func, &stack, &excep);

		stack_free(&stack);

		if (excep.had_exception) {
			err = -EINVAL; /* it dosen't really matter which error. the value of the error will be taken from the answer */
			arg = excep.value;
		} else {
			err = (int)count;
		}

		context_create_reply(file_cont, arg, &excep);

		goto clean;

	case KPLUGS_GET_LAST_EXCEPTION:
		if (NULL != cmd->uptr2 || cmd->len1 < sizeof(exception_t) || cmd->len2) {
			ERROR(create_error(file_cont, -ERROR_PARAM));
		}

		err = context_get_last_exception(file_cont, (exception_t *)cmd->ptr1);
		if (err < 0) {
			return create_error(file_cont, err);
		}

		return count;

	default:
		return create_error(file_cont, -ERROR_PARAM);
	}
clean:
	if (NULL != func) {
		function_put(func);
	} else if (NULL != code) {
		memory_free(code);
	}
	return err;
}
Exemple #2
0
/* copy memory from safely from any type of memory to any type of memory (optional - from different processes) */
int safe_memory_copy(void *dst, const void *src, word len, int dst_hint, int src_hint, word dst_pid, word src_pid)
{
	word new_len = len;
	int dst_type, src_type;
	void *dst_map = NULL;
	void *src_map = NULL;
	struct task_struct *dst_task = current;
	struct task_struct *src_task = current;
	struct pid *pid_struct;
	int err = 0;

	if (!len) {
		return 0;
	}

	/* load the correct task structs: */

	if (dst_pid || src_pid) {
		rcu_read_lock();
	}

	if (dst_pid) {
		pid_struct = find_vpid(dst_pid);
		 if (NULL == pid_struct) {
			ERROR_CLEAN(-ERROR_PARAM);
		}
		dst_task = pid_task(pid_struct, PIDTYPE_PID);
	}

	if (NULL == dst_task) {
		ERROR_CLEAN(-ERROR_PARAM);
	}

	if (src_pid) {
		pid_struct = find_vpid(src_pid);
		 if (NULL == pid_struct) {
			ERROR_CLEAN(-ERROR_PARAM);
		}
		src_task = pid_task(pid_struct, PIDTYPE_PID);
	}

	if (NULL == src_task) {
		ERROR_CLEAN(-ERROR_PARAM);
	}


	/* if we don't know where this addresses came from, find out: */

	if (dst_hint != ADDR_UNDEF) {
		dst_type = dst_hint;
	} else {
		dst_type = memory_check_addr_perm_task(dst, &new_len, 1, NULL, NULL, dst_task);
		if (dst_type == ADDR_UNDEF || new_len != len) {
			ERROR_CLEAN(-ERROR_POINT);
		}
	}

	if (src_hint != ADDR_UNDEF) {
		src_type = src_hint;
	} else {
		src_type = memory_check_addr_perm_task(src, &new_len, 0, NULL, NULL, src_task);
		if (src_type == ADDR_UNDEF || new_len != len) {
			ERROR_CLEAN(-ERROR_POINT);
		}
	}

	/* map user pages if we need to: */

	/* IMPORTANT:
	 * if you need to map user pages it cannot be atomic!
	 * so if you are using a page from user space you should not
	 * use this function in an atomic only context.
	 */
	if (dst_type == ADDR_OUTSIDE) {
		err = memory_map_task(dst, &new_len, &dst_map, (byte **)&dst, 1, dst_task);
		if (err < 0 || new_len != len) {
			goto clean;	
		}
	}

	if (src_type == ADDR_OUTSIDE) {
		err = memory_map_task(src, &new_len, &src_map, (byte **)&src, 0, src_task);
		if (err < 0 || new_len != len) {
			goto clean;	
		}
	}

	memory_copy(dst, src, len);
	err = 0;
clean:
	if (dst_pid || src_pid) {
		rcu_read_unlock();
	}

	if (dst_map) {
		memory_unmap(dst_map);
	}
	if (src_map) {
		memory_unmap(src_map);
	}

	return err;
}
Exemple #3
0
/* the module init function */
static int __init kplugs_init(void)
{
	int err = 0;
	struct device *device = NULL;

	memory_start();

	err = context_create(&GLOBAL_CONTEXT);
	if (err < 0) {
		output_string("Couldn't create the global context.\n");
		ERROR_CLEAN(create_error(NULL, err));
	}

	err = alloc_chrdev_region(&kplugs_devno , 0, 1, DEVICE_NAME);
	if (err < 0) {
		output_string("Couldn't allocate a region.\n");
		ERROR_CLEAN(create_error(NULL, err));
	}

	kplugs_class = class_create(THIS_MODULE, DEVICE_NAME);
	if (NULL == kplugs_class) {
		output_string("Couldn't create class.\n");
		ERROR_CLEAN(-ENOMEM);
	}
	
	kplugs_cdev = cdev_alloc();
	if (NULL == kplugs_cdev) {
		output_string("Couldn't allocate a cdev.\n");
		ERROR_CLEAN(-ENOMEM);
	}

	cdev_init(kplugs_cdev, &kplugs_ops);

	err = cdev_add(kplugs_cdev, kplugs_devno, 1);
	if (err < 0) {
		output_string("Couldn't add the cdev.\n");
		ERROR_CLEAN(create_error(NULL, err));
	}

	device = device_create(kplugs_class, NULL, kplugs_devno, NULL, DEVICE_NAME);
	if (device == NULL) {
		output_string("Couldn't create the device.\n");
		ERROR_CLEAN(-ENOMEM);
	}

	return 0;

clean:
	if (NULL != kplugs_cdev) {
		cdev_del(kplugs_cdev);
	}
	if (NULL != kplugs_class) {
		class_destroy(kplugs_class);
	}
	if (kplugs_devno) {
		unregister_chrdev_region(kplugs_devno, 1);
	}
	if (NULL != GLOBAL_CONTEXT) {
		context_free(GLOBAL_CONTEXT);
	}
	memory_stop();
	return err;
}