Commit | Line | Data |
---|---|---|
cb72d382 HD |
1 | /* |
2 | * CALIPSO - Common Architecture Label IPv6 Security Option | |
3 | * | |
4 | * This is an implementation of the CALIPSO protocol as specified in | |
5 | * RFC 5570. | |
6 | * | |
7 | * Authors: Paul Moore <paul.moore@hp.com> | |
8 | * Huw Davies <huw@codeweavers.com> | |
9 | * | |
10 | */ | |
11 | ||
12 | /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 | |
13 | * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015 | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or modify | |
16 | * it under the terms of the GNU General Public License as published by | |
17 | * the Free Software Foundation; either version 2 of the License, or | |
18 | * (at your option) any later version. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
23 | * the GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
27 | * | |
28 | */ | |
29 | ||
30 | #include <linux/init.h> | |
31 | #include <linux/types.h> | |
32 | #include <linux/rcupdate.h> | |
33 | #include <linux/list.h> | |
34 | #include <linux/spinlock.h> | |
35 | #include <linux/string.h> | |
36 | #include <linux/jhash.h> | |
37 | #include <linux/audit.h> | |
38 | #include <linux/slab.h> | |
39 | #include <net/ip.h> | |
40 | #include <net/icmp.h> | |
41 | #include <net/tcp.h> | |
42 | #include <net/netlabel.h> | |
43 | #include <net/calipso.h> | |
44 | #include <linux/atomic.h> | |
45 | #include <linux/bug.h> | |
46 | #include <asm/unaligned.h> | |
47 | ||
48 | /* List of available DOI definitions */ | |
49 | static DEFINE_SPINLOCK(calipso_doi_list_lock); | |
50 | static LIST_HEAD(calipso_doi_list); | |
51 | ||
52 | /* DOI List Functions | |
53 | */ | |
54 | ||
55 | /** | |
56 | * calipso_doi_search - Searches for a DOI definition | |
57 | * @doi: the DOI to search for | |
58 | * | |
59 | * Description: | |
60 | * Search the DOI definition list for a DOI definition with a DOI value that | |
61 | * matches @doi. The caller is responsible for calling rcu_read_[un]lock(). | |
62 | * Returns a pointer to the DOI definition on success and NULL on failure. | |
63 | */ | |
64 | static struct calipso_doi *calipso_doi_search(u32 doi) | |
65 | { | |
66 | struct calipso_doi *iter; | |
67 | ||
68 | list_for_each_entry_rcu(iter, &calipso_doi_list, list) | |
69 | if (iter->doi == doi && atomic_read(&iter->refcount)) | |
70 | return iter; | |
71 | return NULL; | |
72 | } | |
73 | ||
74 | /** | |
75 | * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine | |
76 | * @doi_def: the DOI structure | |
77 | * @audit_info: NetLabel audit information | |
78 | * | |
79 | * Description: | |
80 | * The caller defines a new DOI for use by the CALIPSO engine and calls this | |
81 | * function to add it to the list of acceptable domains. The caller must | |
82 | * ensure that the mapping table specified in @doi_def->map meets all of the | |
83 | * requirements of the mapping type (see calipso.h for details). Returns | |
84 | * zero on success and non-zero on failure. | |
85 | * | |
86 | */ | |
87 | static int calipso_doi_add(struct calipso_doi *doi_def, | |
88 | struct netlbl_audit *audit_info) | |
89 | { | |
90 | int ret_val = -EINVAL; | |
91 | u32 doi; | |
92 | u32 doi_type; | |
93 | struct audit_buffer *audit_buf; | |
94 | ||
95 | doi = doi_def->doi; | |
96 | doi_type = doi_def->type; | |
97 | ||
98 | if (doi_def->doi == CALIPSO_DOI_UNKNOWN) | |
99 | goto doi_add_return; | |
100 | ||
101 | atomic_set(&doi_def->refcount, 1); | |
102 | ||
103 | spin_lock(&calipso_doi_list_lock); | |
104 | if (calipso_doi_search(doi_def->doi)) { | |
105 | spin_unlock(&calipso_doi_list_lock); | |
106 | ret_val = -EEXIST; | |
107 | goto doi_add_return; | |
108 | } | |
109 | list_add_tail_rcu(&doi_def->list, &calipso_doi_list); | |
110 | spin_unlock(&calipso_doi_list_lock); | |
111 | ret_val = 0; | |
112 | ||
113 | doi_add_return: | |
114 | audit_buf = netlbl_audit_start(AUDIT_MAC_CALIPSO_ADD, audit_info); | |
115 | if (audit_buf) { | |
116 | const char *type_str; | |
117 | ||
118 | switch (doi_type) { | |
119 | case CALIPSO_MAP_PASS: | |
120 | type_str = "pass"; | |
121 | break; | |
122 | default: | |
123 | type_str = "(unknown)"; | |
124 | } | |
125 | audit_log_format(audit_buf, | |
126 | " calipso_doi=%u calipso_type=%s res=%u", | |
127 | doi, type_str, ret_val == 0 ? 1 : 0); | |
128 | audit_log_end(audit_buf); | |
129 | } | |
130 | ||
131 | return ret_val; | |
132 | } | |
133 | ||
134 | /** | |
135 | * calipso_doi_free - Frees a DOI definition | |
136 | * @doi_def: the DOI definition | |
137 | * | |
138 | * Description: | |
139 | * This function frees all of the memory associated with a DOI definition. | |
140 | * | |
141 | */ | |
142 | static void calipso_doi_free(struct calipso_doi *doi_def) | |
143 | { | |
144 | kfree(doi_def); | |
145 | } | |
146 | ||
a5e34490 HD |
147 | /** |
148 | * calipso_doi_free_rcu - Frees a DOI definition via the RCU pointer | |
149 | * @entry: the entry's RCU field | |
150 | * | |
151 | * Description: | |
152 | * This function is designed to be used as a callback to the call_rcu() | |
153 | * function so that the memory allocated to the DOI definition can be released | |
154 | * safely. | |
155 | * | |
156 | */ | |
157 | static void calipso_doi_free_rcu(struct rcu_head *entry) | |
158 | { | |
159 | struct calipso_doi *doi_def; | |
160 | ||
161 | doi_def = container_of(entry, struct calipso_doi, rcu); | |
162 | calipso_doi_free(doi_def); | |
163 | } | |
164 | ||
165 | /** | |
166 | * calipso_doi_getdef - Returns a reference to a valid DOI definition | |
167 | * @doi: the DOI value | |
168 | * | |
169 | * Description: | |
170 | * Searches for a valid DOI definition and if one is found it is returned to | |
171 | * the caller. Otherwise NULL is returned. The caller must ensure that | |
172 | * calipso_doi_putdef() is called when the caller is done. | |
173 | * | |
174 | */ | |
175 | static struct calipso_doi *calipso_doi_getdef(u32 doi) | |
176 | { | |
177 | struct calipso_doi *doi_def; | |
178 | ||
179 | rcu_read_lock(); | |
180 | doi_def = calipso_doi_search(doi); | |
181 | if (!doi_def) | |
182 | goto doi_getdef_return; | |
183 | if (!atomic_inc_not_zero(&doi_def->refcount)) | |
184 | doi_def = NULL; | |
185 | ||
186 | doi_getdef_return: | |
187 | rcu_read_unlock(); | |
188 | return doi_def; | |
189 | } | |
190 | ||
191 | /** | |
192 | * calipso_doi_putdef - Releases a reference for the given DOI definition | |
193 | * @doi_def: the DOI definition | |
194 | * | |
195 | * Description: | |
196 | * Releases a DOI definition reference obtained from calipso_doi_getdef(). | |
197 | * | |
198 | */ | |
199 | static void calipso_doi_putdef(struct calipso_doi *doi_def) | |
200 | { | |
201 | if (!doi_def) | |
202 | return; | |
203 | ||
204 | if (!atomic_dec_and_test(&doi_def->refcount)) | |
205 | return; | |
206 | spin_lock(&calipso_doi_list_lock); | |
207 | list_del_rcu(&doi_def->list); | |
208 | spin_unlock(&calipso_doi_list_lock); | |
209 | ||
210 | call_rcu(&doi_def->rcu, calipso_doi_free_rcu); | |
211 | } | |
212 | ||
cb72d382 HD |
213 | static const struct netlbl_calipso_ops ops = { |
214 | .doi_add = calipso_doi_add, | |
215 | .doi_free = calipso_doi_free, | |
a5e34490 HD |
216 | .doi_getdef = calipso_doi_getdef, |
217 | .doi_putdef = calipso_doi_putdef, | |
cb72d382 HD |
218 | }; |
219 | ||
220 | /** | |
221 | * calipso_init - Initialize the CALIPSO module | |
222 | * | |
223 | * Description: | |
224 | * Initialize the CALIPSO module and prepare it for use. Returns zero on | |
225 | * success and negative values on failure. | |
226 | * | |
227 | */ | |
228 | int __init calipso_init(void) | |
229 | { | |
230 | netlbl_calipso_ops_register(&ops); | |
231 | return 0; | |
232 | } | |
233 | ||
234 | void calipso_exit(void) | |
235 | { | |
236 | netlbl_calipso_ops_register(NULL); | |
237 | } |