diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-06-16 09:22:51 +0200 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 07:34:32 +0200 |
commit | 99a852596beb26cc449ca1a79834c107ef4080e1 (patch) | |
tree | 8d593b0af85f6cbbfe73b916f7449148ccf93133 | |
parent | TOMOYO: Pass parameters via structure. (diff) | |
download | linux-99a852596beb26cc449ca1a79834c107ef4080e1.tar.xz linux-99a852596beb26cc449ca1a79834c107ef4080e1.zip |
TOMOYO: Use callback for permission check.
We can use callback function since parameters are passed via
"const struct tomoyo_request_info".
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/tomoyo/common.h | 3 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 18 | ||||
-rw-r--r-- | security/tomoyo/file.c | 394 | ||||
-rw-r--r-- | security/tomoyo/mount.c | 73 |
4 files changed, 230 insertions, 258 deletions
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index f055e273ec02..36b027460ea6 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -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. **********/ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 35317e783f34..13f4f39baf8f 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -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 diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 32661df10e85..18969e77f5e8 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -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; - } - return error; +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); +} + +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, @@ -870,88 +987,6 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1, } /** - * 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. * * @r: Pointer to "struct tomoyo_request_info". @@ -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; } @@ -1311,47 +1279,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path) } /** - * 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". * * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) @@ -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,15 +1366,9 @@ 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)); - } while (error == TOMOYO_RETRY_REQUEST); + tomoyo_check_acl(&r, tomoyo_check_path2_acl); + error = tomoyo_audit_path2_log(&r); + } while (error == TOMOYO_RETRY_REQUEST); out: kfree(buf1.name); kfree(buf2.name); diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 554de173152c..8f3ac251c571 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -25,6 +25,54 @@ #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. * * @r: Pointer to "struct tomoyo_request_info". @@ -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); |