TOMOYO: Copy directly to userspace buffer.

When userspace program reads policy from /sys/kernel/security/tomoyo/
interface, TOMOYO uses line buffered mode. A line has at least one word.

Commit 006dacc "TOMOYO: Support longer pathname." changed a word's max length
from 4000 bytes to max kmalloc()able bytes. By that commit, a line's max length
changed from 8192 bytes to more than max kmalloc()able bytes.

Max number of words in a line remains finite. This patch changes the way of
buffering so that all words in a line are firstly directly copied to userspace
buffer as much as possible and are secondly queued for next read request.
Words queued are guaranteed to be valid until /sys/kernel/security/tomoyo/
interface is close()d.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
Tetsuo Handa 2010-06-24 14:57:16 +09:00 committed by James Morris
parent 5db5a39b64
commit f23571e866
3 changed files with 510 additions and 470 deletions

File diff suppressed because it is too large Load diff

View file

@ -524,28 +524,11 @@ struct tomoyo_mount_acl {
struct tomoyo_number_union flags;
};
#define TOMOYO_MAX_IO_READ_QUEUE 32
/*
* tomoyo_io_buffer is a structure which is used for reading and modifying
* configuration via /sys/kernel/security/tomoyo/ interface.
* It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as
* cursors.
*
* Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of
* "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info"
* entry has a list of "struct tomoyo_acl_info", we need two cursors when
* reading (one is for traversing tomoyo_domain_list and the other is for
* traversing "struct tomoyo_acl_info"->acl_info_list ).
*
* If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
* "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the
* domain with the domainname specified by the rest of that line (NULL is set
* if seek failed).
* If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
* "delete ", TOMOYO deletes an entry or a domain specified by the rest of that
* line (->write_var1 is set to NULL if a domain was deleted).
* If a line written to /sys/kernel/security/tomoyo/domain_policy starts with
* neither "select " nor "delete ", an entry or a domain specified by that line
* is appended.
* Structure for reading/writing policy via /sys/kernel/security/tomoyo
* interfaces.
*/
struct tomoyo_io_buffer {
void (*read) (struct tomoyo_io_buffer *);
@ -555,26 +538,27 @@ struct tomoyo_io_buffer {
struct mutex io_sem;
/* Index returned by tomoyo_read_lock(). */
int reader_idx;
/* The position currently reading from. */
struct list_head *read_var1;
/* Extra variables for reading. */
struct list_head *read_var2;
char __user *read_user_buf;
int read_user_buf_avail;
struct {
struct list_head *domain;
struct list_head *group;
struct list_head *acl;
int avail;
int step;
int query_index;
u16 index;
u8 bit;
u8 w_pos;
bool eof;
bool print_this_domain_only;
bool print_execute_only;
const char *w[TOMOYO_MAX_IO_READ_QUEUE];
} r;
/* The position currently writing to. */
struct tomoyo_domain_info *write_var1;
/* The step for reading. */
int read_step;
/* Buffer for reading. */
char *read_buf;
/* EOF flag for reading. */
bool read_eof;
/* Read domain ACL of specified PID? */
bool read_single_domain;
/* Extra variable for reading. */
u8 read_bit;
/* Read only TOMOYO_TYPE_EXECUTE */
bool print_execute_only;
/* Bytes available for reading. */
int read_avail;
/* Size of read buffer. */
int readbuf_size;
/* Buffer for writing. */
@ -738,8 +722,7 @@ bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
bool tomoyo_compare_number_union(const unsigned long value,
const struct tomoyo_number_union *ptr);
int tomoyo_get_mode(const u8 profile, const u8 index);
/* Transactional sprintf() for policy dump. */
bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
/* Check whether the domainname is correct. */
bool tomoyo_correct_domain(const unsigned char *domainname);
@ -761,8 +744,6 @@ bool tomoyo_number_matches_group(const unsigned long min,
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
const struct tomoyo_path_info *pattern);
bool tomoyo_print_number_union(struct tomoyo_io_buffer *head,
const struct tomoyo_number_union *ptr);
bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
/* Tokenize a line. */
bool tomoyo_tokenize(char *buffer, char *w[], size_t size);

View file

@ -234,7 +234,7 @@ unsigned int tomoyo_quota_for_query;
*/
void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
{
if (!head->read_eof) {
if (!head->r.eof) {
const unsigned int policy
= atomic_read(&tomoyo_policy_memory_size);
const unsigned int query = tomoyo_query_memory_size;
@ -258,7 +258,7 @@ void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
tomoyo_io_printf(head, "Query lists: %10u%s\n", query,
buffer);
tomoyo_io_printf(head, "Total: %10u\n", policy + query);
head->read_eof = true;
head->r.eof = true;
}
}