diff options
Diffstat (limited to 'net/netlabel/netlabel_mgmt.c')
| -rw-r--r-- | net/netlabel/netlabel_mgmt.c | 410 |
1 files changed, 304 insertions, 106 deletions
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 44be5d5261f4..ee769ecaa13c 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | /* | 12 | /* |
| 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
| 14 | * | 14 | * |
| 15 | * This program is free software; you can redistribute it and/or modify | 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 | 16 | * it under the terms of the GNU General Public License as published by |
| @@ -32,9 +32,13 @@ | |||
| 32 | #include <linux/socket.h> | 32 | #include <linux/socket.h> |
| 33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
| 35 | #include <linux/in.h> | ||
| 36 | #include <linux/in6.h> | ||
| 35 | #include <net/sock.h> | 37 | #include <net/sock.h> |
| 36 | #include <net/netlink.h> | 38 | #include <net/netlink.h> |
| 37 | #include <net/genetlink.h> | 39 | #include <net/genetlink.h> |
| 40 | #include <net/ip.h> | ||
| 41 | #include <net/ipv6.h> | ||
| 38 | #include <net/netlabel.h> | 42 | #include <net/netlabel.h> |
| 39 | #include <net/cipso_ipv4.h> | 43 | #include <net/cipso_ipv4.h> |
| 40 | #include <asm/atomic.h> | 44 | #include <asm/atomic.h> |
| @@ -71,86 +75,337 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { | |||
| 71 | }; | 75 | }; |
| 72 | 76 | ||
| 73 | /* | 77 | /* |
| 74 | * NetLabel Command Handlers | 78 | * Helper Functions |
| 75 | */ | 79 | */ |
| 76 | 80 | ||
| 77 | /** | 81 | /** |
| 78 | * netlbl_mgmt_add - Handle an ADD message | 82 | * netlbl_mgmt_add - Handle an ADD message |
| 79 | * @skb: the NETLINK buffer | ||
| 80 | * @info: the Generic NETLINK info block | 83 | * @info: the Generic NETLINK info block |
| 84 | * @audit_info: NetLabel audit information | ||
| 81 | * | 85 | * |
| 82 | * Description: | 86 | * Description: |
| 83 | * Process a user generated ADD message and add the domains from the message | 87 | * Helper function for the ADD and ADDDEF messages to add the domain mappings |
| 84 | * to the hash table. See netlabel.h for a description of the message format. | 88 | * from the message to the hash table. See netlabel.h for a description of the |
| 85 | * Returns zero on success, negative values on failure. | 89 | * message format. Returns zero on success, negative values on failure. |
| 86 | * | 90 | * |
| 87 | */ | 91 | */ |
| 88 | static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) | 92 | static int netlbl_mgmt_add_common(struct genl_info *info, |
| 93 | struct netlbl_audit *audit_info) | ||
| 89 | { | 94 | { |
| 90 | int ret_val = -EINVAL; | 95 | int ret_val = -EINVAL; |
| 91 | struct netlbl_dom_map *entry = NULL; | 96 | struct netlbl_dom_map *entry = NULL; |
| 92 | size_t tmp_size; | 97 | struct netlbl_domaddr_map *addrmap = NULL; |
| 98 | struct cipso_v4_doi *cipsov4 = NULL; | ||
| 93 | u32 tmp_val; | 99 | u32 tmp_val; |
| 94 | struct netlbl_audit audit_info; | ||
| 95 | |||
| 96 | if (!info->attrs[NLBL_MGMT_A_DOMAIN] || | ||
| 97 | !info->attrs[NLBL_MGMT_A_PROTOCOL]) | ||
| 98 | goto add_failure; | ||
| 99 | |||
| 100 | netlbl_netlink_auditinfo(skb, &audit_info); | ||
| 101 | 100 | ||
| 102 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 101 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
| 103 | if (entry == NULL) { | 102 | if (entry == NULL) { |
| 104 | ret_val = -ENOMEM; | 103 | ret_val = -ENOMEM; |
| 105 | goto add_failure; | 104 | goto add_failure; |
| 106 | } | 105 | } |
| 107 | tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); | ||
| 108 | entry->domain = kmalloc(tmp_size, GFP_KERNEL); | ||
| 109 | if (entry->domain == NULL) { | ||
| 110 | ret_val = -ENOMEM; | ||
| 111 | goto add_failure; | ||
| 112 | } | ||
| 113 | entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); | 106 | entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); |
| 114 | nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); | 107 | if (info->attrs[NLBL_MGMT_A_DOMAIN]) { |
| 108 | size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); | ||
| 109 | entry->domain = kmalloc(tmp_size, GFP_KERNEL); | ||
| 110 | if (entry->domain == NULL) { | ||
| 111 | ret_val = -ENOMEM; | ||
| 112 | goto add_failure; | ||
| 113 | } | ||
| 114 | nla_strlcpy(entry->domain, | ||
| 115 | info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* NOTE: internally we allow/use a entry->type value of | ||
| 119 | * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users | ||
| 120 | * to pass that as a protocol value because we need to know the | ||
| 121 | * "real" protocol */ | ||
| 115 | 122 | ||
| 116 | switch (entry->type) { | 123 | switch (entry->type) { |
| 117 | case NETLBL_NLTYPE_UNLABELED: | 124 | case NETLBL_NLTYPE_UNLABELED: |
| 118 | ret_val = netlbl_domhsh_add(entry, &audit_info); | ||
| 119 | break; | 125 | break; |
| 120 | case NETLBL_NLTYPE_CIPSOV4: | 126 | case NETLBL_NLTYPE_CIPSOV4: |
| 121 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) | 127 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) |
| 122 | goto add_failure; | 128 | goto add_failure; |
| 123 | 129 | ||
| 124 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); | 130 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); |
| 125 | /* We should be holding a rcu_read_lock() here while we hold | 131 | cipsov4 = cipso_v4_doi_getdef(tmp_val); |
| 126 | * the result but since the entry will always be deleted when | 132 | if (cipsov4 == NULL) |
| 127 | * the CIPSO DOI is deleted we aren't going to keep the | ||
| 128 | * lock. */ | ||
| 129 | rcu_read_lock(); | ||
| 130 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); | ||
| 131 | if (entry->type_def.cipsov4 == NULL) { | ||
| 132 | rcu_read_unlock(); | ||
| 133 | goto add_failure; | 133 | goto add_failure; |
| 134 | } | 134 | entry->type_def.cipsov4 = cipsov4; |
| 135 | ret_val = netlbl_domhsh_add(entry, &audit_info); | ||
| 136 | rcu_read_unlock(); | ||
| 137 | break; | 135 | break; |
| 138 | default: | 136 | default: |
| 139 | goto add_failure; | 137 | goto add_failure; |
| 140 | } | 138 | } |
| 139 | |||
| 140 | if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { | ||
| 141 | struct in_addr *addr; | ||
| 142 | struct in_addr *mask; | ||
| 143 | struct netlbl_domaddr4_map *map; | ||
| 144 | |||
| 145 | addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); | ||
| 146 | if (addrmap == NULL) { | ||
| 147 | ret_val = -ENOMEM; | ||
| 148 | goto add_failure; | ||
| 149 | } | ||
| 150 | INIT_LIST_HEAD(&addrmap->list4); | ||
| 151 | INIT_LIST_HEAD(&addrmap->list6); | ||
| 152 | |||
| 153 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != | ||
| 154 | sizeof(struct in_addr)) { | ||
| 155 | ret_val = -EINVAL; | ||
| 156 | goto add_failure; | ||
| 157 | } | ||
| 158 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != | ||
| 159 | sizeof(struct in_addr)) { | ||
| 160 | ret_val = -EINVAL; | ||
| 161 | goto add_failure; | ||
| 162 | } | ||
| 163 | addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); | ||
| 164 | mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); | ||
| 165 | |||
| 166 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
| 167 | if (map == NULL) { | ||
| 168 | ret_val = -ENOMEM; | ||
| 169 | goto add_failure; | ||
| 170 | } | ||
| 171 | map->list.addr = addr->s_addr & mask->s_addr; | ||
| 172 | map->list.mask = mask->s_addr; | ||
| 173 | map->list.valid = 1; | ||
| 174 | map->type = entry->type; | ||
| 175 | if (cipsov4) | ||
| 176 | map->type_def.cipsov4 = cipsov4; | ||
| 177 | |||
| 178 | ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); | ||
| 179 | if (ret_val != 0) { | ||
| 180 | kfree(map); | ||
| 181 | goto add_failure; | ||
| 182 | } | ||
| 183 | |||
| 184 | entry->type = NETLBL_NLTYPE_ADDRSELECT; | ||
| 185 | entry->type_def.addrsel = addrmap; | ||
| 186 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 187 | } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { | ||
| 188 | struct in6_addr *addr; | ||
| 189 | struct in6_addr *mask; | ||
| 190 | struct netlbl_domaddr6_map *map; | ||
| 191 | |||
| 192 | addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); | ||
| 193 | if (addrmap == NULL) { | ||
| 194 | ret_val = -ENOMEM; | ||
| 195 | goto add_failure; | ||
| 196 | } | ||
| 197 | INIT_LIST_HEAD(&addrmap->list4); | ||
| 198 | INIT_LIST_HEAD(&addrmap->list6); | ||
| 199 | |||
| 200 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != | ||
| 201 | sizeof(struct in6_addr)) { | ||
| 202 | ret_val = -EINVAL; | ||
| 203 | goto add_failure; | ||
| 204 | } | ||
| 205 | if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != | ||
| 206 | sizeof(struct in6_addr)) { | ||
| 207 | ret_val = -EINVAL; | ||
| 208 | goto add_failure; | ||
| 209 | } | ||
| 210 | addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); | ||
| 211 | mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); | ||
| 212 | |||
| 213 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
| 214 | if (map == NULL) { | ||
| 215 | ret_val = -ENOMEM; | ||
| 216 | goto add_failure; | ||
| 217 | } | ||
| 218 | ipv6_addr_copy(&map->list.addr, addr); | ||
| 219 | map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; | ||
| 220 | map->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; | ||
| 221 | map->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; | ||
| 222 | map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; | ||
| 223 | ipv6_addr_copy(&map->list.mask, mask); | ||
| 224 | map->list.valid = 1; | ||
| 225 | map->type = entry->type; | ||
| 226 | |||
| 227 | ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); | ||
| 228 | if (ret_val != 0) { | ||
| 229 | kfree(map); | ||
| 230 | goto add_failure; | ||
| 231 | } | ||
| 232 | |||
| 233 | entry->type = NETLBL_NLTYPE_ADDRSELECT; | ||
| 234 | entry->type_def.addrsel = addrmap; | ||
| 235 | #endif /* IPv6 */ | ||
| 236 | } | ||
| 237 | |||
| 238 | ret_val = netlbl_domhsh_add(entry, audit_info); | ||
| 141 | if (ret_val != 0) | 239 | if (ret_val != 0) |
| 142 | goto add_failure; | 240 | goto add_failure; |
| 143 | 241 | ||
| 144 | return 0; | 242 | return 0; |
| 145 | 243 | ||
| 146 | add_failure: | 244 | add_failure: |
| 245 | if (cipsov4) | ||
| 246 | cipso_v4_doi_putdef(cipsov4); | ||
| 147 | if (entry) | 247 | if (entry) |
| 148 | kfree(entry->domain); | 248 | kfree(entry->domain); |
| 249 | kfree(addrmap); | ||
| 149 | kfree(entry); | 250 | kfree(entry); |
| 150 | return ret_val; | 251 | return ret_val; |
| 151 | } | 252 | } |
| 152 | 253 | ||
| 153 | /** | 254 | /** |
| 255 | * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry | ||
| 256 | * @skb: the NETLINK buffer | ||
| 257 | * @entry: the map entry | ||
| 258 | * | ||
| 259 | * Description: | ||
| 260 | * This function is a helper function used by the LISTALL and LISTDEF command | ||
| 261 | * handlers. The caller is responsibile for ensuring that the RCU read lock | ||
| 262 | * is held. Returns zero on success, negative values on failure. | ||
| 263 | * | ||
| 264 | */ | ||
| 265 | static int netlbl_mgmt_listentry(struct sk_buff *skb, | ||
| 266 | struct netlbl_dom_map *entry) | ||
| 267 | { | ||
| 268 | int ret_val; | ||
| 269 | struct nlattr *nla_a; | ||
| 270 | struct nlattr *nla_b; | ||
| 271 | struct netlbl_af4list *iter4; | ||
| 272 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 273 | struct netlbl_af6list *iter6; | ||
| 274 | #endif | ||
| 275 | |||
| 276 | if (entry->domain != NULL) { | ||
| 277 | ret_val = nla_put_string(skb, | ||
| 278 | NLBL_MGMT_A_DOMAIN, entry->domain); | ||
| 279 | if (ret_val != 0) | ||
| 280 | return ret_val; | ||
| 281 | } | ||
| 282 | |||
| 283 | switch (entry->type) { | ||
| 284 | case NETLBL_NLTYPE_ADDRSELECT: | ||
| 285 | nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); | ||
| 286 | if (nla_a == NULL) | ||
| 287 | return -ENOMEM; | ||
| 288 | |||
| 289 | netlbl_af4list_foreach_rcu(iter4, | ||
| 290 | &entry->type_def.addrsel->list4) { | ||
| 291 | struct netlbl_domaddr4_map *map4; | ||
| 292 | struct in_addr addr_struct; | ||
| 293 | |||
| 294 | nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); | ||
| 295 | if (nla_b == NULL) | ||
| 296 | return -ENOMEM; | ||
| 297 | |||
| 298 | addr_struct.s_addr = iter4->addr; | ||
| 299 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR, | ||
| 300 | sizeof(struct in_addr), | ||
| 301 | &addr_struct); | ||
| 302 | if (ret_val != 0) | ||
| 303 | return ret_val; | ||
| 304 | addr_struct.s_addr = iter4->mask; | ||
| 305 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK, | ||
| 306 | sizeof(struct in_addr), | ||
| 307 | &addr_struct); | ||
| 308 | if (ret_val != 0) | ||
| 309 | return ret_val; | ||
| 310 | map4 = netlbl_domhsh_addr4_entry(iter4); | ||
| 311 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, | ||
| 312 | map4->type); | ||
| 313 | if (ret_val != 0) | ||
| 314 | return ret_val; | ||
| 315 | switch (map4->type) { | ||
| 316 | case NETLBL_NLTYPE_CIPSOV4: | ||
| 317 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, | ||
| 318 | map4->type_def.cipsov4->doi); | ||
| 319 | if (ret_val != 0) | ||
| 320 | return ret_val; | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | |||
| 324 | nla_nest_end(skb, nla_b); | ||
| 325 | } | ||
| 326 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 327 | netlbl_af6list_foreach_rcu(iter6, | ||
| 328 | &entry->type_def.addrsel->list6) { | ||
| 329 | struct netlbl_domaddr6_map *map6; | ||
| 330 | |||
| 331 | nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); | ||
| 332 | if (nla_b == NULL) | ||
| 333 | return -ENOMEM; | ||
| 334 | |||
| 335 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR, | ||
| 336 | sizeof(struct in6_addr), | ||
| 337 | &iter6->addr); | ||
| 338 | if (ret_val != 0) | ||
| 339 | return ret_val; | ||
| 340 | ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK, | ||
| 341 | sizeof(struct in6_addr), | ||
| 342 | &iter6->mask); | ||
| 343 | if (ret_val != 0) | ||
| 344 | return ret_val; | ||
| 345 | map6 = netlbl_domhsh_addr6_entry(iter6); | ||
| 346 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, | ||
| 347 | map6->type); | ||
| 348 | if (ret_val != 0) | ||
| 349 | return ret_val; | ||
| 350 | |||
| 351 | nla_nest_end(skb, nla_b); | ||
| 352 | } | ||
| 353 | #endif /* IPv6 */ | ||
| 354 | |||
| 355 | nla_nest_end(skb, nla_a); | ||
| 356 | break; | ||
| 357 | case NETLBL_NLTYPE_UNLABELED: | ||
| 358 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); | ||
| 359 | break; | ||
| 360 | case NETLBL_NLTYPE_CIPSOV4: | ||
| 361 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); | ||
| 362 | if (ret_val != 0) | ||
| 363 | return ret_val; | ||
| 364 | ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, | ||
| 365 | entry->type_def.cipsov4->doi); | ||
| 366 | break; | ||
| 367 | } | ||
| 368 | |||
| 369 | return ret_val; | ||
| 370 | } | ||
| 371 | |||
| 372 | /* | ||
| 373 | * NetLabel Command Handlers | ||
| 374 | */ | ||
| 375 | |||
| 376 | /** | ||
| 377 | * netlbl_mgmt_add - Handle an ADD message | ||
| 378 | * @skb: the NETLINK buffer | ||
| 379 | * @info: the Generic NETLINK info block | ||
| 380 | * | ||
| 381 | * Description: | ||
| 382 | * Process a user generated ADD message and add the domains from the message | ||
| 383 | * to the hash table. See netlabel.h for a description of the message format. | ||
| 384 | * Returns zero on success, negative values on failure. | ||
| 385 | * | ||
| 386 | */ | ||
| 387 | static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) | ||
| 388 | { | ||
| 389 | struct netlbl_audit audit_info; | ||
| 390 | |||
| 391 | if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || | ||
| 392 | (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || | ||
| 393 | (info->attrs[NLBL_MGMT_A_IPV4ADDR] && | ||
| 394 | info->attrs[NLBL_MGMT_A_IPV6ADDR]) || | ||
| 395 | (info->attrs[NLBL_MGMT_A_IPV4MASK] && | ||
| 396 | info->attrs[NLBL_MGMT_A_IPV6MASK]) || | ||
| 397 | ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ | ||
| 398 | (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || | ||
| 399 | ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ | ||
| 400 | (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) | ||
| 401 | return -EINVAL; | ||
| 402 | |||
| 403 | netlbl_netlink_auditinfo(skb, &audit_info); | ||
| 404 | |||
| 405 | return netlbl_mgmt_add_common(info, &audit_info); | ||
| 406 | } | ||
| 407 | |||
| 408 | /** | ||
| 154 | * netlbl_mgmt_remove - Handle a REMOVE message | 409 | * netlbl_mgmt_remove - Handle a REMOVE message |
| 155 | * @skb: the NETLINK buffer | 410 | * @skb: the NETLINK buffer |
| 156 | * @info: the Generic NETLINK info block | 411 | * @info: the Generic NETLINK info block |
| @@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) | |||
| 198 | if (data == NULL) | 453 | if (data == NULL) |
| 199 | goto listall_cb_failure; | 454 | goto listall_cb_failure; |
| 200 | 455 | ||
| 201 | ret_val = nla_put_string(cb_arg->skb, | 456 | ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); |
| 202 | NLBL_MGMT_A_DOMAIN, | ||
| 203 | entry->domain); | ||
| 204 | if (ret_val != 0) | 457 | if (ret_val != 0) |
| 205 | goto listall_cb_failure; | 458 | goto listall_cb_failure; |
| 206 | ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type); | ||
| 207 | if (ret_val != 0) | ||
| 208 | goto listall_cb_failure; | ||
| 209 | switch (entry->type) { | ||
| 210 | case NETLBL_NLTYPE_CIPSOV4: | ||
| 211 | ret_val = nla_put_u32(cb_arg->skb, | ||
| 212 | NLBL_MGMT_A_CV4DOI, | ||
| 213 | entry->type_def.cipsov4->doi); | ||
| 214 | if (ret_val != 0) | ||
| 215 | goto listall_cb_failure; | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | 459 | ||
| 219 | cb_arg->seq++; | 460 | cb_arg->seq++; |
| 220 | return genlmsg_end(cb_arg->skb, data); | 461 | return genlmsg_end(cb_arg->skb, data); |
| @@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb, | |||
| 268 | */ | 509 | */ |
| 269 | static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) | 510 | static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) |
| 270 | { | 511 | { |
| 271 | int ret_val = -EINVAL; | ||
| 272 | struct netlbl_dom_map *entry = NULL; | ||
| 273 | u32 tmp_val; | ||
| 274 | struct netlbl_audit audit_info; | 512 | struct netlbl_audit audit_info; |
| 275 | 513 | ||
| 276 | if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) | 514 | if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || |
| 277 | goto adddef_failure; | 515 | (info->attrs[NLBL_MGMT_A_IPV4ADDR] && |
| 516 | info->attrs[NLBL_MGMT_A_IPV6ADDR]) || | ||
| 517 | (info->attrs[NLBL_MGMT_A_IPV4MASK] && | ||
| 518 | info->attrs[NLBL_MGMT_A_IPV6MASK]) || | ||
| 519 | ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ | ||
| 520 | (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || | ||
| 521 | ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ | ||
| 522 | (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) | ||
| 523 | return -EINVAL; | ||
| 278 | 524 | ||
| 279 | netlbl_netlink_auditinfo(skb, &audit_info); | 525 | netlbl_netlink_auditinfo(skb, &audit_info); |
| 280 | 526 | ||
| 281 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 527 | return netlbl_mgmt_add_common(info, &audit_info); |
| 282 | if (entry == NULL) { | ||
| 283 | ret_val = -ENOMEM; | ||
| 284 | goto adddef_failure; | ||
| 285 | } | ||
| 286 | entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); | ||
| 287 | |||
| 288 | switch (entry->type) { | ||
| 289 | case NETLBL_NLTYPE_UNLABELED: | ||
| 290 | ret_val = netlbl_domhsh_add_default(entry, &audit_info); | ||
| 291 | break; | ||
| 292 | case NETLBL_NLTYPE_CIPSOV4: | ||
| 293 | if (!info->attrs[NLBL_MGMT_A_CV4DOI]) | ||
| 294 | goto adddef_failure; | ||
| 295 | |||
| 296 | tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); | ||
| 297 | /* We should be holding a rcu_read_lock() here while we hold | ||
| 298 | * the result but since the entry will always be deleted when | ||
| 299 | * the CIPSO DOI is deleted we aren't going to keep the | ||
| 300 | * lock. */ | ||
| 301 | rcu_read_lock(); | ||
| 302 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); | ||
| 303 | if (entry->type_def.cipsov4 == NULL) { | ||
| 304 | rcu_read_unlock(); | ||
| 305 | goto adddef_failure; | ||
| 306 | } | ||
| 307 | ret_val = netlbl_domhsh_add_default(entry, &audit_info); | ||
| 308 | rcu_read_unlock(); | ||
| 309 | break; | ||
| 310 | default: | ||
| 311 | goto adddef_failure; | ||
| 312 | } | ||
| 313 | if (ret_val != 0) | ||
| 314 | goto adddef_failure; | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | |||
| 318 | adddef_failure: | ||
| 319 | kfree(entry); | ||
| 320 | return ret_val; | ||
| 321 | } | 528 | } |
| 322 | 529 | ||
| 323 | /** | 530 | /** |
| @@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) | |||
| 371 | ret_val = -ENOENT; | 578 | ret_val = -ENOENT; |
| 372 | goto listdef_failure_lock; | 579 | goto listdef_failure_lock; |
| 373 | } | 580 | } |
| 374 | ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); | 581 | ret_val = netlbl_mgmt_listentry(ans_skb, entry); |
| 375 | if (ret_val != 0) | ||
| 376 | goto listdef_failure_lock; | ||
| 377 | switch (entry->type) { | ||
| 378 | case NETLBL_NLTYPE_CIPSOV4: | ||
| 379 | ret_val = nla_put_u32(ans_skb, | ||
| 380 | NLBL_MGMT_A_CV4DOI, | ||
| 381 | entry->type_def.cipsov4->doi); | ||
| 382 | if (ret_val != 0) | ||
| 383 | goto listdef_failure_lock; | ||
| 384 | break; | ||
| 385 | } | ||
| 386 | rcu_read_unlock(); | 582 | rcu_read_unlock(); |
| 583 | if (ret_val != 0) | ||
| 584 | goto listdef_failure; | ||
| 387 | 585 | ||
| 388 | genlmsg_end(ans_skb, data); | 586 | genlmsg_end(ans_skb, data); |
| 389 | return genlmsg_reply(ans_skb, info); | 587 | return genlmsg_reply(ans_skb, info); |
