Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
domain.c
Go to the documentation of this file.
1 /*
2  * AppArmor security module
3  *
4  * This file contains AppArmor policy attachment and domain transitions
5  *
6  * Copyright (C) 2002-2008 Novell/SUSE
7  * Copyright 2009-2010 Canonical Ltd.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation, version 2 of the
12  * License.
13  */
14 
15 #include <linux/errno.h>
16 #include <linux/fdtable.h>
17 #include <linux/file.h>
18 #include <linux/mount.h>
19 #include <linux/syscalls.h>
20 #include <linux/tracehook.h>
21 #include <linux/personality.h>
22 
23 #include "include/audit.h"
24 #include "include/apparmorfs.h"
25 #include "include/context.h"
26 #include "include/domain.h"
27 #include "include/file.h"
28 #include "include/ipc.h"
29 #include "include/match.h"
30 #include "include/path.h"
31 #include "include/policy.h"
32 
37 void aa_free_domain_entries(struct aa_domain *domain)
38 {
39  int i;
40  if (domain) {
41  if (!domain->table)
42  return;
43 
44  for (i = 0; i < domain->size; i++)
45  kzfree(domain->table[i]);
46  kzfree(domain->table);
47  domain->table = NULL;
48  }
49 }
50 
61 static int may_change_ptraced_domain(struct task_struct *task,
62  struct aa_profile *to_profile)
63 {
64  struct task_struct *tracer;
65  const struct cred *cred = NULL;
66  struct aa_profile *tracerp = NULL;
67  int error = 0;
68 
69  rcu_read_lock();
70  tracer = ptrace_parent(task);
71  if (tracer) {
72  /* released below */
73  cred = get_task_cred(tracer);
74  tracerp = aa_cred_profile(cred);
75  }
76 
77  /* not ptraced */
78  if (!tracer || unconfined(tracerp))
79  goto out;
80 
81  error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
82 
83 out:
84  rcu_read_unlock();
85  if (cred)
86  put_cred(cred);
87 
88  return error;
89 }
90 
101 static struct file_perms change_profile_perms(struct aa_profile *profile,
102  struct aa_namespace *ns,
103  const char *name, u32 request,
104  unsigned int start)
105 {
106  struct file_perms perms;
107  struct path_cond cond = { };
108  unsigned int state;
109 
110  if (unconfined(profile)) {
111  perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
112  perms.audit = perms.quiet = perms.kill = 0;
113  return perms;
114  } else if (!profile->file.dfa) {
115  return nullperms;
116  } else if ((ns == profile->ns)) {
117  /* try matching against rules with out namespace prepended */
118  aa_str_perms(profile->file.dfa, start, name, &cond, &perms);
119  if (COMBINED_PERM_MASK(perms) & request)
120  return perms;
121  }
122 
123  /* try matching with namespace name and then profile */
124  state = aa_dfa_match(profile->file.dfa, start, ns->base.name);
125  state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
126  aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
127 
128  return perms;
129 }
130 
145 static struct aa_profile *__attach_match(const char *name,
146  struct list_head *head)
147 {
148  int len = 0;
149  struct aa_profile *profile, *candidate = NULL;
150 
151  list_for_each_entry(profile, head, base.list) {
152  if (profile->flags & PFLAG_NULL)
153  continue;
154  if (profile->xmatch && profile->xmatch_len > len) {
155  unsigned int state = aa_dfa_match(profile->xmatch,
156  DFA_START, name);
157  u32 perm = dfa_user_allow(profile->xmatch, state);
158  /* any accepting state means a valid match. */
159  if (perm & MAY_EXEC) {
160  candidate = profile;
161  len = profile->xmatch_len;
162  }
163  } else if (!strcmp(profile->base.name, name))
164  /* exact non-re match, no more searching required */
165  return profile;
166  }
167 
168  return candidate;
169 }
170 
179 static struct aa_profile *find_attach(struct aa_namespace *ns,
180  struct list_head *list, const char *name)
181 {
182  struct aa_profile *profile;
183 
184  read_lock(&ns->lock);
185  profile = aa_get_profile(__attach_match(name, list));
186  read_unlock(&ns->lock);
187 
188  return profile;
189 }
190 
212 static const char *separate_fqname(const char *fqname, const char **ns_name)
213 {
214  const char *name;
215 
216  if (fqname[0] == ':') {
217  /* In this case there is guaranteed to be two \0 terminators
218  * in the string. They are verified at load time by
219  * by unpack_trans_table
220  */
221  *ns_name = fqname + 1; /* skip : */
222  name = *ns_name + strlen(*ns_name) + 1;
223  if (!*name)
224  name = NULL;
225  } else {
226  *ns_name = NULL;
227  name = fqname;
228  }
229 
230  return name;
231 }
232 
233 static const char *next_name(int xtype, const char *name)
234 {
235  return NULL;
236 }
237 
245 static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
246 {
247  struct aa_profile *new_profile = NULL;
248  struct aa_namespace *ns = profile->ns;
249  u32 xtype = xindex & AA_X_TYPE_MASK;
250  int index = xindex & AA_X_INDEX_MASK;
251  const char *name;
252 
253  /* index is guaranteed to be in range, validated at load time */
254  for (name = profile->file.trans.table[index]; !new_profile && name;
255  name = next_name(xtype, name)) {
256  struct aa_namespace *new_ns;
257  const char *xname = NULL;
258 
259  new_ns = NULL;
260  if (xindex & AA_X_CHILD) {
261  /* release by caller */
262  new_profile = aa_find_child(profile, name);
263  continue;
264  } else if (*name == ':') {
265  /* switching namespace */
266  const char *ns_name;
267  xname = name = separate_fqname(name, &ns_name);
268  if (!xname)
269  /* no name so use profile name */
270  xname = profile->base.hname;
271  if (*ns_name == '@') {
272  /* TODO: variable support */
273  ;
274  }
275  /* released below */
276  new_ns = aa_find_namespace(ns, ns_name);
277  if (!new_ns)
278  continue;
279  } else if (*name == '@') {
280  /* TODO: variable support */
281  continue;
282  } else {
283  /* basic namespace lookup */
284  xname = name;
285  }
286 
287  /* released by caller */
288  new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname);
289  aa_put_namespace(new_ns);
290  }
291 
292  /* released by caller */
293  return new_profile;
294 }
295 
306 static struct aa_profile *x_to_profile(struct aa_profile *profile,
307  const char *name, u32 xindex)
308 {
309  struct aa_profile *new_profile = NULL;
310  struct aa_namespace *ns = profile->ns;
311  u32 xtype = xindex & AA_X_TYPE_MASK;
312 
313  switch (xtype) {
314  case AA_X_NONE:
315  /* fail exec unless ix || ux fallback - handled by caller */
316  return NULL;
317  case AA_X_NAME:
318  if (xindex & AA_X_CHILD)
319  /* released by caller */
320  new_profile = find_attach(ns, &profile->base.profiles,
321  name);
322  else
323  /* released by caller */
324  new_profile = find_attach(ns, &ns->base.profiles,
325  name);
326  break;
327  case AA_X_TABLE:
328  /* released by caller */
329  new_profile = x_table_lookup(profile, xindex);
330  break;
331  }
332 
333  /* released by caller */
334  return new_profile;
335 }
336 
344 {
345  struct aa_task_cxt *cxt;
346  struct aa_profile *profile, *new_profile = NULL;
347  struct aa_namespace *ns;
348  char *buffer = NULL;
349  unsigned int state;
350  struct file_perms perms = {};
351  struct path_cond cond = {
352  bprm->file->f_path.dentry->d_inode->i_uid,
353  bprm->file->f_path.dentry->d_inode->i_mode
354  };
355  const char *name = NULL, *target = NULL, *info = NULL;
356  int error = cap_bprm_set_creds(bprm);
357  if (error)
358  return error;
359 
360  if (bprm->cred_prepared)
361  return 0;
362 
363  cxt = bprm->cred->security;
364  BUG_ON(!cxt);
365 
366  profile = aa_get_profile(aa_newest_version(cxt->profile));
367  /*
368  * get the namespace from the replacement profile as replacement
369  * can change the namespace
370  */
371  ns = profile->ns;
372  state = profile->file.start;
373 
374  /* buffer freed below, name is pointer into buffer */
375  error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer,
376  &name, &info);
377  if (error) {
378  if (profile->flags &
380  error = 0;
381  name = bprm->filename;
382  goto audit;
383  }
384 
385  /* Test for onexec first as onexec directives override other
386  * x transitions.
387  */
388  if (unconfined(profile)) {
389  /* unconfined task */
390  if (cxt->onexec)
391  /* change_profile on exec already been granted */
392  new_profile = aa_get_profile(cxt->onexec);
393  else
394  new_profile = find_attach(ns, &ns->base.profiles, name);
395  if (!new_profile)
396  goto cleanup;
397  /*
398  * NOTE: Domain transitions from unconfined are allowed
399  * even when no_new_privs is set because this aways results
400  * in a further reduction of permissions.
401  */
402  goto apply;
403  }
404 
405  /* find exec permissions for name */
406  state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
407  if (cxt->onexec) {
408  struct file_perms cp;
409  info = "change_profile onexec";
410  if (!(perms.allow & AA_MAY_ONEXEC))
411  goto audit;
412 
413  /* test if this exec can be paired with change_profile onexec.
414  * onexec permission is linked to exec with a standard pairing
415  * exec\0change_profile
416  */
417  state = aa_dfa_null_transition(profile->file.dfa, state);
418  cp = change_profile_perms(profile, cxt->onexec->ns,
419  cxt->onexec->base.name,
420  AA_MAY_ONEXEC, state);
421 
422  if (!(cp.allow & AA_MAY_ONEXEC))
423  goto audit;
424  new_profile = aa_get_profile(aa_newest_version(cxt->onexec));
425  goto apply;
426  }
427 
428  if (perms.allow & MAY_EXEC) {
429  /* exec permission determine how to transition */
430  new_profile = x_to_profile(profile, name, perms.xindex);
431  if (!new_profile) {
432  if (perms.xindex & AA_X_INHERIT) {
433  /* (p|c|n)ix - don't change profile but do
434  * use the newest version, which was picked
435  * up above when getting profile
436  */
437  info = "ix fallback";
438  new_profile = aa_get_profile(profile);
439  goto x_clear;
440  } else if (perms.xindex & AA_X_UNCONFINED) {
441  new_profile = aa_get_profile(ns->unconfined);
442  info = "ux fallback";
443  } else {
444  error = -ENOENT;
445  info = "profile not found";
446  }
447  }
448  } else if (COMPLAIN_MODE(profile)) {
449  /* no exec permission - are we in learning mode */
450  new_profile = aa_new_null_profile(profile, 0);
451  if (!new_profile) {
452  error = -ENOMEM;
453  info = "could not create null profile";
454  } else {
455  error = -EACCES;
456  target = new_profile->base.hname;
457  }
458  perms.xindex |= AA_X_UNSAFE;
459  } else
460  /* fail exec */
461  error = -EACCES;
462 
463  /*
464  * Policy has specified a domain transition, if no_new_privs then
465  * fail the exec.
466  */
467  if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) {
468  aa_put_profile(new_profile);
469  error = -EPERM;
470  goto cleanup;
471  }
472 
473  if (!new_profile)
474  goto audit;
475 
476  if (bprm->unsafe & LSM_UNSAFE_SHARE) {
477  /* FIXME: currently don't mediate shared state */
478  ;
479  }
480 
482  error = may_change_ptraced_domain(current, new_profile);
483  if (error) {
484  aa_put_profile(new_profile);
485  goto audit;
486  }
487  }
488 
489  /* Determine if secure exec is needed.
490  * Can be at this point for the following reasons:
491  * 1. unconfined switching to confined
492  * 2. confined switching to different confinement
493  * 3. confined switching to unconfined
494  *
495  * Cases 2 and 3 are marked as requiring secure exec
496  * (unless policy specified "unsafe exec")
497  *
498  * bprm->unsafe is used to cache the AA_X_UNSAFE permission
499  * to avoid having to recompute in secureexec
500  */
501  if (!(perms.xindex & AA_X_UNSAFE)) {
502  AA_DEBUG("scrubbing environment variables for %s profile=%s\n",
503  name, new_profile->base.hname);
504  bprm->unsafe |= AA_SECURE_X_NEEDED;
505  }
506 apply:
507  target = new_profile->base.hname;
508  /* when transitioning profiles clear unsafe personality bits */
509  bprm->per_clear |= PER_CLEAR_ON_SETID;
510 
511 x_clear:
512  aa_put_profile(cxt->profile);
513  /* transfer new profile reference will be released when cxt is freed */
514  cxt->profile = new_profile;
515 
516  /* clear out all temporary/transitional state from the context */
517  aa_put_profile(cxt->previous);
518  aa_put_profile(cxt->onexec);
519  cxt->previous = NULL;
520  cxt->onexec = NULL;
521  cxt->token = 0;
522 
523 audit:
524  error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
525  name, target, cond.uid, info, error);
526 
527 cleanup:
528  aa_put_profile(profile);
529  kfree(buffer);
530 
531  return error;
532 }
533 
541 {
542  int ret = cap_bprm_secureexec(bprm);
543 
544  /* the decision to use secure exec is computed in set_creds
545  * and stored in bprm->unsafe.
546  */
547  if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
548  ret = 1;
549 
550  return ret;
551 }
552 
558 {
559  struct aa_profile *profile = __aa_current_profile();
560  struct aa_task_cxt *new_cxt = bprm->cred->security;
561 
562  /* bail out if unconfined or not changing profile */
563  if ((new_cxt->profile == profile) ||
564  (unconfined(new_cxt->profile)))
565  return;
566 
567  current->pdeath_signal = 0;
568 
569  /* reset soft limits and set hard limits for the new profile */
570  __aa_transition_rlimits(profile, new_cxt->profile);
571 }
572 
578 {
579  /* TODO: cleanup signals - ipc mediation */
580  return;
581 }
582 
583 /*
584  * Functions for self directed profile change
585  */
586 
594 static char *new_compound_name(const char *n1, const char *n2)
595 {
596  char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL);
597  if (name)
598  sprintf(name, "%s//%s", n1, n2);
599  return name;
600 }
601 
616 int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
617 {
618  const struct cred *cred;
619  struct aa_task_cxt *cxt;
620  struct aa_profile *profile, *previous_profile, *hat = NULL;
621  char *name = NULL;
622  int i;
623  struct file_perms perms = {};
624  const char *target = NULL, *info = NULL;
625  int error = 0;
626 
627  /*
628  * Fail explicitly requested domain transitions if no_new_privs.
629  * There is no exception for unconfined as change_hat is not
630  * available.
631  */
632  if (current->no_new_privs)
633  return -EPERM;
634 
635  /* released below */
636  cred = get_current_cred();
637  cxt = cred->security;
638  profile = aa_cred_profile(cred);
639  previous_profile = cxt->previous;
640 
641  if (unconfined(profile)) {
642  info = "unconfined";
643  error = -EPERM;
644  goto audit;
645  }
646 
647  if (count) {
648  /* attempting to change into a new hat or switch to a sibling */
649  struct aa_profile *root;
650  root = PROFILE_IS_HAT(profile) ? profile->parent : profile;
651 
652  /* find first matching hat */
653  for (i = 0; i < count && !hat; i++)
654  /* released below */
655  hat = aa_find_child(root, hats[i]);
656  if (!hat) {
657  if (!COMPLAIN_MODE(root) || permtest) {
658  if (list_empty(&root->base.profiles))
659  error = -ECHILD;
660  else
661  error = -ENOENT;
662  goto out;
663  }
664 
665  /*
666  * In complain mode and failed to match any hats.
667  * Audit the failure is based off of the first hat
668  * supplied. This is done due how userspace
669  * interacts with change_hat.
670  *
671  * TODO: Add logging of all failed hats
672  */
673 
674  /* freed below */
675  name = new_compound_name(root->base.hname, hats[0]);
676  target = name;
677  /* released below */
678  hat = aa_new_null_profile(profile, 1);
679  if (!hat) {
680  info = "failed null profile create";
681  error = -ENOMEM;
682  goto audit;
683  }
684  } else {
685  target = hat->base.hname;
686  if (!PROFILE_IS_HAT(hat)) {
687  info = "target not hat";
688  error = -EPERM;
689  goto audit;
690  }
691  }
692 
693  error = may_change_ptraced_domain(current, hat);
694  if (error) {
695  info = "ptraced";
696  error = -EPERM;
697  goto audit;
698  }
699 
700  if (!permtest) {
701  error = aa_set_current_hat(hat, token);
702  if (error == -EACCES)
703  /* kill task in case of brute force attacks */
704  perms.kill = AA_MAY_CHANGEHAT;
705  else if (name && !error)
706  /* reset error for learning of new hats */
707  error = -ENOENT;
708  }
709  } else if (previous_profile) {
710  /* Return to saved profile. Kill task if restore fails
711  * to avoid brute force attacks
712  */
713  target = previous_profile->base.hname;
714  error = aa_restore_previous_profile(token);
715  perms.kill = AA_MAY_CHANGEHAT;
716  } else
717  /* ignore restores when there is no saved profile */
718  goto out;
719 
720 audit:
721  if (!permtest)
722  error = aa_audit_file(profile, &perms, GFP_KERNEL,
724  target, GLOBAL_ROOT_UID, info, error);
725 
726 out:
727  aa_put_profile(hat);
728  kfree(name);
729  put_cred(cred);
730 
731  return error;
732 }
733 
749 int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
750  bool permtest)
751 {
752  const struct cred *cred;
753  struct aa_task_cxt *cxt;
754  struct aa_profile *profile, *target = NULL;
755  struct aa_namespace *ns = NULL;
756  struct file_perms perms = {};
757  const char *name = NULL, *info = NULL;
758  int op, error = 0;
759  u32 request;
760 
761  if (!hname && !ns_name)
762  return -EINVAL;
763 
764  if (onexec) {
765  request = AA_MAY_ONEXEC;
766  op = OP_CHANGE_ONEXEC;
767  } else {
768  request = AA_MAY_CHANGE_PROFILE;
769  op = OP_CHANGE_PROFILE;
770  }
771 
772  cred = get_current_cred();
773  cxt = cred->security;
774  profile = aa_cred_profile(cred);
775 
776  /*
777  * Fail explicitly requested domain transitions if no_new_privs
778  * and not unconfined.
779  * Domain transitions from unconfined are allowed even when
780  * no_new_privs is set because this aways results in a reduction
781  * of permissions.
782  */
783  if (current->no_new_privs && !unconfined(profile)) {
784  put_cred(cred);
785  return -EPERM;
786  }
787 
788  if (ns_name) {
789  /* released below */
790  ns = aa_find_namespace(profile->ns, ns_name);
791  if (!ns) {
792  /* we don't create new namespace in complain mode */
793  name = ns_name;
794  info = "namespace not found";
795  error = -ENOENT;
796  goto audit;
797  }
798  } else
799  /* released below */
800  ns = aa_get_namespace(profile->ns);
801 
802  /* if the name was not specified, use the name of the current profile */
803  if (!hname) {
804  if (unconfined(profile))
805  hname = ns->unconfined->base.hname;
806  else
807  hname = profile->base.hname;
808  }
809 
810  perms = change_profile_perms(profile, ns, hname, request,
811  profile->file.start);
812  if (!(perms.allow & request)) {
813  error = -EACCES;
814  goto audit;
815  }
816 
817  /* released below */
818  target = aa_lookup_profile(ns, hname);
819  if (!target) {
820  info = "profile not found";
821  error = -ENOENT;
822  if (permtest || !COMPLAIN_MODE(profile))
823  goto audit;
824  /* released below */
825  target = aa_new_null_profile(profile, 0);
826  if (!target) {
827  info = "failed null profile create";
828  error = -ENOMEM;
829  goto audit;
830  }
831  }
832 
833  /* check if tracing task is allowed to trace target domain */
834  error = may_change_ptraced_domain(current, target);
835  if (error) {
836  info = "ptrace prevents transition";
837  goto audit;
838  }
839 
840  if (permtest)
841  goto audit;
842 
843  if (onexec)
844  error = aa_set_current_onexec(target);
845  else
846  error = aa_replace_current_profile(target);
847 
848 audit:
849  if (!permtest)
850  error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
851  name, hname, GLOBAL_ROOT_UID, info, error);
852 
853  aa_put_namespace(ns);
854  aa_put_profile(target);
855  put_cred(cred);
856 
857  return error;
858 }