Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
audit.c
Go to the documentation of this file.
1 /*
2  * security/tomoyo/audit.c
3  *
4  * Copyright (C) 2005-2011 NTT DATA CORPORATION
5  */
6 
7 #include "common.h"
8 #include <linux/slab.h>
9 
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 
115 static inline const char *tomoyo_filetype(const umode_t mode)
116 {
117  switch (mode & S_IFMT) {
118  case S_IFREG:
119  case 0:
121  case S_IFDIR:
123  case S_IFLNK:
125  case S_IFIFO:
127  case S_IFSOCK:
129  case S_IFBLK:
131  case S_IFCHR:
133  }
134  return "unknown"; /* This should not happen. */
135 }
136 
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);
151  struct tomoyo_obj_info *obj = r->obj;
152  static const int tomoyo_buffer_len = 4096;
153  char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
154  int pos;
155  u8 i;
156  if (!buffer)
157  return NULL;
158  {
159  struct timeval tv;
160  do_gettimeofday(&tv);
161  tomoyo_convert_time(tv.tv_sec, &stamp);
162  }
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(),
179  if (!obj)
180  goto no_obj_info;
181  if (!obj->validate_done) {
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  if (!obj->stat_valid[i])
190  continue;
191  stat = &obj->stat[i];
192  dev = stat->dev;
193  mode = stat->mode;
194  if (i & 1) {
195  pos += snprintf(buffer + pos,
196  tomoyo_buffer_len - 1 - pos,
197  " path%u.parent={ uid=%u gid=%u "
198  "ino=%lu perm=0%o }", (i >> 1) + 1,
199  from_kuid(&init_user_ns, stat->uid),
200  from_kgid(&init_user_ns, stat->gid),
201  (unsigned long)stat->ino,
202  stat->mode & S_IALLUGO);
203  continue;
204  }
205  pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
206  " path%u={ uid=%u gid=%u ino=%lu major=%u"
207  " minor=%u perm=0%o type=%s", (i >> 1) + 1,
208  from_kuid(&init_user_ns, stat->uid),
209  from_kgid(&init_user_ns, stat->gid),
210  (unsigned long)stat->ino,
211  MAJOR(dev), MINOR(dev),
212  mode & S_IALLUGO, tomoyo_filetype(mode));
213  if (S_ISCHR(mode) || S_ISBLK(mode)) {
214  dev = stat->rdev;
215  pos += snprintf(buffer + pos,
216  tomoyo_buffer_len - 1 - pos,
217  " dev_major=%u dev_minor=%u",
218  MAJOR(dev), MINOR(dev));
219  }
220  pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
221  " }");
222  }
223 no_obj_info:
224  if (pos < tomoyo_buffer_len - 1)
225  return buffer;
226  kfree(buffer);
227  return NULL;
228 }
229 
243 char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
244  va_list args)
245 {
246  char *buf = NULL;
247  char *bprm_info = NULL;
248  const char *header = NULL;
249  char *realpath = NULL;
250  const char *symlink = NULL;
251  int pos;
252  const char *domainname = r->domain->domainname->name;
253  header = tomoyo_print_header(r);
254  if (!header)
255  return NULL;
256  /* +10 is for '\n' etc. and '\0'. */
257  len += strlen(domainname) + strlen(header) + 10;
258  if (r->ee) {
259  struct file *file = r->ee->bprm->file;
260  realpath = tomoyo_realpath_from_path(&file->f_path);
261  bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
262  if (!realpath || !bprm_info)
263  goto out;
264  /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
265  len += strlen(realpath) + 80 + strlen(bprm_info);
266  } else if (r->obj && r->obj->symlink_target) {
267  symlink = r->obj->symlink_target->name;
268  /* +18 is for " symlink.target=\"%s\"" */
269  len += 18 + strlen(symlink);
270  }
271  len = tomoyo_round2(len);
272  buf = kzalloc(len, GFP_NOFS);
273  if (!buf)
274  goto out;
275  len--;
276  pos = snprintf(buf, len, "%s", header);
277  if (realpath) {
278  struct linux_binprm *bprm = r->ee->bprm;
279  pos += snprintf(buf + pos, len - pos,
280  " exec={ realpath=\"%s\" argc=%d envc=%d %s }",
281  realpath, bprm->argc, bprm->envc, bprm_info);
282  } else if (symlink)
283  pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
284  symlink);
285  pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
286  vsnprintf(buf + pos, len - pos, fmt, args);
287 out:
288  kfree(realpath);
289  kfree(bprm_info);
290  kfree(header);
291  return buf;
292 }
293 
294 /* Wait queue for /sys/kernel/security/tomoyo/audit. */
295 static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait);
296 
297 /* Structure for audit log. */
298 struct tomoyo_log {
299  struct list_head list;
300  char *log;
301  int size;
302 };
303 
304 /* The list for "struct tomoyo_log". */
305 static LIST_HEAD(tomoyo_log);
306 
307 /* Lock for "struct list_head tomoyo_log". */
308 static DEFINE_SPINLOCK(tomoyo_log_lock);
309 
310 /* Length of "stuct list_head tomoyo_log". */
311 static unsigned int tomoyo_log_count;
312 
323 static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
324  const u8 profile, const u8 index,
325  const struct tomoyo_acl_info *matched_acl,
326  const bool is_granted)
327 {
328  u8 mode;
331  struct tomoyo_profile *p;
333  return false;
334  p = tomoyo_profile(ns, profile);
335  if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
336  return false;
337  if (is_granted && matched_acl && matched_acl->cond &&
338  matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
339  return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
340  mode = p->config[index];
341  if (mode == TOMOYO_CONFIG_USE_DEFAULT)
342  mode = p->config[category];
343  if (mode == TOMOYO_CONFIG_USE_DEFAULT)
344  mode = p->default_config;
345  if (is_granted)
346  return mode & TOMOYO_CONFIG_WANT_GRANT_LOG;
347  return mode & TOMOYO_CONFIG_WANT_REJECT_LOG;
348 }
349 
360 void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
361  va_list args)
362 {
363  char *buf;
364  struct tomoyo_log *entry;
365  bool quota_exceeded = false;
366  if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
367  r->matched_acl, r->granted))
368  goto out;
369  buf = tomoyo_init_log(r, len, fmt, args);
370  if (!buf)
371  goto out;
372  entry = kzalloc(sizeof(*entry), GFP_NOFS);
373  if (!entry) {
374  kfree(buf);
375  goto out;
376  }
377  entry->log = buf;
378  len = tomoyo_round2(strlen(buf) + 1);
379  /*
380  * The entry->size is used for memory quota checks.
381  * Don't go beyond strlen(entry->log).
382  */
383  entry->size = len + tomoyo_round2(sizeof(*entry));
384  spin_lock(&tomoyo_log_lock);
388  quota_exceeded = true;
389  } else {
391  list_add_tail(&entry->list, &tomoyo_log);
392  tomoyo_log_count++;
393  }
394  spin_unlock(&tomoyo_log_lock);
395  if (quota_exceeded) {
396  kfree(buf);
397  kfree(entry);
398  goto out;
399  }
400  wake_up(&tomoyo_log_wait);
401 out:
402  return;
403 }
404 
413 void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
414 {
415  va_list args;
416  int len;
417  va_start(args, fmt);
418  len = vsnprintf((char *) &len, 1, fmt, args) + 1;
419  va_end(args);
420  va_start(args, fmt);
421  tomoyo_write_log2(r, len, fmt, args);
422  va_end(args);
423 }
424 
433 {
434  struct tomoyo_log *ptr = NULL;
435  if (head->r.w_pos)
436  return;
437  kfree(head->read_buf);
438  head->read_buf = NULL;
439  spin_lock(&tomoyo_log_lock);
440  if (!list_empty(&tomoyo_log)) {
441  ptr = list_entry(tomoyo_log.next, typeof(*ptr), list);
442  list_del(&ptr->list);
443  tomoyo_log_count--;
445  }
446  spin_unlock(&tomoyo_log_lock);
447  if (ptr) {
448  head->read_buf = ptr->log;
449  head->r.w[head->r.w_pos++] = head->read_buf;
450  kfree(ptr);
451  }
452 }
453 
462 unsigned int tomoyo_poll_log(struct file *file, poll_table *wait)
463 {
464  if (tomoyo_log_count)
465  return POLLIN | POLLRDNORM;
466  poll_wait(file, &tomoyo_log_wait, wait);
467  if (tomoyo_log_count)
468  return POLLIN | POLLRDNORM;
469  return 0;
470 }