Commit c8c57e84 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by James Morris

TOMOYO: Support longer pathname.

Allow pathnames longer than 4000 bytes.
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 9b244373
...@@ -33,14 +33,7 @@ struct linux_binprm; ...@@ -33,14 +33,7 @@ struct linux_binprm;
#define TOMOYO_HASH_BITS 8 #define TOMOYO_HASH_BITS 8
#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS) #define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
/* #define TOMOYO_EXEC_TMPSIZE 4096
* This is the max length of a token.
*
* A token consists of only ASCII printable characters.
* Non printable characters in a token is represented in \ooo style
* octal string. Thus, \ itself is represented as \\.
*/
#define TOMOYO_MAX_PATHNAME_LEN 4000
/* Profile number is an integer between 0 and 255. */ /* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256 #define TOMOYO_MAX_PROFILES 256
...@@ -167,17 +160,6 @@ enum tomoyo_securityfs_interface_index { ...@@ -167,17 +160,6 @@ enum tomoyo_securityfs_interface_index {
/********** Structure definitions. **********/ /********** Structure definitions. **********/
/*
* tomoyo_page_buffer is a structure which is used for holding a pathname
* obtained from "struct dentry" and "struct vfsmount" pair.
* As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
* (because TOMOYO escapes non ASCII printable characters using \ooo format),
* we will make the buffer larger.
*/
struct tomoyo_page_buffer {
char buffer[4096];
};
/* /*
* tomoyo_request_info is a structure which is used for holding * tomoyo_request_info is a structure which is used for holding
* *
...@@ -231,28 +213,6 @@ struct tomoyo_name_entry { ...@@ -231,28 +213,6 @@ struct tomoyo_name_entry {
struct tomoyo_path_info entry; struct tomoyo_path_info entry;
}; };
/*
* tomoyo_path_info_with_data is a structure which is used for holding a
* pathname obtained from "struct dentry" and "struct vfsmount" pair.
*
* "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
* and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
* buffer for the pathname only.
*
* "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
* both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
* so that we don't need to return two pointers to the caller. If the caller
* puts "struct tomoyo_path_info" on stack memory, we will be able to remove
* "struct tomoyo_path_info_with_data".
*/
struct tomoyo_path_info_with_data {
/* Keep "head" first, for this pointer is passed to kfree(). */
struct tomoyo_path_info head;
char barrier1[16]; /* Safeguard for overrun. */
char body[TOMOYO_MAX_PATHNAME_LEN];
char barrier2[16]; /* Safeguard for overrun. */
};
struct tomoyo_name_union { struct tomoyo_name_union {
const struct tomoyo_path_info *filename; const struct tomoyo_path_info *filename;
struct tomoyo_path_group *group; struct tomoyo_path_group *group;
...@@ -827,11 +787,7 @@ void tomoyo_load_policy(const char *filename); ...@@ -827,11 +787,7 @@ void tomoyo_load_policy(const char *filename);
void tomoyo_put_number_union(struct tomoyo_number_union *ptr); void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
/* Convert binary string to ascii string. */ /* Convert binary string to ascii string. */
int tomoyo_encode(char *buffer, int buflen, const char *str); char *tomoyo_encode(const char *str);
/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
int tomoyo_realpath_from_path2(struct path *path, char *newname,
int newname_len);
/* /*
* Returns realpath(3) of the given pathname but ignores chroot'ed root. * Returns realpath(3) of the given pathname but ignores chroot'ed root.
......
...@@ -676,47 +676,43 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * ...@@ -676,47 +676,43 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
int tomoyo_find_next_domain(struct linux_binprm *bprm) int tomoyo_find_next_domain(struct linux_binprm *bprm)
{ {
struct tomoyo_request_info r; struct tomoyo_request_info r;
/* char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
* This function assumes that the size of buffer returned by
* tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
*/
struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL; struct tomoyo_domain_info *domain = NULL;
const char *old_domain_name = old_domain->domainname->name; const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename; const char *original_name = bprm->filename;
char *new_domain_name = NULL;
char *real_program_name = NULL;
char *symlink_program_name = NULL;
const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE); const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
int retval = -ENOMEM; int retval = -ENOMEM;
struct tomoyo_path_info rn; /* real name */ bool need_kfree = false;
struct tomoyo_path_info sn; /* symlink name */ struct tomoyo_path_info rn = { }; /* real name */
struct tomoyo_path_info sn = { }; /* symlink name */
struct tomoyo_path_info ln; /* last name */ struct tomoyo_path_info ln; /* last name */
ln.name = tomoyo_get_last_name(old_domain);
tomoyo_fill_path_info(&ln);
tomoyo_init_request_info(&r, NULL); tomoyo_init_request_info(&r, NULL);
if (!tmp) if (!tmp)
goto out; goto out;
retry: retry:
if (need_kfree) {
kfree(rn.name);
need_kfree = false;
}
/* Get tomoyo_realpath of program. */ /* Get tomoyo_realpath of program. */
retval = -ENOENT; retval = -ENOENT;
/* I hope tomoyo_realpath() won't fail with -ENOMEM. */ rn.name = tomoyo_realpath(original_name);
real_program_name = tomoyo_realpath(original_name); if (!rn.name)
if (!real_program_name)
goto out; goto out;
tomoyo_fill_path_info(&rn);
need_kfree = true;
/* Get tomoyo_realpath of symbolic link. */ /* Get tomoyo_realpath of symbolic link. */
symlink_program_name = tomoyo_realpath_nofollow(original_name); sn.name = tomoyo_realpath_nofollow(original_name);
if (!symlink_program_name) if (!sn.name)
goto out; goto out;
rn.name = real_program_name;
tomoyo_fill_path_info(&rn);
sn.name = symlink_program_name;
tomoyo_fill_path_info(&sn); tomoyo_fill_path_info(&sn);
ln.name = tomoyo_get_last_name(old_domain);
tomoyo_fill_path_info(&ln);
/* Check 'alias' directive. */ /* Check 'alias' directive. */
if (tomoyo_pathcmp(&rn, &sn)) { if (tomoyo_pathcmp(&rn, &sn)) {
...@@ -727,10 +723,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -727,10 +723,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
tomoyo_pathcmp(&rn, ptr->original_name) || tomoyo_pathcmp(&rn, ptr->original_name) ||
tomoyo_pathcmp(&sn, ptr->aliased_name)) tomoyo_pathcmp(&sn, ptr->aliased_name))
continue; continue;
memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN); kfree(rn.name);
strncpy(real_program_name, ptr->aliased_name->name, need_kfree = false;
TOMOYO_MAX_PATHNAME_LEN - 1); /* This is OK because it is read only. */
tomoyo_fill_path_info(&rn); rn = *ptr->aliased_name;
break; break;
} }
} }
...@@ -742,11 +738,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -742,11 +738,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
if (retval < 0) if (retval < 0)
goto out; goto out;
new_domain_name = tmp->buffer;
if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) { if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) {
/* Transit to the child of tomoyo_kernel_domain domain. */ /* Transit to the child of tomoyo_kernel_domain domain. */
snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
TOMOYO_ROOT_NAME " " "%s", real_program_name); TOMOYO_ROOT_NAME " " "%s", rn.name);
} else if (old_domain == &tomoyo_kernel_domain && } else if (old_domain == &tomoyo_kernel_domain &&
!tomoyo_policy_loaded) { !tomoyo_policy_loaded) {
/* /*
...@@ -760,29 +755,27 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -760,29 +755,27 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
domain = old_domain; domain = old_domain;
} else { } else {
/* Normal domain transition. */ /* Normal domain transition. */
snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1, snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
"%s %s", old_domain_name, real_program_name); "%s %s", old_domain_name, rn.name);
} }
if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
goto done; goto done;
domain = tomoyo_find_domain(new_domain_name); domain = tomoyo_find_domain(tmp);
if (domain) if (domain)
goto done; goto done;
if (is_enforce) { if (is_enforce) {
int error = tomoyo_supervisor(&r, "# wants to create domain\n" int error = tomoyo_supervisor(&r, "# wants to create domain\n"
"%s\n", new_domain_name); "%s\n", tmp);
if (error == TOMOYO_RETRY_REQUEST) if (error == TOMOYO_RETRY_REQUEST)
goto retry; goto retry;
if (error < 0) if (error < 0)
goto done; goto done;
} }
domain = tomoyo_find_or_assign_new_domain(new_domain_name, domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile);
old_domain->profile);
done: done:
if (domain) if (domain)
goto out; goto out;
printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
new_domain_name);
if (is_enforce) if (is_enforce)
retval = -EPERM; retval = -EPERM;
else else
...@@ -793,8 +786,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) ...@@ -793,8 +786,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
/* Update reference count on "struct tomoyo_domain_info". */ /* Update reference count on "struct tomoyo_domain_info". */
atomic_inc(&domain->users); atomic_inc(&domain->users);
bprm->cred->security = domain; bprm->cred->security = domain;
kfree(real_program_name); if (need_kfree)
kfree(symlink_program_name); kfree(rn.name);
kfree(sn.name);
kfree(tmp); kfree(tmp);
return retval; return retval;
} }
...@@ -148,6 +148,17 @@ const char *tomoyo_path_number2keyword(const u8 operation) ...@@ -148,6 +148,17 @@ const char *tomoyo_path_number2keyword(const u8 operation)
? tomoyo_path_number_keyword[operation] : NULL; ? tomoyo_path_number_keyword[operation] : NULL;
} }
static void tomoyo_add_slash(struct tomoyo_path_info *buf)
{
if (buf->is_dir)
return;
/*
* This is OK because tomoyo_encode() reserves space for appending "/".
*/
strcat((char *) buf->name, "/");
tomoyo_fill_path_info(buf);
}
/** /**
* tomoyo_strendswith - Check whether the token ends with the given token. * tomoyo_strendswith - Check whether the token ends with the given token.
* *
...@@ -167,30 +178,21 @@ static bool tomoyo_strendswith(const char *name, const char *tail) ...@@ -167,30 +178,21 @@ static bool tomoyo_strendswith(const char *name, const char *tail)
} }
/** /**
* tomoyo_get_path - Get realpath. * tomoyo_get_realpath - Get realpath.
* *
* @buf: Pointer to "struct tomoyo_path_info".
* @path: Pointer to "struct path". * @path: Pointer to "struct path".
* *
* Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. * Returns true on success, false otherwise.
*/ */
static struct tomoyo_path_info *tomoyo_get_path(struct path *path) static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
{ {
int error; buf->name = tomoyo_realpath_from_path(path);
struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), if (buf->name) {
GFP_NOFS); tomoyo_fill_path_info(buf);
return true;
if (!buf)
return NULL;
/* Reserve one byte for appending "/". */
error = tomoyo_realpath_from_path2(path, buf->body,
sizeof(buf->body) - 2);
if (!error) {
buf->head.name = buf->body;
tomoyo_fill_path_info(&buf->head);
return &buf->head;
} }
kfree(buf); return false;
return NULL;
} }
static int tomoyo_update_path2_acl(const u8 type, const char *filename1, static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
...@@ -1259,26 +1261,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, ...@@ -1259,26 +1261,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
{ {
struct tomoyo_request_info r; struct tomoyo_request_info r;
int error = -ENOMEM; int error = -ENOMEM;
struct tomoyo_path_info *buf; struct tomoyo_path_info buf;
int idx; int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
!path->mnt || !path->dentry) !path->mnt || !path->dentry)
return 0; return 0;
idx = tomoyo_read_lock(); idx = tomoyo_read_lock();
buf = tomoyo_get_path(path); if (!tomoyo_get_realpath(&buf, path))
if (!buf)
goto out; goto out;
if (type == TOMOYO_TYPE_MKDIR && !buf->is_dir) { if (type == TOMOYO_TYPE_MKDIR)
/* tomoyo_add_slash(&buf);
* tomoyo_get_path() reserves space for appending "/." error = tomoyo_path_number_perm2(&r, type, &buf, number);
*/
strcat((char *) buf->name, "/");
tomoyo_fill_path_info(buf);
}
error = tomoyo_path_number_perm2(&r, type, buf, number);
out: out:
kfree(buf); kfree(buf.name);
tomoyo_read_unlock(idx); tomoyo_read_unlock(idx);
if (r.mode != TOMOYO_CONFIG_ENFORCING) if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0; error = 0;
...@@ -1319,7 +1315,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, ...@@ -1319,7 +1315,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
{ {
const u8 acc_mode = ACC_MODE(flag); const u8 acc_mode = ACC_MODE(flag);
int error = -ENOMEM; int error = -ENOMEM;
struct tomoyo_path_info *buf; struct tomoyo_path_info buf;
struct tomoyo_request_info r; struct tomoyo_request_info r;
int idx; int idx;
...@@ -1335,8 +1331,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, ...@@ -1335,8 +1331,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
*/ */
return 0; return 0;
idx = tomoyo_read_lock(); idx = tomoyo_read_lock();
buf = tomoyo_get_path(path); if (!tomoyo_get_realpath(&buf, path))
if (!buf)
goto out; goto out;
error = 0; error = 0;
/* /*
...@@ -1346,15 +1341,15 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, ...@@ -1346,15 +1341,15 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
*/ */
if ((acc_mode & MAY_WRITE) && if ((acc_mode & MAY_WRITE) &&
((flag & O_TRUNC) || !(flag & O_APPEND)) && ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
(tomoyo_is_no_rewrite_file(buf))) { (tomoyo_is_no_rewrite_file(&buf))) {
error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, buf); error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, &buf);
} }
if (!error) if (!error)
error = tomoyo_file_perm(&r, buf, acc_mode); error = tomoyo_file_perm(&r, &buf, acc_mode);
if (!error && (flag & O_TRUNC)) if (!error && (flag & O_TRUNC))
error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, buf); error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, &buf);
out: out:
kfree(buf); kfree(buf.name);
tomoyo_read_unlock(idx); tomoyo_read_unlock(idx);
if (r.mode != TOMOYO_CONFIG_ENFORCING) if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0; error = 0;
...@@ -1372,7 +1367,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, ...@@ -1372,7 +1367,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
int tomoyo_path_perm(const u8 operation, struct path *path) int tomoyo_path_perm(const u8 operation, struct path *path)
{ {
int error = -ENOMEM; int error = -ENOMEM;
struct tomoyo_path_info *buf; struct tomoyo_path_info buf;
struct tomoyo_request_info r; struct tomoyo_request_info r;
int idx; int idx;
...@@ -1380,29 +1375,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path) ...@@ -1380,29 +1375,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
!path->mnt) !path->mnt)
return 0; return 0;
idx = tomoyo_read_lock(); idx = tomoyo_read_lock();
buf = tomoyo_get_path(path); if (!tomoyo_get_realpath(&buf, path))
if (!buf)
goto out; goto out;
switch (operation) { switch (operation) {
case TOMOYO_TYPE_REWRITE: case TOMOYO_TYPE_REWRITE:
if (!tomoyo_is_no_rewrite_file(buf)) { if (!tomoyo_is_no_rewrite_file(&buf)) {
error = 0; error = 0;
goto out; goto out;
} }
break; break;
case TOMOYO_TYPE_RMDIR: case TOMOYO_TYPE_RMDIR:
case TOMOYO_TYPE_CHROOT: case TOMOYO_TYPE_CHROOT:
if (!buf->is_dir) { tomoyo_add_slash(&buf);
/* break;
* tomoyo_get_path() reserves space for appending "/."
*/
strcat((char *) buf->name, "/");
tomoyo_fill_path_info(buf);
}
} }
error = tomoyo_path_permission(&r, operation, buf); error = tomoyo_path_permission(&r, operation, &buf);
out: out:
kfree(buf); kfree(buf.name);
tomoyo_read_unlock(idx); tomoyo_read_unlock(idx);
if (r.mode != TOMOYO_CONFIG_ENFORCING) if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0; error = 0;
...@@ -1465,7 +1454,7 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path, ...@@ -1465,7 +1454,7 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
{ {
struct tomoyo_request_info r; struct tomoyo_request_info r;
int error = -ENOMEM; int error = -ENOMEM;
struct tomoyo_path_info *buf; struct tomoyo_path_info buf;
int idx; int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
...@@ -1473,11 +1462,10 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path, ...@@ -1473,11 +1462,10 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
return 0; return 0;
idx = tomoyo_read_lock(); idx = tomoyo_read_lock();
error = -ENOMEM; error = -ENOMEM;
buf = tomoyo_get_path(path); if (tomoyo_get_realpath(&buf, path)) {
if (buf) { error = tomoyo_path_number3_perm2(&r, operation, &buf, mode,
error = tomoyo_path_number3_perm2(&r, operation, buf, mode,
new_decode_dev(dev)); new_decode_dev(dev));
kfree(buf); kfree(buf.name);
} }
tomoyo_read_unlock(idx); tomoyo_read_unlock(idx);
if (r.mode != TOMOYO_CONFIG_ENFORCING) if (r.mode != TOMOYO_CONFIG_ENFORCING)
...@@ -1499,48 +1487,40 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, ...@@ -1499,48 +1487,40 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
{ {
int error = -ENOMEM; int error = -ENOMEM;
const char *msg; const char *msg;
struct tomoyo_path_info *buf1; struct tomoyo_path_info buf1;
struct tomoyo_path_info *buf2; struct tomoyo_path_info buf2;
struct tomoyo_request_info r; struct tomoyo_request_info r;
int idx; int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
!path1->mnt || !path2->mnt) !path1->mnt || !path2->mnt)
return 0; return 0;
buf1.name = NULL;
buf2.name = NULL;
idx = tomoyo_read_lock(); idx = tomoyo_read_lock();
buf1 = tomoyo_get_path(path1); if (!tomoyo_get_realpath(&buf1, path1) ||
buf2 = tomoyo_get_path(path2); !tomoyo_get_realpath(&buf2, path2))
if (!buf1 || !buf2)
goto out; goto out;
{ {
struct dentry *dentry = path1->dentry; struct dentry *dentry = path1->dentry;
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
/* tomoyo_add_slash(&buf1);
* tomoyo_get_path() reserves space for appending "/." tomoyo_add_slash(&buf2);
*/
if (!buf1->is_dir) {
strcat((char *) buf1->name, "/");
tomoyo_fill_path_info(buf1);
}
if (!buf2->is_dir) {
strcat((char *) buf2->name, "/");
tomoyo_fill_path_info(buf2);
}
} }
} }
do { do {
error = tomoyo_path2_acl(&r, operation, buf1, buf2); error = tomoyo_path2_acl(&r, operation, &buf1, &buf2);
if (!error) if (!error)
break; break;
msg = tomoyo_path22keyword(operation); msg = tomoyo_path22keyword(operation);
tomoyo_warn_log(&r, "%s %s %s", msg, buf1->name, buf2->name); tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name);
error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg, error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg,
tomoyo_file_pattern(buf1), tomoyo_file_pattern(&buf1),
tomoyo_file_pattern(buf2)); tomoyo_file_pattern(&buf2));
} while (error == TOMOYO_RETRY_REQUEST); } while (error == TOMOYO_RETRY_REQUEST);
out: out:
kfree(buf1); kfree(buf1.name);
kfree(buf2);