1 /* 2 * NetLabel CALIPSO/IPv6 Support 3 * 4 * This file defines the CALIPSO/IPv6 functions for the NetLabel system. The 5 * NetLabel system manages static and dynamic label mappings for network 6 * protocols such as CIPSO and CALIPSO. 7 * 8 * Authors: Paul Moore <paul@paul-moore.com> 9 * Huw Davies <huw@codeweavers.com> 10 * 11 */ 12 13 /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015 15 * 16 * This program is free software; you can redistribute it and/or modify 17 * it under the terms of the GNU General Public License as published by 18 * the Free Software Foundation; either version 2 of the License, or 19 * (at your option) any later version. 20 * 21 * This program is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 24 * the GNU General Public License for more details. 25 * 26 * You should have received a copy of the GNU General Public License 27 * along with this program; if not, see <http://www.gnu.org/licenses/>. 28 * 29 */ 30 31 #include <linux/types.h> 32 #include <linux/socket.h> 33 #include <linux/string.h> 34 #include <linux/skbuff.h> 35 #include <linux/audit.h> 36 #include <linux/slab.h> 37 #include <net/sock.h> 38 #include <net/netlink.h> 39 #include <net/genetlink.h> 40 #include <net/netlabel.h> 41 #include <net/calipso.h> 42 #include <linux/atomic.h> 43 44 #include "netlabel_user.h" 45 #include "netlabel_calipso.h" 46 #include "netlabel_mgmt.h" 47 #include "netlabel_domainhash.h" 48 49 /* Argument struct for calipso_doi_walk() */ 50 struct netlbl_calipso_doiwalk_arg { 51 struct netlink_callback *nl_cb; 52 struct sk_buff *skb; 53 u32 seq; 54 }; 55 56 /* NetLabel Generic NETLINK CALIPSO family */ 57 static struct genl_family netlbl_calipso_gnl_family = { 58 .id = GENL_ID_GENERATE, 59 .hdrsize = 0, 60 .name = NETLBL_NLTYPE_CALIPSO_NAME, 61 .version = NETLBL_PROTO_VERSION, 62 .maxattr = NLBL_CALIPSO_A_MAX, 63 }; 64 65 /* NetLabel Netlink attribute policy */ 66 static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = { 67 [NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 }, 68 [NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 }, 69 }; 70 71 /* NetLabel Command Handlers 72 */ 73 /** 74 * netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition 75 * @info: the Generic NETLINK info block 76 * @audit_info: NetLabel audit information 77 * 78 * Description: 79 * Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message 80 * and add it to the CALIPSO engine. Return zero on success and non-zero on 81 * error. 82 * 83 */ 84 static int netlbl_calipso_add_pass(struct genl_info *info, 85 struct netlbl_audit *audit_info) 86 { 87 int ret_val; 88 struct calipso_doi *doi_def = NULL; 89 90 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); 91 if (!doi_def) 92 return -ENOMEM; 93 doi_def->type = CALIPSO_MAP_PASS; 94 doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]); 95 ret_val = calipso_doi_add(doi_def, audit_info); 96 if (ret_val != 0) 97 calipso_doi_free(doi_def); 98 99 return ret_val; 100 } 101 102 /** 103 * netlbl_calipso_add - Handle an ADD message 104 * @skb: the NETLINK buffer 105 * @info: the Generic NETLINK info block 106 * 107 * Description: 108 * Create a new DOI definition based on the given ADD message and add it to the 109 * CALIPSO engine. Returns zero on success, negative values on failure. 110 * 111 */ 112 static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info) 113 114 { 115 int ret_val = -EINVAL; 116 struct netlbl_audit audit_info; 117 118 if (!info->attrs[NLBL_CALIPSO_A_DOI] || 119 !info->attrs[NLBL_CALIPSO_A_MTYPE]) 120 return -EINVAL; 121 122 netlbl_netlink_auditinfo(skb, &audit_info); 123 switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) { 124 case CALIPSO_MAP_PASS: 125 ret_val = netlbl_calipso_add_pass(info, &audit_info); 126 break; 127 } 128 if (ret_val == 0) 129 atomic_inc(&netlabel_mgmt_protocount); 130 131 return ret_val; 132 } 133 134 /** 135 * netlbl_calipso_list - Handle a LIST message 136 * @skb: the NETLINK buffer 137 * @info: the Generic NETLINK info block 138 * 139 * Description: 140 * Process a user generated LIST message and respond accordingly. 141 * Returns zero on success and negative values on error. 142 * 143 */ 144 static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info) 145 { 146 int ret_val; 147 struct sk_buff *ans_skb = NULL; 148 void *data; 149 u32 doi; 150 struct calipso_doi *doi_def; 151 152 if (!info->attrs[NLBL_CALIPSO_A_DOI]) { 153 ret_val = -EINVAL; 154 goto list_failure; 155 } 156 157 doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]); 158 159 doi_def = calipso_doi_getdef(doi); 160 if (!doi_def) { 161 ret_val = -EINVAL; 162 goto list_failure; 163 } 164 165 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 166 if (!ans_skb) { 167 ret_val = -ENOMEM; 168 goto list_failure_put; 169 } 170 data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family, 171 0, NLBL_CALIPSO_C_LIST); 172 if (!data) { 173 ret_val = -ENOMEM; 174 goto list_failure_put; 175 } 176 177 ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type); 178 if (ret_val != 0) 179 goto list_failure_put; 180 181 calipso_doi_putdef(doi_def); 182 183 genlmsg_end(ans_skb, data); 184 return genlmsg_reply(ans_skb, info); 185 186 list_failure_put: 187 calipso_doi_putdef(doi_def); 188 list_failure: 189 kfree_skb(ans_skb); 190 return ret_val; 191 } 192 193 /** 194 * netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL 195 * @doi_def: the CALIPSO DOI definition 196 * @arg: the netlbl_calipso_doiwalk_arg structure 197 * 198 * Description: 199 * This function is designed to be used as a callback to the 200 * calipso_doi_walk() function for use in generating a response for a LISTALL 201 * message. Returns the size of the message on success, negative values on 202 * failure. 203 * 204 */ 205 static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg) 206 { 207 int ret_val = -ENOMEM; 208 struct netlbl_calipso_doiwalk_arg *cb_arg = arg; 209 void *data; 210 211 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, 212 cb_arg->seq, &netlbl_calipso_gnl_family, 213 NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL); 214 if (!data) 215 goto listall_cb_failure; 216 217 ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi); 218 if (ret_val != 0) 219 goto listall_cb_failure; 220 ret_val = nla_put_u32(cb_arg->skb, 221 NLBL_CALIPSO_A_MTYPE, 222 doi_def->type); 223 if (ret_val != 0) 224 goto listall_cb_failure; 225 226 genlmsg_end(cb_arg->skb, data); 227 return 0; 228 229 listall_cb_failure: 230 genlmsg_cancel(cb_arg->skb, data); 231 return ret_val; 232 } 233 234 /** 235 * netlbl_calipso_listall - Handle a LISTALL message 236 * @skb: the NETLINK buffer 237 * @cb: the NETLINK callback 238 * 239 * Description: 240 * Process a user generated LISTALL message and respond accordingly. Returns 241 * zero on success and negative values on error. 242 * 243 */ 244 static int netlbl_calipso_listall(struct sk_buff *skb, 245 struct netlink_callback *cb) 246 { 247 struct netlbl_calipso_doiwalk_arg cb_arg; 248 u32 doi_skip = cb->args[0]; 249 250 cb_arg.nl_cb = cb; 251 cb_arg.skb = skb; 252 cb_arg.seq = cb->nlh->nlmsg_seq; 253 254 calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg); 255 256 cb->args[0] = doi_skip; 257 return skb->len; 258 } 259 260 /* NetLabel Generic NETLINK Command Definitions 261 */ 262 263 static const struct genl_ops netlbl_calipso_ops[] = { 264 { 265 .cmd = NLBL_CALIPSO_C_ADD, 266 .flags = GENL_ADMIN_PERM, 267 .policy = calipso_genl_policy, 268 .doit = netlbl_calipso_add, 269 .dumpit = NULL, 270 }, 271 { 272 .cmd = NLBL_CALIPSO_C_LIST, 273 .flags = 0, 274 .policy = calipso_genl_policy, 275 .doit = netlbl_calipso_list, 276 .dumpit = NULL, 277 }, 278 { 279 .cmd = NLBL_CALIPSO_C_LISTALL, 280 .flags = 0, 281 .policy = calipso_genl_policy, 282 .doit = NULL, 283 .dumpit = netlbl_calipso_listall, 284 }, 285 }; 286 287 /* NetLabel Generic NETLINK Protocol Functions 288 */ 289 290 /** 291 * netlbl_calipso_genl_init - Register the CALIPSO NetLabel component 292 * 293 * Description: 294 * Register the CALIPSO packet NetLabel component with the Generic NETLINK 295 * mechanism. Returns zero on success, negative values on failure. 296 * 297 */ 298 int __init netlbl_calipso_genl_init(void) 299 { 300 return genl_register_family_with_ops(&netlbl_calipso_gnl_family, 301 netlbl_calipso_ops); 302 } 303 304 static const struct netlbl_calipso_ops *calipso_ops; 305 306 /** 307 * netlbl_calipso_ops_register - Register the CALIPSO operations 308 * 309 * Description: 310 * Register the CALIPSO packet engine operations. 311 * 312 */ 313 const struct netlbl_calipso_ops * 314 netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops) 315 { 316 return xchg(&calipso_ops, ops); 317 } 318 EXPORT_SYMBOL(netlbl_calipso_ops_register); 319 320 static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void) 321 { 322 return ACCESS_ONCE(calipso_ops); 323 } 324 325 /** 326 * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine 327 * @doi_def: the DOI structure 328 * @audit_info: NetLabel audit information 329 * 330 * Description: 331 * The caller defines a new DOI for use by the CALIPSO engine and calls this 332 * function to add it to the list of acceptable domains. The caller must 333 * ensure that the mapping table specified in @doi_def->map meets all of the 334 * requirements of the mapping type (see calipso.h for details). Returns 335 * zero on success and non-zero on failure. 336 * 337 */ 338 int calipso_doi_add(struct calipso_doi *doi_def, 339 struct netlbl_audit *audit_info) 340 { 341 int ret_val = -ENOMSG; 342 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 343 344 if (ops) 345 ret_val = ops->doi_add(doi_def, audit_info); 346 return ret_val; 347 } 348 349 /** 350 * calipso_doi_free - Frees a DOI definition 351 * @doi_def: the DOI definition 352 * 353 * Description: 354 * This function frees all of the memory associated with a DOI definition. 355 * 356 */ 357 void calipso_doi_free(struct calipso_doi *doi_def) 358 { 359 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 360 361 if (ops) 362 ops->doi_free(doi_def); 363 } 364 365 /** 366 * calipso_doi_getdef - Returns a reference to a valid DOI definition 367 * @doi: the DOI value 368 * 369 * Description: 370 * Searches for a valid DOI definition and if one is found it is returned to 371 * the caller. Otherwise NULL is returned. The caller must ensure that 372 * calipso_doi_putdef() is called when the caller is done. 373 * 374 */ 375 struct calipso_doi *calipso_doi_getdef(u32 doi) 376 { 377 struct calipso_doi *ret_val = NULL; 378 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 379 380 if (ops) 381 ret_val = ops->doi_getdef(doi); 382 return ret_val; 383 } 384 385 /** 386 * calipso_doi_putdef - Releases a reference for the given DOI definition 387 * @doi_def: the DOI definition 388 * 389 * Description: 390 * Releases a DOI definition reference obtained from calipso_doi_getdef(). 391 * 392 */ 393 void calipso_doi_putdef(struct calipso_doi *doi_def) 394 { 395 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 396 397 if (ops) 398 ops->doi_putdef(doi_def); 399 } 400 401 /** 402 * calipso_doi_walk - Iterate through the DOI definitions 403 * @skip_cnt: skip past this number of DOI definitions, updated 404 * @callback: callback for each DOI definition 405 * @cb_arg: argument for the callback function 406 * 407 * Description: 408 * Iterate over the DOI definition list, skipping the first @skip_cnt entries. 409 * For each entry call @callback, if @callback returns a negative value stop 410 * 'walking' through the list and return. Updates the value in @skip_cnt upon 411 * return. Returns zero on success, negative values on failure. 412 * 413 */ 414 int calipso_doi_walk(u32 *skip_cnt, 415 int (*callback)(struct calipso_doi *doi_def, void *arg), 416 void *cb_arg) 417 { 418 int ret_val = -ENOMSG; 419 const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get(); 420 421 if (ops) 422 ret_val = ops->doi_walk(skip_cnt, callback, cb_arg); 423 return ret_val; 424 } 425