Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99a85259 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by James Morris
Browse files

TOMOYO: Use callback for permission check.



We can use callback function since parameters are passed via
"const struct tomoyo_request_info".

Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent cf6e9a64
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -952,6 +952,9 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
						  *,
						  const struct tomoyo_acl_head
						  *));
void tomoyo_check_acl(struct tomoyo_request_info *r,
		      bool (*check_entry) (const struct tomoyo_request_info *,
					   const struct tomoyo_acl_info *));

/********** External variable definitions. **********/

+18 −0
Original line number Diff line number Diff line
@@ -109,6 +109,24 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
	return error;
}

void tomoyo_check_acl(struct tomoyo_request_info *r,
		      bool (*check_entry) (const struct tomoyo_request_info *,
					   const struct tomoyo_acl_info *))
{
	const struct tomoyo_domain_info *domain = r->domain;
	struct tomoyo_acl_info *ptr;

	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
		if (ptr->is_deleted || ptr->type != r->param_type)
			continue;
		if (check_entry(r, ptr)) {
			r->granted = true;
			return;
		}
	}
	r->granted = false;
}

/*
 * tomoyo_domain_list is used for holding list of domains.
 * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
+157 −237
Original line number Diff line number Diff line
@@ -218,6 +218,108 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
        return false;
}

/**
 * tomoyo_audit_path_log - Audit path request log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
{
	const char *operation = tomoyo_path_keyword[r->param.path.operation];
	const struct tomoyo_path_info *filename = r->param.path.filename;
	if (r->granted)
		return 0;
	tomoyo_warn_log(r, "%s %s", operation, filename->name);
	return tomoyo_supervisor(r, "allow_%s %s\n", operation,
				 tomoyo_file_pattern(filename));
}

/**
 * tomoyo_audit_path2_log - Audit path/path request log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
{
	const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
	const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
	const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
	if (r->granted)
		return 0;
	tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
			filename2->name);
	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
				 tomoyo_file_pattern(filename1),
				 tomoyo_file_pattern(filename2));
}

/**
 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
{
	const char *operation = tomoyo_path_number32keyword(r->param.mkdev.
							    operation);
	const struct tomoyo_path_info *filename = r->param.mkdev.filename;
	const unsigned int major = r->param.mkdev.major;
	const unsigned int minor = r->param.mkdev.minor;
	const unsigned int mode = r->param.mkdev.mode;
	if (r->granted)
		return 0;
	tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
			major, minor);
	return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
				 tomoyo_file_pattern(filename), mode, major,
				 minor);
}

/**
 * tomoyo_audit_path_number_log - Audit path/number request log.
 *
 * @r:     Pointer to "struct tomoyo_request_info".
 * @error: Error code.
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
{
	const u8 type = r->param.path_number.operation;
	u8 radix;
	const struct tomoyo_path_info *filename = r->param.path_number.filename;
	const char *operation = tomoyo_path_number_keyword[type];
	char buffer[64];
	if (r->granted)
		return 0;
	switch (type) {
	case TOMOYO_TYPE_CREATE:
	case TOMOYO_TYPE_MKDIR:
	case TOMOYO_TYPE_MKFIFO:
	case TOMOYO_TYPE_MKSOCK:
	case TOMOYO_TYPE_CHMOD:
		radix = TOMOYO_VALUE_TYPE_OCTAL;
		break;
	case TOMOYO_TYPE_IOCTL:
		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
		break;
	default:
		radix = TOMOYO_VALUE_TYPE_DECIMAL;
		break;
	}
	tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
			   radix);
	tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
	return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
				 tomoyo_file_pattern(filename), buffer);
}

static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
				   const char *filename2,
				   struct tomoyo_domain_info *const domain,
@@ -637,37 +739,52 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
	return done;
}

/**
 * tomoyo_path_acl - Check permission for single path operation.
 *
 * @r:               Pointer to "struct tomoyo_request_info".
 * @filename:        Filename to check.
 * @perm:            Permission.
 *
 * Returns 0 on success, -EPERM otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_path_acl(const struct tomoyo_request_info *r,
			   const struct tomoyo_path_info *filename,
			   const u32 perm)
static bool tomoyo_check_path_acl(const struct tomoyo_request_info *r,
				  const struct tomoyo_acl_info *ptr)
{
	struct tomoyo_domain_info *domain = r->domain;
	struct tomoyo_acl_info *ptr;
	int error = -EPERM;
	const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
							 head);
	return (acl->perm & (1 << r->param.path.operation)) &&
		tomoyo_compare_name_union(r->param.path.filename, &acl->name);
}

	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
		struct tomoyo_path_acl *acl;
		if (ptr->type != TOMOYO_TYPE_PATH_ACL)
			continue;
		acl = container_of(ptr, struct tomoyo_path_acl, head);
		if (!(acl->perm & perm) ||
		    !tomoyo_compare_name_union(filename, &acl->name))
			continue;
		error = 0;
		break;
static bool tomoyo_check_path_number_acl(const struct tomoyo_request_info *r,
					 const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_path_number_acl *acl =
		container_of(ptr, typeof(*acl), head);
	return (acl->perm & (1 << r->param.path_number.operation)) &&
		tomoyo_compare_number_union(r->param.path_number.number,
					    &acl->number) &&
		tomoyo_compare_name_union(r->param.path_number.filename,
					  &acl->name);
}
	return error;

static bool tomoyo_check_path2_acl(const struct tomoyo_request_info *r,
				   const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_path2_acl *acl =
		container_of(ptr, typeof(*acl), head);
	return (acl->perm & (1 << r->param.path2.operation)) &&
		tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
		&& tomoyo_compare_name_union(r->param.path2.filename2,
					     &acl->name2);
}

static bool tomoyo_check_mkdev_acl(const struct tomoyo_request_info *r,
				const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_path_number3_acl *acl =
		container_of(ptr, typeof(*acl), head);
	return (acl->perm & (1 << r->param.mkdev.operation)) &&
		tomoyo_compare_number_union(r->param.mkdev.mode,
					    &acl->mode) &&
		tomoyo_compare_number_union(r->param.mkdev.major,
					    &acl->major) &&
		tomoyo_compare_number_union(r->param.mkdev.minor,
					    &acl->minor) &&
		tomoyo_compare_name_union(r->param.mkdev.filename,
					  &acl->name);
}

static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
@@ -869,88 +986,6 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
	return error;
}

/**
 * tomoyo_path_number3_acl - Check permission for path/number/number/number operation.
 *
 * @r:        Pointer to "struct tomoyo_request_info".
 * @filename: Filename to check.
 * @perm:     Permission.
 * @mode:     Create mode.
 * @major:    Device major number.
 * @minor:    Device minor number.
 *
 * Returns 0 on success, -EPERM otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_path_number3_acl(struct tomoyo_request_info *r,
				   const struct tomoyo_path_info *filename,
				   const u16 perm, const unsigned int mode,
				   const unsigned int major,
				   const unsigned int minor)
{
	struct tomoyo_domain_info *domain = r->domain;
	struct tomoyo_acl_info *ptr;
	int error = -EPERM;
	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
		struct tomoyo_path_number3_acl *acl;
		if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL)
			continue;
		acl = container_of(ptr, struct tomoyo_path_number3_acl, head);
		if (!tomoyo_compare_number_union(mode, &acl->mode))
			continue;
		if (!tomoyo_compare_number_union(major, &acl->major))
			continue;
		if (!tomoyo_compare_number_union(minor, &acl->minor))
			continue;
		if (!(acl->perm & perm))
			continue;
		if (!tomoyo_compare_name_union(filename, &acl->name))
			continue;
		error = 0;
		break;
	}
	return error;
}

/**
 * tomoyo_path2_acl - Check permission for double path operation.
 *
 * @r:         Pointer to "struct tomoyo_request_info".
 * @type:      Type of operation.
 * @filename1: First filename to check.
 * @filename2: Second filename to check.
 *
 * Returns 0 on success, -EPERM otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type,
			    const struct tomoyo_path_info *filename1,
			    const struct tomoyo_path_info *filename2)
{
	const struct tomoyo_domain_info *domain = r->domain;
	struct tomoyo_acl_info *ptr;
	const u8 perm = 1 << type;
	int error = -EPERM;

	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
		struct tomoyo_path2_acl *acl;
		if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
			continue;
		acl = container_of(ptr, struct tomoyo_path2_acl, head);
		if (!(acl->perm & perm))
			continue;
		if (!tomoyo_compare_name_union(filename1, &acl->name1))
			continue;
		if (!tomoyo_compare_name_union(filename2, &acl->name2))
			continue;
		error = 0;
		break;
	}
	return error;
}

/**
 * tomoyo_path_permission - Check permission for single path operation.
 *
@@ -965,7 +1000,6 @@ static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type,
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
			   const struct tomoyo_path_info *filename)
{
	const char *msg;
	int error;

 next:
@@ -977,17 +1011,12 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
	r->param.path.filename = filename;
	r->param.path.operation = operation;
	do {
		error = tomoyo_path_acl(r, filename, 1 << operation);
		if (error && operation == TOMOYO_TYPE_READ &&
		tomoyo_check_acl(r, tomoyo_check_path_acl);
		if (!r->granted && operation == TOMOYO_TYPE_READ &&
		    !r->domain->ignore_global_allow_read &&
		    tomoyo_is_globally_readable_file(filename))
			error = 0;
		if (!error)
			break;
		msg = tomoyo_path2keyword(operation);
		tomoyo_warn_log(r, "%s %s", msg, filename->name);
		error = tomoyo_supervisor(r, "allow_%s %s\n", msg,
					  tomoyo_file_pattern(filename));
			r->granted = true;
		error = tomoyo_audit_path_log(r);
		/*
		 * Do not retry for execute request, for alias may have
		 * changed.
@@ -1007,42 +1036,6 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
	return error;
}

/**
 * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation.
 *
 * @r:        Pointer to "struct tomoyo_request_info".
 * @type:     Operation.
 * @filename: Filename to check.
 * @number:   Number.
 *
 * Returns 0 on success, -EPERM otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
				  const struct tomoyo_path_info *filename,
				  const unsigned long number)
{
	struct tomoyo_domain_info *domain = r->domain;
	struct tomoyo_acl_info *ptr;
	const u8 perm = 1 << type;
	int error = -EPERM;
	list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
		struct tomoyo_path_number_acl *acl;
		if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL)
			continue;
		acl = container_of(ptr, struct tomoyo_path_number_acl,
				   head);
		if (!(acl->perm & perm) ||
		    !tomoyo_compare_number_union(number, &acl->number) ||
		    !tomoyo_compare_name_union(filename, &acl->name))
			continue;
		error = 0;
		break;
	}
	return error;
}

static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
					const struct tomoyo_acl_info *b)
{
@@ -1123,42 +1116,17 @@ static int tomoyo_path_number_perm2(struct tomoyo_request_info *r,
				    const struct tomoyo_path_info *filename,
				    const unsigned long number)
{
	char buffer[64];
	int error;
	u8 radix;
	const char *msg;

	if (!filename)
		return 0;
	switch (type) {
	case TOMOYO_TYPE_CREATE:
	case TOMOYO_TYPE_MKDIR:
	case TOMOYO_TYPE_MKFIFO:
	case TOMOYO_TYPE_MKSOCK:
	case TOMOYO_TYPE_CHMOD:
		radix = TOMOYO_VALUE_TYPE_OCTAL;
		break;
	case TOMOYO_TYPE_IOCTL:
		radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
		break;
	default:
		radix = TOMOYO_VALUE_TYPE_DECIMAL;
		break;
	}
	tomoyo_print_ulong(buffer, sizeof(buffer), number, radix);
	r->param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
	r->param.path_number.operation = type;
	r->param.path_number.filename = filename;
	r->param.path_number.number = number;
	do {
		error = tomoyo_path_number_acl(r, type, filename, number);
		if (!error)
			break;
		msg = tomoyo_path_number2keyword(type);
		tomoyo_warn_log(r, "%s %s %s", msg, filename->name, buffer);
		error = tomoyo_supervisor(r, "allow_%s %s %s\n", msg,
					  tomoyo_file_pattern(filename),
					  buffer);
		tomoyo_check_acl(r, tomoyo_check_path_number_acl);
		error = tomoyo_audit_path_number_log(r);
	} while (error == TOMOYO_RETRY_REQUEST);
	return error;
}
@@ -1310,47 +1278,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
	return error;
}

/**
 * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation.
 *
 * @r:         Pointer to "struct tomoyo_request_info".
 * @operation: Type of operation.
 * @filename:  Filename to check.
 * @mode:      Create mode.
 * @dev:       Device number.
 *
 * Returns 0 on success, negative value otherwise.
 *
 * Caller holds tomoyo_read_lock().
 */
static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r,
				     const u8 operation,
				     const struct tomoyo_path_info *filename,
				     const unsigned int mode,
				     const unsigned int dev)
{
	int error;
	const char *msg;
	const unsigned int major = MAJOR(dev);
	const unsigned int minor = MINOR(dev);

	do {
		error = tomoyo_path_number3_acl(r, filename, 1 << operation,
						mode, major, minor);
		if (!error)
			break;
		msg = tomoyo_path_number32keyword(operation);
		tomoyo_warn_log(r, "%s %s 0%o %u %u", msg, filename->name,
				mode, major, minor);
		error = tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", msg,
					  tomoyo_file_pattern(filename), mode,
					  major, minor);
	} while (error == TOMOYO_RETRY_REQUEST);
        if (r->mode != TOMOYO_CONFIG_ENFORCING)
		error = 0;
	return error;
}

/**
 * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar".
 *
@@ -1383,8 +1310,8 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
		r.param.mkdev.mode = mode;
		r.param.mkdev.major = MAJOR(dev);
		r.param.mkdev.minor = MINOR(dev);
		error = tomoyo_path_number3_perm2(&r, operation, &buf, mode,
						  dev);
		tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
		error = tomoyo_audit_mkdev_log(&r);
		kfree(buf.name);
	}
	tomoyo_read_unlock(idx);
@@ -1406,7 +1333,6 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
		      struct path *path2)
{
	int error = -ENOMEM;
	const char *msg;
	struct tomoyo_path_info buf1;
	struct tomoyo_path_info buf2;
	struct tomoyo_request_info r;
@@ -1440,14 +1366,8 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
	r.param.path2.filename1 = &buf1;
	r.param.path2.filename2 = &buf2;
	do {
		error = tomoyo_path2_acl(&r, operation, &buf1, &buf2);
		if (!error)
			break;
		msg = tomoyo_path22keyword(operation);
		tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name);
		error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg,
					  tomoyo_file_pattern(&buf1),
					  tomoyo_file_pattern(&buf2));
		tomoyo_check_acl(&r, tomoyo_check_path2_acl);
		error = tomoyo_audit_path2_log(&r);
	} while (error == TOMOYO_RETRY_REQUEST);
 out:
	kfree(buf1.name);
+52 −21
Original line number Diff line number Diff line
@@ -24,6 +24,54 @@
/* Allow to call 'mount --make-shared /dir'           */
#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD                 "--make-shared"

/**
 * tomoyo_audit_mount_log - Audit mount log.
 *
 * @r: Pointer to "struct tomoyo_request_info".
 *
 * Returns 0 on success, negative value otherwise.
 */
static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
{
	const char *dev = r->param.mount.dev->name;
	const char *dir = r->param.mount.dir->name;
	const char *type = r->param.mount.type->name;
	const unsigned long flags = r->param.mount.flags;
	if (r->granted)
		return 0;
	if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
		tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
	else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
		 || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
		tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
				flags);
	else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
		 !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
		 !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
		 !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
		tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
	else
		tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
				flags);
	return tomoyo_supervisor(r,
				 TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
				 tomoyo_file_pattern(r->param.mount.dev),
				 tomoyo_file_pattern(r->param.mount.dir), type,
				 flags);
}

static bool tomoyo_check_mount_acl(const struct tomoyo_request_info *r,
				   const struct tomoyo_acl_info *ptr)
{
	const struct tomoyo_mount_acl *acl =
		container_of(ptr, typeof(*acl), head);
	return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
		tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
		tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
		(!r->param.mount.need_dev ||
		 tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
}

/**
 * tomoyo_mount_acl2 - Check permission for mount() operation.
 *
@@ -41,7 +89,6 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name,
			     struct path *dir, char *type, unsigned long flags)
{
	struct path path;
	struct tomoyo_acl_info *ptr;
	struct file_system_type *fstype = NULL;
	const char *requested_type = NULL;
	const char *requested_dir_name = NULL;
@@ -118,26 +165,10 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name,
	r->param.mount.dir = &rdir;
	r->param.mount.type = &rtype;
	r->param.mount.flags = flags;
	list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) {
		struct tomoyo_mount_acl *acl;
		if (ptr->is_deleted || ptr->type != TOMOYO_TYPE_MOUNT_ACL)
			continue;
		acl = container_of(ptr, struct tomoyo_mount_acl, head);
		if (!tomoyo_compare_number_union(flags, &acl->flags) ||
		    !tomoyo_compare_name_union(&rtype, &acl->fs_type) ||
		    !tomoyo_compare_name_union(&rdir, &acl->dir_name) ||
		    (need_dev &&
		     !tomoyo_compare_name_union(&rdev, &acl->dev_name)))
			continue;
		error = 0;
		break;
	}
	if (error)
		error = tomoyo_supervisor(r, TOMOYO_KEYWORD_ALLOW_MOUNT
					  "%s %s %s 0x%lX\n",
					  tomoyo_file_pattern(&rdev),
					  tomoyo_file_pattern(&rdir),
					  requested_type, flags);
	do {
		tomoyo_check_acl(r, tomoyo_check_mount_acl);
		error = tomoyo_audit_mount_log(r);
	} while (error == TOMOYO_RETRY_REQUEST);
 out:
	kfree(requested_dev_name);
	kfree(requested_dir_name);