aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel/netlabel_cipso_v4.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlabel/netlabel_cipso_v4.c')
-rw-r--r--net/netlabel/netlabel_cipso_v4.c628
1 files changed, 413 insertions, 215 deletions
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index a4f40adc447b..4125a55f469f 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -41,15 +41,37 @@
41#include "netlabel_user.h" 41#include "netlabel_user.h"
42#include "netlabel_cipso_v4.h" 42#include "netlabel_cipso_v4.h"
43 43
44/* Argument struct for cipso_v4_doi_walk() */
45struct netlbl_cipsov4_doiwalk_arg {
46 struct netlink_callback *nl_cb;
47 struct sk_buff *skb;
48 u32 seq;
49};
50
44/* NetLabel Generic NETLINK CIPSOv4 family */ 51/* NetLabel Generic NETLINK CIPSOv4 family */
45static struct genl_family netlbl_cipsov4_gnl_family = { 52static struct genl_family netlbl_cipsov4_gnl_family = {
46 .id = GENL_ID_GENERATE, 53 .id = GENL_ID_GENERATE,
47 .hdrsize = 0, 54 .hdrsize = 0,
48 .name = NETLBL_NLTYPE_CIPSOV4_NAME, 55 .name = NETLBL_NLTYPE_CIPSOV4_NAME,
49 .version = NETLBL_PROTO_VERSION, 56 .version = NETLBL_PROTO_VERSION,
50 .maxattr = 0, 57 .maxattr = NLBL_CIPSOV4_A_MAX,
51}; 58};
52 59
60/* NetLabel Netlink attribute policy */
61static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
62 [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
63 [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
64 [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
65 [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
66 [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
67 [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
68 [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
69 [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
70 [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
71 [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
72 [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
73 [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
74};
53 75
54/* 76/*
55 * Helper Functions 77 * Helper Functions
@@ -81,6 +103,41 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
81 kfree(ptr); 103 kfree(ptr);
82} 104}
83 105
106/**
107 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
108 * @info: the Generic NETLINK info block
109 * @doi_def: the CIPSO V4 DOI definition
110 *
111 * Description:
112 * Parse the common sections of a ADD message and fill in the related values
113 * in @doi_def. Returns zero on success, negative values on failure.
114 *
115 */
116static int netlbl_cipsov4_add_common(struct genl_info *info,
117 struct cipso_v4_doi *doi_def)
118{
119 struct nlattr *nla;
120 int nla_rem;
121 u32 iter = 0;
122
123 doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
124
125 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
126 NLBL_CIPSOV4_A_MAX,
127 netlbl_cipsov4_genl_policy) != 0)
128 return -EINVAL;
129
130 nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
131 if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
132 if (iter > CIPSO_V4_TAG_MAXCNT)
133 return -EINVAL;
134 doi_def->tags[iter++] = nla_get_u8(nla);
135 }
136 if (iter < CIPSO_V4_TAG_MAXCNT)
137 doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
138
139 return 0;
140}
84 141
85/* 142/*
86 * NetLabel Command Handlers 143 * NetLabel Command Handlers
@@ -88,9 +145,7 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
88 145
89/** 146/**
90 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition 147 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
91 * @doi: the DOI value 148 * @info: the Generic NETLINK info block
92 * @msg: the ADD message data
93 * @msg_size: the size of the ADD message buffer
94 * 149 *
95 * Description: 150 * Description:
96 * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message 151 * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
@@ -98,29 +153,28 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
98 * error. 153 * error.
99 * 154 *
100 */ 155 */
101static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size) 156static int netlbl_cipsov4_add_std(struct genl_info *info)
102{ 157{
103 int ret_val = -EINVAL; 158 int ret_val = -EINVAL;
104 int msg_len = msg_size;
105 u32 num_tags;
106 u32 num_lvls;
107 u32 num_cats;
108 struct cipso_v4_doi *doi_def = NULL; 159 struct cipso_v4_doi *doi_def = NULL;
109 u32 iter; 160 struct nlattr *nla_a;
110 u32 tmp_val_a; 161 struct nlattr *nla_b;
111 u32 tmp_val_b; 162 int nla_a_rem;
163 int nla_b_rem;
112 164
113 if (msg_len < NETLBL_LEN_U32) 165 if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
114 goto add_std_failure; 166 !info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
115 num_tags = netlbl_getinc_u32(&msg, &msg_len); 167 !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
116 if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT) 168 return -EINVAL;
117 goto add_std_failure; 169
170 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
171 NLBL_CIPSOV4_A_MAX,
172 netlbl_cipsov4_genl_policy) != 0)
173 return -EINVAL;
118 174
119 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); 175 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
120 if (doi_def == NULL) { 176 if (doi_def == NULL)
121 ret_val = -ENOMEM; 177 return -ENOMEM;
122 goto add_std_failure;
123 }
124 doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL); 178 doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
125 if (doi_def->map.std == NULL) { 179 if (doi_def->map.std == NULL) {
126 ret_val = -ENOMEM; 180 ret_val = -ENOMEM;
@@ -128,28 +182,32 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
128 } 182 }
129 doi_def->type = CIPSO_V4_MAP_STD; 183 doi_def->type = CIPSO_V4_MAP_STD;
130 184
131 for (iter = 0; iter < num_tags; iter++) { 185 ret_val = netlbl_cipsov4_add_common(info, doi_def);
132 if (msg_len < NETLBL_LEN_U8) 186 if (ret_val != 0)
133 goto add_std_failure;
134 doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
135 switch (doi_def->tags[iter]) {
136 case CIPSO_V4_TAG_RBITMAP:
137 break;
138 default:
139 goto add_std_failure;
140 }
141 }
142 if (iter < CIPSO_V4_TAG_MAXCNT)
143 doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
144
145 if (msg_len < 6 * NETLBL_LEN_U32)
146 goto add_std_failure; 187 goto add_std_failure;
147 188
148 num_lvls = netlbl_getinc_u32(&msg, &msg_len); 189 nla_for_each_nested(nla_a,
149 if (num_lvls == 0) 190 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
150 goto add_std_failure; 191 nla_a_rem)
151 doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg, &msg_len); 192 if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
152 if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS) 193 nla_for_each_nested(nla_b, nla_a, nla_b_rem)
194 switch (nla_b->nla_type) {
195 case NLBL_CIPSOV4_A_MLSLVLLOC:
196 if (nla_get_u32(nla_b) >=
197 doi_def->map.std->lvl.local_size)
198 doi_def->map.std->lvl.local_size =
199 nla_get_u32(nla_b) + 1;
200 break;
201 case NLBL_CIPSOV4_A_MLSLVLREM:
202 if (nla_get_u32(nla_b) >=
203 doi_def->map.std->lvl.cipso_size)
204 doi_def->map.std->lvl.cipso_size =
205 nla_get_u32(nla_b) + 1;
206 break;
207 }
208 }
209 if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS ||
210 doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
153 goto add_std_failure; 211 goto add_std_failure;
154 doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size, 212 doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
155 sizeof(u32), 213 sizeof(u32),
@@ -158,9 +216,6 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
158 ret_val = -ENOMEM; 216 ret_val = -ENOMEM;
159 goto add_std_failure; 217 goto add_std_failure;
160 } 218 }
161 doi_def->map.std->lvl.cipso_size = netlbl_getinc_u8(&msg, &msg_len);
162 if (doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
163 goto add_std_failure;
164 doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size, 219 doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
165 sizeof(u32), 220 sizeof(u32),
166 GFP_KERNEL); 221 GFP_KERNEL);
@@ -168,68 +223,101 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
168 ret_val = -ENOMEM; 223 ret_val = -ENOMEM;
169 goto add_std_failure; 224 goto add_std_failure;
170 } 225 }
226 nla_for_each_nested(nla_a,
227 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
228 nla_a_rem)
229 if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
230 struct nlattr *lvl_loc;
231 struct nlattr *lvl_rem;
232
233 if (nla_validate_nested(nla_a,
234 NLBL_CIPSOV4_A_MAX,
235 netlbl_cipsov4_genl_policy) != 0)
236 goto add_std_failure;
237
238 lvl_loc = nla_find_nested(nla_a,
239 NLBL_CIPSOV4_A_MLSLVLLOC);
240 lvl_rem = nla_find_nested(nla_a,
241 NLBL_CIPSOV4_A_MLSLVLREM);
242 if (lvl_loc == NULL || lvl_rem == NULL)
243 goto add_std_failure;
244 doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
245 nla_get_u32(lvl_rem);
246 doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
247 nla_get_u32(lvl_loc);
248 }
171 249
172 num_cats = netlbl_getinc_u32(&msg, &msg_len); 250 if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
173 doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len); 251 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
174 if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS) 252 NLBL_CIPSOV4_A_MAX,
175 goto add_std_failure; 253 netlbl_cipsov4_genl_policy) != 0)
176 doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size, 254 goto add_std_failure;
255
256 nla_for_each_nested(nla_a,
257 info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
258 nla_a_rem)
259 if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
260 if (nla_validate_nested(nla_a,
261 NLBL_CIPSOV4_A_MAX,
262 netlbl_cipsov4_genl_policy) != 0)
263 goto add_std_failure;
264 nla_for_each_nested(nla_b, nla_a, nla_b_rem)
265 switch (nla_b->nla_type) {
266 case NLBL_CIPSOV4_A_MLSCATLOC:
267 if (nla_get_u32(nla_b) >=
268 doi_def->map.std->cat.local_size)
269 doi_def->map.std->cat.local_size =
270 nla_get_u32(nla_b) + 1;
271 break;
272 case NLBL_CIPSOV4_A_MLSCATREM:
273 if (nla_get_u32(nla_b) >=
274 doi_def->map.std->cat.cipso_size)
275 doi_def->map.std->cat.cipso_size =
276 nla_get_u32(nla_b) + 1;
277 break;
278 }
279 }
280 if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS ||
281 doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
282 goto add_std_failure;
283 doi_def->map.std->cat.local = kcalloc(
284 doi_def->map.std->cat.local_size,
177 sizeof(u32), 285 sizeof(u32),
178 GFP_KERNEL); 286 GFP_KERNEL);
179 if (doi_def->map.std->cat.local == NULL) { 287 if (doi_def->map.std->cat.local == NULL) {
180 ret_val = -ENOMEM; 288 ret_val = -ENOMEM;
181 goto add_std_failure; 289 goto add_std_failure;
182 } 290 }
183 doi_def->map.std->cat.cipso_size = netlbl_getinc_u16(&msg, &msg_len); 291 doi_def->map.std->cat.cipso = kcalloc(
184 if (doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS) 292 doi_def->map.std->cat.cipso_size,
185 goto add_std_failure;
186 doi_def->map.std->cat.cipso = kcalloc(doi_def->map.std->cat.cipso_size,
187 sizeof(u32), 293 sizeof(u32),
188 GFP_KERNEL); 294 GFP_KERNEL);
189 if (doi_def->map.std->cat.cipso == NULL) { 295 if (doi_def->map.std->cat.cipso == NULL) {
190 ret_val = -ENOMEM; 296 ret_val = -ENOMEM;
191 goto add_std_failure;
192 }
193
194 if (msg_len <
195 num_lvls * (NETLBL_LEN_U32 + NETLBL_LEN_U8) +
196 num_cats * (NETLBL_LEN_U32 + NETLBL_LEN_U16))
197 goto add_std_failure;
198
199 for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
200 doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
201 for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
202 doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
203 for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
204 doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
205 for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
206 doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
207
208 for (iter = 0; iter < num_lvls; iter++) {
209 tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
210 tmp_val_b = netlbl_getinc_u8(&msg, &msg_len);
211
212 if (tmp_val_a >= doi_def->map.std->lvl.local_size ||
213 tmp_val_b >= doi_def->map.std->lvl.cipso_size)
214 goto add_std_failure;
215
216 doi_def->map.std->lvl.cipso[tmp_val_b] = tmp_val_a;
217 doi_def->map.std->lvl.local[tmp_val_a] = tmp_val_b;
218 }
219
220 for (iter = 0; iter < num_cats; iter++) {
221 tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
222 tmp_val_b = netlbl_getinc_u16(&msg, &msg_len);
223
224 if (tmp_val_a >= doi_def->map.std->cat.local_size ||
225 tmp_val_b >= doi_def->map.std->cat.cipso_size)
226 goto add_std_failure; 297 goto add_std_failure;
227 298 }
228 doi_def->map.std->cat.cipso[tmp_val_b] = tmp_val_a; 299 nla_for_each_nested(nla_a,
229 doi_def->map.std->cat.local[tmp_val_a] = tmp_val_b; 300 info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
301 nla_a_rem)
302 if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
303 struct nlattr *cat_loc;
304 struct nlattr *cat_rem;
305
306 cat_loc = nla_find_nested(nla_a,
307 NLBL_CIPSOV4_A_MLSCATLOC);
308 cat_rem = nla_find_nested(nla_a,
309 NLBL_CIPSOV4_A_MLSCATREM);
310 if (cat_loc == NULL || cat_rem == NULL)
311 goto add_std_failure;
312 doi_def->map.std->cat.local[
313 nla_get_u32(cat_loc)] =
314 nla_get_u32(cat_rem);
315 doi_def->map.std->cat.cipso[
316 nla_get_u32(cat_rem)] =
317 nla_get_u32(cat_loc);
318 }
230 } 319 }
231 320
232 doi_def->doi = doi;
233 ret_val = cipso_v4_doi_add(doi_def); 321 ret_val = cipso_v4_doi_add(doi_def);
234 if (ret_val != 0) 322 if (ret_val != 0)
235 goto add_std_failure; 323 goto add_std_failure;
@@ -243,9 +331,7 @@ add_std_failure:
243 331
244/** 332/**
245 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition 333 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
246 * @doi: the DOI value 334 * @info: the Generic NETLINK info block
247 * @msg: the ADD message data
248 * @msg_size: the size of the ADD message buffer
249 * 335 *
250 * Description: 336 * Description:
251 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message 337 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
@@ -253,52 +339,31 @@ add_std_failure:
253 * error. 339 * error.
254 * 340 *
255 */ 341 */
256static int netlbl_cipsov4_add_pass(u32 doi, 342static int netlbl_cipsov4_add_pass(struct genl_info *info)
257 struct nlattr *msg,
258 size_t msg_size)
259{ 343{
260 int ret_val = -EINVAL; 344 int ret_val;
261 int msg_len = msg_size;
262 u32 num_tags;
263 struct cipso_v4_doi *doi_def = NULL; 345 struct cipso_v4_doi *doi_def = NULL;
264 u32 iter;
265 346
266 if (msg_len < NETLBL_LEN_U32) 347 if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
267 goto add_pass_failure; 348 !info->attrs[NLBL_CIPSOV4_A_TAGLST])
268 num_tags = netlbl_getinc_u32(&msg, &msg_len); 349 return -EINVAL;
269 if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
270 goto add_pass_failure;
271 350
272 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); 351 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
273 if (doi_def == NULL) { 352 if (doi_def == NULL)
274 ret_val = -ENOMEM; 353 return -ENOMEM;
275 goto add_pass_failure;
276 }
277 doi_def->type = CIPSO_V4_MAP_PASS; 354 doi_def->type = CIPSO_V4_MAP_PASS;
278 355
279 for (iter = 0; iter < num_tags; iter++) { 356 ret_val = netlbl_cipsov4_add_common(info, doi_def);
280 if (msg_len < NETLBL_LEN_U8) 357 if (ret_val != 0)
281 goto add_pass_failure; 358 goto add_pass_failure;
282 doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
283 switch (doi_def->tags[iter]) {
284 case CIPSO_V4_TAG_RBITMAP:
285 break;
286 default:
287 goto add_pass_failure;
288 }
289 }
290 if (iter < CIPSO_V4_TAG_MAXCNT)
291 doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
292 359
293 doi_def->doi = doi;
294 ret_val = cipso_v4_doi_add(doi_def); 360 ret_val = cipso_v4_doi_add(doi_def);
295 if (ret_val != 0) 361 if (ret_val != 0)
296 goto add_pass_failure; 362 goto add_pass_failure;
297 return 0; 363 return 0;
298 364
299add_pass_failure: 365add_pass_failure:
300 if (doi_def) 366 netlbl_cipsov4_doi_free(&doi_def->rcu);
301 netlbl_cipsov4_doi_free(&doi_def->rcu);
302 return ret_val; 367 return ret_val;
303} 368}
304 369
@@ -316,34 +381,21 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
316 381
317{ 382{
318 int ret_val = -EINVAL; 383 int ret_val = -EINVAL;
319 u32 doi;
320 u32 map_type; 384 u32 map_type;
321 int msg_len = netlbl_netlink_payload_len(skb);
322 struct nlattr *msg = netlbl_netlink_payload_data(skb);
323
324 ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
325 if (ret_val != 0)
326 goto add_return;
327 385
328 if (msg_len < 2 * NETLBL_LEN_U32) 386 if (!info->attrs[NLBL_CIPSOV4_A_MTYPE])
329 goto add_return; 387 return -EINVAL;
330 388
331 doi = netlbl_getinc_u32(&msg, &msg_len); 389 map_type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
332 map_type = netlbl_getinc_u32(&msg, &msg_len);
333 switch (map_type) { 390 switch (map_type) {
334 case CIPSO_V4_MAP_STD: 391 case CIPSO_V4_MAP_STD:
335 ret_val = netlbl_cipsov4_add_std(doi, msg, msg_len); 392 ret_val = netlbl_cipsov4_add_std(info);
336 break; 393 break;
337 case CIPSO_V4_MAP_PASS: 394 case CIPSO_V4_MAP_PASS:
338 ret_val = netlbl_cipsov4_add_pass(doi, msg, msg_len); 395 ret_val = netlbl_cipsov4_add_pass(info);
339 break; 396 break;
340 } 397 }
341 398
342add_return:
343 netlbl_netlink_send_ack(info,
344 netlbl_cipsov4_gnl_family.id,
345 NLBL_CIPSOV4_C_ACK,
346 -ret_val);
347 return ret_val; 399 return ret_val;
348} 400}
349 401
@@ -353,84 +405,239 @@ add_return:
353 * @info: the Generic NETLINK info block 405 * @info: the Generic NETLINK info block
354 * 406 *
355 * Description: 407 * Description:
356 * Process a user generated LIST message and respond accordingly. Returns 408 * Process a user generated LIST message and respond accordingly. While the
357 * zero on success and negative values on error. 409 * response message generated by the kernel is straightforward, determining
410 * before hand the size of the buffer to allocate is not (we have to generate
411 * the message to know the size). In order to keep this function sane what we
412 * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
413 * that size, if we fail then we restart with a larger buffer and try again.
414 * We continue in this manner until we hit a limit of failed attempts then we
415 * give up and just send an error message. Returns zero on success and
416 * negative values on error.
358 * 417 *
359 */ 418 */
360static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) 419static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
361{ 420{
362 int ret_val = -EINVAL; 421 int ret_val;
422 struct sk_buff *ans_skb = NULL;
423 u32 nlsze_mult = 1;
424 void *data;
363 u32 doi; 425 u32 doi;
364 struct nlattr *msg = netlbl_netlink_payload_data(skb); 426 struct nlattr *nla_a;
365 struct sk_buff *ans_skb; 427 struct nlattr *nla_b;
428 struct cipso_v4_doi *doi_def;
429 u32 iter;
366 430
367 if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) 431 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
432 ret_val = -EINVAL;
368 goto list_failure; 433 goto list_failure;
434 }
369 435
370 doi = nla_get_u32(msg); 436list_start:
371 ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN)); 437 ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL);
372 if (ans_skb == NULL) { 438 if (ans_skb == NULL) {
373 ret_val = -ENOMEM; 439 ret_val = -ENOMEM;
374 goto list_failure; 440 goto list_failure;
375 } 441 }
376 netlbl_netlink_hdr_push(ans_skb, 442 data = netlbl_netlink_hdr_put(ans_skb,
377 info->snd_pid, 443 info->snd_pid,
378 0, 444 info->snd_seq,
379 netlbl_cipsov4_gnl_family.id, 445 netlbl_cipsov4_gnl_family.id,
380 NLBL_CIPSOV4_C_LIST); 446 0,
447 NLBL_CIPSOV4_C_LIST);
448 if (data == NULL) {
449 ret_val = -ENOMEM;
450 goto list_failure;
451 }
452
453 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
454
455 rcu_read_lock();
456 doi_def = cipso_v4_doi_getdef(doi);
457 if (doi_def == NULL) {
458 ret_val = -EINVAL;
459 goto list_failure;
460 }
461
462 ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
463 if (ret_val != 0)
464 goto list_failure_lock;
465
466 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
467 if (nla_a == NULL) {
468 ret_val = -ENOMEM;
469 goto list_failure_lock;
470 }
471 for (iter = 0;
472 iter < CIPSO_V4_TAG_MAXCNT &&
473 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
474 iter++) {
475 ret_val = nla_put_u8(ans_skb,
476 NLBL_CIPSOV4_A_TAG,
477 doi_def->tags[iter]);
478 if (ret_val != 0)
479 goto list_failure_lock;
480 }
481 nla_nest_end(ans_skb, nla_a);
482
483 switch (doi_def->type) {
484 case CIPSO_V4_MAP_STD:
485 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
486 if (nla_a == NULL) {
487 ret_val = -ENOMEM;
488 goto list_failure_lock;
489 }
490 for (iter = 0;
491 iter < doi_def->map.std->lvl.local_size;
492 iter++) {
493 if (doi_def->map.std->lvl.local[iter] ==
494 CIPSO_V4_INV_LVL)
495 continue;
496
497 nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
498 if (nla_b == NULL) {
499 ret_val = -ENOMEM;
500 goto list_retry;
501 }
502 ret_val = nla_put_u32(ans_skb,
503 NLBL_CIPSOV4_A_MLSLVLLOC,
504 iter);
505 if (ret_val != 0)
506 goto list_retry;
507 ret_val = nla_put_u32(ans_skb,
508 NLBL_CIPSOV4_A_MLSLVLREM,
509 doi_def->map.std->lvl.local[iter]);
510 if (ret_val != 0)
511 goto list_retry;
512 nla_nest_end(ans_skb, nla_b);
513 }
514 nla_nest_end(ans_skb, nla_a);
515
516 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
517 if (nla_a == NULL) {
518 ret_val = -ENOMEM;
519 goto list_retry;
520 }
521 for (iter = 0;
522 iter < doi_def->map.std->cat.local_size;
523 iter++) {
524 if (doi_def->map.std->cat.local[iter] ==
525 CIPSO_V4_INV_CAT)
526 continue;
527
528 nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
529 if (nla_b == NULL) {
530 ret_val = -ENOMEM;
531 goto list_retry;
532 }
533 ret_val = nla_put_u32(ans_skb,
534 NLBL_CIPSOV4_A_MLSCATLOC,
535 iter);
536 if (ret_val != 0)
537 goto list_retry;
538 ret_val = nla_put_u32(ans_skb,
539 NLBL_CIPSOV4_A_MLSCATREM,
540 doi_def->map.std->cat.local[iter]);
541 if (ret_val != 0)
542 goto list_retry;
543 nla_nest_end(ans_skb, nla_b);
544 }
545 nla_nest_end(ans_skb, nla_a);
546
547 break;
548 }
549 rcu_read_unlock();
381 550
382 ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); 551 genlmsg_end(ans_skb, data);
552
553 ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
383 if (ret_val != 0) 554 if (ret_val != 0)
384 goto list_failure; 555 goto list_failure;
385 556
386 return 0; 557 return 0;
387 558
559list_retry:
560 /* XXX - this limit is a guesstimate */
561 if (nlsze_mult < 4) {
562 rcu_read_unlock();
563 kfree_skb(ans_skb);
564 nlsze_mult++;
565 goto list_start;
566 }
567list_failure_lock:
568 rcu_read_unlock();
388list_failure: 569list_failure:
389 netlbl_netlink_send_ack(info, 570 kfree_skb(ans_skb);
390 netlbl_cipsov4_gnl_family.id, 571 return ret_val;
391 NLBL_CIPSOV4_C_ACK, 572}
392 -ret_val); 573
574/**
575 * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
576 * @doi_def: the CIPSOv4 DOI definition
577 * @arg: the netlbl_cipsov4_doiwalk_arg structure
578 *
579 * Description:
580 * This function is designed to be used as a callback to the
581 * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
582 * message. Returns the size of the message on success, negative values on
583 * failure.
584 *
585 */
586static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
587{
588 int ret_val = -ENOMEM;
589 struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
590 void *data;
591
592 data = netlbl_netlink_hdr_put(cb_arg->skb,
593 NETLINK_CB(cb_arg->nl_cb->skb).pid,
594 cb_arg->seq,
595 netlbl_cipsov4_gnl_family.id,
596 NLM_F_MULTI,
597 NLBL_CIPSOV4_C_LISTALL);
598 if (data == NULL)
599 goto listall_cb_failure;
600
601 ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
602 if (ret_val != 0)
603 goto listall_cb_failure;
604 ret_val = nla_put_u32(cb_arg->skb,
605 NLBL_CIPSOV4_A_MTYPE,
606 doi_def->type);
607 if (ret_val != 0)
608 goto listall_cb_failure;
609
610 return genlmsg_end(cb_arg->skb, data);
611
612listall_cb_failure:
613 genlmsg_cancel(cb_arg->skb, data);
393 return ret_val; 614 return ret_val;
394} 615}
395 616
396/** 617/**
397 * netlbl_cipsov4_listall - Handle a LISTALL message 618 * netlbl_cipsov4_listall - Handle a LISTALL message
398 * @skb: the NETLINK buffer 619 * @skb: the NETLINK buffer
399 * @info: the Generic NETLINK info block 620 * @cb: the NETLINK callback
400 * 621 *
401 * Description: 622 * Description:
402 * Process a user generated LISTALL message and respond accordingly. Returns 623 * Process a user generated LISTALL message and respond accordingly. Returns
403 * zero on success and negative values on error. 624 * zero on success and negative values on error.
404 * 625 *
405 */ 626 */
406static int netlbl_cipsov4_listall(struct sk_buff *skb, struct genl_info *info) 627static int netlbl_cipsov4_listall(struct sk_buff *skb,
628 struct netlink_callback *cb)
407{ 629{
408 int ret_val = -EINVAL; 630 struct netlbl_cipsov4_doiwalk_arg cb_arg;
409 struct sk_buff *ans_skb; 631 int doi_skip = cb->args[0];
410 632
411 ans_skb = cipso_v4_doi_dump_all(NLMSG_SPACE(GENL_HDRLEN)); 633 cb_arg.nl_cb = cb;
412 if (ans_skb == NULL) { 634 cb_arg.skb = skb;
413 ret_val = -ENOMEM; 635 cb_arg.seq = cb->nlh->nlmsg_seq;
414 goto listall_failure;
415 }
416 netlbl_netlink_hdr_push(ans_skb,
417 info->snd_pid,
418 0,
419 netlbl_cipsov4_gnl_family.id,
420 NLBL_CIPSOV4_C_LISTALL);
421 636
422 ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); 637 cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
423 if (ret_val != 0)
424 goto listall_failure;
425
426 return 0;
427 638
428listall_failure: 639 cb->args[0] = doi_skip;
429 netlbl_netlink_send_ack(info, 640 return skb->len;
430 netlbl_cipsov4_gnl_family.id,
431 NLBL_CIPSOV4_C_ACK,
432 -ret_val);
433 return ret_val;
434} 641}
435 642
436/** 643/**
@@ -445,27 +652,14 @@ listall_failure:
445 */ 652 */
446static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) 653static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
447{ 654{
448 int ret_val; 655 int ret_val = -EINVAL;
449 u32 doi; 656 u32 doi;
450 struct nlattr *msg = netlbl_netlink_payload_data(skb);
451 657
452 ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); 658 if (info->attrs[NLBL_CIPSOV4_A_DOI]) {
453 if (ret_val != 0) 659 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
454 goto remove_return; 660 ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
455
456 if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) {
457 ret_val = -EINVAL;
458 goto remove_return;
459 } 661 }
460 662
461 doi = nla_get_u32(msg);
462 ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
463
464remove_return:
465 netlbl_netlink_send_ack(info,
466 netlbl_cipsov4_gnl_family.id,
467 NLBL_CIPSOV4_C_ACK,
468 -ret_val);
469 return ret_val; 663 return ret_val;
470} 664}
471 665
@@ -475,14 +669,16 @@ remove_return:
475 669
476static struct genl_ops netlbl_cipsov4_genl_c_add = { 670static struct genl_ops netlbl_cipsov4_genl_c_add = {
477 .cmd = NLBL_CIPSOV4_C_ADD, 671 .cmd = NLBL_CIPSOV4_C_ADD,
478 .flags = 0, 672 .flags = GENL_ADMIN_PERM,
673 .policy = netlbl_cipsov4_genl_policy,
479 .doit = netlbl_cipsov4_add, 674 .doit = netlbl_cipsov4_add,
480 .dumpit = NULL, 675 .dumpit = NULL,
481}; 676};
482 677
483static struct genl_ops netlbl_cipsov4_genl_c_remove = { 678static struct genl_ops netlbl_cipsov4_genl_c_remove = {
484 .cmd = NLBL_CIPSOV4_C_REMOVE, 679 .cmd = NLBL_CIPSOV4_C_REMOVE,
485 .flags = 0, 680 .flags = GENL_ADMIN_PERM,
681 .policy = netlbl_cipsov4_genl_policy,
486 .doit = netlbl_cipsov4_remove, 682 .doit = netlbl_cipsov4_remove,
487 .dumpit = NULL, 683 .dumpit = NULL,
488}; 684};
@@ -490,6 +686,7 @@ static struct genl_ops netlbl_cipsov4_genl_c_remove = {
490static struct genl_ops netlbl_cipsov4_genl_c_list = { 686static struct genl_ops netlbl_cipsov4_genl_c_list = {
491 .cmd = NLBL_CIPSOV4_C_LIST, 687 .cmd = NLBL_CIPSOV4_C_LIST,
492 .flags = 0, 688 .flags = 0,
689 .policy = netlbl_cipsov4_genl_policy,
493 .doit = netlbl_cipsov4_list, 690 .doit = netlbl_cipsov4_list,
494 .dumpit = NULL, 691 .dumpit = NULL,
495}; 692};
@@ -497,8 +694,9 @@ static struct genl_ops netlbl_cipsov4_genl_c_list = {
497static struct genl_ops netlbl_cipsov4_genl_c_listall = { 694static struct genl_ops netlbl_cipsov4_genl_c_listall = {
498 .cmd = NLBL_CIPSOV4_C_LISTALL, 695 .cmd = NLBL_CIPSOV4_C_LISTALL,
499 .flags = 0, 696 .flags = 0,
500 .doit = netlbl_cipsov4_listall, 697 .policy = netlbl_cipsov4_genl_policy,
501 .dumpit = NULL, 698 .doit = NULL,
699 .dumpit = netlbl_cipsov4_listall,
502}; 700};
503 701
504/* 702/*