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