Blame view

security/apparmor/capability.c 3.74 KB
0ed3b28ab   John Johansen   AppArmor: mediati...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /*
   * AppArmor security module
   *
   * This file contains AppArmor capability mediation functions
   *
   * Copyright (C) 1998-2008 Novell/SUSE
   * Copyright 2009-2010 Canonical Ltd.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation, version 2 of the
   * License.
   */
  
  #include <linux/capability.h>
  #include <linux/errno.h>
  #include <linux/gfp.h>
  
  #include "include/apparmor.h"
  #include "include/capability.h"
  #include "include/context.h"
  #include "include/policy.h"
  #include "include/audit.h"
  
  /*
   * Table of capability names: we generate it from capabilities.h.
   */
  #include "capability_names.h"
84f1f7874   John Johansen   apparmor: export ...
29
30
31
32
  struct aa_fs_entry aa_fs_entry_caps[] = {
  	AA_FS_FILE_STRING("mask", AA_FS_CAPS_MASK),
  	{ }
  };
0ed3b28ab   John Johansen   AppArmor: mediati...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  struct audit_cache {
  	struct aa_profile *profile;
  	kernel_cap_t caps;
  };
  
  static DEFINE_PER_CPU(struct audit_cache, audit_cache);
  
  /**
   * audit_cb - call back for capability components of audit struct
   * @ab - audit buffer   (NOT NULL)
   * @va - audit struct to audit data from  (NOT NULL)
   */
  static void audit_cb(struct audit_buffer *ab, void *va)
  {
  	struct common_audit_data *sa = va;
  	audit_log_format(ab, " capname=");
  	audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
  }
  
  /**
   * audit_caps - audit a capability
dd0c6e86f   John Johansen   apparmor: fix cap...
54
   * @profile: profile being tested for confinement (NOT NULL)
0ed3b28ab   John Johansen   AppArmor: mediati...
55
56
57
58
59
60
61
62
   * @cap: capability tested
   * @error: error code returned by test
   *
   * Do auditing of capability and handle, audit/complain/kill modes switching
   * and duplicate message elimination.
   *
   * Returns: 0 or sa->error on success,  error code on failure
   */
dd0c6e86f   John Johansen   apparmor: fix cap...
63
  static int audit_caps(struct aa_profile *profile, int cap, int error)
0ed3b28ab   John Johansen   AppArmor: mediati...
64
65
66
67
  {
  	struct audit_cache *ent;
  	int type = AUDIT_APPARMOR_AUTO;
  	struct common_audit_data sa;
3b3b0e4fc   Eric Paris   LSM: shrink sizeo...
68
  	struct apparmor_audit_data aad = {0,};
50c205f5e   Eric Paris   LSM: do not initi...
69
  	sa.type = LSM_AUDIT_DATA_CAP;
3b3b0e4fc   Eric Paris   LSM: shrink sizeo...
70
  	sa.aad = &aad;
0ed3b28ab   John Johansen   AppArmor: mediati...
71
  	sa.u.cap = cap;
3b3b0e4fc   Eric Paris   LSM: shrink sizeo...
72
73
  	sa.aad->op = OP_CAPABLE;
  	sa.aad->error = error;
0ed3b28ab   John Johansen   AppArmor: mediati...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  
  	if (likely(!error)) {
  		/* test if auditing is being forced */
  		if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
  			   !cap_raised(profile->caps.audit, cap)))
  			return 0;
  		type = AUDIT_APPARMOR_AUDIT;
  	} else if (KILL_MODE(profile) ||
  		   cap_raised(profile->caps.kill, cap)) {
  		type = AUDIT_APPARMOR_KILL;
  	} else if (cap_raised(profile->caps.quiet, cap) &&
  		   AUDIT_MODE(profile) != AUDIT_NOQUIET &&
  		   AUDIT_MODE(profile) != AUDIT_ALL) {
  		/* quiet auditing */
  		return error;
  	}
  
  	/* Do simple duplicate message elimination */
  	ent = &get_cpu_var(audit_cache);
  	if (profile == ent->profile && cap_raised(ent->caps, cap)) {
  		put_cpu_var(audit_cache);
  		if (COMPLAIN_MODE(profile))
  			return complain_error(error);
  		return error;
  	} else {
  		aa_put_profile(ent->profile);
  		ent->profile = aa_get_profile(profile);
  		cap_raise(ent->caps, cap);
  	}
  	put_cpu_var(audit_cache);
  
  	return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
  }
  
  /**
   * profile_capable - test if profile allows use of capability @cap
   * @profile: profile being enforced    (NOT NULL, NOT unconfined)
   * @cap: capability to test if allowed
   *
   * Returns: 0 if allowed else -EPERM
   */
  static int profile_capable(struct aa_profile *profile, int cap)
  {
  	return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
  }
  
  /**
   * aa_capable - test permission to use capability
dd0c6e86f   John Johansen   apparmor: fix cap...
122
   * @profile: profile being tested against (NOT NULL)
0ed3b28ab   John Johansen   AppArmor: mediati...
123
124
125
126
127
128
129
   * @cap: capability to be tested
   * @audit: whether an audit record should be generated
   *
   * Look up capability in profile capability set.
   *
   * Returns: 0 on success, or else an error code.
   */
dd0c6e86f   John Johansen   apparmor: fix cap...
130
  int aa_capable(struct aa_profile *profile, int cap, int audit)
0ed3b28ab   John Johansen   AppArmor: mediati...
131
132
133
134
135
136
137
138
  {
  	int error = profile_capable(profile, cap);
  
  	if (!audit) {
  		if (COMPLAIN_MODE(profile))
  			return complain_error(error);
  		return error;
  	}
dd0c6e86f   John Johansen   apparmor: fix cap...
139
  	return audit_caps(profile, cap, error);
0ed3b28ab   John Johansen   AppArmor: mediati...
140
  }