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