Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (24 commits)
integrity: special fs magic
As pointed out by Jonathan Corbet, the timer must be deleted before
ERROR: code indent should use tabs where possible
The tpm_dev_release function is only called for platform devices, not pnp
Protect tpm_chip_list when transversing it.
Renames num_open to is_open, as only one process can open the file at a time.
Remove the BKL calls from the TPM driver, which were added in the overall
netlabel: Add configuration support for local labeling
cipso: Add support for native local labeling and fixup mapping names
netlabel: Changes to the NetLabel security attributes to allow LSMs to pass full contexts
selinux: Cache NetLabel secattrs in the socket's security struct
selinux: Set socket NetLabel based on connection endpoint
netlabel: Add functionality to set the security attributes of a packet
netlabel: Add network address selectors to the NetLabel/LSM domain mapping
netlabel: Add a generic way to create ordered linked lists of network addrs
netlabel: Replace protocol/NetLabel linking with refrerence counts
smack: Fix missing calls to netlbl_skbuff_err()
selinux: Fix missing calls to netlbl_skbuff_err()
selinux: Fix a problem in security_netlbl_sid_to_secattr()
selinux: Better local/forward check in selinux_ip_postroute()
...

+2849 -1080
+47 -51
drivers/char/tpm/tpm.c
··· 954 954 955 955 /* 956 956 * Device file system interface to the TPM 957 + * 958 + * It's assured that the chip will be opened just once, 959 + * by the check of is_open variable, which is protected 960 + * by driver_lock. 957 961 */ 958 962 int tpm_open(struct inode *inode, struct file *file) 959 963 { 960 - int rc = 0, minor = iminor(inode); 964 + int minor = iminor(inode); 961 965 struct tpm_chip *chip = NULL, *pos; 962 966 963 - lock_kernel(); 964 - spin_lock(&driver_lock); 965 - 966 - list_for_each_entry(pos, &tpm_chip_list, list) { 967 + rcu_read_lock(); 968 + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { 967 969 if (pos->vendor.miscdev.minor == minor) { 968 970 chip = pos; 971 + get_device(chip->dev); 969 972 break; 970 973 } 971 974 } 975 + rcu_read_unlock(); 972 976 973 - if (chip == NULL) { 974 - rc = -ENODEV; 975 - goto err_out; 976 - } 977 + if (!chip) 978 + return -ENODEV; 977 979 978 - if (chip->num_opens) { 980 + if (test_and_set_bit(0, &chip->is_open)) { 979 981 dev_dbg(chip->dev, "Another process owns this TPM\n"); 980 - rc = -EBUSY; 981 - goto err_out; 982 + put_device(chip->dev); 983 + return -EBUSY; 982 984 } 983 - 984 - chip->num_opens++; 985 - get_device(chip->dev); 986 - 987 - spin_unlock(&driver_lock); 988 985 989 986 chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); 990 987 if (chip->data_buffer == NULL) { 991 - chip->num_opens--; 988 + clear_bit(0, &chip->is_open); 992 989 put_device(chip->dev); 993 - unlock_kernel(); 994 990 return -ENOMEM; 995 991 } 996 992 997 993 atomic_set(&chip->data_pending, 0); 998 994 999 995 file->private_data = chip; 1000 - unlock_kernel(); 1001 996 return 0; 1002 - 1003 - err_out: 1004 - spin_unlock(&driver_lock); 1005 - unlock_kernel(); 1006 - return rc; 1007 997 } 1008 998 EXPORT_SYMBOL_GPL(tpm_open); 1009 999 1000 + /* 1001 + * Called on file close 1002 + */ 1010 1003 int tpm_release(struct inode *inode, struct file *file) 1011 1004 { 1012 1005 struct tpm_chip *chip = file->private_data; 1013 1006 1014 - flush_scheduled_work(); 1015 - spin_lock(&driver_lock); 1016 - file->private_data = NULL; 1017 1007 del_singleshot_timer_sync(&chip->user_read_timer); 1008 + flush_scheduled_work(); 1009 + file->private_data = NULL; 1018 1010 atomic_set(&chip->data_pending, 0); 1019 - chip->num_opens--; 1020 - put_device(chip->dev); 1021 1011 kfree(chip->data_buffer); 1022 - spin_unlock(&driver_lock); 1012 + clear_bit(0, &chip->is_open); 1013 + put_device(chip->dev); 1023 1014 return 0; 1024 1015 } 1025 1016 EXPORT_SYMBOL_GPL(tpm_release); ··· 1084 1093 } 1085 1094 1086 1095 spin_lock(&driver_lock); 1087 - 1088 - list_del(&chip->list); 1089 - 1096 + list_del_rcu(&chip->list); 1090 1097 spin_unlock(&driver_lock); 1098 + synchronize_rcu(); 1091 1099 1092 1100 misc_deregister(&chip->vendor.miscdev); 1093 - 1094 1101 sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); 1095 1102 tpm_bios_log_teardown(chip->bios_dir); 1096 1103 ··· 1133 1144 } 1134 1145 EXPORT_SYMBOL_GPL(tpm_pm_resume); 1135 1146 1147 + /* In case vendor provided release function, call it too.*/ 1148 + 1149 + void tpm_dev_vendor_release(struct tpm_chip *chip) 1150 + { 1151 + if (chip->vendor.release) 1152 + chip->vendor.release(chip->dev); 1153 + 1154 + clear_bit(chip->dev_num, dev_mask); 1155 + kfree(chip->vendor.miscdev.name); 1156 + } 1157 + EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); 1158 + 1159 + 1136 1160 /* 1137 1161 * Once all references to platform device are down to 0, 1138 1162 * release all allocated structures. 1139 - * In case vendor provided release function, 1140 - * call it too. 1141 1163 */ 1142 1164 static void tpm_dev_release(struct device *dev) 1143 1165 { 1144 1166 struct tpm_chip *chip = dev_get_drvdata(dev); 1145 1167 1146 - if (chip->vendor.release) 1147 - chip->vendor.release(dev); 1168 + tpm_dev_vendor_release(chip); 1148 1169 1149 1170 chip->release(dev); 1150 - 1151 - clear_bit(chip->dev_num, dev_mask); 1152 - kfree(chip->vendor.miscdev.name); 1153 1171 kfree(chip); 1154 1172 } 1173 + EXPORT_SYMBOL_GPL(tpm_dev_release); 1155 1174 1156 1175 /* 1157 1176 * Called from tpm_<specific>.c probe function only for devices ··· 1168 1171 * upon errant exit from this function specific probe function should call 1169 1172 * pci_disable_device 1170 1173 */ 1171 - struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific 1172 - *entry) 1174 + struct tpm_chip *tpm_register_hardware(struct device *dev, 1175 + const struct tpm_vendor_specific *entry) 1173 1176 { 1174 1177 #define DEVNAME_SIZE 7 1175 1178 ··· 1228 1231 return NULL; 1229 1232 } 1230 1233 1231 - spin_lock(&driver_lock); 1232 - 1233 - list_add(&chip->list, &tpm_chip_list); 1234 - 1235 - spin_unlock(&driver_lock); 1236 - 1237 1234 if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { 1238 - list_del(&chip->list); 1239 1235 misc_deregister(&chip->vendor.miscdev); 1240 1236 put_device(chip->dev); 1237 + 1241 1238 return NULL; 1242 1239 } 1243 1240 1244 1241 chip->bios_dir = tpm_bios_log_setup(devname); 1242 + 1243 + /* Make chip available */ 1244 + spin_lock(&driver_lock); 1245 + list_add_rcu(&chip->list, &tpm_chip_list); 1246 + spin_unlock(&driver_lock); 1245 1247 1246 1248 return chip; 1247 1249 }
+2 -1
drivers/char/tpm/tpm.h
··· 90 90 struct device *dev; /* Device stuff */ 91 91 92 92 int dev_num; /* /dev/tpm# */ 93 - int num_opens; /* only one allowed */ 93 + unsigned long is_open; /* only one allowed */ 94 94 int time_expired; 95 95 96 96 /* Data passed to and from the tpm via the read/write calls */ ··· 132 132 const struct tpm_vendor_specific *); 133 133 extern int tpm_open(struct inode *, struct file *); 134 134 extern int tpm_release(struct inode *, struct file *); 135 + extern void tpm_dev_vendor_release(struct tpm_chip *); 135 136 extern ssize_t tpm_write(struct file *, const char __user *, size_t, 136 137 loff_t *); 137 138 extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
+13 -1
drivers/char/tpm/tpm_tis.c
··· 630 630 {"", 0} /* Terminator */ 631 631 }; 632 632 633 + static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) 634 + { 635 + struct tpm_chip *chip = pnp_get_drvdata(dev); 636 + 637 + tpm_dev_vendor_release(chip); 638 + 639 + kfree(chip); 640 + } 641 + 642 + 633 643 static struct pnp_driver tis_pnp_driver = { 634 644 .name = "tpm_tis", 635 645 .id_table = tpm_pnp_tbl, 636 646 .probe = tpm_tis_pnp_init, 637 647 .suspend = tpm_tis_pnp_suspend, 638 648 .resume = tpm_tis_pnp_resume, 649 + .remove = tpm_tis_pnp_remove, 639 650 }; 640 651 641 652 #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 ··· 694 683 spin_lock(&tis_lock); 695 684 list_for_each_entry_safe(i, j, &tis_chips, list) { 696 685 chip = to_tpm_chip(i); 686 + tpm_remove_hardware(chip->dev); 697 687 iowrite32(~TPM_GLOBAL_INT_ENABLE & 698 688 ioread32(chip->vendor.iobase + 699 689 TPM_INT_ENABLE(chip->vendor. ··· 706 694 free_irq(chip->vendor.irq, chip); 707 695 iounmap(i->iobase); 708 696 list_del(&i->list); 709 - tpm_remove_hardware(chip->dev); 710 697 } 711 698 spin_unlock(&tis_lock); 699 + 712 700 if (force) { 713 701 platform_device_unregister(pdev); 714 702 driver_unregister(&tis_drv);
+1 -2
fs/debugfs/inode.c
··· 26 26 #include <linux/debugfs.h> 27 27 #include <linux/fsnotify.h> 28 28 #include <linux/string.h> 29 - 30 - #define DEBUGFS_MAGIC 0x64626720 29 + #include <linux/magic.h> 31 30 32 31 static struct vfsmount *debugfs_mount; 33 32 static int debugfs_mount_count;
+4
include/linux/magic.h
··· 6 6 #define AFS_SUPER_MAGIC 0x5346414F 7 7 #define AUTOFS_SUPER_MAGIC 0x0187 8 8 #define CODA_SUPER_MAGIC 0x73757245 9 + #define DEBUGFS_MAGIC 0x64626720 10 + #define SYSFS_MAGIC 0x62656572 11 + #define SECURITYFS_MAGIC 0x73636673 12 + #define TMPFS_MAGIC 0x01021994 9 13 #define EFS_SUPER_MAGIC 0x414A53 10 14 #define EXT2_SUPER_MAGIC 0xEF53 11 15 #define EXT3_SUPER_MAGIC 0xEF53
+41 -14
include/net/cipso_ipv4.h
··· 40 40 #include <linux/net.h> 41 41 #include <linux/skbuff.h> 42 42 #include <net/netlabel.h> 43 + #include <asm/atomic.h> 43 44 44 45 /* known doi values */ 45 46 #define CIPSO_V4_DOI_UNKNOWN 0x00000000 46 47 47 - /* tag types */ 48 + /* standard tag types */ 48 49 #define CIPSO_V4_TAG_INVALID 0 49 50 #define CIPSO_V4_TAG_RBITMAP 1 50 51 #define CIPSO_V4_TAG_ENUM 2 ··· 53 52 #define CIPSO_V4_TAG_PBITMAP 6 54 53 #define CIPSO_V4_TAG_FREEFORM 7 55 54 55 + /* non-standard tag types (tags > 127) */ 56 + #define CIPSO_V4_TAG_LOCAL 128 57 + 56 58 /* doi mapping types */ 57 59 #define CIPSO_V4_MAP_UNKNOWN 0 58 - #define CIPSO_V4_MAP_STD 1 60 + #define CIPSO_V4_MAP_TRANS 1 59 61 #define CIPSO_V4_MAP_PASS 2 62 + #define CIPSO_V4_MAP_LOCAL 3 60 63 61 64 /* limits */ 62 65 #define CIPSO_V4_MAX_REM_LVLS 255 ··· 84 79 } map; 85 80 u8 tags[CIPSO_V4_TAG_MAXCNT]; 86 81 87 - u32 valid; 82 + atomic_t refcount; 88 83 struct list_head list; 89 84 struct rcu_head rcu; 90 - struct list_head dom_list; 91 85 }; 92 86 93 87 /* Standard CIPSO mapping table */ ··· 132 128 133 129 #ifdef CONFIG_NETLABEL 134 130 int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); 135 - int cipso_v4_doi_remove(u32 doi, 136 - struct netlbl_audit *audit_info, 137 - void (*callback) (struct rcu_head * head)); 131 + void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); 132 + int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); 138 133 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); 134 + void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def); 139 135 int cipso_v4_doi_walk(u32 *skip_cnt, 140 136 int (*callback) (struct cipso_v4_doi *doi_def, void *arg), 141 137 void *cb_arg); 142 - int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain); 143 - int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, 144 - const char *domain); 145 138 #else 146 139 static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) 147 140 { 148 141 return -ENOSYS; 149 142 } 150 143 144 + static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) 145 + { 146 + return; 147 + } 148 + 151 149 static inline int cipso_v4_doi_remove(u32 doi, 152 - struct netlbl_audit *audit_info, 153 - void (*callback) (struct rcu_head * head)) 150 + struct netlbl_audit *audit_info) 154 151 { 155 152 return 0; 156 153 } ··· 211 206 int cipso_v4_sock_setattr(struct sock *sk, 212 207 const struct cipso_v4_doi *doi_def, 213 208 const struct netlbl_lsm_secattr *secattr); 209 + void cipso_v4_sock_delattr(struct sock *sk); 214 210 int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); 211 + int cipso_v4_skbuff_setattr(struct sk_buff *skb, 212 + const struct cipso_v4_doi *doi_def, 213 + const struct netlbl_lsm_secattr *secattr); 214 + int cipso_v4_skbuff_delattr(struct sk_buff *skb); 215 215 int cipso_v4_skbuff_getattr(const struct sk_buff *skb, 216 216 struct netlbl_lsm_secattr *secattr); 217 - int cipso_v4_validate(unsigned char **option); 217 + int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); 218 218 #else 219 219 static inline void cipso_v4_error(struct sk_buff *skb, 220 220 int error, ··· 235 225 return -ENOSYS; 236 226 } 237 227 228 + static inline void cipso_v4_sock_delattr(struct sock *sk) 229 + { 230 + } 231 + 238 232 static inline int cipso_v4_sock_getattr(struct sock *sk, 239 233 struct netlbl_lsm_secattr *secattr) 234 + { 235 + return -ENOSYS; 236 + } 237 + 238 + static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, 239 + const struct cipso_v4_doi *doi_def, 240 + const struct netlbl_lsm_secattr *secattr) 241 + { 242 + return -ENOSYS; 243 + } 244 + 245 + static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb) 240 246 { 241 247 return -ENOSYS; 242 248 } ··· 263 237 return -ENOSYS; 264 238 } 265 239 266 - static inline int cipso_v4_validate(unsigned char **option) 240 + static inline int cipso_v4_validate(const struct sk_buff *skb, 241 + unsigned char **option) 267 242 { 268 243 return -ENOSYS; 269 244 }
+33 -18
include/net/netlabel.h
··· 9 9 */ 10 10 11 11 /* 12 - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 12 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 13 13 * 14 14 * This program is free software; you can redistribute it and/or modify 15 15 * it under the terms of the GNU General Public License as published by ··· 72 72 /* NetLabel NETLINK protocol version 73 73 * 1: initial version 74 74 * 2: added static labels for unlabeled connections 75 + * 3: network selectors added to the NetLabel/LSM domain mapping and the 76 + * CIPSO_V4_MAP_LOCAL CIPSO mapping was added 75 77 */ 76 - #define NETLBL_PROTO_VERSION 2 78 + #define NETLBL_PROTO_VERSION 3 77 79 78 80 /* NetLabel NETLINK types/families */ 79 81 #define NETLBL_NLTYPE_NONE 0 ··· 89 87 #define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" 90 88 #define NETLBL_NLTYPE_UNLABELED 5 91 89 #define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" 90 + #define NETLBL_NLTYPE_ADDRSELECT 6 91 + #define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL" 92 92 93 93 /* 94 94 * NetLabel - Kernel API for accessing the network packet label mappings. ··· 204 200 u32 type; 205 201 char *domain; 206 202 struct netlbl_lsm_cache *cache; 207 - union { 203 + struct { 208 204 struct { 209 205 struct netlbl_lsm_secattr_catmap *cat; 210 206 u32 lvl; ··· 356 352 int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info); 357 353 int netlbl_cfg_unlbl_add_map(const char *domain, 358 354 struct netlbl_audit *audit_info); 359 - int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, 360 - struct netlbl_audit *audit_info); 361 355 int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, 362 356 const char *domain, 363 357 struct netlbl_audit *audit_info); 364 - int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info); 365 358 366 359 /* 367 360 * LSM security attribute operations ··· 381 380 int netlbl_enabled(void); 382 381 int netlbl_sock_setattr(struct sock *sk, 383 382 const struct netlbl_lsm_secattr *secattr); 383 + void netlbl_sock_delattr(struct sock *sk); 384 384 int netlbl_sock_getattr(struct sock *sk, 385 385 struct netlbl_lsm_secattr *secattr); 386 + int netlbl_conn_setattr(struct sock *sk, 387 + struct sockaddr *addr, 388 + const struct netlbl_lsm_secattr *secattr); 389 + int netlbl_skbuff_setattr(struct sk_buff *skb, 390 + u16 family, 391 + const struct netlbl_lsm_secattr *secattr); 386 392 int netlbl_skbuff_getattr(const struct sk_buff *skb, 387 393 u16 family, 388 394 struct netlbl_lsm_secattr *secattr); 389 - void netlbl_skbuff_err(struct sk_buff *skb, int error); 395 + void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway); 390 396 391 397 /* 392 398 * LSM label mapping cache operations ··· 412 404 { 413 405 return -ENOSYS; 414 406 } 415 - static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, 416 - struct netlbl_audit *audit_info) 417 - { 418 - return -ENOSYS; 419 - } 420 407 static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, 421 408 const char *domain, 422 409 struct netlbl_audit *audit_info) 423 - { 424 - return -ENOSYS; 425 - } 426 - static inline int netlbl_cfg_cipsov4_del(u32 doi, 427 - struct netlbl_audit *audit_info) 428 410 { 429 411 return -ENOSYS; 430 412 } ··· 454 456 { 455 457 return -ENOSYS; 456 458 } 459 + static inline void netlbl_sock_delattr(struct sock *sk) 460 + { 461 + } 457 462 static inline int netlbl_sock_getattr(struct sock *sk, 458 463 struct netlbl_lsm_secattr *secattr) 464 + { 465 + return -ENOSYS; 466 + } 467 + static inline int netlbl_conn_setattr(struct sock *sk, 468 + struct sockaddr *addr, 469 + const struct netlbl_lsm_secattr *secattr) 470 + { 471 + return -ENOSYS; 472 + } 473 + static inline int netlbl_skbuff_setattr(struct sk_buff *skb, 474 + u16 family, 475 + const struct netlbl_lsm_secattr *secattr) 459 476 { 460 477 return -ENOSYS; 461 478 } ··· 480 467 { 481 468 return -ENOSYS; 482 469 } 483 - static inline void netlbl_skbuff_err(struct sk_buff *skb, int error) 470 + static inline void netlbl_skbuff_err(struct sk_buff *skb, 471 + int error, 472 + int gateway) 484 473 { 485 474 return; 486 475 }
+1 -3
mm/shmem.c
··· 50 50 #include <linux/migrate.h> 51 51 #include <linux/highmem.h> 52 52 #include <linux/seq_file.h> 53 + #include <linux/magic.h> 53 54 54 55 #include <asm/uaccess.h> 55 56 #include <asm/div64.h> 56 57 #include <asm/pgtable.h> 57 - 58 - /* This magic number is used in glibc for posix shared memory */ 59 - #define TMPFS_MAGIC 0x01021994 60 58 61 59 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) 62 60 #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
+470 -204
net/ipv4/cipso_ipv4.c
··· 13 13 */ 14 14 15 15 /* 16 - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 16 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 17 17 * 18 18 * This program is free software; you can redistribute it and/or modify 19 19 * it under the terms of the GNU General Public License as published by ··· 47 47 #include <asm/bug.h> 48 48 #include <asm/unaligned.h> 49 49 50 - struct cipso_v4_domhsh_entry { 51 - char *domain; 52 - u32 valid; 53 - struct list_head list; 54 - struct rcu_head rcu; 55 - }; 56 - 57 50 /* List of available DOI definitions */ 58 - /* XXX - Updates should be minimal so having a single lock for the 59 - * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be 60 - * okay. */ 61 51 /* XXX - This currently assumes a minimal number of different DOIs in use, 62 52 * if in practice there are a lot of different DOIs this list should 63 53 * probably be turned into a hash table or something similar so we ··· 108 118 * zero then it is possibile to fit 8 category ranges because the zero should 109 119 * be omitted. */ 110 120 #define CIPSO_V4_TAG_RNG_CAT_MAX 8 121 + 122 + /* Base length of the local tag (non-standard tag). 123 + * Tag definition (may change between kernel versions) 124 + * 125 + * 0 8 16 24 32 126 + * +----------+----------+----------+----------+ 127 + * | 10000000 | 00000110 | 32-bit secid value | 128 + * +----------+----------+----------+----------+ 129 + * | in (host byte order)| 130 + * +----------+----------+ 131 + * 132 + */ 133 + #define CIPSO_V4_TAG_LOC_BLEN 6 111 134 112 135 /* 113 136 * Helper Functions ··· 194 191 bitmap[byte_spot] |= bitmask; 195 192 else 196 193 bitmap[byte_spot] &= ~bitmask; 197 - } 198 - 199 - /** 200 - * cipso_v4_doi_domhsh_free - Frees a domain list entry 201 - * @entry: the entry's RCU field 202 - * 203 - * Description: 204 - * This function is designed to be used as a callback to the call_rcu() 205 - * function so that the memory allocated to a domain list entry can be released 206 - * safely. 207 - * 208 - */ 209 - static void cipso_v4_doi_domhsh_free(struct rcu_head *entry) 210 - { 211 - struct cipso_v4_domhsh_entry *ptr; 212 - 213 - ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu); 214 - kfree(ptr->domain); 215 - kfree(ptr); 216 194 } 217 195 218 196 /** ··· 441 457 struct cipso_v4_doi *iter; 442 458 443 459 list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) 444 - if (iter->doi == doi && iter->valid) 460 + if (iter->doi == doi && atomic_read(&iter->refcount)) 445 461 return iter; 446 462 return NULL; 447 463 } ··· 480 496 if (doi_def->type != CIPSO_V4_MAP_PASS) 481 497 return -EINVAL; 482 498 break; 499 + case CIPSO_V4_TAG_LOCAL: 500 + if (doi_def->type != CIPSO_V4_MAP_LOCAL) 501 + return -EINVAL; 502 + break; 483 503 default: 484 504 return -EINVAL; 485 505 } 486 506 } 487 507 488 - doi_def->valid = 1; 508 + atomic_set(&doi_def->refcount, 1); 489 509 INIT_RCU_HEAD(&doi_def->rcu); 490 - INIT_LIST_HEAD(&doi_def->dom_list); 491 510 492 511 spin_lock(&cipso_v4_doi_list_lock); 493 512 if (cipso_v4_doi_search(doi_def->doi) != NULL) ··· 506 519 } 507 520 508 521 /** 509 - * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine 510 - * @doi: the DOI value 511 - * @audit_secid: the LSM secid to use in the audit message 512 - * @callback: the DOI cleanup/free callback 522 + * cipso_v4_doi_free - Frees a DOI definition 523 + * @entry: the entry's RCU field 513 524 * 514 525 * Description: 515 - * Removes a DOI definition from the CIPSO engine, @callback is called to 516 - * free any memory. The NetLabel routines will be called to release their own 517 - * LSM domain mappings as well as our own domain list. Returns zero on 518 - * success and negative values on failure. 526 + * This function frees all of the memory associated with a DOI definition. 519 527 * 520 528 */ 521 - int cipso_v4_doi_remove(u32 doi, 522 - struct netlbl_audit *audit_info, 523 - void (*callback) (struct rcu_head * head)) 529 + void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) 524 530 { 525 - struct cipso_v4_doi *doi_def; 526 - struct cipso_v4_domhsh_entry *dom_iter; 531 + if (doi_def == NULL) 532 + return; 527 533 528 - spin_lock(&cipso_v4_doi_list_lock); 529 - doi_def = cipso_v4_doi_search(doi); 530 - if (doi_def != NULL) { 531 - doi_def->valid = 0; 532 - list_del_rcu(&doi_def->list); 533 - spin_unlock(&cipso_v4_doi_list_lock); 534 - rcu_read_lock(); 535 - list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) 536 - if (dom_iter->valid) 537 - netlbl_cfg_map_del(dom_iter->domain, 538 - audit_info); 539 - rcu_read_unlock(); 540 - cipso_v4_cache_invalidate(); 541 - call_rcu(&doi_def->rcu, callback); 542 - return 0; 534 + switch (doi_def->type) { 535 + case CIPSO_V4_MAP_TRANS: 536 + kfree(doi_def->map.std->lvl.cipso); 537 + kfree(doi_def->map.std->lvl.local); 538 + kfree(doi_def->map.std->cat.cipso); 539 + kfree(doi_def->map.std->cat.local); 540 + break; 543 541 } 544 - spin_unlock(&cipso_v4_doi_list_lock); 545 - 546 - return -ENOENT; 542 + kfree(doi_def); 547 543 } 548 544 549 545 /** 550 - * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition 546 + * cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer 547 + * @entry: the entry's RCU field 548 + * 549 + * Description: 550 + * This function is designed to be used as a callback to the call_rcu() 551 + * function so that the memory allocated to the DOI definition can be released 552 + * safely. 553 + * 554 + */ 555 + static void cipso_v4_doi_free_rcu(struct rcu_head *entry) 556 + { 557 + struct cipso_v4_doi *doi_def; 558 + 559 + doi_def = container_of(entry, struct cipso_v4_doi, rcu); 560 + cipso_v4_doi_free(doi_def); 561 + } 562 + 563 + /** 564 + * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine 565 + * @doi: the DOI value 566 + * @audit_secid: the LSM secid to use in the audit message 567 + * 568 + * Description: 569 + * Removes a DOI definition from the CIPSO engine. The NetLabel routines will 570 + * be called to release their own LSM domain mappings as well as our own 571 + * domain list. Returns zero on success and negative values on failure. 572 + * 573 + */ 574 + int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) 575 + { 576 + struct cipso_v4_doi *doi_def; 577 + 578 + spin_lock(&cipso_v4_doi_list_lock); 579 + doi_def = cipso_v4_doi_search(doi); 580 + if (doi_def == NULL) { 581 + spin_unlock(&cipso_v4_doi_list_lock); 582 + return -ENOENT; 583 + } 584 + if (!atomic_dec_and_test(&doi_def->refcount)) { 585 + spin_unlock(&cipso_v4_doi_list_lock); 586 + return -EBUSY; 587 + } 588 + list_del_rcu(&doi_def->list); 589 + spin_unlock(&cipso_v4_doi_list_lock); 590 + 591 + cipso_v4_cache_invalidate(); 592 + call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); 593 + 594 + return 0; 595 + } 596 + 597 + /** 598 + * cipso_v4_doi_getdef - Returns a reference to a valid DOI definition 551 599 * @doi: the DOI value 552 600 * 553 601 * Description: 554 602 * Searches for a valid DOI definition and if one is found it is returned to 555 603 * the caller. Otherwise NULL is returned. The caller must ensure that 556 - * rcu_read_lock() is held while accessing the returned definition. 604 + * rcu_read_lock() is held while accessing the returned definition and the DOI 605 + * definition reference count is decremented when the caller is done. 557 606 * 558 607 */ 559 608 struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) 560 609 { 561 - return cipso_v4_doi_search(doi); 610 + struct cipso_v4_doi *doi_def; 611 + 612 + rcu_read_lock(); 613 + doi_def = cipso_v4_doi_search(doi); 614 + if (doi_def == NULL) 615 + goto doi_getdef_return; 616 + if (!atomic_inc_not_zero(&doi_def->refcount)) 617 + doi_def = NULL; 618 + 619 + doi_getdef_return: 620 + rcu_read_unlock(); 621 + return doi_def; 622 + } 623 + 624 + /** 625 + * cipso_v4_doi_putdef - Releases a reference for the given DOI definition 626 + * @doi_def: the DOI definition 627 + * 628 + * Description: 629 + * Releases a DOI definition reference obtained from cipso_v4_doi_getdef(). 630 + * 631 + */ 632 + void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def) 633 + { 634 + if (doi_def == NULL) 635 + return; 636 + 637 + if (!atomic_dec_and_test(&doi_def->refcount)) 638 + return; 639 + spin_lock(&cipso_v4_doi_list_lock); 640 + list_del_rcu(&doi_def->list); 641 + spin_unlock(&cipso_v4_doi_list_lock); 642 + 643 + cipso_v4_cache_invalidate(); 644 + call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); 562 645 } 563 646 564 647 /** ··· 654 597 655 598 rcu_read_lock(); 656 599 list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) 657 - if (iter_doi->valid) { 600 + if (atomic_read(&iter_doi->refcount) > 0) { 658 601 if (doi_cnt++ < *skip_cnt) 659 602 continue; 660 603 ret_val = callback(iter_doi, cb_arg); ··· 668 611 rcu_read_unlock(); 669 612 *skip_cnt = doi_cnt; 670 613 return ret_val; 671 - } 672 - 673 - /** 674 - * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition 675 - * @doi_def: the DOI definition 676 - * @domain: the domain to add 677 - * 678 - * Description: 679 - * Adds the @domain to the DOI specified by @doi_def, this function 680 - * should only be called by external functions (i.e. NetLabel). This function 681 - * does allocate memory. Returns zero on success, negative values on failure. 682 - * 683 - */ 684 - int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain) 685 - { 686 - struct cipso_v4_domhsh_entry *iter; 687 - struct cipso_v4_domhsh_entry *new_dom; 688 - 689 - new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL); 690 - if (new_dom == NULL) 691 - return -ENOMEM; 692 - if (domain) { 693 - new_dom->domain = kstrdup(domain, GFP_KERNEL); 694 - if (new_dom->domain == NULL) { 695 - kfree(new_dom); 696 - return -ENOMEM; 697 - } 698 - } 699 - new_dom->valid = 1; 700 - INIT_RCU_HEAD(&new_dom->rcu); 701 - 702 - spin_lock(&cipso_v4_doi_list_lock); 703 - list_for_each_entry(iter, &doi_def->dom_list, list) 704 - if (iter->valid && 705 - ((domain != NULL && iter->domain != NULL && 706 - strcmp(iter->domain, domain) == 0) || 707 - (domain == NULL && iter->domain == NULL))) { 708 - spin_unlock(&cipso_v4_doi_list_lock); 709 - kfree(new_dom->domain); 710 - kfree(new_dom); 711 - return -EEXIST; 712 - } 713 - list_add_tail_rcu(&new_dom->list, &doi_def->dom_list); 714 - spin_unlock(&cipso_v4_doi_list_lock); 715 - 716 - return 0; 717 - } 718 - 719 - /** 720 - * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition 721 - * @doi_def: the DOI definition 722 - * @domain: the domain to remove 723 - * 724 - * Description: 725 - * Removes the @domain from the DOI specified by @doi_def, this function 726 - * should only be called by external functions (i.e. NetLabel). Returns zero 727 - * on success and negative values on error. 728 - * 729 - */ 730 - int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, 731 - const char *domain) 732 - { 733 - struct cipso_v4_domhsh_entry *iter; 734 - 735 - spin_lock(&cipso_v4_doi_list_lock); 736 - list_for_each_entry(iter, &doi_def->dom_list, list) 737 - if (iter->valid && 738 - ((domain != NULL && iter->domain != NULL && 739 - strcmp(iter->domain, domain) == 0) || 740 - (domain == NULL && iter->domain == NULL))) { 741 - iter->valid = 0; 742 - list_del_rcu(&iter->list); 743 - spin_unlock(&cipso_v4_doi_list_lock); 744 - call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free); 745 - return 0; 746 - } 747 - spin_unlock(&cipso_v4_doi_list_lock); 748 - 749 - return -ENOENT; 750 614 } 751 615 752 616 /* ··· 690 712 switch (doi_def->type) { 691 713 case CIPSO_V4_MAP_PASS: 692 714 return 0; 693 - case CIPSO_V4_MAP_STD: 715 + case CIPSO_V4_MAP_TRANS: 694 716 if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) 695 717 return 0; 696 718 break; ··· 719 741 case CIPSO_V4_MAP_PASS: 720 742 *net_lvl = host_lvl; 721 743 return 0; 722 - case CIPSO_V4_MAP_STD: 744 + case CIPSO_V4_MAP_TRANS: 723 745 if (host_lvl < doi_def->map.std->lvl.local_size && 724 746 doi_def->map.std->lvl.local[host_lvl] < CIPSO_V4_INV_LVL) { 725 747 *net_lvl = doi_def->map.std->lvl.local[host_lvl]; ··· 753 775 case CIPSO_V4_MAP_PASS: 754 776 *host_lvl = net_lvl; 755 777 return 0; 756 - case CIPSO_V4_MAP_STD: 778 + case CIPSO_V4_MAP_TRANS: 757 779 map_tbl = doi_def->map.std; 758 780 if (net_lvl < map_tbl->lvl.cipso_size && 759 781 map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { ··· 790 812 switch (doi_def->type) { 791 813 case CIPSO_V4_MAP_PASS: 792 814 return 0; 793 - case CIPSO_V4_MAP_STD: 815 + case CIPSO_V4_MAP_TRANS: 794 816 cipso_cat_size = doi_def->map.std->cat.cipso_size; 795 817 cipso_array = doi_def->map.std->cat.cipso; 796 818 for (;;) { ··· 838 860 u32 host_cat_size = 0; 839 861 u32 *host_cat_array = NULL; 840 862 841 - if (doi_def->type == CIPSO_V4_MAP_STD) { 863 + if (doi_def->type == CIPSO_V4_MAP_TRANS) { 842 864 host_cat_size = doi_def->map.std->cat.local_size; 843 865 host_cat_array = doi_def->map.std->cat.local; 844 866 } ··· 853 875 case CIPSO_V4_MAP_PASS: 854 876 net_spot = host_spot; 855 877 break; 856 - case CIPSO_V4_MAP_STD: 878 + case CIPSO_V4_MAP_TRANS: 857 879 if (host_spot >= host_cat_size) 858 880 return -EPERM; 859 881 net_spot = host_cat_array[host_spot]; ··· 899 921 u32 net_cat_size = 0; 900 922 u32 *net_cat_array = NULL; 901 923 902 - if (doi_def->type == CIPSO_V4_MAP_STD) { 924 + if (doi_def->type == CIPSO_V4_MAP_TRANS) { 903 925 net_cat_size = doi_def->map.std->cat.cipso_size; 904 926 net_cat_array = doi_def->map.std->cat.cipso; 905 927 } ··· 919 941 case CIPSO_V4_MAP_PASS: 920 942 host_spot = net_spot; 921 943 break; 922 - case CIPSO_V4_MAP_STD: 944 + case CIPSO_V4_MAP_TRANS: 923 945 if (net_spot >= net_cat_size) 924 946 return -EPERM; 925 947 host_spot = net_cat_array[net_spot]; ··· 1255 1277 } else 1256 1278 tag_len = 4; 1257 1279 1258 - buffer[0] = 0x01; 1280 + buffer[0] = CIPSO_V4_TAG_RBITMAP; 1259 1281 buffer[1] = tag_len; 1260 1282 buffer[3] = level; 1261 1283 ··· 1351 1373 } else 1352 1374 tag_len = 4; 1353 1375 1354 - buffer[0] = 0x02; 1376 + buffer[0] = CIPSO_V4_TAG_ENUM; 1355 1377 buffer[1] = tag_len; 1356 1378 buffer[3] = level; 1357 1379 ··· 1447 1469 } else 1448 1470 tag_len = 4; 1449 1471 1450 - buffer[0] = 0x05; 1472 + buffer[0] = CIPSO_V4_TAG_RANGE; 1451 1473 buffer[1] = tag_len; 1452 1474 buffer[3] = level; 1453 1475 ··· 1501 1523 } 1502 1524 1503 1525 /** 1526 + * cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard) 1527 + * @doi_def: the DOI definition 1528 + * @secattr: the security attributes 1529 + * @buffer: the option buffer 1530 + * @buffer_len: length of buffer in bytes 1531 + * 1532 + * Description: 1533 + * Generate a CIPSO option using the local tag. Returns the size of the tag 1534 + * on success, negative values on failure. 1535 + * 1536 + */ 1537 + static int cipso_v4_gentag_loc(const struct cipso_v4_doi *doi_def, 1538 + const struct netlbl_lsm_secattr *secattr, 1539 + unsigned char *buffer, 1540 + u32 buffer_len) 1541 + { 1542 + if (!(secattr->flags & NETLBL_SECATTR_SECID)) 1543 + return -EPERM; 1544 + 1545 + buffer[0] = CIPSO_V4_TAG_LOCAL; 1546 + buffer[1] = CIPSO_V4_TAG_LOC_BLEN; 1547 + *(u32 *)&buffer[2] = secattr->attr.secid; 1548 + 1549 + return CIPSO_V4_TAG_LOC_BLEN; 1550 + } 1551 + 1552 + /** 1553 + * cipso_v4_parsetag_loc - Parse a CIPSO local tag 1554 + * @doi_def: the DOI definition 1555 + * @tag: the CIPSO tag 1556 + * @secattr: the security attributes 1557 + * 1558 + * Description: 1559 + * Parse a CIPSO local tag and return the security attributes in @secattr. 1560 + * Return zero on success, negatives values on failure. 1561 + * 1562 + */ 1563 + static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def, 1564 + const unsigned char *tag, 1565 + struct netlbl_lsm_secattr *secattr) 1566 + { 1567 + secattr->attr.secid = *(u32 *)&tag[2]; 1568 + secattr->flags |= NETLBL_SECATTR_SECID; 1569 + 1570 + return 0; 1571 + } 1572 + 1573 + /** 1504 1574 * cipso_v4_validate - Validate a CIPSO option 1505 1575 * @option: the start of the option, on error it is set to point to the error 1506 1576 * ··· 1567 1541 * that is unrecognized." 1568 1542 * 1569 1543 */ 1570 - int cipso_v4_validate(unsigned char **option) 1544 + int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) 1571 1545 { 1572 1546 unsigned char *opt = *option; 1573 1547 unsigned char *tag; ··· 1592 1566 goto validate_return_locked; 1593 1567 } 1594 1568 1595 - opt_iter = 6; 1569 + opt_iter = CIPSO_V4_HDR_LEN; 1596 1570 tag = opt + opt_iter; 1597 1571 while (opt_iter < opt_len) { 1598 1572 for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) ··· 1610 1584 1611 1585 switch (tag[0]) { 1612 1586 case CIPSO_V4_TAG_RBITMAP: 1613 - if (tag_len < 4) { 1587 + if (tag_len < CIPSO_V4_TAG_RBM_BLEN) { 1614 1588 err_offset = opt_iter + 1; 1615 1589 goto validate_return_locked; 1616 1590 } ··· 1628 1602 err_offset = opt_iter + 3; 1629 1603 goto validate_return_locked; 1630 1604 } 1631 - if (tag_len > 4 && 1605 + if (tag_len > CIPSO_V4_TAG_RBM_BLEN && 1632 1606 cipso_v4_map_cat_rbm_valid(doi_def, 1633 1607 &tag[4], 1634 1608 tag_len - 4) < 0) { ··· 1638 1612 } 1639 1613 break; 1640 1614 case CIPSO_V4_TAG_ENUM: 1641 - if (tag_len < 4) { 1615 + if (tag_len < CIPSO_V4_TAG_ENUM_BLEN) { 1642 1616 err_offset = opt_iter + 1; 1643 1617 goto validate_return_locked; 1644 1618 } ··· 1648 1622 err_offset = opt_iter + 3; 1649 1623 goto validate_return_locked; 1650 1624 } 1651 - if (tag_len > 4 && 1625 + if (tag_len > CIPSO_V4_TAG_ENUM_BLEN && 1652 1626 cipso_v4_map_cat_enum_valid(doi_def, 1653 1627 &tag[4], 1654 1628 tag_len - 4) < 0) { ··· 1657 1631 } 1658 1632 break; 1659 1633 case CIPSO_V4_TAG_RANGE: 1660 - if (tag_len < 4) { 1634 + if (tag_len < CIPSO_V4_TAG_RNG_BLEN) { 1661 1635 err_offset = opt_iter + 1; 1662 1636 goto validate_return_locked; 1663 1637 } ··· 1667 1641 err_offset = opt_iter + 3; 1668 1642 goto validate_return_locked; 1669 1643 } 1670 - if (tag_len > 4 && 1644 + if (tag_len > CIPSO_V4_TAG_RNG_BLEN && 1671 1645 cipso_v4_map_cat_rng_valid(doi_def, 1672 1646 &tag[4], 1673 1647 tag_len - 4) < 0) { 1674 1648 err_offset = opt_iter + 4; 1649 + goto validate_return_locked; 1650 + } 1651 + break; 1652 + case CIPSO_V4_TAG_LOCAL: 1653 + /* This is a non-standard tag that we only allow for 1654 + * local connections, so if the incoming interface is 1655 + * not the loopback device drop the packet. */ 1656 + if (!(skb->dev->flags & IFF_LOOPBACK)) { 1657 + err_offset = opt_iter; 1658 + goto validate_return_locked; 1659 + } 1660 + if (tag_len != CIPSO_V4_TAG_LOC_BLEN) { 1661 + err_offset = opt_iter + 1; 1675 1662 goto validate_return_locked; 1676 1663 } 1677 1664 break; ··· 1743 1704 } 1744 1705 1745 1706 /** 1746 - * cipso_v4_sock_setattr - Add a CIPSO option to a socket 1747 - * @sk: the socket 1707 + * cipso_v4_genopt - Generate a CIPSO option 1708 + * @buf: the option buffer 1709 + * @buf_len: the size of opt_buf 1748 1710 * @doi_def: the CIPSO DOI to use 1749 - * @secattr: the specific security attributes of the socket 1711 + * @secattr: the security attributes 1750 1712 * 1751 1713 * Description: 1752 - * Set the CIPSO option on the given socket using the DOI definition and 1753 - * security attributes passed to the function. This function requires 1754 - * exclusive access to @sk, which means it either needs to be in the 1755 - * process of being created or locked. Returns zero on success and negative 1756 - * values on failure. 1714 + * Generate a CIPSO option using the DOI definition and security attributes 1715 + * passed to the function. Returns the length of the option on success and 1716 + * negative values on failure. 1757 1717 * 1758 1718 */ 1759 - int cipso_v4_sock_setattr(struct sock *sk, 1760 - const struct cipso_v4_doi *doi_def, 1761 - const struct netlbl_lsm_secattr *secattr) 1719 + static int cipso_v4_genopt(unsigned char *buf, u32 buf_len, 1720 + const struct cipso_v4_doi *doi_def, 1721 + const struct netlbl_lsm_secattr *secattr) 1762 1722 { 1763 - int ret_val = -EPERM; 1723 + int ret_val; 1764 1724 u32 iter; 1765 - unsigned char *buf; 1766 - u32 buf_len = 0; 1767 - u32 opt_len; 1768 - struct ip_options *opt = NULL; 1769 - struct inet_sock *sk_inet; 1770 - struct inet_connection_sock *sk_conn; 1771 1725 1772 - /* In the case of sock_create_lite(), the sock->sk field is not 1773 - * defined yet but it is not a problem as the only users of these 1774 - * "lite" PF_INET sockets are functions which do an accept() call 1775 - * afterwards so we will label the socket as part of the accept(). */ 1776 - if (sk == NULL) 1777 - return 0; 1778 - 1779 - /* We allocate the maximum CIPSO option size here so we are probably 1780 - * being a little wasteful, but it makes our life _much_ easier later 1781 - * on and after all we are only talking about 40 bytes. */ 1782 - buf_len = CIPSO_V4_OPT_LEN_MAX; 1783 - buf = kmalloc(buf_len, GFP_ATOMIC); 1784 - if (buf == NULL) { 1785 - ret_val = -ENOMEM; 1786 - goto socket_setattr_failure; 1787 - } 1726 + if (buf_len <= CIPSO_V4_HDR_LEN) 1727 + return -ENOSPC; 1788 1728 1789 1729 /* XXX - This code assumes only one tag per CIPSO option which isn't 1790 1730 * really a good assumption to make but since we only support the MAC ··· 1790 1772 &buf[CIPSO_V4_HDR_LEN], 1791 1773 buf_len - CIPSO_V4_HDR_LEN); 1792 1774 break; 1775 + case CIPSO_V4_TAG_LOCAL: 1776 + ret_val = cipso_v4_gentag_loc(doi_def, 1777 + secattr, 1778 + &buf[CIPSO_V4_HDR_LEN], 1779 + buf_len - CIPSO_V4_HDR_LEN); 1780 + break; 1793 1781 default: 1794 - ret_val = -EPERM; 1795 - goto socket_setattr_failure; 1782 + return -EPERM; 1796 1783 } 1797 1784 1798 1785 iter++; ··· 1805 1782 iter < CIPSO_V4_TAG_MAXCNT && 1806 1783 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); 1807 1784 if (ret_val < 0) 1808 - goto socket_setattr_failure; 1785 + return ret_val; 1809 1786 cipso_v4_gentag_hdr(doi_def, buf, ret_val); 1810 - buf_len = CIPSO_V4_HDR_LEN + ret_val; 1787 + return CIPSO_V4_HDR_LEN + ret_val; 1788 + } 1789 + 1790 + /** 1791 + * cipso_v4_sock_setattr - Add a CIPSO option to a socket 1792 + * @sk: the socket 1793 + * @doi_def: the CIPSO DOI to use 1794 + * @secattr: the specific security attributes of the socket 1795 + * 1796 + * Description: 1797 + * Set the CIPSO option on the given socket using the DOI definition and 1798 + * security attributes passed to the function. This function requires 1799 + * exclusive access to @sk, which means it either needs to be in the 1800 + * process of being created or locked. Returns zero on success and negative 1801 + * values on failure. 1802 + * 1803 + */ 1804 + int cipso_v4_sock_setattr(struct sock *sk, 1805 + const struct cipso_v4_doi *doi_def, 1806 + const struct netlbl_lsm_secattr *secattr) 1807 + { 1808 + int ret_val = -EPERM; 1809 + unsigned char *buf = NULL; 1810 + u32 buf_len; 1811 + u32 opt_len; 1812 + struct ip_options *opt = NULL; 1813 + struct inet_sock *sk_inet; 1814 + struct inet_connection_sock *sk_conn; 1815 + 1816 + /* In the case of sock_create_lite(), the sock->sk field is not 1817 + * defined yet but it is not a problem as the only users of these 1818 + * "lite" PF_INET sockets are functions which do an accept() call 1819 + * afterwards so we will label the socket as part of the accept(). */ 1820 + if (sk == NULL) 1821 + return 0; 1822 + 1823 + /* We allocate the maximum CIPSO option size here so we are probably 1824 + * being a little wasteful, but it makes our life _much_ easier later 1825 + * on and after all we are only talking about 40 bytes. */ 1826 + buf_len = CIPSO_V4_OPT_LEN_MAX; 1827 + buf = kmalloc(buf_len, GFP_ATOMIC); 1828 + if (buf == NULL) { 1829 + ret_val = -ENOMEM; 1830 + goto socket_setattr_failure; 1831 + } 1832 + 1833 + ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr); 1834 + if (ret_val < 0) 1835 + goto socket_setattr_failure; 1836 + buf_len = ret_val; 1811 1837 1812 1838 /* We can't use ip_options_get() directly because it makes a call to 1813 1839 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and ··· 1891 1819 kfree(buf); 1892 1820 kfree(opt); 1893 1821 return ret_val; 1822 + } 1823 + 1824 + /** 1825 + * cipso_v4_sock_delattr - Delete the CIPSO option from a socket 1826 + * @sk: the socket 1827 + * 1828 + * Description: 1829 + * Removes the CIPSO option from a socket, if present. 1830 + * 1831 + */ 1832 + void cipso_v4_sock_delattr(struct sock *sk) 1833 + { 1834 + u8 hdr_delta; 1835 + struct ip_options *opt; 1836 + struct inet_sock *sk_inet; 1837 + 1838 + sk_inet = inet_sk(sk); 1839 + opt = sk_inet->opt; 1840 + if (opt == NULL || opt->cipso == 0) 1841 + return; 1842 + 1843 + if (opt->srr || opt->rr || opt->ts || opt->router_alert) { 1844 + u8 cipso_len; 1845 + u8 cipso_off; 1846 + unsigned char *cipso_ptr; 1847 + int iter; 1848 + int optlen_new; 1849 + 1850 + cipso_off = opt->cipso - sizeof(struct iphdr); 1851 + cipso_ptr = &opt->__data[cipso_off]; 1852 + cipso_len = cipso_ptr[1]; 1853 + 1854 + if (opt->srr > opt->cipso) 1855 + opt->srr -= cipso_len; 1856 + if (opt->rr > opt->cipso) 1857 + opt->rr -= cipso_len; 1858 + if (opt->ts > opt->cipso) 1859 + opt->ts -= cipso_len; 1860 + if (opt->router_alert > opt->cipso) 1861 + opt->router_alert -= cipso_len; 1862 + opt->cipso = 0; 1863 + 1864 + memmove(cipso_ptr, cipso_ptr + cipso_len, 1865 + opt->optlen - cipso_off - cipso_len); 1866 + 1867 + /* determining the new total option length is tricky because of 1868 + * the padding necessary, the only thing i can think to do at 1869 + * this point is walk the options one-by-one, skipping the 1870 + * padding at the end to determine the actual option size and 1871 + * from there we can determine the new total option length */ 1872 + iter = 0; 1873 + optlen_new = 0; 1874 + while (iter < opt->optlen) 1875 + if (opt->__data[iter] != IPOPT_NOP) { 1876 + iter += opt->__data[iter + 1]; 1877 + optlen_new = iter; 1878 + } else 1879 + iter++; 1880 + hdr_delta = opt->optlen; 1881 + opt->optlen = (optlen_new + 3) & ~3; 1882 + hdr_delta -= opt->optlen; 1883 + } else { 1884 + /* only the cipso option was present on the socket so we can 1885 + * remove the entire option struct */ 1886 + sk_inet->opt = NULL; 1887 + hdr_delta = opt->optlen; 1888 + kfree(opt); 1889 + } 1890 + 1891 + if (sk_inet->is_icsk && hdr_delta > 0) { 1892 + struct inet_connection_sock *sk_conn = inet_csk(sk); 1893 + sk_conn->icsk_ext_hdr_len -= hdr_delta; 1894 + sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); 1895 + } 1894 1896 } 1895 1897 1896 1898 /** ··· 2005 1859 case CIPSO_V4_TAG_RANGE: 2006 1860 ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); 2007 1861 break; 1862 + case CIPSO_V4_TAG_LOCAL: 1863 + ret_val = cipso_v4_parsetag_loc(doi_def, &cipso[6], secattr); 1864 + break; 2008 1865 } 2009 1866 if (ret_val == 0) 2010 1867 secattr->type = NETLBL_NLTYPE_CIPSOV4; ··· 2039 1890 2040 1891 return cipso_v4_getattr(opt->__data + opt->cipso - sizeof(struct iphdr), 2041 1892 secattr); 1893 + } 1894 + 1895 + /** 1896 + * cipso_v4_skbuff_setattr - Set the CIPSO option on a packet 1897 + * @skb: the packet 1898 + * @secattr: the security attributes 1899 + * 1900 + * Description: 1901 + * Set the CIPSO option on the given packet based on the security attributes. 1902 + * Returns a pointer to the IP header on success and NULL on failure. 1903 + * 1904 + */ 1905 + int cipso_v4_skbuff_setattr(struct sk_buff *skb, 1906 + const struct cipso_v4_doi *doi_def, 1907 + const struct netlbl_lsm_secattr *secattr) 1908 + { 1909 + int ret_val; 1910 + struct iphdr *iph; 1911 + struct ip_options *opt = &IPCB(skb)->opt; 1912 + unsigned char buf[CIPSO_V4_OPT_LEN_MAX]; 1913 + u32 buf_len = CIPSO_V4_OPT_LEN_MAX; 1914 + u32 opt_len; 1915 + int len_delta; 1916 + 1917 + buf_len = cipso_v4_genopt(buf, buf_len, doi_def, secattr); 1918 + if (buf_len < 0) 1919 + return buf_len; 1920 + opt_len = (buf_len + 3) & ~3; 1921 + 1922 + /* we overwrite any existing options to ensure that we have enough 1923 + * room for the CIPSO option, the reason is that we _need_ to guarantee 1924 + * that the security label is applied to the packet - we do the same 1925 + * thing when using the socket options and it hasn't caused a problem, 1926 + * if we need to we can always revisit this choice later */ 1927 + 1928 + len_delta = opt_len - opt->optlen; 1929 + /* if we don't ensure enough headroom we could panic on the skb_push() 1930 + * call below so make sure we have enough, we are also "mangling" the 1931 + * packet so we should probably do a copy-on-write call anyway */ 1932 + ret_val = skb_cow(skb, skb_headroom(skb) + len_delta); 1933 + if (ret_val < 0) 1934 + return ret_val; 1935 + 1936 + if (len_delta > 0) { 1937 + /* we assume that the header + opt->optlen have already been 1938 + * "pushed" in ip_options_build() or similar */ 1939 + iph = ip_hdr(skb); 1940 + skb_push(skb, len_delta); 1941 + memmove((char *)iph - len_delta, iph, iph->ihl << 2); 1942 + skb_reset_network_header(skb); 1943 + iph = ip_hdr(skb); 1944 + } else if (len_delta < 0) { 1945 + iph = ip_hdr(skb); 1946 + memset(iph + 1, IPOPT_NOP, opt->optlen); 1947 + } else 1948 + iph = ip_hdr(skb); 1949 + 1950 + if (opt->optlen > 0) 1951 + memset(opt, 0, sizeof(*opt)); 1952 + opt->optlen = opt_len; 1953 + opt->cipso = sizeof(struct iphdr); 1954 + opt->is_changed = 1; 1955 + 1956 + /* we have to do the following because we are being called from a 1957 + * netfilter hook which means the packet already has had the header 1958 + * fields populated and the checksum calculated - yes this means we 1959 + * are doing more work than needed but we do it to keep the core 1960 + * stack clean and tidy */ 1961 + memcpy(iph + 1, buf, buf_len); 1962 + if (opt_len > buf_len) 1963 + memset((char *)(iph + 1) + buf_len, 0, opt_len - buf_len); 1964 + if (len_delta != 0) { 1965 + iph->ihl = 5 + (opt_len >> 2); 1966 + iph->tot_len = htons(skb->len); 1967 + } 1968 + ip_send_check(iph); 1969 + 1970 + return 0; 1971 + } 1972 + 1973 + /** 1974 + * cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet 1975 + * @skb: the packet 1976 + * 1977 + * Description: 1978 + * Removes any and all CIPSO options from the given packet. Returns zero on 1979 + * success, negative values on failure. 1980 + * 1981 + */ 1982 + int cipso_v4_skbuff_delattr(struct sk_buff *skb) 1983 + { 1984 + int ret_val; 1985 + struct iphdr *iph; 1986 + struct ip_options *opt = &IPCB(skb)->opt; 1987 + unsigned char *cipso_ptr; 1988 + 1989 + if (opt->cipso == 0) 1990 + return 0; 1991 + 1992 + /* since we are changing the packet we should make a copy */ 1993 + ret_val = skb_cow(skb, skb_headroom(skb)); 1994 + if (ret_val < 0) 1995 + return ret_val; 1996 + 1997 + /* the easiest thing to do is just replace the cipso option with noop 1998 + * options since we don't change the size of the packet, although we 1999 + * still need to recalculate the checksum */ 2000 + 2001 + iph = ip_hdr(skb); 2002 + cipso_ptr = (unsigned char *)iph + opt->cipso; 2003 + memset(cipso_ptr, IPOPT_NOOP, cipso_ptr[1]); 2004 + opt->cipso = 0; 2005 + opt->is_changed = 1; 2006 + 2007 + ip_send_check(iph); 2008 + 2009 + return 0; 2042 2010 } 2043 2011 2044 2012 /**
+1 -1
net/ipv4/ip_options.c
··· 438 438 goto error; 439 439 } 440 440 opt->cipso = optptr - iph; 441 - if (cipso_v4_validate(&optptr)) { 441 + if (cipso_v4_validate(skb, &optptr)) { 442 442 pp_ptr = optptr; 443 443 goto error; 444 444 }
+2 -1
net/netlabel/Makefile
··· 5 5 # 6 6 7 7 # base objects 8 - obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o 8 + obj-y := netlabel_user.o netlabel_kapi.o 9 + obj-y += netlabel_domainhash.o netlabel_addrlist.o 9 10 10 11 # management objects 11 12 obj-y += netlabel_mgmt.o
+388
net/netlabel/netlabel_addrlist.c
··· 1 + /* 2 + * NetLabel Network Address Lists 3 + * 4 + * This file contains network address list functions used to manage ordered 5 + * lists of network addresses for use by the NetLabel subsystem. The NetLabel 6 + * system manages static and dynamic label mappings for network protocols such 7 + * as CIPSO and RIPSO. 8 + * 9 + * Author: Paul Moore <paul.moore@hp.com> 10 + * 11 + */ 12 + 13 + /* 14 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 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, write to the Free Software 28 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29 + * 30 + */ 31 + 32 + #include <linux/types.h> 33 + #include <linux/rcupdate.h> 34 + #include <linux/list.h> 35 + #include <linux/spinlock.h> 36 + #include <linux/in.h> 37 + #include <linux/in6.h> 38 + #include <linux/ip.h> 39 + #include <linux/ipv6.h> 40 + #include <net/ip.h> 41 + #include <net/ipv6.h> 42 + #include <linux/audit.h> 43 + 44 + #include "netlabel_addrlist.h" 45 + 46 + /* 47 + * Address List Functions 48 + */ 49 + 50 + /** 51 + * netlbl_af4list_search - Search for a matching IPv4 address entry 52 + * @addr: IPv4 address 53 + * @head: the list head 54 + * 55 + * Description: 56 + * Searches the IPv4 address list given by @head. If a matching address entry 57 + * is found it is returned, otherwise NULL is returned. The caller is 58 + * responsible for calling the rcu_read_[un]lock() functions. 59 + * 60 + */ 61 + struct netlbl_af4list *netlbl_af4list_search(__be32 addr, 62 + struct list_head *head) 63 + { 64 + struct netlbl_af4list *iter; 65 + 66 + list_for_each_entry_rcu(iter, head, list) 67 + if (iter->valid && (addr & iter->mask) == iter->addr) 68 + return iter; 69 + 70 + return NULL; 71 + } 72 + 73 + /** 74 + * netlbl_af4list_search_exact - Search for an exact IPv4 address entry 75 + * @addr: IPv4 address 76 + * @mask: IPv4 address mask 77 + * @head: the list head 78 + * 79 + * Description: 80 + * Searches the IPv4 address list given by @head. If an exact match if found 81 + * it is returned, otherwise NULL is returned. The caller is responsible for 82 + * calling the rcu_read_[un]lock() functions. 83 + * 84 + */ 85 + struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr, 86 + __be32 mask, 87 + struct list_head *head) 88 + { 89 + struct netlbl_af4list *iter; 90 + 91 + list_for_each_entry_rcu(iter, head, list) 92 + if (iter->valid && iter->addr == addr && iter->mask == mask) 93 + return iter; 94 + 95 + return NULL; 96 + } 97 + 98 + 99 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 100 + /** 101 + * netlbl_af6list_search - Search for a matching IPv6 address entry 102 + * @addr: IPv6 address 103 + * @head: the list head 104 + * 105 + * Description: 106 + * Searches the IPv6 address list given by @head. If a matching address entry 107 + * is found it is returned, otherwise NULL is returned. The caller is 108 + * responsible for calling the rcu_read_[un]lock() functions. 109 + * 110 + */ 111 + struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr, 112 + struct list_head *head) 113 + { 114 + struct netlbl_af6list *iter; 115 + 116 + list_for_each_entry_rcu(iter, head, list) 117 + if (iter->valid && 118 + ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0) 119 + return iter; 120 + 121 + return NULL; 122 + } 123 + 124 + /** 125 + * netlbl_af6list_search_exact - Search for an exact IPv6 address entry 126 + * @addr: IPv6 address 127 + * @mask: IPv6 address mask 128 + * @head: the list head 129 + * 130 + * Description: 131 + * Searches the IPv6 address list given by @head. If an exact match if found 132 + * it is returned, otherwise NULL is returned. The caller is responsible for 133 + * calling the rcu_read_[un]lock() functions. 134 + * 135 + */ 136 + struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr, 137 + const struct in6_addr *mask, 138 + struct list_head *head) 139 + { 140 + struct netlbl_af6list *iter; 141 + 142 + list_for_each_entry_rcu(iter, head, list) 143 + if (iter->valid && 144 + ipv6_addr_equal(&iter->addr, addr) && 145 + ipv6_addr_equal(&iter->mask, mask)) 146 + return iter; 147 + 148 + return NULL; 149 + } 150 + #endif /* IPv6 */ 151 + 152 + /** 153 + * netlbl_af4list_add - Add a new IPv4 address entry to a list 154 + * @entry: address entry 155 + * @head: the list head 156 + * 157 + * Description: 158 + * Add a new address entry to the list pointed to by @head. On success zero is 159 + * returned, otherwise a negative value is returned. The caller is responsible 160 + * for calling the necessary locking functions. 161 + * 162 + */ 163 + int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head) 164 + { 165 + struct netlbl_af4list *iter; 166 + 167 + iter = netlbl_af4list_search(entry->addr, head); 168 + if (iter != NULL && 169 + iter->addr == entry->addr && iter->mask == entry->mask) 170 + return -EEXIST; 171 + 172 + /* in order to speed up address searches through the list (the common 173 + * case) we need to keep the list in order based on the size of the 174 + * address mask such that the entry with the widest mask (smallest 175 + * numerical value) appears first in the list */ 176 + list_for_each_entry_rcu(iter, head, list) 177 + if (iter->valid && 178 + ntohl(entry->mask) > ntohl(iter->mask)) { 179 + __list_add_rcu(&entry->list, 180 + iter->list.prev, 181 + &iter->list); 182 + return 0; 183 + } 184 + list_add_tail_rcu(&entry->list, head); 185 + return 0; 186 + } 187 + 188 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 189 + /** 190 + * netlbl_af6list_add - Add a new IPv6 address entry to a list 191 + * @entry: address entry 192 + * @head: the list head 193 + * 194 + * Description: 195 + * Add a new address entry to the list pointed to by @head. On success zero is 196 + * returned, otherwise a negative value is returned. The caller is responsible 197 + * for calling the necessary locking functions. 198 + * 199 + */ 200 + int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head) 201 + { 202 + struct netlbl_af6list *iter; 203 + 204 + iter = netlbl_af6list_search(&entry->addr, head); 205 + if (iter != NULL && 206 + ipv6_addr_equal(&iter->addr, &entry->addr) && 207 + ipv6_addr_equal(&iter->mask, &entry->mask)) 208 + return -EEXIST; 209 + 210 + /* in order to speed up address searches through the list (the common 211 + * case) we need to keep the list in order based on the size of the 212 + * address mask such that the entry with the widest mask (smallest 213 + * numerical value) appears first in the list */ 214 + list_for_each_entry_rcu(iter, head, list) 215 + if (iter->valid && 216 + ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) { 217 + __list_add_rcu(&entry->list, 218 + iter->list.prev, 219 + &iter->list); 220 + return 0; 221 + } 222 + list_add_tail_rcu(&entry->list, head); 223 + return 0; 224 + } 225 + #endif /* IPv6 */ 226 + 227 + /** 228 + * netlbl_af4list_remove_entry - Remove an IPv4 address entry 229 + * @entry: address entry 230 + * 231 + * Description: 232 + * Remove the specified IP address entry. The caller is responsible for 233 + * calling the necessary locking functions. 234 + * 235 + */ 236 + void netlbl_af4list_remove_entry(struct netlbl_af4list *entry) 237 + { 238 + entry->valid = 0; 239 + list_del_rcu(&entry->list); 240 + } 241 + 242 + /** 243 + * netlbl_af4list_remove - Remove an IPv4 address entry 244 + * @addr: IP address 245 + * @mask: IP address mask 246 + * @head: the list head 247 + * 248 + * Description: 249 + * Remove an IP address entry from the list pointed to by @head. Returns the 250 + * entry on success, NULL on failure. The caller is responsible for calling 251 + * the necessary locking functions. 252 + * 253 + */ 254 + struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask, 255 + struct list_head *head) 256 + { 257 + struct netlbl_af4list *entry; 258 + 259 + entry = netlbl_af4list_search(addr, head); 260 + if (entry != NULL && entry->addr == addr && entry->mask == mask) { 261 + netlbl_af4list_remove_entry(entry); 262 + return entry; 263 + } 264 + 265 + return NULL; 266 + } 267 + 268 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 269 + /** 270 + * netlbl_af6list_remove_entry - Remove an IPv6 address entry 271 + * @entry: address entry 272 + * 273 + * Description: 274 + * Remove the specified IP address entry. The caller is responsible for 275 + * calling the necessary locking functions. 276 + * 277 + */ 278 + void netlbl_af6list_remove_entry(struct netlbl_af6list *entry) 279 + { 280 + entry->valid = 0; 281 + list_del_rcu(&entry->list); 282 + } 283 + 284 + /** 285 + * netlbl_af6list_remove - Remove an IPv6 address entry 286 + * @addr: IP address 287 + * @mask: IP address mask 288 + * @head: the list head 289 + * 290 + * Description: 291 + * Remove an IP address entry from the list pointed to by @head. Returns the 292 + * entry on success, NULL on failure. The caller is responsible for calling 293 + * the necessary locking functions. 294 + * 295 + */ 296 + struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr, 297 + const struct in6_addr *mask, 298 + struct list_head *head) 299 + { 300 + struct netlbl_af6list *entry; 301 + 302 + entry = netlbl_af6list_search(addr, head); 303 + if (entry != NULL && 304 + ipv6_addr_equal(&entry->addr, addr) && 305 + ipv6_addr_equal(&entry->mask, mask)) { 306 + netlbl_af6list_remove_entry(entry); 307 + return entry; 308 + } 309 + 310 + return NULL; 311 + } 312 + #endif /* IPv6 */ 313 + 314 + /* 315 + * Audit Helper Functions 316 + */ 317 + 318 + /** 319 + * netlbl_af4list_audit_addr - Audit an IPv4 address 320 + * @audit_buf: audit buffer 321 + * @src: true if source address, false if destination 322 + * @dev: network interface 323 + * @addr: IP address 324 + * @mask: IP address mask 325 + * 326 + * Description: 327 + * Write the IPv4 address and address mask, if necessary, to @audit_buf. 328 + * 329 + */ 330 + void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, 331 + int src, const char *dev, 332 + __be32 addr, __be32 mask) 333 + { 334 + u32 mask_val = ntohl(mask); 335 + char *dir = (src ? "src" : "dst"); 336 + 337 + if (dev != NULL) 338 + audit_log_format(audit_buf, " netif=%s", dev); 339 + audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr)); 340 + if (mask_val != 0xffffffff) { 341 + u32 mask_len = 0; 342 + while (mask_val > 0) { 343 + mask_val <<= 1; 344 + mask_len++; 345 + } 346 + audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len); 347 + } 348 + } 349 + 350 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 351 + /** 352 + * netlbl_af6list_audit_addr - Audit an IPv6 address 353 + * @audit_buf: audit buffer 354 + * @src: true if source address, false if destination 355 + * @dev: network interface 356 + * @addr: IP address 357 + * @mask: IP address mask 358 + * 359 + * Description: 360 + * Write the IPv6 address and address mask, if necessary, to @audit_buf. 361 + * 362 + */ 363 + void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, 364 + int src, 365 + const char *dev, 366 + const struct in6_addr *addr, 367 + const struct in6_addr *mask) 368 + { 369 + char *dir = (src ? "src" : "dst"); 370 + 371 + if (dev != NULL) 372 + audit_log_format(audit_buf, " netif=%s", dev); 373 + audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr)); 374 + if (ntohl(mask->s6_addr32[3]) != 0xffffffff) { 375 + u32 mask_len = 0; 376 + u32 mask_val; 377 + int iter = -1; 378 + while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff) 379 + mask_len += 32; 380 + mask_val = ntohl(mask->s6_addr32[iter]); 381 + while (mask_val > 0) { 382 + mask_val <<= 1; 383 + mask_len++; 384 + } 385 + audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len); 386 + } 387 + } 388 + #endif /* IPv6 */
+189
net/netlabel/netlabel_addrlist.h
··· 1 + /* 2 + * NetLabel Network Address Lists 3 + * 4 + * This file contains network address list functions used to manage ordered 5 + * lists of network addresses for use by the NetLabel subsystem. The NetLabel 6 + * system manages static and dynamic label mappings for network protocols such 7 + * as CIPSO and RIPSO. 8 + * 9 + * Author: Paul Moore <paul.moore@hp.com> 10 + * 11 + */ 12 + 13 + /* 14 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 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, write to the Free Software 28 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29 + * 30 + */ 31 + 32 + #ifndef _NETLABEL_ADDRLIST_H 33 + #define _NETLABEL_ADDRLIST_H 34 + 35 + #include <linux/types.h> 36 + #include <linux/rcupdate.h> 37 + #include <linux/list.h> 38 + #include <linux/in6.h> 39 + #include <linux/audit.h> 40 + 41 + /** 42 + * struct netlbl_af4list - NetLabel IPv4 address list 43 + * @addr: IPv4 address 44 + * @mask: IPv4 address mask 45 + * @valid: valid flag 46 + * @list: list structure, used internally 47 + */ 48 + struct netlbl_af4list { 49 + __be32 addr; 50 + __be32 mask; 51 + 52 + u32 valid; 53 + struct list_head list; 54 + }; 55 + 56 + /** 57 + * struct netlbl_af6list - NetLabel IPv6 address list 58 + * @addr: IPv6 address 59 + * @mask: IPv6 address mask 60 + * @valid: valid flag 61 + * @list: list structure, used internally 62 + */ 63 + struct netlbl_af6list { 64 + struct in6_addr addr; 65 + struct in6_addr mask; 66 + 67 + u32 valid; 68 + struct list_head list; 69 + }; 70 + 71 + #define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list) 72 + 73 + static inline struct netlbl_af4list *__af4list_valid(struct list_head *s, 74 + struct list_head *h) 75 + { 76 + struct list_head *i = s; 77 + struct netlbl_af4list *n = __af4list_entry(s); 78 + while (i != h && !n->valid) { 79 + i = i->next; 80 + n = __af4list_entry(i); 81 + } 82 + return n; 83 + } 84 + 85 + static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s, 86 + struct list_head *h) 87 + { 88 + struct list_head *i = s; 89 + struct netlbl_af4list *n = __af4list_entry(s); 90 + while (i != h && !n->valid) { 91 + i = rcu_dereference(i->next); 92 + n = __af4list_entry(i); 93 + } 94 + return n; 95 + } 96 + 97 + #define netlbl_af4list_foreach(iter, head) \ 98 + for (iter = __af4list_valid((head)->next, head); \ 99 + prefetch(iter->list.next), &iter->list != (head); \ 100 + iter = __af4list_valid(iter->list.next, head)) 101 + 102 + #define netlbl_af4list_foreach_rcu(iter, head) \ 103 + for (iter = __af4list_valid_rcu((head)->next, head); \ 104 + prefetch(iter->list.next), &iter->list != (head); \ 105 + iter = __af4list_valid_rcu(iter->list.next, head)) 106 + 107 + #define netlbl_af4list_foreach_safe(iter, tmp, head) \ 108 + for (iter = __af4list_valid((head)->next, head), \ 109 + tmp = __af4list_valid(iter->list.next, head); \ 110 + &iter->list != (head); \ 111 + iter = tmp, tmp = __af4list_valid(iter->list.next, head)) 112 + 113 + int netlbl_af4list_add(struct netlbl_af4list *entry, 114 + struct list_head *head); 115 + struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask, 116 + struct list_head *head); 117 + void netlbl_af4list_remove_entry(struct netlbl_af4list *entry); 118 + struct netlbl_af4list *netlbl_af4list_search(__be32 addr, 119 + struct list_head *head); 120 + struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr, 121 + __be32 mask, 122 + struct list_head *head); 123 + void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, 124 + int src, const char *dev, 125 + __be32 addr, __be32 mask); 126 + 127 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 128 + 129 + #define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list) 130 + 131 + static inline struct netlbl_af6list *__af6list_valid(struct list_head *s, 132 + struct list_head *h) 133 + { 134 + struct list_head *i = s; 135 + struct netlbl_af6list *n = __af6list_entry(s); 136 + while (i != h && !n->valid) { 137 + i = i->next; 138 + n = __af6list_entry(i); 139 + } 140 + return n; 141 + } 142 + 143 + static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s, 144 + struct list_head *h) 145 + { 146 + struct list_head *i = s; 147 + struct netlbl_af6list *n = __af6list_entry(s); 148 + while (i != h && !n->valid) { 149 + i = rcu_dereference(i->next); 150 + n = __af6list_entry(i); 151 + } 152 + return n; 153 + } 154 + 155 + #define netlbl_af6list_foreach(iter, head) \ 156 + for (iter = __af6list_valid((head)->next, head); \ 157 + prefetch(iter->list.next), &iter->list != (head); \ 158 + iter = __af6list_valid(iter->list.next, head)) 159 + 160 + #define netlbl_af6list_foreach_rcu(iter, head) \ 161 + for (iter = __af6list_valid_rcu((head)->next, head); \ 162 + prefetch(iter->list.next), &iter->list != (head); \ 163 + iter = __af6list_valid_rcu(iter->list.next, head)) 164 + 165 + #define netlbl_af6list_foreach_safe(iter, tmp, head) \ 166 + for (iter = __af6list_valid((head)->next, head), \ 167 + tmp = __af6list_valid(iter->list.next, head); \ 168 + &iter->list != (head); \ 169 + iter = tmp, tmp = __af6list_valid(iter->list.next, head)) 170 + 171 + int netlbl_af6list_add(struct netlbl_af6list *entry, 172 + struct list_head *head); 173 + struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr, 174 + const struct in6_addr *mask, 175 + struct list_head *head); 176 + void netlbl_af6list_remove_entry(struct netlbl_af6list *entry); 177 + struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr, 178 + struct list_head *head); 179 + struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr, 180 + const struct in6_addr *mask, 181 + struct list_head *head); 182 + void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, 183 + int src, 184 + const char *dev, 185 + const struct in6_addr *addr, 186 + const struct in6_addr *mask); 187 + #endif /* IPV6 */ 188 + 189 + #endif
+94 -42
net/netlabel/netlabel_cipso_v4.c
··· 43 43 #include "netlabel_user.h" 44 44 #include "netlabel_cipso_v4.h" 45 45 #include "netlabel_mgmt.h" 46 + #include "netlabel_domainhash.h" 46 47 47 48 /* Argument struct for cipso_v4_doi_walk() */ 48 49 struct netlbl_cipsov4_doiwalk_arg { 49 50 struct netlink_callback *nl_cb; 50 51 struct sk_buff *skb; 51 52 u32 seq; 53 + }; 54 + 55 + /* Argument struct for netlbl_domhsh_walk() */ 56 + struct netlbl_domhsh_walk_arg { 57 + struct netlbl_audit *audit_info; 58 + u32 doi; 52 59 }; 53 60 54 61 /* NetLabel Generic NETLINK CIPSOv4 family */ ··· 86 79 /* 87 80 * Helper Functions 88 81 */ 89 - 90 - /** 91 - * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition 92 - * @entry: the entry's RCU field 93 - * 94 - * Description: 95 - * This function is designed to be used as a callback to the call_rcu() 96 - * function so that the memory allocated to the DOI definition can be released 97 - * safely. 98 - * 99 - */ 100 - void netlbl_cipsov4_doi_free(struct rcu_head *entry) 101 - { 102 - struct cipso_v4_doi *ptr; 103 - 104 - ptr = container_of(entry, struct cipso_v4_doi, rcu); 105 - switch (ptr->type) { 106 - case CIPSO_V4_MAP_STD: 107 - kfree(ptr->map.std->lvl.cipso); 108 - kfree(ptr->map.std->lvl.local); 109 - kfree(ptr->map.std->cat.cipso); 110 - kfree(ptr->map.std->cat.local); 111 - break; 112 - } 113 - kfree(ptr); 114 - } 115 82 116 83 /** 117 84 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message ··· 132 151 * @info: the Generic NETLINK info block 133 152 * 134 153 * Description: 135 - * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message 136 - * and add it to the CIPSO V4 engine. Return zero on success and non-zero on 137 - * error. 154 + * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD 155 + * message and add it to the CIPSO V4 engine. Return zero on success and 156 + * non-zero on error. 138 157 * 139 158 */ 140 159 static int netlbl_cipsov4_add_std(struct genl_info *info) ··· 164 183 ret_val = -ENOMEM; 165 184 goto add_std_failure; 166 185 } 167 - doi_def->type = CIPSO_V4_MAP_STD; 186 + doi_def->type = CIPSO_V4_MAP_TRANS; 168 187 169 188 ret_val = netlbl_cipsov4_add_common(info, doi_def); 170 189 if (ret_val != 0) ··· 323 342 324 343 add_std_failure: 325 344 if (doi_def) 326 - netlbl_cipsov4_doi_free(&doi_def->rcu); 345 + cipso_v4_doi_free(doi_def); 327 346 return ret_val; 328 347 } 329 348 ··· 360 379 return 0; 361 380 362 381 add_pass_failure: 363 - netlbl_cipsov4_doi_free(&doi_def->rcu); 382 + cipso_v4_doi_free(doi_def); 383 + return ret_val; 384 + } 385 + 386 + /** 387 + * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition 388 + * @info: the Generic NETLINK info block 389 + * 390 + * Description: 391 + * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD 392 + * message and add it to the CIPSO V4 engine. Return zero on success and 393 + * non-zero on error. 394 + * 395 + */ 396 + static int netlbl_cipsov4_add_local(struct genl_info *info) 397 + { 398 + int ret_val; 399 + struct cipso_v4_doi *doi_def = NULL; 400 + 401 + if (!info->attrs[NLBL_CIPSOV4_A_TAGLST]) 402 + return -EINVAL; 403 + 404 + doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); 405 + if (doi_def == NULL) 406 + return -ENOMEM; 407 + doi_def->type = CIPSO_V4_MAP_LOCAL; 408 + 409 + ret_val = netlbl_cipsov4_add_common(info, doi_def); 410 + if (ret_val != 0) 411 + goto add_local_failure; 412 + 413 + ret_val = cipso_v4_doi_add(doi_def); 414 + if (ret_val != 0) 415 + goto add_local_failure; 416 + return 0; 417 + 418 + add_local_failure: 419 + cipso_v4_doi_free(doi_def); 364 420 return ret_val; 365 421 } 366 422 ··· 430 412 431 413 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); 432 414 switch (type) { 433 - case CIPSO_V4_MAP_STD: 434 - type_str = "std"; 415 + case CIPSO_V4_MAP_TRANS: 416 + type_str = "trans"; 435 417 ret_val = netlbl_cipsov4_add_std(info); 436 418 break; 437 419 case CIPSO_V4_MAP_PASS: 438 420 type_str = "pass"; 439 421 ret_val = netlbl_cipsov4_add_pass(info); 422 + break; 423 + case CIPSO_V4_MAP_LOCAL: 424 + type_str = "local"; 425 + ret_val = netlbl_cipsov4_add_local(info); 440 426 break; 441 427 } 442 428 if (ret_val == 0) ··· 513 491 doi_def = cipso_v4_doi_getdef(doi); 514 492 if (doi_def == NULL) { 515 493 ret_val = -EINVAL; 516 - goto list_failure; 494 + goto list_failure_lock; 517 495 } 518 496 519 497 ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); ··· 538 516 nla_nest_end(ans_skb, nla_a); 539 517 540 518 switch (doi_def->type) { 541 - case CIPSO_V4_MAP_STD: 519 + case CIPSO_V4_MAP_TRANS: 542 520 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); 543 521 if (nla_a == NULL) { 544 522 ret_val = -ENOMEM; ··· 677 655 struct netlink_callback *cb) 678 656 { 679 657 struct netlbl_cipsov4_doiwalk_arg cb_arg; 680 - int doi_skip = cb->args[0]; 658 + u32 doi_skip = cb->args[0]; 681 659 682 660 cb_arg.nl_cb = cb; 683 661 cb_arg.skb = skb; ··· 687 665 688 666 cb->args[0] = doi_skip; 689 667 return skb->len; 668 + } 669 + 670 + /** 671 + * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE 672 + * @entry: LSM domain mapping entry 673 + * @arg: the netlbl_domhsh_walk_arg structure 674 + * 675 + * Description: 676 + * This function is intended for use by netlbl_cipsov4_remove() as the callback 677 + * for the netlbl_domhsh_walk() function; it removes LSM domain map entries 678 + * which are associated with the CIPSO DOI specified in @arg. Returns zero on 679 + * success, negative values on failure. 680 + * 681 + */ 682 + static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg) 683 + { 684 + struct netlbl_domhsh_walk_arg *cb_arg = arg; 685 + 686 + if (entry->type == NETLBL_NLTYPE_CIPSOV4 && 687 + entry->type_def.cipsov4->doi == cb_arg->doi) 688 + return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info); 689 + 690 + return 0; 690 691 } 691 692 692 693 /** ··· 726 681 { 727 682 int ret_val = -EINVAL; 728 683 u32 doi = 0; 684 + struct netlbl_domhsh_walk_arg cb_arg; 729 685 struct audit_buffer *audit_buf; 730 686 struct netlbl_audit audit_info; 687 + u32 skip_bkt = 0; 688 + u32 skip_chain = 0; 731 689 732 690 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) 733 691 return -EINVAL; ··· 738 690 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); 739 691 netlbl_netlink_auditinfo(skb, &audit_info); 740 692 741 - ret_val = cipso_v4_doi_remove(doi, 742 - &audit_info, 743 - netlbl_cipsov4_doi_free); 744 - if (ret_val == 0) 745 - atomic_dec(&netlabel_mgmt_protocount); 693 + cb_arg.doi = doi; 694 + cb_arg.audit_info = &audit_info; 695 + ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, 696 + netlbl_cipsov4_remove_cb, &cb_arg); 697 + if (ret_val == 0 || ret_val == -ENOENT) { 698 + ret_val = cipso_v4_doi_remove(doi, &audit_info); 699 + if (ret_val == 0) 700 + atomic_dec(&netlabel_mgmt_protocount); 701 + } 746 702 747 703 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, 748 704 &audit_info);
+6 -4
net/netlabel/netlabel_cipso_v4.h
··· 45 45 * NLBL_CIPSOV4_A_MTYPE 46 46 * NLBL_CIPSOV4_A_TAGLST 47 47 * 48 - * If using CIPSO_V4_MAP_STD the following attributes are required: 48 + * If using CIPSO_V4_MAP_TRANS the following attributes are required: 49 49 * 50 50 * NLBL_CIPSOV4_A_MLSLVLLST 51 51 * NLBL_CIPSOV4_A_MLSCATLST 52 52 * 53 - * If using CIPSO_V4_MAP_PASS no additional attributes are required. 53 + * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes 54 + * are required. 54 55 * 55 56 * o REMOVE: 56 57 * Sent by an application to remove a specific DOI mapping table from the ··· 77 76 * NLBL_CIPSOV4_A_MTYPE 78 77 * NLBL_CIPSOV4_A_TAGLST 79 78 * 80 - * If using CIPSO_V4_MAP_STD the following attributes are required: 79 + * If using CIPSO_V4_MAP_TRANS the following attributes are required: 81 80 * 82 81 * NLBL_CIPSOV4_A_MLSLVLLST 83 82 * NLBL_CIPSOV4_A_MLSCATLST 84 83 * 85 - * If using CIPSO_V4_MAP_PASS no additional attributes are required. 84 + * If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes 85 + * are required. 86 86 * 87 87 * o LISTALL: 88 88 * This message is sent by an application to list the valid DOIs on the
+315 -100
net/netlabel/netlabel_domainhash.c
··· 11 11 */ 12 12 13 13 /* 14 - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 15 15 * 16 16 * This program is free software; you can redistribute it and/or modify 17 17 * it under the terms of the GNU General Public License as published by ··· 40 40 #include <asm/bug.h> 41 41 42 42 #include "netlabel_mgmt.h" 43 + #include "netlabel_addrlist.h" 43 44 #include "netlabel_domainhash.h" 44 45 #include "netlabel_user.h" 45 46 ··· 73 72 static void netlbl_domhsh_free_entry(struct rcu_head *entry) 74 73 { 75 74 struct netlbl_dom_map *ptr; 75 + struct netlbl_af4list *iter4; 76 + struct netlbl_af4list *tmp4; 77 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 78 + struct netlbl_af6list *iter6; 79 + struct netlbl_af6list *tmp6; 80 + #endif /* IPv6 */ 76 81 77 82 ptr = container_of(entry, struct netlbl_dom_map, rcu); 83 + if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) { 84 + netlbl_af4list_foreach_safe(iter4, tmp4, 85 + &ptr->type_def.addrsel->list4) { 86 + netlbl_af4list_remove_entry(iter4); 87 + kfree(netlbl_domhsh_addr4_entry(iter4)); 88 + } 89 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 90 + netlbl_af6list_foreach_safe(iter6, tmp6, 91 + &ptr->type_def.addrsel->list6) { 92 + netlbl_af6list_remove_entry(iter6); 93 + kfree(netlbl_domhsh_addr6_entry(iter6)); 94 + } 95 + #endif /* IPv6 */ 96 + } 78 97 kfree(ptr->domain); 79 98 kfree(ptr); 80 99 } ··· 136 115 static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) 137 116 { 138 117 u32 bkt; 118 + struct list_head *bkt_list; 139 119 struct netlbl_dom_map *iter; 140 120 141 121 if (domain != NULL) { 142 122 bkt = netlbl_domhsh_hash(domain); 143 - list_for_each_entry_rcu(iter, 144 - &rcu_dereference(netlbl_domhsh)->tbl[bkt], 145 - list) 123 + bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; 124 + list_for_each_entry_rcu(iter, bkt_list, list) 146 125 if (iter->valid && strcmp(iter->domain, domain) == 0) 147 126 return iter; 148 127 } ··· 175 154 } 176 155 177 156 return entry; 157 + } 158 + 159 + /** 160 + * netlbl_domhsh_audit_add - Generate an audit entry for an add event 161 + * @entry: the entry being added 162 + * @addr4: the IPv4 address information 163 + * @addr6: the IPv6 address information 164 + * @result: the result code 165 + * @audit_info: NetLabel audit information 166 + * 167 + * Description: 168 + * Generate an audit record for adding a new NetLabel/LSM mapping entry with 169 + * the given information. Caller is responsibile for holding the necessary 170 + * locks. 171 + * 172 + */ 173 + static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, 174 + struct netlbl_af4list *addr4, 175 + struct netlbl_af6list *addr6, 176 + int result, 177 + struct netlbl_audit *audit_info) 178 + { 179 + struct audit_buffer *audit_buf; 180 + struct cipso_v4_doi *cipsov4 = NULL; 181 + u32 type; 182 + 183 + audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); 184 + if (audit_buf != NULL) { 185 + audit_log_format(audit_buf, " nlbl_domain=%s", 186 + entry->domain ? entry->domain : "(default)"); 187 + if (addr4 != NULL) { 188 + struct netlbl_domaddr4_map *map4; 189 + map4 = netlbl_domhsh_addr4_entry(addr4); 190 + type = map4->type; 191 + cipsov4 = map4->type_def.cipsov4; 192 + netlbl_af4list_audit_addr(audit_buf, 0, NULL, 193 + addr4->addr, addr4->mask); 194 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 195 + } else if (addr6 != NULL) { 196 + struct netlbl_domaddr6_map *map6; 197 + map6 = netlbl_domhsh_addr6_entry(addr6); 198 + type = map6->type; 199 + netlbl_af6list_audit_addr(audit_buf, 0, NULL, 200 + &addr6->addr, &addr6->mask); 201 + #endif /* IPv6 */ 202 + } else { 203 + type = entry->type; 204 + cipsov4 = entry->type_def.cipsov4; 205 + } 206 + switch (type) { 207 + case NETLBL_NLTYPE_UNLABELED: 208 + audit_log_format(audit_buf, " nlbl_protocol=unlbl"); 209 + break; 210 + case NETLBL_NLTYPE_CIPSOV4: 211 + BUG_ON(cipsov4 == NULL); 212 + audit_log_format(audit_buf, 213 + " nlbl_protocol=cipsov4 cipso_doi=%u", 214 + cipsov4->doi); 215 + break; 216 + } 217 + audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0); 218 + audit_log_end(audit_buf); 219 + } 178 220 } 179 221 180 222 /* ··· 297 213 int netlbl_domhsh_add(struct netlbl_dom_map *entry, 298 214 struct netlbl_audit *audit_info) 299 215 { 300 - int ret_val; 301 - u32 bkt; 302 - struct audit_buffer *audit_buf; 303 - 304 - switch (entry->type) { 305 - case NETLBL_NLTYPE_UNLABELED: 306 - ret_val = 0; 307 - break; 308 - case NETLBL_NLTYPE_CIPSOV4: 309 - ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4, 310 - entry->domain); 311 - break; 312 - default: 313 - return -EINVAL; 314 - } 315 - if (ret_val != 0) 316 - return ret_val; 317 - 318 - entry->valid = 1; 319 - INIT_RCU_HEAD(&entry->rcu); 216 + int ret_val = 0; 217 + struct netlbl_dom_map *entry_old; 218 + struct netlbl_af4list *iter4; 219 + struct netlbl_af4list *tmp4; 220 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 221 + struct netlbl_af6list *iter6; 222 + struct netlbl_af6list *tmp6; 223 + #endif /* IPv6 */ 320 224 321 225 rcu_read_lock(); 226 + 322 227 spin_lock(&netlbl_domhsh_lock); 323 - if (entry->domain != NULL) { 324 - bkt = netlbl_domhsh_hash(entry->domain); 325 - if (netlbl_domhsh_search(entry->domain) == NULL) 228 + if (entry->domain != NULL) 229 + entry_old = netlbl_domhsh_search(entry->domain); 230 + else 231 + entry_old = netlbl_domhsh_search_def(entry->domain); 232 + if (entry_old == NULL) { 233 + entry->valid = 1; 234 + INIT_RCU_HEAD(&entry->rcu); 235 + 236 + if (entry->domain != NULL) { 237 + u32 bkt = netlbl_domhsh_hash(entry->domain); 326 238 list_add_tail_rcu(&entry->list, 327 239 &rcu_dereference(netlbl_domhsh)->tbl[bkt]); 328 - else 329 - ret_val = -EEXIST; 330 - } else { 331 - INIT_LIST_HEAD(&entry->list); 332 - if (rcu_dereference(netlbl_domhsh_def) == NULL) 240 + } else { 241 + INIT_LIST_HEAD(&entry->list); 333 242 rcu_assign_pointer(netlbl_domhsh_def, entry); 334 - else 335 - ret_val = -EEXIST; 336 - } 243 + } 244 + 245 + if (entry->type == NETLBL_NLTYPE_ADDRSELECT) { 246 + netlbl_af4list_foreach_rcu(iter4, 247 + &entry->type_def.addrsel->list4) 248 + netlbl_domhsh_audit_add(entry, iter4, NULL, 249 + ret_val, audit_info); 250 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 251 + netlbl_af6list_foreach_rcu(iter6, 252 + &entry->type_def.addrsel->list6) 253 + netlbl_domhsh_audit_add(entry, NULL, iter6, 254 + ret_val, audit_info); 255 + #endif /* IPv6 */ 256 + } else 257 + netlbl_domhsh_audit_add(entry, NULL, NULL, 258 + ret_val, audit_info); 259 + } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT && 260 + entry->type == NETLBL_NLTYPE_ADDRSELECT) { 261 + struct list_head *old_list4; 262 + struct list_head *old_list6; 263 + 264 + old_list4 = &entry_old->type_def.addrsel->list4; 265 + old_list6 = &entry_old->type_def.addrsel->list6; 266 + 267 + /* we only allow the addition of address selectors if all of 268 + * the selectors do not exist in the existing domain map */ 269 + netlbl_af4list_foreach_rcu(iter4, 270 + &entry->type_def.addrsel->list4) 271 + if (netlbl_af4list_search_exact(iter4->addr, 272 + iter4->mask, 273 + old_list4)) { 274 + ret_val = -EEXIST; 275 + goto add_return; 276 + } 277 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 278 + netlbl_af6list_foreach_rcu(iter6, 279 + &entry->type_def.addrsel->list6) 280 + if (netlbl_af6list_search_exact(&iter6->addr, 281 + &iter6->mask, 282 + old_list6)) { 283 + ret_val = -EEXIST; 284 + goto add_return; 285 + } 286 + #endif /* IPv6 */ 287 + 288 + netlbl_af4list_foreach_safe(iter4, tmp4, 289 + &entry->type_def.addrsel->list4) { 290 + netlbl_af4list_remove_entry(iter4); 291 + iter4->valid = 1; 292 + ret_val = netlbl_af4list_add(iter4, old_list4); 293 + netlbl_domhsh_audit_add(entry_old, iter4, NULL, 294 + ret_val, audit_info); 295 + if (ret_val != 0) 296 + goto add_return; 297 + } 298 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 299 + netlbl_af6list_foreach_safe(iter6, tmp6, 300 + &entry->type_def.addrsel->list6) { 301 + netlbl_af6list_remove_entry(iter6); 302 + iter6->valid = 1; 303 + ret_val = netlbl_af6list_add(iter6, old_list6); 304 + netlbl_domhsh_audit_add(entry_old, NULL, iter6, 305 + ret_val, audit_info); 306 + if (ret_val != 0) 307 + goto add_return; 308 + } 309 + #endif /* IPv6 */ 310 + } else 311 + ret_val = -EINVAL; 312 + 313 + add_return: 337 314 spin_unlock(&netlbl_domhsh_lock); 338 - audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); 339 - if (audit_buf != NULL) { 340 - audit_log_format(audit_buf, 341 - " nlbl_domain=%s", 342 - entry->domain ? entry->domain : "(default)"); 343 - switch (entry->type) { 344 - case NETLBL_NLTYPE_UNLABELED: 345 - audit_log_format(audit_buf, " nlbl_protocol=unlbl"); 346 - break; 347 - case NETLBL_NLTYPE_CIPSOV4: 348 - audit_log_format(audit_buf, 349 - " nlbl_protocol=cipsov4 cipso_doi=%u", 350 - entry->type_def.cipsov4->doi); 351 - break; 352 - } 353 - audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); 354 - audit_log_end(audit_buf); 355 - } 356 315 rcu_read_unlock(); 357 - 358 - if (ret_val != 0) { 359 - switch (entry->type) { 360 - case NETLBL_NLTYPE_CIPSOV4: 361 - if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, 362 - entry->domain) != 0) 363 - BUG(); 364 - break; 365 - } 366 - } 367 - 368 316 return ret_val; 369 317 } 370 318 ··· 418 302 } 419 303 420 304 /** 305 + * netlbl_domhsh_remove_entry - Removes a given entry from the domain table 306 + * @entry: the entry to remove 307 + * @audit_info: NetLabel audit information 308 + * 309 + * Description: 310 + * Removes an entry from the domain hash table and handles any updates to the 311 + * lower level protocol handler (i.e. CIPSO). Caller is responsible for 312 + * ensuring that the RCU read lock is held. Returns zero on success, negative 313 + * on failure. 314 + * 315 + */ 316 + int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, 317 + struct netlbl_audit *audit_info) 318 + { 319 + int ret_val = 0; 320 + struct audit_buffer *audit_buf; 321 + 322 + if (entry == NULL) 323 + return -ENOENT; 324 + 325 + spin_lock(&netlbl_domhsh_lock); 326 + if (entry->valid) { 327 + entry->valid = 0; 328 + if (entry != rcu_dereference(netlbl_domhsh_def)) 329 + list_del_rcu(&entry->list); 330 + else 331 + rcu_assign_pointer(netlbl_domhsh_def, NULL); 332 + } else 333 + ret_val = -ENOENT; 334 + spin_unlock(&netlbl_domhsh_lock); 335 + 336 + audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); 337 + if (audit_buf != NULL) { 338 + audit_log_format(audit_buf, 339 + " nlbl_domain=%s res=%u", 340 + entry->domain ? entry->domain : "(default)", 341 + ret_val == 0 ? 1 : 0); 342 + audit_log_end(audit_buf); 343 + } 344 + 345 + if (ret_val == 0) { 346 + struct netlbl_af4list *iter4; 347 + struct netlbl_domaddr4_map *map4; 348 + 349 + switch (entry->type) { 350 + case NETLBL_NLTYPE_ADDRSELECT: 351 + netlbl_af4list_foreach_rcu(iter4, 352 + &entry->type_def.addrsel->list4) { 353 + map4 = netlbl_domhsh_addr4_entry(iter4); 354 + cipso_v4_doi_putdef(map4->type_def.cipsov4); 355 + } 356 + /* no need to check the IPv6 list since we currently 357 + * support only unlabeled protocols for IPv6 */ 358 + break; 359 + case NETLBL_NLTYPE_CIPSOV4: 360 + cipso_v4_doi_putdef(entry->type_def.cipsov4); 361 + break; 362 + } 363 + call_rcu(&entry->rcu, netlbl_domhsh_free_entry); 364 + } 365 + 366 + return ret_val; 367 + } 368 + 369 + /** 421 370 * netlbl_domhsh_remove - Removes an entry from the domain hash table 422 371 * @domain: the domain to remove 423 372 * @audit_info: NetLabel audit information ··· 495 314 */ 496 315 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) 497 316 { 498 - int ret_val = -ENOENT; 317 + int ret_val; 499 318 struct netlbl_dom_map *entry; 500 - struct audit_buffer *audit_buf; 501 319 502 320 rcu_read_lock(); 503 321 if (domain) 504 322 entry = netlbl_domhsh_search(domain); 505 323 else 506 324 entry = netlbl_domhsh_search_def(domain); 507 - if (entry == NULL) 508 - goto remove_return; 509 - switch (entry->type) { 510 - case NETLBL_NLTYPE_CIPSOV4: 511 - cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, 512 - entry->domain); 513 - break; 514 - } 515 - spin_lock(&netlbl_domhsh_lock); 516 - if (entry->valid) { 517 - entry->valid = 0; 518 - if (entry != rcu_dereference(netlbl_domhsh_def)) 519 - list_del_rcu(&entry->list); 520 - else 521 - rcu_assign_pointer(netlbl_domhsh_def, NULL); 522 - ret_val = 0; 523 - } 524 - spin_unlock(&netlbl_domhsh_lock); 525 - 526 - audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); 527 - if (audit_buf != NULL) { 528 - audit_log_format(audit_buf, 529 - " nlbl_domain=%s res=%u", 530 - entry->domain ? entry->domain : "(default)", 531 - ret_val == 0 ? 1 : 0); 532 - audit_log_end(audit_buf); 533 - } 534 - 535 - remove_return: 325 + ret_val = netlbl_domhsh_remove_entry(entry, audit_info); 536 326 rcu_read_unlock(); 537 - if (ret_val == 0) 538 - call_rcu(&entry->rcu, netlbl_domhsh_free_entry); 327 + 539 328 return ret_val; 540 329 } 541 330 ··· 540 389 } 541 390 542 391 /** 392 + * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table 393 + * @domain: the domain name to search for 394 + * @addr: the IP address to search for 395 + * 396 + * Description: 397 + * Look through the domain hash table searching for an entry to match @domain 398 + * and @addr, return a pointer to a copy of the entry or NULL. The caller is 399 + * responsible for ensuring that rcu_read_[un]lock() is called. 400 + * 401 + */ 402 + struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, 403 + __be32 addr) 404 + { 405 + struct netlbl_dom_map *dom_iter; 406 + struct netlbl_af4list *addr_iter; 407 + 408 + dom_iter = netlbl_domhsh_search_def(domain); 409 + if (dom_iter == NULL) 410 + return NULL; 411 + if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) 412 + return NULL; 413 + 414 + addr_iter = netlbl_af4list_search(addr, 415 + &dom_iter->type_def.addrsel->list4); 416 + if (addr_iter == NULL) 417 + return NULL; 418 + 419 + return netlbl_domhsh_addr4_entry(addr_iter); 420 + } 421 + 422 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 423 + /** 424 + * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table 425 + * @domain: the domain name to search for 426 + * @addr: the IP address to search for 427 + * 428 + * Description: 429 + * Look through the domain hash table searching for an entry to match @domain 430 + * and @addr, return a pointer to a copy of the entry or NULL. The caller is 431 + * responsible for ensuring that rcu_read_[un]lock() is called. 432 + * 433 + */ 434 + struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, 435 + const struct in6_addr *addr) 436 + { 437 + struct netlbl_dom_map *dom_iter; 438 + struct netlbl_af6list *addr_iter; 439 + 440 + dom_iter = netlbl_domhsh_search_def(domain); 441 + if (dom_iter == NULL) 442 + return NULL; 443 + if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) 444 + return NULL; 445 + 446 + addr_iter = netlbl_af6list_search(addr, 447 + &dom_iter->type_def.addrsel->list6); 448 + if (addr_iter == NULL) 449 + return NULL; 450 + 451 + return netlbl_domhsh_addr6_entry(addr_iter); 452 + } 453 + #endif /* IPv6 */ 454 + 455 + /** 543 456 * netlbl_domhsh_walk - Iterate through the domain mapping hash table 544 457 * @skip_bkt: the number of buckets to skip at the start 545 458 * @skip_chain: the number of entries to skip in the first iterated bucket ··· 625 410 { 626 411 int ret_val = -ENOENT; 627 412 u32 iter_bkt; 413 + struct list_head *iter_list; 628 414 struct netlbl_dom_map *iter_entry; 629 415 u32 chain_cnt = 0; 630 416 ··· 633 417 for (iter_bkt = *skip_bkt; 634 418 iter_bkt < rcu_dereference(netlbl_domhsh)->size; 635 419 iter_bkt++, chain_cnt = 0) { 636 - list_for_each_entry_rcu(iter_entry, 637 - &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt], 638 - list) 420 + iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt]; 421 + list_for_each_entry_rcu(iter_entry, iter_list, list) 639 422 if (iter_entry->valid) { 640 423 if (chain_cnt++ < *skip_chain) 641 424 continue;
+38 -2
net/netlabel/netlabel_domainhash.h
··· 11 11 */ 12 12 13 13 /* 14 - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 15 15 * 16 16 * This program is free software; you can redistribute it and/or modify 17 17 * it under the terms of the GNU General Public License as published by ··· 36 36 #include <linux/rcupdate.h> 37 37 #include <linux/list.h> 38 38 39 + #include "netlabel_addrlist.h" 40 + 39 41 /* Domain hash table size */ 40 42 /* XXX - currently this number is an uneducated guess */ 41 43 #define NETLBL_DOMHSH_BITSIZE 7 42 44 43 - /* Domain mapping definition struct */ 45 + /* Domain mapping definition structures */ 46 + #define netlbl_domhsh_addr4_entry(iter) \ 47 + container_of(iter, struct netlbl_domaddr4_map, list) 48 + struct netlbl_domaddr4_map { 49 + u32 type; 50 + union { 51 + struct cipso_v4_doi *cipsov4; 52 + } type_def; 53 + 54 + struct netlbl_af4list list; 55 + }; 56 + #define netlbl_domhsh_addr6_entry(iter) \ 57 + container_of(iter, struct netlbl_domaddr6_map, list) 58 + struct netlbl_domaddr6_map { 59 + u32 type; 60 + 61 + /* NOTE: no 'type_def' union needed at present since we don't currently 62 + * support any IPv6 labeling protocols */ 63 + 64 + struct netlbl_af6list list; 65 + }; 66 + struct netlbl_domaddr_map { 67 + struct list_head list4; 68 + struct list_head list6; 69 + }; 44 70 struct netlbl_dom_map { 45 71 char *domain; 46 72 u32 type; 47 73 union { 48 74 struct cipso_v4_doi *cipsov4; 75 + struct netlbl_domaddr_map *addrsel; 49 76 } type_def; 50 77 51 78 u32 valid; ··· 88 61 struct netlbl_audit *audit_info); 89 62 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, 90 63 struct netlbl_audit *audit_info); 64 + int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, 65 + struct netlbl_audit *audit_info); 91 66 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); 92 67 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); 93 68 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); 69 + struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, 70 + __be32 addr); 94 71 int netlbl_domhsh_walk(u32 *skip_bkt, 95 72 u32 *skip_chain, 96 73 int (*callback) (struct netlbl_dom_map *entry, void *arg), 97 74 void *cb_arg); 75 + 76 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 77 + struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, 78 + const struct in6_addr *addr); 79 + #endif /* IPv6 */ 98 80 99 81 #endif
+193 -81
net/netlabel/netlabel_kapi.c
··· 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 15 * This program is free software; you can redistribute it and/or modify 16 16 * it under the terms of the GNU General Public License as published by ··· 82 82 83 83 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 84 84 if (entry == NULL) 85 - goto cfg_unlbl_add_map_failure; 85 + return -ENOMEM; 86 86 if (domain != NULL) { 87 87 entry->domain = kstrdup(domain, GFP_ATOMIC); 88 88 if (entry->domain == NULL) ··· 104 104 } 105 105 106 106 /** 107 - * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition 108 - * @doi_def: the DOI definition 109 - * @audit_info: NetLabel audit information 110 - * 111 - * Description: 112 - * Add a new CIPSOv4 DOI definition to the NetLabel subsystem. Returns zero on 113 - * success, negative values on failure. 114 - * 115 - */ 116 - int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, 117 - struct netlbl_audit *audit_info) 118 - { 119 - int ret_val; 120 - const char *type_str; 121 - struct audit_buffer *audit_buf; 122 - 123 - ret_val = cipso_v4_doi_add(doi_def); 124 - 125 - audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, 126 - audit_info); 127 - if (audit_buf != NULL) { 128 - switch (doi_def->type) { 129 - case CIPSO_V4_MAP_STD: 130 - type_str = "std"; 131 - break; 132 - case CIPSO_V4_MAP_PASS: 133 - type_str = "pass"; 134 - break; 135 - default: 136 - type_str = "(unknown)"; 137 - } 138 - audit_log_format(audit_buf, 139 - " cipso_doi=%u cipso_type=%s res=%u", 140 - doi_def->doi, 141 - type_str, 142 - ret_val == 0 ? 1 : 0); 143 - audit_log_end(audit_buf); 144 - } 145 - 146 - return ret_val; 147 - } 148 - 149 - /** 150 107 * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping 151 108 * @doi_def: the DOI definition 152 109 * @domain: the domain mapping to add ··· 121 164 struct netlbl_audit *audit_info) 122 165 { 123 166 int ret_val = -ENOMEM; 167 + u32 doi; 168 + u32 doi_type; 124 169 struct netlbl_dom_map *entry; 170 + const char *type_str; 171 + struct audit_buffer *audit_buf; 172 + 173 + doi = doi_def->doi; 174 + doi_type = doi_def->type; 125 175 126 176 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 127 177 if (entry == NULL) 128 - goto cfg_cipsov4_add_map_failure; 178 + return -ENOMEM; 129 179 if (domain != NULL) { 130 180 entry->domain = kstrdup(domain, GFP_ATOMIC); 131 181 if (entry->domain == NULL) 132 182 goto cfg_cipsov4_add_map_failure; 133 183 } 134 - entry->type = NETLBL_NLTYPE_CIPSOV4; 135 - entry->type_def.cipsov4 = doi_def; 136 184 137 - /* Grab a RCU read lock here so nothing happens to the doi_def variable 138 - * between adding it to the CIPSOv4 protocol engine and adding a 139 - * domain mapping for it. */ 140 - 141 - rcu_read_lock(); 142 - ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info); 143 - if (ret_val != 0) 144 - goto cfg_cipsov4_add_map_failure_unlock; 145 - ret_val = netlbl_domhsh_add(entry, audit_info); 185 + ret_val = cipso_v4_doi_add(doi_def); 146 186 if (ret_val != 0) 147 187 goto cfg_cipsov4_add_map_failure_remove_doi; 148 - rcu_read_unlock(); 188 + entry->type = NETLBL_NLTYPE_CIPSOV4; 189 + entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi); 190 + if (entry->type_def.cipsov4 == NULL) { 191 + ret_val = -ENOENT; 192 + goto cfg_cipsov4_add_map_failure_remove_doi; 193 + } 194 + ret_val = netlbl_domhsh_add(entry, audit_info); 195 + if (ret_val != 0) 196 + goto cfg_cipsov4_add_map_failure_release_doi; 149 197 150 - return 0; 198 + cfg_cipsov4_add_map_return: 199 + audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, 200 + audit_info); 201 + if (audit_buf != NULL) { 202 + switch (doi_type) { 203 + case CIPSO_V4_MAP_TRANS: 204 + type_str = "trans"; 205 + break; 206 + case CIPSO_V4_MAP_PASS: 207 + type_str = "pass"; 208 + break; 209 + case CIPSO_V4_MAP_LOCAL: 210 + type_str = "local"; 211 + break; 212 + default: 213 + type_str = "(unknown)"; 214 + } 215 + audit_log_format(audit_buf, 216 + " cipso_doi=%u cipso_type=%s res=%u", 217 + doi, type_str, ret_val == 0 ? 1 : 0); 218 + audit_log_end(audit_buf); 219 + } 151 220 221 + return ret_val; 222 + 223 + cfg_cipsov4_add_map_failure_release_doi: 224 + cipso_v4_doi_putdef(doi_def); 152 225 cfg_cipsov4_add_map_failure_remove_doi: 153 - cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free); 154 - cfg_cipsov4_add_map_failure_unlock: 155 - rcu_read_unlock(); 226 + cipso_v4_doi_remove(doi, audit_info); 156 227 cfg_cipsov4_add_map_failure: 157 228 if (entry != NULL) 158 229 kfree(entry->domain); 159 230 kfree(entry); 160 - return ret_val; 161 - } 162 - 163 - /** 164 - * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition 165 - * @doi: the CIPSO DOI value 166 - * @audit_info: NetLabel audit information 167 - * 168 - * Description: 169 - * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem. 170 - * Returns zero on success, negative values on failure. 171 - * 172 - */ 173 - int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info) 174 - { 175 - return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free); 231 + goto cfg_cipsov4_add_map_return; 176 232 } 177 233 178 234 /* ··· 422 452 * Attach the correct label to the given socket using the security attributes 423 453 * specified in @secattr. This function requires exclusive access to @sk, 424 454 * which means it either needs to be in the process of being created or locked. 425 - * Returns zero on success, negative values on failure. 455 + * Returns zero on success, -EDESTADDRREQ if the domain is configured to use 456 + * network address selectors (can't blindly label the socket), and negative 457 + * values on all other failures. 426 458 * 427 459 */ 428 460 int netlbl_sock_setattr(struct sock *sk, ··· 438 466 if (dom_entry == NULL) 439 467 goto socket_setattr_return; 440 468 switch (dom_entry->type) { 469 + case NETLBL_NLTYPE_ADDRSELECT: 470 + ret_val = -EDESTADDRREQ; 471 + break; 441 472 case NETLBL_NLTYPE_CIPSOV4: 442 473 ret_val = cipso_v4_sock_setattr(sk, 443 474 dom_entry->type_def.cipsov4, ··· 459 484 } 460 485 461 486 /** 487 + * netlbl_sock_delattr - Delete all the NetLabel labels on a socket 488 + * @sk: the socket 489 + * 490 + * Description: 491 + * Remove all the NetLabel labeling from @sk. The caller is responsible for 492 + * ensuring that @sk is locked. 493 + * 494 + */ 495 + void netlbl_sock_delattr(struct sock *sk) 496 + { 497 + cipso_v4_sock_delattr(sk); 498 + } 499 + 500 + /** 462 501 * netlbl_sock_getattr - Determine the security attributes of a sock 463 502 * @sk: the sock 464 503 * @secattr: the security attributes ··· 487 498 int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) 488 499 { 489 500 return cipso_v4_sock_getattr(sk, secattr); 501 + } 502 + 503 + /** 504 + * netlbl_conn_setattr - Label a connected socket using the correct protocol 505 + * @sk: the socket to label 506 + * @addr: the destination address 507 + * @secattr: the security attributes 508 + * 509 + * Description: 510 + * Attach the correct label to the given connected socket using the security 511 + * attributes specified in @secattr. The caller is responsible for ensuring 512 + * that @sk is locked. Returns zero on success, negative values on failure. 513 + * 514 + */ 515 + int netlbl_conn_setattr(struct sock *sk, 516 + struct sockaddr *addr, 517 + const struct netlbl_lsm_secattr *secattr) 518 + { 519 + int ret_val; 520 + struct sockaddr_in *addr4; 521 + struct netlbl_domaddr4_map *af4_entry; 522 + 523 + rcu_read_lock(); 524 + switch (addr->sa_family) { 525 + case AF_INET: 526 + addr4 = (struct sockaddr_in *)addr; 527 + af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, 528 + addr4->sin_addr.s_addr); 529 + if (af4_entry == NULL) { 530 + ret_val = -ENOENT; 531 + goto conn_setattr_return; 532 + } 533 + switch (af4_entry->type) { 534 + case NETLBL_NLTYPE_CIPSOV4: 535 + ret_val = cipso_v4_sock_setattr(sk, 536 + af4_entry->type_def.cipsov4, 537 + secattr); 538 + break; 539 + case NETLBL_NLTYPE_UNLABELED: 540 + /* just delete the protocols we support for right now 541 + * but we could remove other protocols if needed */ 542 + cipso_v4_sock_delattr(sk); 543 + ret_val = 0; 544 + break; 545 + default: 546 + ret_val = -ENOENT; 547 + } 548 + break; 549 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 550 + case AF_INET6: 551 + /* since we don't support any IPv6 labeling protocols right 552 + * now we can optimize everything away until we do */ 553 + ret_val = 0; 554 + break; 555 + #endif /* IPv6 */ 556 + default: 557 + ret_val = 0; 558 + } 559 + 560 + conn_setattr_return: 561 + rcu_read_unlock(); 562 + return ret_val; 563 + } 564 + 565 + /** 566 + * netlbl_skbuff_setattr - Label a packet using the correct protocol 567 + * @skb: the packet 568 + * @family: protocol family 569 + * @secattr: the security attributes 570 + * 571 + * Description: 572 + * Attach the correct label to the given packet using the security attributes 573 + * specified in @secattr. Returns zero on success, negative values on failure. 574 + * 575 + */ 576 + int netlbl_skbuff_setattr(struct sk_buff *skb, 577 + u16 family, 578 + const struct netlbl_lsm_secattr *secattr) 579 + { 580 + int ret_val; 581 + struct iphdr *hdr4; 582 + struct netlbl_domaddr4_map *af4_entry; 583 + 584 + rcu_read_lock(); 585 + switch (family) { 586 + case AF_INET: 587 + hdr4 = ip_hdr(skb); 588 + af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, 589 + hdr4->daddr); 590 + if (af4_entry == NULL) { 591 + ret_val = -ENOENT; 592 + goto skbuff_setattr_return; 593 + } 594 + switch (af4_entry->type) { 595 + case NETLBL_NLTYPE_CIPSOV4: 596 + ret_val = cipso_v4_skbuff_setattr(skb, 597 + af4_entry->type_def.cipsov4, 598 + secattr); 599 + break; 600 + case NETLBL_NLTYPE_UNLABELED: 601 + /* just delete the protocols we support for right now 602 + * but we could remove other protocols if needed */ 603 + ret_val = cipso_v4_skbuff_delattr(skb); 604 + break; 605 + default: 606 + ret_val = -ENOENT; 607 + } 608 + break; 609 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 610 + case AF_INET6: 611 + /* since we don't support any IPv6 labeling protocols right 612 + * now we can optimize everything away until we do */ 613 + ret_val = 0; 614 + break; 615 + #endif /* IPv6 */ 616 + default: 617 + ret_val = 0; 618 + } 619 + 620 + skbuff_setattr_return: 621 + rcu_read_unlock(); 622 + return ret_val; 490 623 } 491 624 492 625 /** ··· 639 528 * netlbl_skbuff_err - Handle a LSM error on a sk_buff 640 529 * @skb: the packet 641 530 * @error: the error code 531 + * @gateway: true if host is acting as a gateway, false otherwise 642 532 * 643 533 * Description: 644 534 * Deal with a LSM problem when handling the packet in @skb, typically this is ··· 647 535 * according to the packet's labeling protocol. 648 536 * 649 537 */ 650 - void netlbl_skbuff_err(struct sk_buff *skb, int error) 538 + void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) 651 539 { 652 540 if (CIPSO_V4_OPTEXIST(skb)) 653 - cipso_v4_error(skb, error, 0); 541 + cipso_v4_error(skb, error, gateway); 654 542 } 655 543 656 544 /**
+327 -129
net/netlabel/netlabel_mgmt.c
··· 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 15 * This program is free software; you can redistribute it and/or modify 16 16 * it under the terms of the GNU General Public License as published by ··· 32 32 #include <linux/socket.h> 33 33 #include <linux/string.h> 34 34 #include <linux/skbuff.h> 35 + #include <linux/in.h> 36 + #include <linux/in6.h> 35 37 #include <net/sock.h> 36 38 #include <net/netlink.h> 37 39 #include <net/genetlink.h> 40 + #include <net/ip.h> 41 + #include <net/ipv6.h> 38 42 #include <net/netlabel.h> 39 43 #include <net/cipso_ipv4.h> 40 44 #include <asm/atomic.h> ··· 75 71 }; 76 72 77 73 /* 74 + * Helper Functions 75 + */ 76 + 77 + /** 78 + * netlbl_mgmt_add - Handle an ADD message 79 + * @info: the Generic NETLINK info block 80 + * @audit_info: NetLabel audit information 81 + * 82 + * Description: 83 + * Helper function for the ADD and ADDDEF messages to add the domain mappings 84 + * from the message to the hash table. See netlabel.h for a description of the 85 + * message format. Returns zero on success, negative values on failure. 86 + * 87 + */ 88 + static int netlbl_mgmt_add_common(struct genl_info *info, 89 + struct netlbl_audit *audit_info) 90 + { 91 + int ret_val = -EINVAL; 92 + struct netlbl_dom_map *entry = NULL; 93 + struct netlbl_domaddr_map *addrmap = NULL; 94 + struct cipso_v4_doi *cipsov4 = NULL; 95 + u32 tmp_val; 96 + 97 + entry = kzalloc(sizeof(*entry), GFP_KERNEL); 98 + if (entry == NULL) { 99 + ret_val = -ENOMEM; 100 + goto add_failure; 101 + } 102 + entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 103 + if (info->attrs[NLBL_MGMT_A_DOMAIN]) { 104 + size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); 105 + entry->domain = kmalloc(tmp_size, GFP_KERNEL); 106 + if (entry->domain == NULL) { 107 + ret_val = -ENOMEM; 108 + goto add_failure; 109 + } 110 + nla_strlcpy(entry->domain, 111 + info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 112 + } 113 + 114 + /* NOTE: internally we allow/use a entry->type value of 115 + * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users 116 + * to pass that as a protocol value because we need to know the 117 + * "real" protocol */ 118 + 119 + switch (entry->type) { 120 + case NETLBL_NLTYPE_UNLABELED: 121 + break; 122 + case NETLBL_NLTYPE_CIPSOV4: 123 + if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 124 + goto add_failure; 125 + 126 + tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 127 + cipsov4 = cipso_v4_doi_getdef(tmp_val); 128 + if (cipsov4 == NULL) 129 + goto add_failure; 130 + entry->type_def.cipsov4 = cipsov4; 131 + break; 132 + default: 133 + goto add_failure; 134 + } 135 + 136 + if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { 137 + struct in_addr *addr; 138 + struct in_addr *mask; 139 + struct netlbl_domaddr4_map *map; 140 + 141 + addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 142 + if (addrmap == NULL) { 143 + ret_val = -ENOMEM; 144 + goto add_failure; 145 + } 146 + INIT_LIST_HEAD(&addrmap->list4); 147 + INIT_LIST_HEAD(&addrmap->list6); 148 + 149 + if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != 150 + sizeof(struct in_addr)) { 151 + ret_val = -EINVAL; 152 + goto add_failure; 153 + } 154 + if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != 155 + sizeof(struct in_addr)) { 156 + ret_val = -EINVAL; 157 + goto add_failure; 158 + } 159 + addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); 160 + mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); 161 + 162 + map = kzalloc(sizeof(*map), GFP_KERNEL); 163 + if (map == NULL) { 164 + ret_val = -ENOMEM; 165 + goto add_failure; 166 + } 167 + map->list.addr = addr->s_addr & mask->s_addr; 168 + map->list.mask = mask->s_addr; 169 + map->list.valid = 1; 170 + map->type = entry->type; 171 + if (cipsov4) 172 + map->type_def.cipsov4 = cipsov4; 173 + 174 + ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); 175 + if (ret_val != 0) { 176 + kfree(map); 177 + goto add_failure; 178 + } 179 + 180 + entry->type = NETLBL_NLTYPE_ADDRSELECT; 181 + entry->type_def.addrsel = addrmap; 182 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 183 + } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { 184 + struct in6_addr *addr; 185 + struct in6_addr *mask; 186 + struct netlbl_domaddr6_map *map; 187 + 188 + addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 189 + if (addrmap == NULL) { 190 + ret_val = -ENOMEM; 191 + goto add_failure; 192 + } 193 + INIT_LIST_HEAD(&addrmap->list4); 194 + INIT_LIST_HEAD(&addrmap->list6); 195 + 196 + if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != 197 + sizeof(struct in6_addr)) { 198 + ret_val = -EINVAL; 199 + goto add_failure; 200 + } 201 + if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != 202 + sizeof(struct in6_addr)) { 203 + ret_val = -EINVAL; 204 + goto add_failure; 205 + } 206 + addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); 207 + mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); 208 + 209 + map = kzalloc(sizeof(*map), GFP_KERNEL); 210 + if (map == NULL) { 211 + ret_val = -ENOMEM; 212 + goto add_failure; 213 + } 214 + ipv6_addr_copy(&map->list.addr, addr); 215 + map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 216 + map->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 217 + map->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 218 + map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 219 + ipv6_addr_copy(&map->list.mask, mask); 220 + map->list.valid = 1; 221 + map->type = entry->type; 222 + 223 + ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); 224 + if (ret_val != 0) { 225 + kfree(map); 226 + goto add_failure; 227 + } 228 + 229 + entry->type = NETLBL_NLTYPE_ADDRSELECT; 230 + entry->type_def.addrsel = addrmap; 231 + #endif /* IPv6 */ 232 + } 233 + 234 + ret_val = netlbl_domhsh_add(entry, audit_info); 235 + if (ret_val != 0) 236 + goto add_failure; 237 + 238 + return 0; 239 + 240 + add_failure: 241 + if (cipsov4) 242 + cipso_v4_doi_putdef(cipsov4); 243 + if (entry) 244 + kfree(entry->domain); 245 + kfree(addrmap); 246 + kfree(entry); 247 + return ret_val; 248 + } 249 + 250 + /** 251 + * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry 252 + * @skb: the NETLINK buffer 253 + * @entry: the map entry 254 + * 255 + * Description: 256 + * This function is a helper function used by the LISTALL and LISTDEF command 257 + * handlers. The caller is responsibile for ensuring that the RCU read lock 258 + * is held. Returns zero on success, negative values on failure. 259 + * 260 + */ 261 + static int netlbl_mgmt_listentry(struct sk_buff *skb, 262 + struct netlbl_dom_map *entry) 263 + { 264 + int ret_val; 265 + struct nlattr *nla_a; 266 + struct nlattr *nla_b; 267 + struct netlbl_af4list *iter4; 268 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 269 + struct netlbl_af6list *iter6; 270 + #endif 271 + 272 + if (entry->domain != NULL) { 273 + ret_val = nla_put_string(skb, 274 + NLBL_MGMT_A_DOMAIN, entry->domain); 275 + if (ret_val != 0) 276 + return ret_val; 277 + } 278 + 279 + switch (entry->type) { 280 + case NETLBL_NLTYPE_ADDRSELECT: 281 + nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); 282 + if (nla_a == NULL) 283 + return -ENOMEM; 284 + 285 + netlbl_af4list_foreach_rcu(iter4, 286 + &entry->type_def.addrsel->list4) { 287 + struct netlbl_domaddr4_map *map4; 288 + struct in_addr addr_struct; 289 + 290 + nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 291 + if (nla_b == NULL) 292 + return -ENOMEM; 293 + 294 + addr_struct.s_addr = iter4->addr; 295 + ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR, 296 + sizeof(struct in_addr), 297 + &addr_struct); 298 + if (ret_val != 0) 299 + return ret_val; 300 + addr_struct.s_addr = iter4->mask; 301 + ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK, 302 + sizeof(struct in_addr), 303 + &addr_struct); 304 + if (ret_val != 0) 305 + return ret_val; 306 + map4 = netlbl_domhsh_addr4_entry(iter4); 307 + ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 308 + map4->type); 309 + if (ret_val != 0) 310 + return ret_val; 311 + switch (map4->type) { 312 + case NETLBL_NLTYPE_CIPSOV4: 313 + ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 314 + map4->type_def.cipsov4->doi); 315 + if (ret_val != 0) 316 + return ret_val; 317 + break; 318 + } 319 + 320 + nla_nest_end(skb, nla_b); 321 + } 322 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 323 + netlbl_af6list_foreach_rcu(iter6, 324 + &entry->type_def.addrsel->list6) { 325 + struct netlbl_domaddr6_map *map6; 326 + 327 + nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 328 + if (nla_b == NULL) 329 + return -ENOMEM; 330 + 331 + ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR, 332 + sizeof(struct in6_addr), 333 + &iter6->addr); 334 + if (ret_val != 0) 335 + return ret_val; 336 + ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK, 337 + sizeof(struct in6_addr), 338 + &iter6->mask); 339 + if (ret_val != 0) 340 + return ret_val; 341 + map6 = netlbl_domhsh_addr6_entry(iter6); 342 + ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 343 + map6->type); 344 + if (ret_val != 0) 345 + return ret_val; 346 + 347 + nla_nest_end(skb, nla_b); 348 + } 349 + #endif /* IPv6 */ 350 + 351 + nla_nest_end(skb, nla_a); 352 + break; 353 + case NETLBL_NLTYPE_UNLABELED: 354 + ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); 355 + break; 356 + case NETLBL_NLTYPE_CIPSOV4: 357 + ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); 358 + if (ret_val != 0) 359 + return ret_val; 360 + ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 361 + entry->type_def.cipsov4->doi); 362 + break; 363 + } 364 + 365 + return ret_val; 366 + } 367 + 368 + /* 78 369 * NetLabel Command Handlers 79 370 */ 80 371 ··· 386 87 */ 387 88 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 388 89 { 389 - int ret_val = -EINVAL; 390 - struct netlbl_dom_map *entry = NULL; 391 - size_t tmp_size; 392 - u32 tmp_val; 393 90 struct netlbl_audit audit_info; 394 91 395 - if (!info->attrs[NLBL_MGMT_A_DOMAIN] || 396 - !info->attrs[NLBL_MGMT_A_PROTOCOL]) 397 - goto add_failure; 92 + if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || 93 + (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 94 + (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 95 + info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 96 + (info->attrs[NLBL_MGMT_A_IPV4MASK] && 97 + info->attrs[NLBL_MGMT_A_IPV6MASK]) || 98 + ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 99 + (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 100 + ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 101 + (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 102 + return -EINVAL; 398 103 399 104 netlbl_netlink_auditinfo(skb, &audit_info); 400 105 401 - entry = kzalloc(sizeof(*entry), GFP_KERNEL); 402 - if (entry == NULL) { 403 - ret_val = -ENOMEM; 404 - goto add_failure; 405 - } 406 - tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); 407 - entry->domain = kmalloc(tmp_size, GFP_KERNEL); 408 - if (entry->domain == NULL) { 409 - ret_val = -ENOMEM; 410 - goto add_failure; 411 - } 412 - entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 413 - nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 414 - 415 - switch (entry->type) { 416 - case NETLBL_NLTYPE_UNLABELED: 417 - ret_val = netlbl_domhsh_add(entry, &audit_info); 418 - break; 419 - case NETLBL_NLTYPE_CIPSOV4: 420 - if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 421 - goto add_failure; 422 - 423 - tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 424 - /* We should be holding a rcu_read_lock() here while we hold 425 - * the result but since the entry will always be deleted when 426 - * the CIPSO DOI is deleted we aren't going to keep the 427 - * lock. */ 428 - rcu_read_lock(); 429 - entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 430 - if (entry->type_def.cipsov4 == NULL) { 431 - rcu_read_unlock(); 432 - goto add_failure; 433 - } 434 - ret_val = netlbl_domhsh_add(entry, &audit_info); 435 - rcu_read_unlock(); 436 - break; 437 - default: 438 - goto add_failure; 439 - } 440 - if (ret_val != 0) 441 - goto add_failure; 442 - 443 - return 0; 444 - 445 - add_failure: 446 - if (entry) 447 - kfree(entry->domain); 448 - kfree(entry); 449 - return ret_val; 106 + return netlbl_mgmt_add_common(info, &audit_info); 450 107 } 451 108 452 109 /** ··· 453 198 if (data == NULL) 454 199 goto listall_cb_failure; 455 200 456 - ret_val = nla_put_string(cb_arg->skb, 457 - NLBL_MGMT_A_DOMAIN, 458 - entry->domain); 201 + ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); 459 202 if (ret_val != 0) 460 203 goto listall_cb_failure; 461 - ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type); 462 - if (ret_val != 0) 463 - goto listall_cb_failure; 464 - switch (entry->type) { 465 - case NETLBL_NLTYPE_CIPSOV4: 466 - ret_val = nla_put_u32(cb_arg->skb, 467 - NLBL_MGMT_A_CV4DOI, 468 - entry->type_def.cipsov4->doi); 469 - if (ret_val != 0) 470 - goto listall_cb_failure; 471 - break; 472 - } 473 204 474 205 cb_arg->seq++; 475 206 return genlmsg_end(cb_arg->skb, data); ··· 509 268 */ 510 269 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 511 270 { 512 - int ret_val = -EINVAL; 513 - struct netlbl_dom_map *entry = NULL; 514 - u32 tmp_val; 515 271 struct netlbl_audit audit_info; 516 272 517 - if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) 518 - goto adddef_failure; 273 + if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 274 + (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 275 + info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 276 + (info->attrs[NLBL_MGMT_A_IPV4MASK] && 277 + info->attrs[NLBL_MGMT_A_IPV6MASK]) || 278 + ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 279 + (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 280 + ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 281 + (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 282 + return -EINVAL; 519 283 520 284 netlbl_netlink_auditinfo(skb, &audit_info); 521 285 522 - entry = kzalloc(sizeof(*entry), GFP_KERNEL); 523 - if (entry == NULL) { 524 - ret_val = -ENOMEM; 525 - goto adddef_failure; 526 - } 527 - entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 528 - 529 - switch (entry->type) { 530 - case NETLBL_NLTYPE_UNLABELED: 531 - ret_val = netlbl_domhsh_add_default(entry, &audit_info); 532 - break; 533 - case NETLBL_NLTYPE_CIPSOV4: 534 - if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 535 - goto adddef_failure; 536 - 537 - tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 538 - /* We should be holding a rcu_read_lock() here while we hold 539 - * the result but since the entry will always be deleted when 540 - * the CIPSO DOI is deleted we aren't going to keep the 541 - * lock. */ 542 - rcu_read_lock(); 543 - entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 544 - if (entry->type_def.cipsov4 == NULL) { 545 - rcu_read_unlock(); 546 - goto adddef_failure; 547 - } 548 - ret_val = netlbl_domhsh_add_default(entry, &audit_info); 549 - rcu_read_unlock(); 550 - break; 551 - default: 552 - goto adddef_failure; 553 - } 554 - if (ret_val != 0) 555 - goto adddef_failure; 556 - 557 - return 0; 558 - 559 - adddef_failure: 560 - kfree(entry); 561 - return ret_val; 286 + return netlbl_mgmt_add_common(info, &audit_info); 562 287 } 563 288 564 289 /** ··· 578 371 ret_val = -ENOENT; 579 372 goto listdef_failure_lock; 580 373 } 581 - ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); 582 - if (ret_val != 0) 583 - goto listdef_failure_lock; 584 - switch (entry->type) { 585 - case NETLBL_NLTYPE_CIPSOV4: 586 - ret_val = nla_put_u32(ans_skb, 587 - NLBL_MGMT_A_CV4DOI, 588 - entry->type_def.cipsov4->doi); 589 - if (ret_val != 0) 590 - goto listdef_failure_lock; 591 - break; 592 - } 374 + ret_val = netlbl_mgmt_listentry(ans_skb, entry); 593 375 rcu_read_unlock(); 376 + if (ret_val != 0) 377 + goto listdef_failure; 594 378 595 379 genlmsg_end(ans_skb, data); 596 380 return genlmsg_reply(ans_skb, info);
+54 -5
net/netlabel/netlabel_mgmt.h
··· 45 45 * NLBL_MGMT_A_DOMAIN 46 46 * NLBL_MGMT_A_PROTOCOL 47 47 * 48 + * If IPv4 is specified the following attributes are required: 49 + * 50 + * NLBL_MGMT_A_IPV4ADDR 51 + * NLBL_MGMT_A_IPV4MASK 52 + * 53 + * If IPv6 is specified the following attributes are required: 54 + * 55 + * NLBL_MGMT_A_IPV6ADDR 56 + * NLBL_MGMT_A_IPV6MASK 57 + * 48 58 * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 49 59 * 50 60 * NLBL_MGMT_A_CV4DOI ··· 78 68 * Required attributes: 79 69 * 80 70 * NLBL_MGMT_A_DOMAIN 71 + * 72 + * If the IP address selectors are not used the following attribute is 73 + * required: 74 + * 81 75 * NLBL_MGMT_A_PROTOCOL 82 76 * 83 - * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 77 + * If the IP address selectors are used then the following attritbute is 78 + * required: 79 + * 80 + * NLBL_MGMT_A_SELECTORLIST 81 + * 82 + * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following 83 + * attributes are required: 84 84 * 85 85 * NLBL_MGMT_A_CV4DOI 86 86 * 87 - * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 87 + * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other 88 + * attributes are required. 88 89 * 89 90 * o ADDDEF: 90 91 * Sent by an application to set the default domain mapping for the NetLabel ··· 121 100 * application there is no payload. On success the kernel should send a 122 101 * response using the following format. 123 102 * 124 - * Required attributes: 103 + * If the IP address selectors are not used the following attribute is 104 + * required: 125 105 * 126 106 * NLBL_MGMT_A_PROTOCOL 127 107 * 128 - * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: 108 + * If the IP address selectors are used then the following attritbute is 109 + * required: 110 + * 111 + * NLBL_MGMT_A_SELECTORLIST 112 + * 113 + * If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following 114 + * attributes are required: 129 115 * 130 116 * NLBL_MGMT_A_CV4DOI 131 117 * 132 - * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. 118 + * If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other 119 + * attributes are required. 133 120 * 134 121 * o PROTOCOLS: 135 122 * Sent by an application to request a list of configured NetLabel protocols ··· 191 162 NLBL_MGMT_A_CV4DOI, 192 163 /* (NLA_U32) 193 164 * the CIPSOv4 DOI value */ 165 + NLBL_MGMT_A_IPV6ADDR, 166 + /* (NLA_BINARY, struct in6_addr) 167 + * an IPv6 address */ 168 + NLBL_MGMT_A_IPV6MASK, 169 + /* (NLA_BINARY, struct in6_addr) 170 + * an IPv6 address mask */ 171 + NLBL_MGMT_A_IPV4ADDR, 172 + /* (NLA_BINARY, struct in_addr) 173 + * an IPv4 address */ 174 + NLBL_MGMT_A_IPV4MASK, 175 + /* (NLA_BINARY, struct in_addr) 176 + * and IPv4 address mask */ 177 + NLBL_MGMT_A_ADDRSELECTOR, 178 + /* (NLA_NESTED) 179 + * an IP address selector, must contain an address, mask, and protocol 180 + * attribute plus any protocol specific attributes */ 181 + NLBL_MGMT_A_SELECTORLIST, 182 + /* (NLA_NESTED) 183 + * the selector list, there must be at least one 184 + * NLBL_MGMT_A_ADDRSELECTOR attribute */ 194 185 __NLBL_MGMT_A_MAX, 195 186 }; 196 187 #define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
+153 -303
net/netlabel/netlabel_unlabeled.c
··· 10 10 */ 11 11 12 12 /* 13 - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2007 13 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 2008 14 14 * 15 15 * This program is free software; you can redistribute it and/or modify 16 16 * it under the terms of the GNU General Public License as published by ··· 54 54 #include <asm/atomic.h> 55 55 56 56 #include "netlabel_user.h" 57 + #include "netlabel_addrlist.h" 57 58 #include "netlabel_domainhash.h" 58 59 #include "netlabel_unlabeled.h" 59 60 #include "netlabel_mgmt.h" ··· 77 76 struct list_head *tbl; 78 77 u32 size; 79 78 }; 79 + #define netlbl_unlhsh_addr4_entry(iter) \ 80 + container_of(iter, struct netlbl_unlhsh_addr4, list) 80 81 struct netlbl_unlhsh_addr4 { 81 - __be32 addr; 82 - __be32 mask; 83 82 u32 secid; 84 83 85 - u32 valid; 86 - struct list_head list; 84 + struct netlbl_af4list list; 87 85 struct rcu_head rcu; 88 86 }; 87 + #define netlbl_unlhsh_addr6_entry(iter) \ 88 + container_of(iter, struct netlbl_unlhsh_addr6, list) 89 89 struct netlbl_unlhsh_addr6 { 90 - struct in6_addr addr; 91 - struct in6_addr mask; 92 90 u32 secid; 93 91 94 - u32 valid; 95 - struct list_head list; 92 + struct netlbl_af6list list; 96 93 struct rcu_head rcu; 97 94 }; 98 95 struct netlbl_unlhsh_iface { ··· 144 145 .len = IFNAMSIZ - 1 }, 145 146 [NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY } 146 147 }; 147 - 148 - /* 149 - * Audit Helper Functions 150 - */ 151 - 152 - /** 153 - * netlbl_unlabel_audit_addr4 - Audit an IPv4 address 154 - * @audit_buf: audit buffer 155 - * @dev: network interface 156 - * @addr: IP address 157 - * @mask: IP address mask 158 - * 159 - * Description: 160 - * Write the IPv4 address and address mask, if necessary, to @audit_buf. 161 - * 162 - */ 163 - static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf, 164 - const char *dev, 165 - __be32 addr, __be32 mask) 166 - { 167 - u32 mask_val = ntohl(mask); 168 - 169 - if (dev != NULL) 170 - audit_log_format(audit_buf, " netif=%s", dev); 171 - audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr)); 172 - if (mask_val != 0xffffffff) { 173 - u32 mask_len = 0; 174 - while (mask_val > 0) { 175 - mask_val <<= 1; 176 - mask_len++; 177 - } 178 - audit_log_format(audit_buf, " src_prefixlen=%d", mask_len); 179 - } 180 - } 181 - 182 - #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 183 - /** 184 - * netlbl_unlabel_audit_addr6 - Audit an IPv6 address 185 - * @audit_buf: audit buffer 186 - * @dev: network interface 187 - * @addr: IP address 188 - * @mask: IP address mask 189 - * 190 - * Description: 191 - * Write the IPv6 address and address mask, if necessary, to @audit_buf. 192 - * 193 - */ 194 - static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf, 195 - const char *dev, 196 - const struct in6_addr *addr, 197 - const struct in6_addr *mask) 198 - { 199 - if (dev != NULL) 200 - audit_log_format(audit_buf, " netif=%s", dev); 201 - audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr)); 202 - if (ntohl(mask->s6_addr32[3]) != 0xffffffff) { 203 - u32 mask_len = 0; 204 - u32 mask_val; 205 - int iter = -1; 206 - while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff) 207 - mask_len += 32; 208 - mask_val = ntohl(mask->s6_addr32[iter]); 209 - while (mask_val > 0) { 210 - mask_val <<= 1; 211 - mask_len++; 212 - } 213 - audit_log_format(audit_buf, " src_prefixlen=%d", mask_len); 214 - } 215 - } 216 - #endif /* IPv6 */ 217 148 218 149 /* 219 150 * Unlabeled Connection Hash Table Functions ··· 203 274 static void netlbl_unlhsh_free_iface(struct rcu_head *entry) 204 275 { 205 276 struct netlbl_unlhsh_iface *iface; 206 - struct netlbl_unlhsh_addr4 *iter4; 207 - struct netlbl_unlhsh_addr4 *tmp4; 208 - struct netlbl_unlhsh_addr6 *iter6; 209 - struct netlbl_unlhsh_addr6 *tmp6; 277 + struct netlbl_af4list *iter4; 278 + struct netlbl_af4list *tmp4; 279 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 280 + struct netlbl_af6list *iter6; 281 + struct netlbl_af6list *tmp6; 282 + #endif /* IPv6 */ 210 283 211 284 iface = container_of(entry, struct netlbl_unlhsh_iface, rcu); 212 285 213 286 /* no need for locks here since we are the only one with access to this 214 287 * structure */ 215 288 216 - list_for_each_entry_safe(iter4, tmp4, &iface->addr4_list, list) 217 - if (iter4->valid) { 218 - list_del_rcu(&iter4->list); 219 - kfree(iter4); 220 - } 221 - list_for_each_entry_safe(iter6, tmp6, &iface->addr6_list, list) 222 - if (iter6->valid) { 223 - list_del_rcu(&iter6->list); 224 - kfree(iter6); 225 - } 289 + netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) { 290 + netlbl_af4list_remove_entry(iter4); 291 + kfree(netlbl_unlhsh_addr4_entry(iter4)); 292 + } 293 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 294 + netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) { 295 + netlbl_af6list_remove_entry(iter6); 296 + kfree(netlbl_unlhsh_addr6_entry(iter6)); 297 + } 298 + #endif /* IPv6 */ 226 299 kfree(iface); 227 300 } 228 301 ··· 247 316 } 248 317 249 318 /** 250 - * netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry 251 - * @addr: IPv4 address 252 - * @iface: the network interface entry 253 - * 254 - * Description: 255 - * Searches the IPv4 address list of the network interface specified by @iface. 256 - * If a matching address entry is found it is returned, otherwise NULL is 257 - * returned. The caller is responsible for calling the rcu_read_[un]lock() 258 - * functions. 259 - * 260 - */ 261 - static struct netlbl_unlhsh_addr4 *netlbl_unlhsh_search_addr4( 262 - __be32 addr, 263 - const struct netlbl_unlhsh_iface *iface) 264 - { 265 - struct netlbl_unlhsh_addr4 *iter; 266 - 267 - list_for_each_entry_rcu(iter, &iface->addr4_list, list) 268 - if (iter->valid && (addr & iter->mask) == iter->addr) 269 - return iter; 270 - 271 - return NULL; 272 - } 273 - 274 - #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 275 - /** 276 - * netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry 277 - * @addr: IPv6 address 278 - * @iface: the network interface entry 279 - * 280 - * Description: 281 - * Searches the IPv6 address list of the network interface specified by @iface. 282 - * If a matching address entry is found it is returned, otherwise NULL is 283 - * returned. The caller is responsible for calling the rcu_read_[un]lock() 284 - * functions. 285 - * 286 - */ 287 - static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6( 288 - const struct in6_addr *addr, 289 - const struct netlbl_unlhsh_iface *iface) 290 - { 291 - struct netlbl_unlhsh_addr6 *iter; 292 - 293 - list_for_each_entry_rcu(iter, &iface->addr6_list, list) 294 - if (iter->valid && 295 - ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0) 296 - return iter; 297 - 298 - return NULL; 299 - } 300 - #endif /* IPv6 */ 301 - 302 - /** 303 319 * netlbl_unlhsh_search_iface - Search for a matching interface entry 304 320 * @ifindex: the network interface 305 321 * ··· 259 381 static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex) 260 382 { 261 383 u32 bkt; 384 + struct list_head *bkt_list; 262 385 struct netlbl_unlhsh_iface *iter; 263 386 264 387 bkt = netlbl_unlhsh_hash(ifindex); 265 - list_for_each_entry_rcu(iter, 266 - &rcu_dereference(netlbl_unlhsh)->tbl[bkt], 267 - list) 388 + bkt_list = &rcu_dereference(netlbl_unlhsh)->tbl[bkt]; 389 + list_for_each_entry_rcu(iter, bkt_list, list) 268 390 if (iter->valid && iter->ifindex == ifindex) 269 391 return iter; 270 392 ··· 317 439 const struct in_addr *mask, 318 440 u32 secid) 319 441 { 442 + int ret_val; 320 443 struct netlbl_unlhsh_addr4 *entry; 321 - struct netlbl_unlhsh_addr4 *iter; 322 444 323 445 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 324 446 if (entry == NULL) 325 447 return -ENOMEM; 326 448 327 - entry->addr = addr->s_addr & mask->s_addr; 328 - entry->mask = mask->s_addr; 329 - entry->secid = secid; 330 - entry->valid = 1; 449 + entry->list.addr = addr->s_addr & mask->s_addr; 450 + entry->list.mask = mask->s_addr; 451 + entry->list.valid = 1; 331 452 INIT_RCU_HEAD(&entry->rcu); 453 + entry->secid = secid; 332 454 333 455 spin_lock(&netlbl_unlhsh_lock); 334 - iter = netlbl_unlhsh_search_addr4(entry->addr, iface); 335 - if (iter != NULL && 336 - iter->addr == addr->s_addr && iter->mask == mask->s_addr) { 337 - spin_unlock(&netlbl_unlhsh_lock); 338 - kfree(entry); 339 - return -EEXIST; 340 - } 341 - /* in order to speed up address searches through the list (the common 342 - * case) we need to keep the list in order based on the size of the 343 - * address mask such that the entry with the widest mask (smallest 344 - * numerical value) appears first in the list */ 345 - list_for_each_entry_rcu(iter, &iface->addr4_list, list) 346 - if (iter->valid && 347 - ntohl(entry->mask) > ntohl(iter->mask)) { 348 - __list_add_rcu(&entry->list, 349 - iter->list.prev, 350 - &iter->list); 351 - spin_unlock(&netlbl_unlhsh_lock); 352 - return 0; 353 - } 354 - list_add_tail_rcu(&entry->list, &iface->addr4_list); 456 + ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list); 355 457 spin_unlock(&netlbl_unlhsh_lock); 356 - return 0; 458 + 459 + if (ret_val != 0) 460 + kfree(entry); 461 + return ret_val; 357 462 } 358 463 359 464 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ··· 359 498 const struct in6_addr *mask, 360 499 u32 secid) 361 500 { 501 + int ret_val; 362 502 struct netlbl_unlhsh_addr6 *entry; 363 - struct netlbl_unlhsh_addr6 *iter; 364 503 365 504 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 366 505 if (entry == NULL) 367 506 return -ENOMEM; 368 507 369 - ipv6_addr_copy(&entry->addr, addr); 370 - entry->addr.s6_addr32[0] &= mask->s6_addr32[0]; 371 - entry->addr.s6_addr32[1] &= mask->s6_addr32[1]; 372 - entry->addr.s6_addr32[2] &= mask->s6_addr32[2]; 373 - entry->addr.s6_addr32[3] &= mask->s6_addr32[3]; 374 - ipv6_addr_copy(&entry->mask, mask); 375 - entry->secid = secid; 376 - entry->valid = 1; 508 + ipv6_addr_copy(&entry->list.addr, addr); 509 + entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 510 + entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 511 + entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 512 + entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 513 + ipv6_addr_copy(&entry->list.mask, mask); 514 + entry->list.valid = 1; 377 515 INIT_RCU_HEAD(&entry->rcu); 516 + entry->secid = secid; 378 517 379 518 spin_lock(&netlbl_unlhsh_lock); 380 - iter = netlbl_unlhsh_search_addr6(&entry->addr, iface); 381 - if (iter != NULL && 382 - (ipv6_addr_equal(&iter->addr, addr) && 383 - ipv6_addr_equal(&iter->mask, mask))) { 384 - spin_unlock(&netlbl_unlhsh_lock); 385 - kfree(entry); 386 - return -EEXIST; 387 - } 388 - /* in order to speed up address searches through the list (the common 389 - * case) we need to keep the list in order based on the size of the 390 - * address mask such that the entry with the widest mask (smallest 391 - * numerical value) appears first in the list */ 392 - list_for_each_entry_rcu(iter, &iface->addr6_list, list) 393 - if (iter->valid && 394 - ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) { 395 - __list_add_rcu(&entry->list, 396 - iter->list.prev, 397 - &iter->list); 398 - spin_unlock(&netlbl_unlhsh_lock); 399 - return 0; 400 - } 401 - list_add_tail_rcu(&entry->list, &iface->addr6_list); 519 + ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list); 402 520 spin_unlock(&netlbl_unlhsh_lock); 521 + 522 + if (ret_val != 0) 523 + kfree(entry); 403 524 return 0; 404 525 } 405 526 #endif /* IPv6 */ ··· 501 658 mask4 = (struct in_addr *)mask; 502 659 ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); 503 660 if (audit_buf != NULL) 504 - netlbl_unlabel_audit_addr4(audit_buf, 505 - dev_name, 506 - addr4->s_addr, 507 - mask4->s_addr); 661 + netlbl_af4list_audit_addr(audit_buf, 1, 662 + dev_name, 663 + addr4->s_addr, 664 + mask4->s_addr); 508 665 break; 509 666 } 510 667 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ··· 515 672 mask6 = (struct in6_addr *)mask; 516 673 ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); 517 674 if (audit_buf != NULL) 518 - netlbl_unlabel_audit_addr6(audit_buf, 519 - dev_name, 520 - addr6, mask6); 675 + netlbl_af6list_audit_addr(audit_buf, 1, 676 + dev_name, 677 + addr6, mask6); 521 678 break; 522 679 } 523 680 #endif /* IPv6 */ ··· 562 719 const struct in_addr *mask, 563 720 struct netlbl_audit *audit_info) 564 721 { 565 - int ret_val = -ENOENT; 722 + int ret_val = 0; 723 + struct netlbl_af4list *list_entry; 566 724 struct netlbl_unlhsh_addr4 *entry; 567 - struct audit_buffer *audit_buf = NULL; 725 + struct audit_buffer *audit_buf; 568 726 struct net_device *dev; 569 - char *secctx = NULL; 727 + char *secctx; 570 728 u32 secctx_len; 571 729 572 730 spin_lock(&netlbl_unlhsh_lock); 573 - entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface); 574 - if (entry != NULL && 575 - entry->addr == addr->s_addr && entry->mask == mask->s_addr) { 576 - entry->valid = 0; 577 - list_del_rcu(&entry->list); 578 - ret_val = 0; 579 - } 731 + list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr, 732 + &iface->addr4_list); 580 733 spin_unlock(&netlbl_unlhsh_lock); 734 + if (list_entry == NULL) 735 + ret_val = -ENOENT; 736 + entry = netlbl_unlhsh_addr4_entry(list_entry); 581 737 582 738 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 583 739 audit_info); 584 740 if (audit_buf != NULL) { 585 741 dev = dev_get_by_index(net, iface->ifindex); 586 - netlbl_unlabel_audit_addr4(audit_buf, 587 - (dev != NULL ? dev->name : NULL), 588 - entry->addr, entry->mask); 742 + netlbl_af4list_audit_addr(audit_buf, 1, 743 + (dev != NULL ? dev->name : NULL), 744 + addr->s_addr, mask->s_addr); 589 745 if (dev != NULL) 590 746 dev_put(dev); 591 - if (security_secid_to_secctx(entry->secid, 592 - &secctx, 593 - &secctx_len) == 0) { 747 + if (entry && security_secid_to_secctx(entry->secid, 748 + &secctx, 749 + &secctx_len) == 0) { 594 750 audit_log_format(audit_buf, " sec_obj=%s", secctx); 595 751 security_release_secctx(secctx, secctx_len); 596 752 } ··· 623 781 const struct in6_addr *mask, 624 782 struct netlbl_audit *audit_info) 625 783 { 626 - int ret_val = -ENOENT; 784 + int ret_val = 0; 785 + struct netlbl_af6list *list_entry; 627 786 struct netlbl_unlhsh_addr6 *entry; 628 - struct audit_buffer *audit_buf = NULL; 787 + struct audit_buffer *audit_buf; 629 788 struct net_device *dev; 630 - char *secctx = NULL; 789 + char *secctx; 631 790 u32 secctx_len; 632 791 633 792 spin_lock(&netlbl_unlhsh_lock); 634 - entry = netlbl_unlhsh_search_addr6(addr, iface); 635 - if (entry != NULL && 636 - (ipv6_addr_equal(&entry->addr, addr) && 637 - ipv6_addr_equal(&entry->mask, mask))) { 638 - entry->valid = 0; 639 - list_del_rcu(&entry->list); 640 - ret_val = 0; 641 - } 793 + list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list); 642 794 spin_unlock(&netlbl_unlhsh_lock); 795 + if (list_entry == NULL) 796 + ret_val = -ENOENT; 797 + entry = netlbl_unlhsh_addr6_entry(list_entry); 643 798 644 799 audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL, 645 800 audit_info); 646 801 if (audit_buf != NULL) { 647 802 dev = dev_get_by_index(net, iface->ifindex); 648 - netlbl_unlabel_audit_addr6(audit_buf, 649 - (dev != NULL ? dev->name : NULL), 650 - addr, mask); 803 + netlbl_af6list_audit_addr(audit_buf, 1, 804 + (dev != NULL ? dev->name : NULL), 805 + addr, mask); 651 806 if (dev != NULL) 652 807 dev_put(dev); 653 - if (security_secid_to_secctx(entry->secid, 654 - &secctx, 655 - &secctx_len) == 0) { 808 + if (entry && security_secid_to_secctx(entry->secid, 809 + &secctx, 810 + &secctx_len) == 0) { 656 811 audit_log_format(audit_buf, " sec_obj=%s", secctx); 657 812 security_release_secctx(secctx, secctx_len); 658 813 } ··· 675 836 */ 676 837 static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface) 677 838 { 678 - struct netlbl_unlhsh_addr4 *iter4; 679 - struct netlbl_unlhsh_addr6 *iter6; 839 + struct netlbl_af4list *iter4; 840 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 841 + struct netlbl_af6list *iter6; 842 + #endif /* IPv6 */ 680 843 681 844 spin_lock(&netlbl_unlhsh_lock); 682 - list_for_each_entry_rcu(iter4, &iface->addr4_list, list) 683 - if (iter4->valid) 684 - goto unlhsh_condremove_failure; 685 - list_for_each_entry_rcu(iter6, &iface->addr6_list, list) 686 - if (iter6->valid) 687 - goto unlhsh_condremove_failure; 845 + netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list) 846 + goto unlhsh_condremove_failure; 847 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 848 + netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list) 849 + goto unlhsh_condremove_failure; 850 + #endif /* IPv6 */ 688 851 iface->valid = 0; 689 852 if (iface->ifindex > 0) 690 853 list_del_rcu(&iface->list); ··· 1190 1349 if (addr4) { 1191 1350 struct in_addr addr_struct; 1192 1351 1193 - addr_struct.s_addr = addr4->addr; 1352 + addr_struct.s_addr = addr4->list.addr; 1194 1353 ret_val = nla_put(cb_arg->skb, 1195 1354 NLBL_UNLABEL_A_IPV4ADDR, 1196 1355 sizeof(struct in_addr), ··· 1198 1357 if (ret_val != 0) 1199 1358 goto list_cb_failure; 1200 1359 1201 - addr_struct.s_addr = addr4->mask; 1360 + addr_struct.s_addr = addr4->list.mask; 1202 1361 ret_val = nla_put(cb_arg->skb, 1203 1362 NLBL_UNLABEL_A_IPV4MASK, 1204 1363 sizeof(struct in_addr), ··· 1211 1370 ret_val = nla_put(cb_arg->skb, 1212 1371 NLBL_UNLABEL_A_IPV6ADDR, 1213 1372 sizeof(struct in6_addr), 1214 - &addr6->addr); 1373 + &addr6->list.addr); 1215 1374 if (ret_val != 0) 1216 1375 goto list_cb_failure; 1217 1376 1218 1377 ret_val = nla_put(cb_arg->skb, 1219 1378 NLBL_UNLABEL_A_IPV6MASK, 1220 1379 sizeof(struct in6_addr), 1221 - &addr6->mask); 1380 + &addr6->list.mask); 1222 1381 if (ret_val != 0) 1223 1382 goto list_cb_failure; 1224 1383 ··· 1266 1425 u32 iter_bkt; 1267 1426 u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0; 1268 1427 struct netlbl_unlhsh_iface *iface; 1269 - struct netlbl_unlhsh_addr4 *addr4; 1270 - struct netlbl_unlhsh_addr6 *addr6; 1428 + struct list_head *iter_list; 1429 + struct netlbl_af4list *addr4; 1430 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1431 + struct netlbl_af6list *addr6; 1432 + #endif 1271 1433 1272 1434 cb_arg.nl_cb = cb; 1273 1435 cb_arg.skb = skb; ··· 1280 1436 for (iter_bkt = skip_bkt; 1281 1437 iter_bkt < rcu_dereference(netlbl_unlhsh)->size; 1282 1438 iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) { 1283 - list_for_each_entry_rcu(iface, 1284 - &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt], 1285 - list) { 1439 + iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt]; 1440 + list_for_each_entry_rcu(iface, iter_list, list) { 1286 1441 if (!iface->valid || 1287 1442 iter_chain++ < skip_chain) 1288 1443 continue; 1289 - list_for_each_entry_rcu(addr4, 1290 - &iface->addr4_list, 1291 - list) { 1292 - if (!addr4->valid || iter_addr4++ < skip_addr4) 1444 + netlbl_af4list_foreach_rcu(addr4, 1445 + &iface->addr4_list) { 1446 + if (iter_addr4++ < skip_addr4) 1293 1447 continue; 1294 1448 if (netlbl_unlabel_staticlist_gen( 1295 - NLBL_UNLABEL_C_STATICLIST, 1296 - iface, 1297 - addr4, 1298 - NULL, 1299 - &cb_arg) < 0) { 1449 + NLBL_UNLABEL_C_STATICLIST, 1450 + iface, 1451 + netlbl_unlhsh_addr4_entry(addr4), 1452 + NULL, 1453 + &cb_arg) < 0) { 1300 1454 iter_addr4--; 1301 1455 iter_chain--; 1302 1456 goto unlabel_staticlist_return; 1303 1457 } 1304 1458 } 1305 - list_for_each_entry_rcu(addr6, 1306 - &iface->addr6_list, 1307 - list) { 1308 - if (!addr6->valid || iter_addr6++ < skip_addr6) 1459 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1460 + netlbl_af6list_foreach_rcu(addr6, 1461 + &iface->addr6_list) { 1462 + if (iter_addr6++ < skip_addr6) 1309 1463 continue; 1310 1464 if (netlbl_unlabel_staticlist_gen( 1311 - NLBL_UNLABEL_C_STATICLIST, 1312 - iface, 1313 - NULL, 1314 - addr6, 1315 - &cb_arg) < 0) { 1465 + NLBL_UNLABEL_C_STATICLIST, 1466 + iface, 1467 + NULL, 1468 + netlbl_unlhsh_addr6_entry(addr6), 1469 + &cb_arg) < 0) { 1316 1470 iter_addr6--; 1317 1471 iter_chain--; 1318 1472 goto unlabel_staticlist_return; 1319 1473 } 1320 1474 } 1475 + #endif /* IPv6 */ 1321 1476 } 1322 1477 } 1323 1478 ··· 1347 1504 struct netlbl_unlhsh_iface *iface; 1348 1505 u32 skip_addr4 = cb->args[0]; 1349 1506 u32 skip_addr6 = cb->args[1]; 1350 - u32 iter_addr4 = 0, iter_addr6 = 0; 1351 - struct netlbl_unlhsh_addr4 *addr4; 1352 - struct netlbl_unlhsh_addr6 *addr6; 1507 + u32 iter_addr4 = 0; 1508 + struct netlbl_af4list *addr4; 1509 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1510 + u32 iter_addr6 = 0; 1511 + struct netlbl_af6list *addr6; 1512 + #endif 1353 1513 1354 1514 cb_arg.nl_cb = cb; 1355 1515 cb_arg.skb = skb; ··· 1363 1517 if (iface == NULL || !iface->valid) 1364 1518 goto unlabel_staticlistdef_return; 1365 1519 1366 - list_for_each_entry_rcu(addr4, &iface->addr4_list, list) { 1367 - if (!addr4->valid || iter_addr4++ < skip_addr4) 1520 + netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) { 1521 + if (iter_addr4++ < skip_addr4) 1368 1522 continue; 1369 1523 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 1370 - iface, 1371 - addr4, 1372 - NULL, 1373 - &cb_arg) < 0) { 1524 + iface, 1525 + netlbl_unlhsh_addr4_entry(addr4), 1526 + NULL, 1527 + &cb_arg) < 0) { 1374 1528 iter_addr4--; 1375 1529 goto unlabel_staticlistdef_return; 1376 1530 } 1377 1531 } 1378 - list_for_each_entry_rcu(addr6, &iface->addr6_list, list) { 1379 - if (!addr6->valid || iter_addr6++ < skip_addr6) 1532 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1533 + netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) { 1534 + if (iter_addr6++ < skip_addr6) 1380 1535 continue; 1381 1536 if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF, 1382 - iface, 1383 - NULL, 1384 - addr6, 1385 - &cb_arg) < 0) { 1537 + iface, 1538 + NULL, 1539 + netlbl_unlhsh_addr6_entry(addr6), 1540 + &cb_arg) < 0) { 1386 1541 iter_addr6--; 1387 1542 goto unlabel_staticlistdef_return; 1388 1543 } 1389 1544 } 1545 + #endif /* IPv6 */ 1390 1546 1391 1547 unlabel_staticlistdef_return: 1392 1548 rcu_read_unlock(); ··· 1566 1718 switch (family) { 1567 1719 case PF_INET: { 1568 1720 struct iphdr *hdr4; 1569 - struct netlbl_unlhsh_addr4 *addr4; 1721 + struct netlbl_af4list *addr4; 1570 1722 1571 1723 hdr4 = ip_hdr(skb); 1572 - addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); 1724 + addr4 = netlbl_af4list_search(hdr4->saddr, 1725 + &iface->addr4_list); 1573 1726 if (addr4 == NULL) 1574 1727 goto unlabel_getattr_nolabel; 1575 - secattr->attr.secid = addr4->secid; 1728 + secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid; 1576 1729 break; 1577 1730 } 1578 1731 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1579 1732 case PF_INET6: { 1580 1733 struct ipv6hdr *hdr6; 1581 - struct netlbl_unlhsh_addr6 *addr6; 1734 + struct netlbl_af6list *addr6; 1582 1735 1583 1736 hdr6 = ipv6_hdr(skb); 1584 - addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); 1737 + addr6 = netlbl_af6list_search(&hdr6->saddr, 1738 + &iface->addr6_list); 1585 1739 if (addr6 == NULL) 1586 1740 goto unlabel_getattr_nolabel; 1587 - secattr->attr.secid = addr6->secid; 1741 + secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid; 1588 1742 break; 1589 1743 } 1590 1744 #endif /* IPv6 */
+1 -2
security/inode.c
··· 20 20 #include <linux/init.h> 21 21 #include <linux/namei.h> 22 22 #include <linux/security.h> 23 - 24 - #define SECURITYFS_MAGIC 0x73636673 23 + #include <linux/magic.h> 25 24 26 25 static struct vfsmount *mount; 27 26 static int mount_count;
+169 -60
security/selinux/hooks.c
··· 291 291 struct sk_security_struct *ssec = sk->sk_security; 292 292 293 293 sk->sk_security = NULL; 294 + selinux_netlbl_sk_security_free(ssec); 294 295 kfree(ssec); 295 296 } 296 297 ··· 3801 3800 3802 3801 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) 3803 3802 { 3803 + struct sock *sk = sock->sk; 3804 3804 struct inode_security_struct *isec; 3805 3805 int err; 3806 3806 ··· 3815 3813 isec = SOCK_INODE(sock)->i_security; 3816 3814 if (isec->sclass == SECCLASS_TCP_SOCKET || 3817 3815 isec->sclass == SECCLASS_DCCP_SOCKET) { 3818 - struct sock *sk = sock->sk; 3819 3816 struct avc_audit_data ad; 3820 3817 struct sockaddr_in *addr4 = NULL; 3821 3818 struct sockaddr_in6 *addr6 = NULL; ··· 3847 3846 if (err) 3848 3847 goto out; 3849 3848 } 3849 + 3850 + err = selinux_netlbl_socket_connect(sk, address); 3850 3851 3851 3852 out: 3852 3853 return err; ··· 4079 4076 } 4080 4077 4081 4078 static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 4082 - struct avc_audit_data *ad, 4083 - u16 family, char *addrp) 4079 + u16 family) 4084 4080 { 4085 4081 int err; 4086 4082 struct sk_security_struct *sksec = sk->sk_security; 4087 4083 u32 peer_sid; 4088 4084 u32 sk_sid = sksec->sid; 4085 + struct avc_audit_data ad; 4086 + char *addrp; 4087 + 4088 + AVC_AUDIT_DATA_INIT(&ad, NET); 4089 + ad.u.net.netif = skb->iif; 4090 + ad.u.net.family = family; 4091 + err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 4092 + if (err) 4093 + return err; 4089 4094 4090 4095 if (selinux_compat_net) 4091 - err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, 4096 + err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, 4092 4097 family, addrp); 4093 4098 else 4094 4099 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, 4095 - PACKET__RECV, ad); 4100 + PACKET__RECV, &ad); 4096 4101 if (err) 4097 4102 return err; 4098 4103 ··· 4109 4098 if (err) 4110 4099 return err; 4111 4100 err = avc_has_perm(sk_sid, peer_sid, 4112 - SECCLASS_PEER, PEER__RECV, ad); 4101 + SECCLASS_PEER, PEER__RECV, &ad); 4102 + if (err) 4103 + selinux_netlbl_err(skb, err, 0); 4113 4104 } else { 4114 - err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); 4105 + err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); 4115 4106 if (err) 4116 4107 return err; 4117 - err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); 4108 + err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); 4118 4109 } 4119 4110 4120 4111 return err; ··· 4130 4117 u32 sk_sid = sksec->sid; 4131 4118 struct avc_audit_data ad; 4132 4119 char *addrp; 4120 + u8 secmark_active; 4121 + u8 peerlbl_active; 4133 4122 4134 4123 if (family != PF_INET && family != PF_INET6) 4135 4124 return 0; ··· 4140 4125 if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 4141 4126 family = PF_INET; 4142 4127 4128 + /* If any sort of compatibility mode is enabled then handoff processing 4129 + * to the selinux_sock_rcv_skb_compat() function to deal with the 4130 + * special handling. We do this in an attempt to keep this function 4131 + * as fast and as clean as possible. */ 4132 + if (selinux_compat_net || !selinux_policycap_netpeer) 4133 + return selinux_sock_rcv_skb_compat(sk, skb, family); 4134 + 4135 + secmark_active = selinux_secmark_enabled(); 4136 + peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); 4137 + if (!secmark_active && !peerlbl_active) 4138 + return 0; 4139 + 4143 4140 AVC_AUDIT_DATA_INIT(&ad, NET); 4144 4141 ad.u.net.netif = skb->iif; 4145 4142 ad.u.net.family = family; ··· 4159 4132 if (err) 4160 4133 return err; 4161 4134 4162 - /* If any sort of compatibility mode is enabled then handoff processing 4163 - * to the selinux_sock_rcv_skb_compat() function to deal with the 4164 - * special handling. We do this in an attempt to keep this function 4165 - * as fast and as clean as possible. */ 4166 - if (selinux_compat_net || !selinux_policycap_netpeer) 4167 - return selinux_sock_rcv_skb_compat(sk, skb, &ad, 4168 - family, addrp); 4169 - 4170 - if (netlbl_enabled() || selinux_xfrm_enabled()) { 4135 + if (peerlbl_active) { 4171 4136 u32 peer_sid; 4172 4137 4173 4138 err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); ··· 4167 4148 return err; 4168 4149 err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, 4169 4150 peer_sid, &ad); 4170 - if (err) 4151 + if (err) { 4152 + selinux_netlbl_err(skb, err, 0); 4171 4153 return err; 4154 + } 4172 4155 err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, 4173 4156 PEER__RECV, &ad); 4157 + if (err) 4158 + selinux_netlbl_err(skb, err, 0); 4174 4159 } 4175 4160 4176 - if (selinux_secmark_enabled()) { 4161 + if (secmark_active) { 4177 4162 err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, 4178 4163 PACKET__RECV, &ad); 4179 4164 if (err) ··· 4236 4213 u32 peer_secid = SECSID_NULL; 4237 4214 u16 family; 4238 4215 4239 - if (sock) 4216 + if (skb && skb->protocol == htons(ETH_P_IP)) 4217 + family = PF_INET; 4218 + else if (skb && skb->protocol == htons(ETH_P_IPV6)) 4219 + family = PF_INET6; 4220 + else if (sock) 4240 4221 family = sock->sk->sk_family; 4241 - else if (skb && skb->sk) 4242 - family = skb->sk->sk_family; 4243 4222 else 4244 4223 goto out; 4245 4224 ··· 4299 4274 sk->sk_family == PF_UNIX) 4300 4275 isec->sid = sksec->sid; 4301 4276 sksec->sclass = isec->sclass; 4302 - 4303 - selinux_netlbl_sock_graft(sk, parent); 4304 4277 } 4305 4278 4306 4279 static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, ··· 4306 4283 { 4307 4284 struct sk_security_struct *sksec = sk->sk_security; 4308 4285 int err; 4286 + u16 family = sk->sk_family; 4309 4287 u32 newsid; 4310 4288 u32 peersid; 4311 4289 4312 - err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); 4290 + /* handle mapped IPv4 packets arriving via IPv6 sockets */ 4291 + if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 4292 + family = PF_INET; 4293 + 4294 + err = selinux_skb_peerlbl_sid(skb, family, &peersid); 4313 4295 if (err) 4314 4296 return err; 4315 4297 if (peersid == SECSID_NULL) { ··· 4349 4321 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); 4350 4322 } 4351 4323 4352 - static void selinux_inet_conn_established(struct sock *sk, 4353 - struct sk_buff *skb) 4324 + static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 4354 4325 { 4326 + u16 family = sk->sk_family; 4355 4327 struct sk_security_struct *sksec = sk->sk_security; 4356 4328 4357 - selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); 4329 + /* handle mapped IPv4 packets arriving via IPv6 sockets */ 4330 + if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 4331 + family = PF_INET; 4332 + 4333 + selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 4334 + 4335 + selinux_netlbl_inet_conn_established(sk, family); 4358 4336 } 4359 4337 4360 4338 static void selinux_req_classify_flow(const struct request_sock *req, ··· 4410 4376 static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, 4411 4377 u16 family) 4412 4378 { 4379 + int err; 4413 4380 char *addrp; 4414 4381 u32 peer_sid; 4415 4382 struct avc_audit_data ad; 4416 4383 u8 secmark_active; 4384 + u8 netlbl_active; 4417 4385 u8 peerlbl_active; 4418 4386 4419 4387 if (!selinux_policycap_netpeer) 4420 4388 return NF_ACCEPT; 4421 4389 4422 4390 secmark_active = selinux_secmark_enabled(); 4423 - peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); 4391 + netlbl_active = netlbl_enabled(); 4392 + peerlbl_active = netlbl_active || selinux_xfrm_enabled(); 4424 4393 if (!secmark_active && !peerlbl_active) 4425 4394 return NF_ACCEPT; 4395 + 4396 + if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) 4397 + return NF_DROP; 4426 4398 4427 4399 AVC_AUDIT_DATA_INIT(&ad, NET); 4428 4400 ad.u.net.netif = ifindex; ··· 4436 4396 if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) 4437 4397 return NF_DROP; 4438 4398 4439 - if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) 4440 - return NF_DROP; 4441 - 4442 - if (peerlbl_active) 4443 - if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, 4444 - peer_sid, &ad) != 0) 4399 + if (peerlbl_active) { 4400 + err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, 4401 + peer_sid, &ad); 4402 + if (err) { 4403 + selinux_netlbl_err(skb, err, 1); 4445 4404 return NF_DROP; 4405 + } 4406 + } 4446 4407 4447 4408 if (secmark_active) 4448 4409 if (avc_has_perm(peer_sid, skb->secmark, 4449 4410 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) 4411 + return NF_DROP; 4412 + 4413 + if (netlbl_active) 4414 + /* we do this in the FORWARD path and not the POST_ROUTING 4415 + * path because we want to make sure we apply the necessary 4416 + * labeling before IPsec is applied so we can leverage AH 4417 + * protection */ 4418 + if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) 4450 4419 return NF_DROP; 4451 4420 4452 4421 return NF_ACCEPT; ··· 4480 4431 return selinux_ip_forward(skb, in->ifindex, PF_INET6); 4481 4432 } 4482 4433 #endif /* IPV6 */ 4434 + 4435 + static unsigned int selinux_ip_output(struct sk_buff *skb, 4436 + u16 family) 4437 + { 4438 + u32 sid; 4439 + 4440 + if (!netlbl_enabled()) 4441 + return NF_ACCEPT; 4442 + 4443 + /* we do this in the LOCAL_OUT path and not the POST_ROUTING path 4444 + * because we want to make sure we apply the necessary labeling 4445 + * before IPsec is applied so we can leverage AH protection */ 4446 + if (skb->sk) { 4447 + struct sk_security_struct *sksec = skb->sk->sk_security; 4448 + sid = sksec->sid; 4449 + } else 4450 + sid = SECINITSID_KERNEL; 4451 + if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) 4452 + return NF_DROP; 4453 + 4454 + return NF_ACCEPT; 4455 + } 4456 + 4457 + static unsigned int selinux_ipv4_output(unsigned int hooknum, 4458 + struct sk_buff *skb, 4459 + const struct net_device *in, 4460 + const struct net_device *out, 4461 + int (*okfn)(struct sk_buff *)) 4462 + { 4463 + return selinux_ip_output(skb, PF_INET); 4464 + } 4483 4465 4484 4466 static int selinux_ip_postroute_iptables_compat(struct sock *sk, 4485 4467 int ifindex, ··· 4579 4499 4580 4500 static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, 4581 4501 int ifindex, 4582 - struct avc_audit_data *ad, 4583 - u16 family, 4584 - char *addrp, 4585 - u8 proto) 4502 + u16 family) 4586 4503 { 4587 4504 struct sock *sk = skb->sk; 4588 4505 struct sk_security_struct *sksec; 4506 + struct avc_audit_data ad; 4507 + char *addrp; 4508 + u8 proto; 4589 4509 4590 4510 if (sk == NULL) 4591 4511 return NF_ACCEPT; 4592 4512 sksec = sk->sk_security; 4593 4513 4514 + AVC_AUDIT_DATA_INIT(&ad, NET); 4515 + ad.u.net.netif = ifindex; 4516 + ad.u.net.family = family; 4517 + if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) 4518 + return NF_DROP; 4519 + 4594 4520 if (selinux_compat_net) { 4595 4521 if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, 4596 - ad, family, addrp)) 4522 + &ad, family, addrp)) 4597 4523 return NF_DROP; 4598 4524 } else { 4599 4525 if (avc_has_perm(sksec->sid, skb->secmark, 4600 - SECCLASS_PACKET, PACKET__SEND, ad)) 4526 + SECCLASS_PACKET, PACKET__SEND, &ad)) 4601 4527 return NF_DROP; 4602 4528 } 4603 4529 4604 4530 if (selinux_policycap_netpeer) 4605 - if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) 4531 + if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) 4606 4532 return NF_DROP; 4607 4533 4608 4534 return NF_ACCEPT; ··· 4622 4536 struct sock *sk; 4623 4537 struct avc_audit_data ad; 4624 4538 char *addrp; 4625 - u8 proto; 4626 4539 u8 secmark_active; 4627 4540 u8 peerlbl_active; 4628 - 4629 - AVC_AUDIT_DATA_INIT(&ad, NET); 4630 - ad.u.net.netif = ifindex; 4631 - ad.u.net.family = family; 4632 - if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) 4633 - return NF_DROP; 4634 4541 4635 4542 /* If any sort of compatibility mode is enabled then handoff processing 4636 4543 * to the selinux_ip_postroute_compat() function to deal with the 4637 4544 * special handling. We do this in an attempt to keep this function 4638 4545 * as fast and as clean as possible. */ 4639 4546 if (selinux_compat_net || !selinux_policycap_netpeer) 4640 - return selinux_ip_postroute_compat(skb, ifindex, &ad, 4641 - family, addrp, proto); 4547 + return selinux_ip_postroute_compat(skb, ifindex, family); 4642 4548 4643 4549 /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec 4644 4550 * packet transformation so allow the packet to pass without any checks ··· 4646 4568 if (!secmark_active && !peerlbl_active) 4647 4569 return NF_ACCEPT; 4648 4570 4649 - /* if the packet is locally generated (skb->sk != NULL) then use the 4650 - * socket's label as the peer label, otherwise the packet is being 4651 - * forwarded through this system and we need to fetch the peer label 4652 - * directly from the packet */ 4571 + /* if the packet is being forwarded then get the peer label from the 4572 + * packet itself; otherwise check to see if it is from a local 4573 + * application or the kernel, if from an application get the peer label 4574 + * from the sending socket, otherwise use the kernel's sid */ 4653 4575 sk = skb->sk; 4654 - if (sk) { 4576 + if (sk == NULL) { 4577 + switch (family) { 4578 + case PF_INET: 4579 + if (IPCB(skb)->flags & IPSKB_FORWARDED) 4580 + secmark_perm = PACKET__FORWARD_OUT; 4581 + else 4582 + secmark_perm = PACKET__SEND; 4583 + break; 4584 + case PF_INET6: 4585 + if (IP6CB(skb)->flags & IP6SKB_FORWARDED) 4586 + secmark_perm = PACKET__FORWARD_OUT; 4587 + else 4588 + secmark_perm = PACKET__SEND; 4589 + break; 4590 + default: 4591 + return NF_DROP; 4592 + } 4593 + if (secmark_perm == PACKET__FORWARD_OUT) { 4594 + if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 4595 + return NF_DROP; 4596 + } else 4597 + peer_sid = SECINITSID_KERNEL; 4598 + } else { 4655 4599 struct sk_security_struct *sksec = sk->sk_security; 4656 4600 peer_sid = sksec->sid; 4657 4601 secmark_perm = PACKET__SEND; 4658 - } else { 4659 - if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 4660 - return NF_DROP; 4661 - secmark_perm = PACKET__FORWARD_OUT; 4662 4602 } 4603 + 4604 + AVC_AUDIT_DATA_INIT(&ad, NET); 4605 + ad.u.net.netif = ifindex; 4606 + ad.u.net.family = family; 4607 + if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) 4608 + return NF_DROP; 4663 4609 4664 4610 if (secmark_active) 4665 4611 if (avc_has_perm(peer_sid, skb->secmark, ··· 5757 5655 .owner = THIS_MODULE, 5758 5656 .pf = PF_INET, 5759 5657 .hooknum = NF_INET_FORWARD, 5658 + .priority = NF_IP_PRI_SELINUX_FIRST, 5659 + }, 5660 + { 5661 + .hook = selinux_ipv4_output, 5662 + .owner = THIS_MODULE, 5663 + .pf = PF_INET, 5664 + .hooknum = NF_INET_LOCAL_OUT, 5760 5665 .priority = NF_IP_PRI_SELINUX_FIRST, 5761 5666 } 5762 5667 };
+41 -3
security/selinux/include/netlabel.h
··· 39 39 #ifdef CONFIG_NETLABEL 40 40 void selinux_netlbl_cache_invalidate(void); 41 41 42 + void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); 43 + 44 + void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); 42 45 void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec, 43 46 int family); 44 47 ··· 49 46 u16 family, 50 47 u32 *type, 51 48 u32 *sid); 49 + int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 50 + u16 family, 51 + u32 sid); 52 52 53 - void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); 53 + void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family); 54 54 int selinux_netlbl_socket_post_create(struct socket *sock); 55 55 int selinux_netlbl_inode_permission(struct inode *inode, int mask); 56 56 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, ··· 63 57 int selinux_netlbl_socket_setsockopt(struct socket *sock, 64 58 int level, 65 59 int optname); 60 + int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); 61 + 66 62 #else 67 63 static inline void selinux_netlbl_cache_invalidate(void) 64 + { 65 + return; 66 + } 67 + 68 + static inline void selinux_netlbl_err(struct sk_buff *skb, 69 + int error, 70 + int gateway) 71 + { 72 + return; 73 + } 74 + 75 + static inline void selinux_netlbl_sk_security_free( 76 + struct sk_security_struct *ssec) 68 77 { 69 78 return; 70 79 } ··· 100 79 *sid = SECSID_NULL; 101 80 return 0; 102 81 } 82 + static inline int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 83 + u16 family, 84 + u32 sid) 85 + { 86 + return 0; 87 + } 103 88 104 - static inline void selinux_netlbl_sock_graft(struct sock *sk, 105 - struct socket *sock) 89 + static inline int selinux_netlbl_conn_setsid(struct sock *sk, 90 + struct sockaddr *addr) 91 + { 92 + return 0; 93 + } 94 + 95 + static inline void selinux_netlbl_inet_conn_established(struct sock *sk, 96 + u16 family) 106 97 { 107 98 return; 108 99 } ··· 137 104 static inline int selinux_netlbl_socket_setsockopt(struct socket *sock, 138 105 int level, 139 106 int optname) 107 + { 108 + return 0; 109 + } 110 + static inline int selinux_netlbl_socket_connect(struct sock *sk, 111 + struct sockaddr *addr) 140 112 { 141 113 return 0; 142 114 }
+6 -3
security/selinux/include/objsec.h
··· 109 109 }; 110 110 111 111 struct sk_security_struct { 112 - u32 sid; /* SID of this object */ 113 - u32 peer_sid; /* SID of peer */ 114 - u16 sclass; /* sock security class */ 115 112 #ifdef CONFIG_NETLABEL 116 113 enum { /* NetLabel state */ 117 114 NLBL_UNSET = 0, 118 115 NLBL_REQUIRE, 119 116 NLBL_LABELED, 117 + NLBL_REQSKB, 118 + NLBL_CONNLABELED, 120 119 } nlbl_state; 120 + struct netlbl_lsm_secattr *nlbl_secattr; /* NetLabel sec attributes */ 121 121 #endif 122 + u32 sid; /* SID of this object */ 123 + u32 peer_sid; /* SID of peer */ 124 + u16 sclass; /* sock security class */ 122 125 }; 123 126 124 127 struct key_security_struct {
+243 -45
security/selinux/netlabel.c
··· 9 9 */ 10 10 11 11 /* 12 - * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 12 + * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 13 13 * 14 14 * This program is free software; you can redistribute it and/or modify 15 15 * it under the terms of the GNU General Public License as published by ··· 29 29 30 30 #include <linux/spinlock.h> 31 31 #include <linux/rcupdate.h> 32 + #include <linux/ip.h> 33 + #include <linux/ipv6.h> 32 34 #include <net/sock.h> 33 35 #include <net/netlabel.h> 36 + #include <net/ip.h> 37 + #include <net/ipv6.h> 34 38 35 39 #include "objsec.h" 36 40 #include "security.h" ··· 68 64 } 69 65 70 66 /** 71 - * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism 72 - * @sk: the socket to label 73 - * @sid: the SID to use 67 + * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr 68 + * @sk: the socket 74 69 * 75 70 * Description: 76 - * Attempt to label a socket using the NetLabel mechanism using the given 77 - * SID. Returns zero values on success, negative values on failure. 71 + * Generate the NetLabel security attributes for a socket, making full use of 72 + * the socket's attribute cache. Returns a pointer to the security attributes 73 + * on success, NULL on failure. 78 74 * 79 75 */ 80 - static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid) 76 + static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) 81 77 { 82 78 int rc; 83 79 struct sk_security_struct *sksec = sk->sk_security; 84 - struct netlbl_lsm_secattr secattr; 80 + struct netlbl_lsm_secattr *secattr; 85 81 86 - netlbl_secattr_init(&secattr); 82 + if (sksec->nlbl_secattr != NULL) 83 + return sksec->nlbl_secattr; 87 84 88 - rc = security_netlbl_sid_to_secattr(sid, &secattr); 89 - if (rc != 0) 90 - goto sock_setsid_return; 91 - rc = netlbl_sock_setattr(sk, &secattr); 92 - if (rc == 0) 85 + secattr = netlbl_secattr_alloc(GFP_ATOMIC); 86 + if (secattr == NULL) 87 + return NULL; 88 + rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); 89 + if (rc != 0) { 90 + netlbl_secattr_free(secattr); 91 + return NULL; 92 + } 93 + sksec->nlbl_secattr = secattr; 94 + 95 + return secattr; 96 + } 97 + 98 + /** 99 + * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism 100 + * @sk: the socket to label 101 + * 102 + * Description: 103 + * Attempt to label a socket using the NetLabel mechanism. Returns zero values 104 + * on success, negative values on failure. 105 + * 106 + */ 107 + static int selinux_netlbl_sock_setsid(struct sock *sk) 108 + { 109 + int rc; 110 + struct sk_security_struct *sksec = sk->sk_security; 111 + struct netlbl_lsm_secattr *secattr; 112 + 113 + if (sksec->nlbl_state != NLBL_REQUIRE) 114 + return 0; 115 + 116 + secattr = selinux_netlbl_sock_genattr(sk); 117 + if (secattr == NULL) 118 + return -ENOMEM; 119 + rc = netlbl_sock_setattr(sk, secattr); 120 + switch (rc) { 121 + case 0: 93 122 sksec->nlbl_state = NLBL_LABELED; 123 + break; 124 + case -EDESTADDRREQ: 125 + sksec->nlbl_state = NLBL_REQSKB; 126 + rc = 0; 127 + break; 128 + } 94 129 95 - sock_setsid_return: 96 - netlbl_secattr_destroy(&secattr); 97 130 return rc; 98 131 } 99 132 ··· 144 103 void selinux_netlbl_cache_invalidate(void) 145 104 { 146 105 netlbl_cache_invalidate(); 106 + } 107 + 108 + /** 109 + * selinux_netlbl_err - Handle a NetLabel packet error 110 + * @skb: the packet 111 + * @error: the error code 112 + * @gateway: true if host is acting as a gateway, false otherwise 113 + * 114 + * Description: 115 + * When a packet is dropped due to a call to avc_has_perm() pass the error 116 + * code to the NetLabel subsystem so any protocol specific processing can be 117 + * done. This is safe to call even if you are unsure if NetLabel labeling is 118 + * present on the packet, NetLabel is smart enough to only act when it should. 119 + * 120 + */ 121 + void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) 122 + { 123 + netlbl_skbuff_err(skb, error, gateway); 124 + } 125 + 126 + /** 127 + * selinux_netlbl_sk_security_free - Free the NetLabel fields 128 + * @sssec: the sk_security_struct 129 + * 130 + * Description: 131 + * Free all of the memory in the NetLabel fields of a sk_security_struct. 132 + * 133 + */ 134 + void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) 135 + { 136 + if (ssec->nlbl_secattr != NULL) 137 + netlbl_secattr_free(ssec->nlbl_secattr); 147 138 } 148 139 149 140 /** ··· 236 163 } 237 164 238 165 /** 239 - * selinux_netlbl_sock_graft - Netlabel the new socket 240 - * @sk: the new connection 241 - * @sock: the new socket 166 + * selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid 167 + * @skb: the packet 168 + * @family: protocol family 169 + * @sid: the SID 242 170 * 243 - * Description: 244 - * The connection represented by @sk is being grafted onto @sock so set the 245 - * socket's NetLabel to match the SID of @sk. 171 + * Description 172 + * Call the NetLabel mechanism to set the label of a packet using @sid. 173 + * Returns zero on auccess, negative values on failure. 246 174 * 247 175 */ 248 - void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) 176 + int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, 177 + u16 family, 178 + u32 sid) 249 179 { 180 + int rc; 181 + struct netlbl_lsm_secattr secattr_storage; 182 + struct netlbl_lsm_secattr *secattr = NULL; 183 + struct sock *sk; 184 + 185 + /* if this is a locally generated packet check to see if it is already 186 + * being labeled by it's parent socket, if it is just exit */ 187 + sk = skb->sk; 188 + if (sk != NULL) { 189 + struct sk_security_struct *sksec = sk->sk_security; 190 + if (sksec->nlbl_state != NLBL_REQSKB) 191 + return 0; 192 + secattr = sksec->nlbl_secattr; 193 + } 194 + if (secattr == NULL) { 195 + secattr = &secattr_storage; 196 + netlbl_secattr_init(secattr); 197 + rc = security_netlbl_sid_to_secattr(sid, secattr); 198 + if (rc != 0) 199 + goto skbuff_setsid_return; 200 + } 201 + 202 + rc = netlbl_skbuff_setattr(skb, family, secattr); 203 + 204 + skbuff_setsid_return: 205 + if (secattr == &secattr_storage) 206 + netlbl_secattr_destroy(secattr); 207 + return rc; 208 + } 209 + 210 + /** 211 + * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection 212 + * @sk: the new connection 213 + * 214 + * Description: 215 + * A new connection has been established on @sk so make sure it is labeled 216 + * correctly with the NetLabel susbsystem. 217 + * 218 + */ 219 + void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family) 220 + { 221 + int rc; 250 222 struct sk_security_struct *sksec = sk->sk_security; 251 - struct netlbl_lsm_secattr secattr; 252 - u32 nlbl_peer_sid; 223 + struct netlbl_lsm_secattr *secattr; 224 + struct inet_sock *sk_inet = inet_sk(sk); 225 + struct sockaddr_in addr; 253 226 254 227 if (sksec->nlbl_state != NLBL_REQUIRE) 255 228 return; 256 229 257 - netlbl_secattr_init(&secattr); 258 - if (netlbl_sock_getattr(sk, &secattr) == 0 && 259 - secattr.flags != NETLBL_SECATTR_NONE && 260 - security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0) 261 - sksec->peer_sid = nlbl_peer_sid; 262 - netlbl_secattr_destroy(&secattr); 230 + secattr = selinux_netlbl_sock_genattr(sk); 231 + if (secattr == NULL) 232 + return; 263 233 264 - /* Try to set the NetLabel on the socket to save time later, if we fail 265 - * here we will pick up the pieces in later calls to 266 - * selinux_netlbl_inode_permission(). */ 267 - selinux_netlbl_sock_setsid(sk, sksec->sid); 234 + rc = netlbl_sock_setattr(sk, secattr); 235 + switch (rc) { 236 + case 0: 237 + sksec->nlbl_state = NLBL_LABELED; 238 + break; 239 + case -EDESTADDRREQ: 240 + /* no PF_INET6 support yet because we don't support any IPv6 241 + * labeling protocols */ 242 + if (family != PF_INET) { 243 + sksec->nlbl_state = NLBL_UNSET; 244 + return; 245 + } 246 + 247 + addr.sin_family = family; 248 + addr.sin_addr.s_addr = sk_inet->daddr; 249 + if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, 250 + secattr) != 0) { 251 + /* we failed to label the connected socket (could be 252 + * for a variety of reasons, the actual "why" isn't 253 + * important here) so we have to go to our backup plan, 254 + * labeling the packets individually in the netfilter 255 + * local output hook. this is okay but we need to 256 + * adjust the MSS of the connection to take into 257 + * account any labeling overhead, since we don't know 258 + * the exact overhead at this point we'll use the worst 259 + * case value which is 40 bytes for IPv4 */ 260 + struct inet_connection_sock *sk_conn = inet_csk(sk); 261 + sk_conn->icsk_ext_hdr_len += 40 - 262 + (sk_inet->opt ? sk_inet->opt->optlen : 0); 263 + sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); 264 + 265 + sksec->nlbl_state = NLBL_REQSKB; 266 + } else 267 + sksec->nlbl_state = NLBL_CONNLABELED; 268 + break; 269 + default: 270 + /* note that we are failing to label the socket which could be 271 + * a bad thing since it means traffic could leave the system 272 + * without the desired labeling, however, all is not lost as 273 + * we have a check in selinux_netlbl_inode_permission() to 274 + * pick up the pieces that we might drop here because we can't 275 + * return an error code */ 276 + break; 277 + } 268 278 } 269 279 270 280 /** ··· 361 205 */ 362 206 int selinux_netlbl_socket_post_create(struct socket *sock) 363 207 { 364 - struct sock *sk = sock->sk; 365 - struct sk_security_struct *sksec = sk->sk_security; 366 - 367 - if (sksec->nlbl_state != NLBL_REQUIRE) 368 - return 0; 369 - 370 - return selinux_netlbl_sock_setsid(sk, sksec->sid); 208 + return selinux_netlbl_sock_setsid(sock->sk); 371 209 } 372 210 373 211 /** ··· 396 246 local_bh_disable(); 397 247 bh_lock_sock_nested(sk); 398 248 if (likely(sksec->nlbl_state == NLBL_REQUIRE)) 399 - rc = selinux_netlbl_sock_setsid(sk, sksec->sid); 249 + rc = selinux_netlbl_sock_setsid(sk); 400 250 else 401 251 rc = 0; 402 252 bh_unlock_sock(sk); ··· 457 307 return 0; 458 308 459 309 if (nlbl_sid != SECINITSID_UNLABELED) 460 - netlbl_skbuff_err(skb, rc); 310 + netlbl_skbuff_err(skb, rc, 0); 461 311 return rc; 462 312 } 463 313 ··· 484 334 struct netlbl_lsm_secattr secattr; 485 335 486 336 if (level == IPPROTO_IP && optname == IP_OPTIONS && 487 - sksec->nlbl_state == NLBL_LABELED) { 337 + (sksec->nlbl_state == NLBL_LABELED || 338 + sksec->nlbl_state == NLBL_CONNLABELED)) { 488 339 netlbl_secattr_init(&secattr); 489 340 lock_sock(sk); 490 341 rc = netlbl_sock_getattr(sk, &secattr); ··· 495 344 netlbl_secattr_destroy(&secattr); 496 345 } 497 346 347 + return rc; 348 + } 349 + 350 + /** 351 + * selinux_netlbl_socket_connect - Label a client-side socket on connect 352 + * @sk: the socket to label 353 + * @addr: the destination address 354 + * 355 + * Description: 356 + * Attempt to label a connected socket with NetLabel using the given address. 357 + * Returns zero values on success, negative values on failure. 358 + * 359 + */ 360 + int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) 361 + { 362 + int rc; 363 + struct sk_security_struct *sksec = sk->sk_security; 364 + struct netlbl_lsm_secattr *secattr; 365 + 366 + if (sksec->nlbl_state != NLBL_REQSKB && 367 + sksec->nlbl_state != NLBL_CONNLABELED) 368 + return 0; 369 + 370 + local_bh_disable(); 371 + bh_lock_sock_nested(sk); 372 + 373 + /* connected sockets are allowed to disconnect when the address family 374 + * is set to AF_UNSPEC, if that is what is happening we want to reset 375 + * the socket */ 376 + if (addr->sa_family == AF_UNSPEC) { 377 + netlbl_sock_delattr(sk); 378 + sksec->nlbl_state = NLBL_REQSKB; 379 + rc = 0; 380 + goto socket_connect_return; 381 + } 382 + secattr = selinux_netlbl_sock_genattr(sk); 383 + if (secattr == NULL) { 384 + rc = -ENOMEM; 385 + goto socket_connect_return; 386 + } 387 + rc = netlbl_conn_setattr(sk, addr, secattr); 388 + if (rc == 0) 389 + sksec->nlbl_state = NLBL_CONNLABELED; 390 + 391 + socket_connect_return: 392 + bh_unlock_sock(sk); 393 + local_bh_enable(); 498 394 return rc; 499 395 }
+10 -3
security/selinux/ss/services.c
··· 2955 2955 */ 2956 2956 int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) 2957 2957 { 2958 - int rc = -ENOENT; 2958 + int rc; 2959 2959 struct context *ctx; 2960 2960 2961 2961 if (!ss_initialized) ··· 2963 2963 2964 2964 read_lock(&policy_rwlock); 2965 2965 ctx = sidtab_search(&sidtab, sid); 2966 - if (ctx == NULL) 2966 + if (ctx == NULL) { 2967 + rc = -ENOENT; 2967 2968 goto netlbl_sid_to_secattr_failure; 2969 + } 2968 2970 secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], 2969 2971 GFP_ATOMIC); 2970 - secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; 2972 + if (secattr->domain == NULL) { 2973 + rc = -ENOMEM; 2974 + goto netlbl_sid_to_secattr_failure; 2975 + } 2976 + secattr->attr.secid = sid; 2977 + secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 2971 2978 mls_export_netlbl_lvl(ctx, secattr); 2972 2979 rc = mls_export_netlbl_cat(ctx, secattr); 2973 2980 if (rc != 0)
+4 -1
security/smack/smack_lsm.c
··· 2179 2179 * This is the simplist possible security model 2180 2180 * for networking. 2181 2181 */ 2182 - return smk_access(smack, ssp->smk_in, MAY_WRITE); 2182 + rc = smk_access(smack, ssp->smk_in, MAY_WRITE); 2183 + if (rc != 0) 2184 + netlbl_skbuff_err(skb, rc, 0); 2185 + return rc; 2183 2186 } 2184 2187 2185 2188 /**
+3 -1
security/smack/smackfs.c
··· 354 354 doip->tags[rc] = CIPSO_V4_TAG_INVALID; 355 355 356 356 rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); 357 - if (rc != 0) 357 + if (rc != 0) { 358 358 printk(KERN_WARNING "%s:%d add rc = %d\n", 359 359 __func__, __LINE__, rc); 360 + kfree(doip); 361 + } 360 362 } 361 363 362 364 /**