diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 70858dccaca2..60aafb4a8adf 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -455,6 +455,10 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | |||
455 | switch (doi_def->tags[iter]) { | 455 | switch (doi_def->tags[iter]) { |
456 | case CIPSO_V4_TAG_RBITMAP: | 456 | case CIPSO_V4_TAG_RBITMAP: |
457 | break; | 457 | break; |
458 | case CIPSO_V4_TAG_RANGE: | ||
459 | if (doi_def->type != CIPSO_V4_MAP_PASS) | ||
460 | return -EINVAL; | ||
461 | break; | ||
458 | case CIPSO_V4_TAG_INVALID: | 462 | case CIPSO_V4_TAG_INVALID: |
459 | if (iter == 0) | 463 | if (iter == 0) |
460 | return -EINVAL; | 464 | return -EINVAL; |
@@ -1045,6 +1049,148 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, | |||
1045 | return 0; | 1049 | return 0; |
1046 | } | 1050 | } |
1047 | 1051 | ||
1052 | /** | ||
1053 | * cipso_v4_map_cat_rng_valid - Checks to see if the categories are valid | ||
1054 | * @doi_def: the DOI definition | ||
1055 | * @rngcat: category list | ||
1056 | * @rngcat_len: length of the category list in bytes | ||
1057 | * | ||
1058 | * Description: | ||
1059 | * Checks the given categories against the given DOI definition and returns a | ||
1060 | * negative value if any of the categories do not have a valid mapping and a | ||
1061 | * zero value if all of the categories are valid. | ||
1062 | * | ||
1063 | */ | ||
1064 | static int cipso_v4_map_cat_rng_valid(const struct cipso_v4_doi *doi_def, | ||
1065 | const unsigned char *rngcat, | ||
1066 | u32 rngcat_len) | ||
1067 | { | ||
1068 | u16 cat_high; | ||
1069 | u16 cat_low; | ||
1070 | u32 cat_prev = CIPSO_V4_MAX_REM_CATS + 1; | ||
1071 | u32 iter; | ||
1072 | |||
1073 | if (doi_def->type != CIPSO_V4_MAP_PASS || rngcat_len & 0x01) | ||
1074 | return -EFAULT; | ||
1075 | |||
1076 | for (iter = 0; iter < rngcat_len; iter += 4) { | ||
1077 | cat_high = ntohs(*((__be16 *)&rngcat[iter])); | ||
1078 | if ((iter + 4) <= rngcat_len) | ||
1079 | cat_low = ntohs(*((__be16 *)&rngcat[iter + 2])); | ||
1080 | else | ||
1081 | cat_low = 0; | ||
1082 | |||
1083 | if (cat_high > cat_prev) | ||
1084 | return -EFAULT; | ||
1085 | |||
1086 | cat_prev = cat_low; | ||
1087 | } | ||
1088 | |||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | /** | ||
1093 | * cipso_v4_map_cat_rng_hton - Perform a category mapping from host to network | ||
1094 | * @doi_def: the DOI definition | ||
1095 | * @secattr: the security attributes | ||
1096 | * @net_cat: the zero'd out category list in network/CIPSO format | ||
1097 | * @net_cat_len: the length of the CIPSO category list in bytes | ||
1098 | * | ||
1099 | * Description: | ||
1100 | * Perform a label mapping to translate a local MLS category bitmap to the | ||
1101 | * correct CIPSO category list using the given DOI definition. Returns the | ||
1102 | * size in bytes of the network category bitmap on success, negative values | ||
1103 | * otherwise. | ||
1104 | * | ||
1105 | */ | ||
1106 | static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, | ||
1107 | const struct netlbl_lsm_secattr *secattr, | ||
1108 | unsigned char *net_cat, | ||
1109 | u32 net_cat_len) | ||
1110 | { | ||
1111 | /* The constant '16' is not random, it is the maximum number of | ||
1112 | * high/low category range pairs as permitted by the CIPSO draft based | ||
1113 | * on a maximum IPv4 header length of 60 bytes - the BUG_ON() assertion | ||
1114 | * does a sanity check to make sure we don't overflow the array. */ | ||
1115 | int iter = -1; | ||
1116 | u16 array[16]; | ||
1117 | u32 array_cnt = 0; | ||
1118 | u32 cat_size = 0; | ||
1119 | |||
1120 | BUG_ON(net_cat_len > 30); | ||
1121 | |||
1122 | for (;;) { | ||
1123 | iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); | ||
1124 | if (iter < 0) | ||
1125 | break; | ||
1126 | cat_size += (iter == 0 ? 0 : sizeof(u16)); | ||
1127 | if (cat_size > net_cat_len) | ||
1128 | return -ENOSPC; | ||
1129 | array[array_cnt++] = iter; | ||
1130 | |||
1131 | iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); | ||
1132 | if (iter < 0) | ||
1133 | return -EFAULT; | ||
1134 | cat_size += sizeof(u16); | ||
1135 | if (cat_size > net_cat_len) | ||
1136 | return -ENOSPC; | ||
1137 | array[array_cnt++] = iter; | ||
1138 | } | ||
1139 | |||
1140 | for (iter = 0; array_cnt > 0;) { | ||
1141 | *((__be16 *)&net_cat[iter]) = htons(array[--array_cnt]); | ||
1142 | iter += 2; | ||
1143 | array_cnt--; | ||
1144 | if (array[array_cnt] != 0) { | ||
1145 | *((__be16 *)&net_cat[iter]) = htons(array[array_cnt]); | ||
1146 | iter += 2; | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | return cat_size; | ||
1151 | } | ||
1152 | |||
1153 | /** | ||
1154 | * cipso_v4_map_cat_rng_ntoh - Perform a category mapping from network to host | ||
1155 | * @doi_def: the DOI definition | ||
1156 | * @net_cat: the category list in network/CIPSO format | ||
1157 | * @net_cat_len: the length of the CIPSO bitmap in bytes | ||
1158 | * @secattr: the security attributes | ||
1159 | * | ||
1160 | * Description: | ||
1161 | * Perform a label mapping to translate a CIPSO category list to the correct | ||
1162 | * local MLS category bitmap using the given DOI definition. Returns zero on | ||
1163 | * success, negative values on failure. | ||
1164 | * | ||
1165 | */ | ||
1166 | static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, | ||
1167 | const unsigned char *net_cat, | ||
1168 | u32 net_cat_len, | ||
1169 | struct netlbl_lsm_secattr *secattr) | ||
1170 | { | ||
1171 | int ret_val; | ||
1172 | u32 net_iter; | ||
1173 | u16 cat_low; | ||
1174 | u16 cat_high; | ||
1175 | |||
1176 | for(net_iter = 0; net_iter < net_cat_len; net_iter += 4) { | ||
1177 | cat_high = ntohs(*((__be16 *)&net_cat[net_iter])); | ||
1178 | if ((net_iter + 4) <= net_cat_len) | ||
1179 | cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2])); | ||
1180 | else | ||
1181 | cat_low = 0; | ||
1182 | |||
1183 | ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, | ||
1184 | cat_low, | ||
1185 | cat_high, | ||
1186 | GFP_ATOMIC); | ||
1187 | if (ret_val != 0) | ||
1188 | return ret_val; | ||
1189 | } | ||
1190 | |||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1048 | /* | 1194 | /* |
1049 | * Protocol Handling Functions | 1195 | * Protocol Handling Functions |
1050 | */ | 1196 | */ |
@@ -1266,6 +1412,98 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, | |||
1266 | } | 1412 | } |
1267 | 1413 | ||
1268 | /** | 1414 | /** |
1415 | * cipso_v4_gentag_rng - Generate a CIPSO ranged tag (type #5) | ||
1416 | * @doi_def: the DOI definition | ||
1417 | * @secattr: the security attributes | ||
1418 | * @buffer: the option buffer | ||
1419 | * @buffer_len: length of buffer in bytes | ||
1420 | * | ||
1421 | * Description: | ||
1422 | * Generate a CIPSO option using the ranged tag, tag type #5. Returns the | ||
1423 | * size of the tag on success, negative values on failure. | ||
1424 | * | ||
1425 | */ | ||
1426 | static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, | ||
1427 | const struct netlbl_lsm_secattr *secattr, | ||
1428 | unsigned char *buffer, | ||
1429 | u32 buffer_len) | ||
1430 | { | ||
1431 | int ret_val; | ||
1432 | u32 tag_len; | ||
1433 | u32 level; | ||
1434 | |||
1435 | if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) | ||
1436 | return -EPERM; | ||
1437 | |||
1438 | ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); | ||
1439 | if (ret_val != 0) | ||
1440 | return ret_val; | ||
1441 | |||
1442 | if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { | ||
1443 | ret_val = cipso_v4_map_cat_rng_hton(doi_def, | ||
1444 | secattr, | ||
1445 | &buffer[4], | ||
1446 | buffer_len - 4); | ||
1447 | if (ret_val < 0) | ||
1448 | return ret_val; | ||
1449 | |||
1450 | tag_len = 4 + ret_val; | ||
1451 | } else | ||
1452 | tag_len = 4; | ||
1453 | |||
1454 | buffer[0] = 0x05; | ||
1455 | buffer[1] = tag_len; | ||
1456 | buffer[3] = level; | ||
1457 | |||
1458 | return tag_len; | ||
1459 | } | ||
1460 | |||
1461 | /** | ||
1462 | * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag | ||
1463 | * @doi_def: the DOI definition | ||
1464 | * @tag: the CIPSO tag | ||
1465 | * @secattr: the security attributes | ||
1466 | * | ||
1467 | * Description: | ||
1468 | * Parse a CIPSO ranged tag (tag type #5) and return the security attributes | ||
1469 | * in @secattr. Return zero on success, negatives values on failure. | ||
1470 | * | ||
1471 | */ | ||
1472 | static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, | ||
1473 | const unsigned char *tag, | ||
1474 | struct netlbl_lsm_secattr *secattr) | ||
1475 | { | ||
1476 | int ret_val; | ||
1477 | u8 tag_len = tag[1]; | ||
1478 | u32 level; | ||
1479 | |||
1480 | ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); | ||
1481 | if (ret_val != 0) | ||
1482 | return ret_val; | ||
1483 | secattr->mls_lvl = level; | ||
1484 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | ||
1485 | |||
1486 | if (tag_len > 4) { | ||
1487 | secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1488 | if (secattr->mls_cat == NULL) | ||
1489 | return -ENOMEM; | ||
1490 | |||
1491 | ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, | ||
1492 | &tag[4], | ||
1493 | tag_len - 4, | ||
1494 | secattr); | ||
1495 | if (ret_val != 0) { | ||
1496 | netlbl_secattr_catmap_free(secattr->mls_cat); | ||
1497 | return ret_val; | ||
1498 | } | ||
1499 | |||
1500 | secattr->flags |= NETLBL_SECATTR_MLS_CAT; | ||
1501 | } | ||
1502 | |||
1503 | return 0; | ||
1504 | } | ||
1505 | |||
1506 | /** | ||
1269 | * cipso_v4_validate - Validate a CIPSO option | 1507 | * cipso_v4_validate - Validate a CIPSO option |
1270 | * @option: the start of the option, on error it is set to point to the error | 1508 | * @option: the start of the option, on error it is set to point to the error |
1271 | * | 1509 | * |
@@ -1373,6 +1611,25 @@ int cipso_v4_validate(unsigned char **option) | |||
1373 | goto validate_return_locked; | 1611 | goto validate_return_locked; |
1374 | } | 1612 | } |
1375 | break; | 1613 | break; |
1614 | case CIPSO_V4_TAG_RANGE: | ||
1615 | if (tag_len < 4) { | ||
1616 | err_offset = opt_iter + 1; | ||
1617 | goto validate_return_locked; | ||
1618 | } | ||
1619 | |||
1620 | if (cipso_v4_map_lvl_valid(doi_def, | ||
1621 | tag[3]) < 0) { | ||
1622 | err_offset = opt_iter + 3; | ||
1623 | goto validate_return_locked; | ||
1624 | } | ||
1625 | if (tag_len > 4 && | ||
1626 | cipso_v4_map_cat_rng_valid(doi_def, | ||
1627 | &tag[4], | ||
1628 | tag_len - 4) < 0) { | ||
1629 | err_offset = opt_iter + 4; | ||
1630 | goto validate_return_locked; | ||
1631 | } | ||
1632 | break; | ||
1376 | default: | 1633 | default: |
1377 | err_offset = opt_iter; | 1634 | err_offset = opt_iter; |
1378 | goto validate_return_locked; | 1635 | goto validate_return_locked; |
@@ -1492,6 +1749,12 @@ int cipso_v4_socket_setattr(const struct socket *sock, | |||
1492 | &buf[CIPSO_V4_HDR_LEN], | 1749 | &buf[CIPSO_V4_HDR_LEN], |
1493 | buf_len - CIPSO_V4_HDR_LEN); | 1750 | buf_len - CIPSO_V4_HDR_LEN); |
1494 | break; | 1751 | break; |
1752 | case CIPSO_V4_TAG_RANGE: | ||
1753 | ret_val = cipso_v4_gentag_rng(doi_def, | ||
1754 | secattr, | ||
1755 | &buf[CIPSO_V4_HDR_LEN], | ||
1756 | buf_len - CIPSO_V4_HDR_LEN); | ||
1757 | break; | ||
1495 | default: | 1758 | default: |
1496 | ret_val = -EPERM; | 1759 | ret_val = -EPERM; |
1497 | goto socket_setattr_failure; | 1760 | goto socket_setattr_failure; |
@@ -1593,6 +1856,11 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) | |||
1593 | &cipso_ptr[6], | 1856 | &cipso_ptr[6], |
1594 | secattr); | 1857 | secattr); |
1595 | break; | 1858 | break; |
1859 | case CIPSO_V4_TAG_RANGE: | ||
1860 | ret_val = cipso_v4_parsetag_rng(doi_def, | ||
1861 | &cipso_ptr[6], | ||
1862 | secattr); | ||
1863 | break; | ||
1596 | } | 1864 | } |
1597 | rcu_read_unlock(); | 1865 | rcu_read_unlock(); |
1598 | 1866 | ||