| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 1 | /* | 
 | 2 |  * security/tomoyo/audit.c | 
 | 3 |  * | 
| Tetsuo Handa | 0f2a55d | 2011-07-14 14:46:51 +0900 | [diff] [blame] | 4 |  * Copyright (C) 2005-2011  NTT DATA CORPORATION | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 5 |  */ | 
 | 6 |  | 
 | 7 | #include "common.h" | 
 | 8 | #include <linux/slab.h> | 
 | 9 |  | 
 | 10 | /** | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 11 |  * tomoyo_print_bprm - Print "struct linux_binprm" for auditing. | 
 | 12 |  * | 
 | 13 |  * @bprm: Pointer to "struct linux_binprm". | 
 | 14 |  * @dump: Pointer to "struct tomoyo_page_dump". | 
 | 15 |  * | 
 | 16 |  * Returns the contents of @bprm on success, NULL otherwise. | 
 | 17 |  * | 
 | 18 |  * This function uses kzalloc(), so caller must kfree() if this function | 
 | 19 |  * didn't return NULL. | 
 | 20 |  */ | 
 | 21 | static char *tomoyo_print_bprm(struct linux_binprm *bprm, | 
 | 22 | 			       struct tomoyo_page_dump *dump) | 
 | 23 | { | 
 | 24 | 	static const int tomoyo_buffer_len = 4096 * 2; | 
 | 25 | 	char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS); | 
 | 26 | 	char *cp; | 
 | 27 | 	char *last_start; | 
 | 28 | 	int len; | 
 | 29 | 	unsigned long pos = bprm->p; | 
 | 30 | 	int offset = pos % PAGE_SIZE; | 
 | 31 | 	int argv_count = bprm->argc; | 
 | 32 | 	int envp_count = bprm->envc; | 
 | 33 | 	bool truncated = false; | 
 | 34 | 	if (!buffer) | 
 | 35 | 		return NULL; | 
 | 36 | 	len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ "); | 
 | 37 | 	cp = buffer + len; | 
 | 38 | 	if (!argv_count) { | 
 | 39 | 		memmove(cp, "} envp[]={ ", 11); | 
 | 40 | 		cp += 11; | 
 | 41 | 	} | 
 | 42 | 	last_start = cp; | 
 | 43 | 	while (argv_count || envp_count) { | 
 | 44 | 		if (!tomoyo_dump_page(bprm, pos, dump)) | 
 | 45 | 			goto out; | 
 | 46 | 		pos += PAGE_SIZE - offset; | 
 | 47 | 		/* Read. */ | 
 | 48 | 		while (offset < PAGE_SIZE) { | 
 | 49 | 			const char *kaddr = dump->data; | 
 | 50 | 			const unsigned char c = kaddr[offset++]; | 
 | 51 | 			if (cp == last_start) | 
 | 52 | 				*cp++ = '"'; | 
 | 53 | 			if (cp >= buffer + tomoyo_buffer_len - 32) { | 
 | 54 | 				/* Reserve some room for "..." string. */ | 
 | 55 | 				truncated = true; | 
 | 56 | 			} else if (c == '\\') { | 
 | 57 | 				*cp++ = '\\'; | 
 | 58 | 				*cp++ = '\\'; | 
 | 59 | 			} else if (c > ' ' && c < 127) { | 
 | 60 | 				*cp++ = c; | 
 | 61 | 			} else if (!c) { | 
 | 62 | 				*cp++ = '"'; | 
 | 63 | 				*cp++ = ' '; | 
 | 64 | 				last_start = cp; | 
 | 65 | 			} else { | 
 | 66 | 				*cp++ = '\\'; | 
 | 67 | 				*cp++ = (c >> 6) + '0'; | 
 | 68 | 				*cp++ = ((c >> 3) & 7) + '0'; | 
 | 69 | 				*cp++ = (c & 7) + '0'; | 
 | 70 | 			} | 
 | 71 | 			if (c) | 
 | 72 | 				continue; | 
 | 73 | 			if (argv_count) { | 
 | 74 | 				if (--argv_count == 0) { | 
 | 75 | 					if (truncated) { | 
 | 76 | 						cp = last_start; | 
 | 77 | 						memmove(cp, "... ", 4); | 
 | 78 | 						cp += 4; | 
 | 79 | 					} | 
 | 80 | 					memmove(cp, "} envp[]={ ", 11); | 
 | 81 | 					cp += 11; | 
 | 82 | 					last_start = cp; | 
 | 83 | 					truncated = false; | 
 | 84 | 				} | 
 | 85 | 			} else if (envp_count) { | 
 | 86 | 				if (--envp_count == 0) { | 
 | 87 | 					if (truncated) { | 
 | 88 | 						cp = last_start; | 
 | 89 | 						memmove(cp, "... ", 4); | 
 | 90 | 						cp += 4; | 
 | 91 | 					} | 
 | 92 | 				} | 
 | 93 | 			} | 
 | 94 | 			if (!argv_count && !envp_count) | 
 | 95 | 				break; | 
 | 96 | 		} | 
 | 97 | 		offset = 0; | 
 | 98 | 	} | 
 | 99 | 	*cp++ = '}'; | 
 | 100 | 	*cp = '\0'; | 
 | 101 | 	return buffer; | 
 | 102 | out: | 
 | 103 | 	snprintf(buffer, tomoyo_buffer_len - 1, | 
 | 104 | 		 "argv[]={ ... } envp[]= { ... }"); | 
 | 105 | 	return buffer; | 
 | 106 | } | 
 | 107 |  | 
 | 108 | /** | 
| Tetsuo Handa | 8761afd | 2011-07-08 13:22:41 +0900 | [diff] [blame] | 109 |  * tomoyo_filetype - Get string representation of file type. | 
 | 110 |  * | 
 | 111 |  * @mode: Mode value for stat(). | 
 | 112 |  * | 
 | 113 |  * Returns file type string. | 
 | 114 |  */ | 
| Al Viro | d179333f | 2011-08-26 23:03:17 -0400 | [diff] [blame] | 115 | static inline const char *tomoyo_filetype(const umode_t mode) | 
| Tetsuo Handa | 8761afd | 2011-07-08 13:22:41 +0900 | [diff] [blame] | 116 | { | 
 | 117 | 	switch (mode & S_IFMT) { | 
 | 118 | 	case S_IFREG: | 
 | 119 | 	case 0: | 
 | 120 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE]; | 
 | 121 | 	case S_IFDIR: | 
 | 122 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY]; | 
 | 123 | 	case S_IFLNK: | 
 | 124 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK]; | 
 | 125 | 	case S_IFIFO: | 
 | 126 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO]; | 
 | 127 | 	case S_IFSOCK: | 
 | 128 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET]; | 
 | 129 | 	case S_IFBLK: | 
 | 130 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV]; | 
 | 131 | 	case S_IFCHR: | 
 | 132 | 		return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV]; | 
 | 133 | 	} | 
 | 134 | 	return "unknown"; /* This should not happen. */ | 
 | 135 | } | 
 | 136 |  | 
 | 137 | /** | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 138 |  * tomoyo_print_header - Get header line of audit log. | 
 | 139 |  * | 
 | 140 |  * @r: Pointer to "struct tomoyo_request_info". | 
 | 141 |  * | 
 | 142 |  * Returns string representation. | 
 | 143 |  * | 
 | 144 |  * This function uses kmalloc(), so caller must kfree() if this function | 
 | 145 |  * didn't return NULL. | 
 | 146 |  */ | 
 | 147 | static char *tomoyo_print_header(struct tomoyo_request_info *r) | 
 | 148 | { | 
 | 149 | 	struct tomoyo_time stamp; | 
 | 150 | 	const pid_t gpid = task_pid_nr(current); | 
| Tetsuo Handa | 8761afd | 2011-07-08 13:22:41 +0900 | [diff] [blame] | 151 | 	struct tomoyo_obj_info *obj = r->obj; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 152 | 	static const int tomoyo_buffer_len = 4096; | 
 | 153 | 	char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); | 
| Tetsuo Handa | 2066a36 | 2011-07-08 13:21:37 +0900 | [diff] [blame] | 154 | 	int pos; | 
| Tetsuo Handa | 8761afd | 2011-07-08 13:22:41 +0900 | [diff] [blame] | 155 | 	u8 i; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 156 | 	if (!buffer) | 
 | 157 | 		return NULL; | 
 | 158 | 	{ | 
 | 159 | 		struct timeval tv; | 
 | 160 | 		do_gettimeofday(&tv); | 
 | 161 | 		tomoyo_convert_time(tv.tv_sec, &stamp); | 
 | 162 | 	} | 
| Tetsuo Handa | 2066a36 | 2011-07-08 13:21:37 +0900 | [diff] [blame] | 163 | 	pos = snprintf(buffer, tomoyo_buffer_len - 1, | 
 | 164 | 		       "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " | 
 | 165 | 		       "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " | 
 | 166 | 		       "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " | 
 | 167 | 		       "fsuid=%u fsgid=%u }", stamp.year, stamp.month, | 
 | 168 | 		       stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, | 
 | 169 | 		       tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, | 
 | 170 | 		       tomoyo_sys_getpid(), tomoyo_sys_getppid(), | 
 | 171 | 		       current_uid(), current_gid(), current_euid(), | 
 | 172 | 		       current_egid(), current_suid(), current_sgid(), | 
 | 173 | 		       current_fsuid(), current_fsgid()); | 
| Tetsuo Handa | 8761afd | 2011-07-08 13:22:41 +0900 | [diff] [blame] | 174 | 	if (!obj) | 
 | 175 | 		goto no_obj_info; | 
 | 176 | 	if (!obj->validate_done) { | 
 | 177 | 		tomoyo_get_attributes(obj); | 
 | 178 | 		obj->validate_done = true; | 
 | 179 | 	} | 
 | 180 | 	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { | 
 | 181 | 		struct tomoyo_mini_stat *stat; | 
 | 182 | 		unsigned int dev; | 
| Al Viro | d179333f | 2011-08-26 23:03:17 -0400 | [diff] [blame] | 183 | 		umode_t mode; | 
| Tetsuo Handa | 8761afd | 2011-07-08 13:22:41 +0900 | [diff] [blame] | 184 | 		if (!obj->stat_valid[i]) | 
 | 185 | 			continue; | 
 | 186 | 		stat = &obj->stat[i]; | 
 | 187 | 		dev = stat->dev; | 
 | 188 | 		mode = stat->mode; | 
 | 189 | 		if (i & 1) { | 
 | 190 | 			pos += snprintf(buffer + pos, | 
 | 191 | 					tomoyo_buffer_len - 1 - pos, | 
 | 192 | 					" path%u.parent={ uid=%u gid=%u " | 
 | 193 | 					"ino=%lu perm=0%o }", (i >> 1) + 1, | 
 | 194 | 					stat->uid, stat->gid, (unsigned long) | 
 | 195 | 					stat->ino, stat->mode & S_IALLUGO); | 
 | 196 | 			continue; | 
 | 197 | 		} | 
 | 198 | 		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | 
 | 199 | 				" path%u={ uid=%u gid=%u ino=%lu major=%u" | 
 | 200 | 				" minor=%u perm=0%o type=%s", (i >> 1) + 1, | 
 | 201 | 				stat->uid, stat->gid, (unsigned long) | 
 | 202 | 				stat->ino, MAJOR(dev), MINOR(dev), | 
 | 203 | 				mode & S_IALLUGO, tomoyo_filetype(mode)); | 
 | 204 | 		if (S_ISCHR(mode) || S_ISBLK(mode)) { | 
 | 205 | 			dev = stat->rdev; | 
 | 206 | 			pos += snprintf(buffer + pos, | 
 | 207 | 					tomoyo_buffer_len - 1 - pos, | 
 | 208 | 					" dev_major=%u dev_minor=%u", | 
 | 209 | 					MAJOR(dev), MINOR(dev)); | 
 | 210 | 		} | 
 | 211 | 		pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, | 
 | 212 | 				" }"); | 
 | 213 | 	} | 
 | 214 | no_obj_info: | 
| Tetsuo Handa | 2066a36 | 2011-07-08 13:21:37 +0900 | [diff] [blame] | 215 | 	if (pos < tomoyo_buffer_len - 1) | 
 | 216 | 		return buffer; | 
 | 217 | 	kfree(buffer); | 
 | 218 | 	return NULL; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 219 | } | 
 | 220 |  | 
 | 221 | /** | 
 | 222 |  * tomoyo_init_log - Allocate buffer for audit logs. | 
 | 223 |  * | 
 | 224 |  * @r:    Pointer to "struct tomoyo_request_info". | 
 | 225 |  * @len:  Buffer size needed for @fmt and @args. | 
 | 226 |  * @fmt:  The printf()'s format string. | 
 | 227 |  * @args: va_list structure for @fmt. | 
 | 228 |  * | 
 | 229 |  * Returns pointer to allocated memory. | 
 | 230 |  * | 
 | 231 |  * This function uses kzalloc(), so caller must kfree() if this function | 
 | 232 |  * didn't return NULL. | 
 | 233 |  */ | 
 | 234 | char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, | 
 | 235 | 		      va_list args) | 
 | 236 | { | 
 | 237 | 	char *buf = NULL; | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 238 | 	char *bprm_info = NULL; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 239 | 	const char *header = NULL; | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 240 | 	char *realpath = NULL; | 
 | 241 | 	const char *symlink = NULL; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 242 | 	int pos; | 
| Tetsuo Handa | ea50481 | 2011-06-30 17:32:30 +0900 | [diff] [blame] | 243 | 	const char *domainname = r->domain->domainname->name; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 244 | 	header = tomoyo_print_header(r); | 
 | 245 | 	if (!header) | 
 | 246 | 		return NULL; | 
 | 247 | 	/* +10 is for '\n' etc. and '\0'. */ | 
 | 248 | 	len += strlen(domainname) + strlen(header) + 10; | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 249 | 	if (r->ee) { | 
 | 250 | 		struct file *file = r->ee->bprm->file; | 
 | 251 | 		realpath = tomoyo_realpath_from_path(&file->f_path); | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 252 | 		bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump); | 
 | 253 | 		if (!realpath || !bprm_info) | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 254 | 			goto out; | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 255 | 		/* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */ | 
 | 256 | 		len += strlen(realpath) + 80 + strlen(bprm_info); | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 257 | 	} else if (r->obj && r->obj->symlink_target) { | 
 | 258 | 		symlink = r->obj->symlink_target->name; | 
 | 259 | 		/* +18 is for " symlink.target=\"%s\"" */ | 
 | 260 | 		len += 18 + strlen(symlink); | 
 | 261 | 	} | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 262 | 	len = tomoyo_round2(len); | 
 | 263 | 	buf = kzalloc(len, GFP_NOFS); | 
 | 264 | 	if (!buf) | 
 | 265 | 		goto out; | 
 | 266 | 	len--; | 
 | 267 | 	pos = snprintf(buf, len, "%s", header); | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 268 | 	if (realpath) { | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 269 | 		struct linux_binprm *bprm = r->ee->bprm; | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 270 | 		pos += snprintf(buf + pos, len - pos, | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 271 | 				" exec={ realpath=\"%s\" argc=%d envc=%d %s }", | 
 | 272 | 				realpath, bprm->argc, bprm->envc, bprm_info); | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 273 | 	} else if (symlink) | 
 | 274 | 		pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"", | 
 | 275 | 				symlink); | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 276 | 	pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname); | 
 | 277 | 	vsnprintf(buf + pos, len - pos, fmt, args); | 
 | 278 | out: | 
| Tetsuo Handa | 2ca9bf4 | 2011-07-08 13:23:44 +0900 | [diff] [blame] | 279 | 	kfree(realpath); | 
| Tetsuo Handa | 5b63685 | 2011-07-08 13:24:54 +0900 | [diff] [blame] | 280 | 	kfree(bprm_info); | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 281 | 	kfree(header); | 
 | 282 | 	return buf; | 
 | 283 | } | 
 | 284 |  | 
 | 285 | /* Wait queue for /sys/kernel/security/tomoyo/audit. */ | 
 | 286 | static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait); | 
 | 287 |  | 
 | 288 | /* Structure for audit log. */ | 
 | 289 | struct tomoyo_log { | 
 | 290 | 	struct list_head list; | 
 | 291 | 	char *log; | 
 | 292 | 	int size; | 
 | 293 | }; | 
 | 294 |  | 
 | 295 | /* The list for "struct tomoyo_log". */ | 
 | 296 | static LIST_HEAD(tomoyo_log); | 
 | 297 |  | 
 | 298 | /* Lock for "struct list_head tomoyo_log". */ | 
 | 299 | static DEFINE_SPINLOCK(tomoyo_log_lock); | 
 | 300 |  | 
 | 301 | /* Length of "stuct list_head tomoyo_log". */ | 
 | 302 | static unsigned int tomoyo_log_count; | 
 | 303 |  | 
 | 304 | /** | 
 | 305 |  * tomoyo_get_audit - Get audit mode. | 
 | 306 |  * | 
| Tetsuo Handa | bd03a3e | 2011-06-26 23:19:52 +0900 | [diff] [blame] | 307 |  * @ns:          Pointer to "struct tomoyo_policy_namespace". | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 308 |  * @profile:     Profile number. | 
 | 309 |  * @index:       Index number of functionality. | 
 | 310 |  * @is_granted:  True if granted log, false otherwise. | 
 | 311 |  * | 
 | 312 |  * Returns true if this request should be audited, false otherwise. | 
 | 313 |  */ | 
| Tetsuo Handa | bd03a3e | 2011-06-26 23:19:52 +0900 | [diff] [blame] | 314 | static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns, | 
 | 315 | 			     const u8 profile, const u8 index, | 
| Tetsuo Handa | 1f067a6 | 2011-09-10 15:24:56 +0900 | [diff] [blame] | 316 | 			     const struct tomoyo_acl_info *matched_acl, | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 317 | 			     const bool is_granted) | 
 | 318 | { | 
 | 319 | 	u8 mode; | 
| Tetsuo Handa | 2c47ab9 | 2011-06-26 23:21:19 +0900 | [diff] [blame] | 320 | 	const u8 category = tomoyo_index2category[index] + | 
 | 321 | 		TOMOYO_MAX_MAC_INDEX; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 322 | 	struct tomoyo_profile *p; | 
 | 323 | 	if (!tomoyo_policy_loaded) | 
 | 324 | 		return false; | 
| Tetsuo Handa | bd03a3e | 2011-06-26 23:19:52 +0900 | [diff] [blame] | 325 | 	p = tomoyo_profile(ns, profile); | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 326 | 	if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG]) | 
 | 327 | 		return false; | 
| Tetsuo Handa | 1f067a6 | 2011-09-10 15:24:56 +0900 | [diff] [blame] | 328 | 	if (is_granted && matched_acl && matched_acl->cond && | 
 | 329 | 	    matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO) | 
 | 330 | 		return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES; | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 331 | 	mode = p->config[index]; | 
 | 332 | 	if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 
 | 333 | 		mode = p->config[category]; | 
 | 334 | 	if (mode == TOMOYO_CONFIG_USE_DEFAULT) | 
 | 335 | 		mode = p->default_config; | 
 | 336 | 	if (is_granted) | 
 | 337 | 		return mode & TOMOYO_CONFIG_WANT_GRANT_LOG; | 
 | 338 | 	return mode & TOMOYO_CONFIG_WANT_REJECT_LOG; | 
 | 339 | } | 
 | 340 |  | 
 | 341 | /** | 
 | 342 |  * tomoyo_write_log2 - Write an audit log. | 
 | 343 |  * | 
 | 344 |  * @r:    Pointer to "struct tomoyo_request_info". | 
 | 345 |  * @len:  Buffer size needed for @fmt and @args. | 
 | 346 |  * @fmt:  The printf()'s format string. | 
 | 347 |  * @args: va_list structure for @fmt. | 
 | 348 |  * | 
 | 349 |  * Returns nothing. | 
 | 350 |  */ | 
 | 351 | void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, | 
 | 352 | 		       va_list args) | 
 | 353 | { | 
 | 354 | 	char *buf; | 
 | 355 | 	struct tomoyo_log *entry; | 
 | 356 | 	bool quota_exceeded = false; | 
| Tetsuo Handa | 1f067a6 | 2011-09-10 15:24:56 +0900 | [diff] [blame] | 357 | 	if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, | 
 | 358 | 			      r->matched_acl, r->granted)) | 
| Tetsuo Handa | eadd99c | 2011-06-26 23:18:58 +0900 | [diff] [blame] | 359 | 		goto out; | 
 | 360 | 	buf = tomoyo_init_log(r, len, fmt, args); | 
 | 361 | 	if (!buf) | 
 | 362 | 		goto out; | 
 | 363 | 	entry = kzalloc(sizeof(*entry), GFP_NOFS); | 
 | 364 | 	if (!entry) { | 
 | 365 | 		kfree(buf); | 
 | 366 | 		goto out; | 
 | 367 | 	} | 
 | 368 | 	entry->log = buf; | 
 | 369 | 	len = tomoyo_round2(strlen(buf) + 1); | 
 | 370 | 	/* | 
 | 371 | 	 * The entry->size is used for memory quota checks. | 
 | 372 | 	 * Don't go beyond strlen(entry->log). | 
 | 373 | 	 */ | 
 | 374 | 	entry->size = len + tomoyo_round2(sizeof(*entry)); | 
 | 375 | 	spin_lock(&tomoyo_log_lock); | 
 | 376 | 	if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] && | 
 | 377 | 	    tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >= | 
 | 378 | 	    tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) { | 
 | 379 | 		quota_exceeded = true; | 
 | 380 | 	} else { | 
 | 381 | 		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size; | 
 | 382 | 		list_add_tail(&entry->list, &tomoyo_log); | 
 | 383 | 		tomoyo_log_count++; | 
 | 384 | 	} | 
 | 385 | 	spin_unlock(&tomoyo_log_lock); | 
 | 386 | 	if (quota_exceeded) { | 
 | 387 | 		kfree(buf); | 
 | 388 | 		kfree(entry); | 
 | 389 | 		goto out; | 
 | 390 | 	} | 
 | 391 | 	wake_up(&tomoyo_log_wait); | 
 | 392 | out: | 
 | 393 | 	return; | 
 | 394 | } | 
 | 395 |  | 
 | 396 | /** | 
 | 397 |  * tomoyo_write_log - Write an audit log. | 
 | 398 |  * | 
 | 399 |  * @r:   Pointer to "struct tomoyo_request_info". | 
 | 400 |  * @fmt: The printf()'s format string, followed by parameters. | 
 | 401 |  * | 
 | 402 |  * Returns nothing. | 
 | 403 |  */ | 
 | 404 | void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) | 
 | 405 | { | 
 | 406 | 	va_list args; | 
 | 407 | 	int len; | 
 | 408 | 	va_start(args, fmt); | 
 | 409 | 	len = vsnprintf((char *) &len, 1, fmt, args) + 1; | 
 | 410 | 	va_end(args); | 
 | 411 | 	va_start(args, fmt); | 
 | 412 | 	tomoyo_write_log2(r, len, fmt, args); | 
 | 413 | 	va_end(args); | 
 | 414 | } | 
 | 415 |  | 
 | 416 | /** | 
 | 417 |  * tomoyo_read_log - Read an audit log. | 
 | 418 |  * | 
 | 419 |  * @head: Pointer to "struct tomoyo_io_buffer". | 
 | 420 |  * | 
 | 421 |  * Returns nothing. | 
 | 422 |  */ | 
 | 423 | void tomoyo_read_log(struct tomoyo_io_buffer *head) | 
 | 424 | { | 
 | 425 | 	struct tomoyo_log *ptr = NULL; | 
 | 426 | 	if (head->r.w_pos) | 
 | 427 | 		return; | 
 | 428 | 	kfree(head->read_buf); | 
 | 429 | 	head->read_buf = NULL; | 
 | 430 | 	spin_lock(&tomoyo_log_lock); | 
 | 431 | 	if (!list_empty(&tomoyo_log)) { | 
 | 432 | 		ptr = list_entry(tomoyo_log.next, typeof(*ptr), list); | 
 | 433 | 		list_del(&ptr->list); | 
 | 434 | 		tomoyo_log_count--; | 
 | 435 | 		tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size; | 
 | 436 | 	} | 
 | 437 | 	spin_unlock(&tomoyo_log_lock); | 
 | 438 | 	if (ptr) { | 
 | 439 | 		head->read_buf = ptr->log; | 
 | 440 | 		head->r.w[head->r.w_pos++] = head->read_buf; | 
 | 441 | 		kfree(ptr); | 
 | 442 | 	} | 
 | 443 | } | 
 | 444 |  | 
 | 445 | /** | 
 | 446 |  * tomoyo_poll_log - Wait for an audit log. | 
 | 447 |  * | 
 | 448 |  * @file: Pointer to "struct file". | 
 | 449 |  * @wait: Pointer to "poll_table". | 
 | 450 |  * | 
 | 451 |  * Returns POLLIN | POLLRDNORM when ready to read an audit log. | 
 | 452 |  */ | 
 | 453 | int tomoyo_poll_log(struct file *file, poll_table *wait) | 
 | 454 | { | 
 | 455 | 	if (tomoyo_log_count) | 
 | 456 | 		return POLLIN | POLLRDNORM; | 
 | 457 | 	poll_wait(file, &tomoyo_log_wait, wait); | 
 | 458 | 	if (tomoyo_log_count) | 
 | 459 | 		return POLLIN | POLLRDNORM; | 
 | 460 | 	return 0; | 
 | 461 | } |