cipso_ipv4.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474
  1. /*
  2. * CIPSO - Commercial IP Security Option
  3. *
  4. * This is an implementation of the CIPSO 2.2 protocol as specified in
  5. * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
  6. * FIPS-188, copies of both documents can be found in the Documentation
  7. * directory. While CIPSO never became a full IETF RFC standard many vendors
  8. * have chosen to adopt the protocol and over the years it has become a
  9. * de-facto standard for labeled networking.
  10. *
  11. * Author: Paul Moore <paul.moore@hp.com>
  12. *
  13. */
  14. /*
  15. * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
  16. *
  17. * This program is free software; you can redistribute it and/or modify
  18. * it under the terms of the GNU General Public License as published by
  19. * the Free Software Foundation; either version 2 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  25. * the GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  30. *
  31. */
  32. #include <linux/init.h>
  33. #include <linux/types.h>
  34. #include <linux/rcupdate.h>
  35. #include <linux/list.h>
  36. #include <linux/spinlock.h>
  37. #include <linux/string.h>
  38. #include <linux/jhash.h>
  39. #include <net/ip.h>
  40. #include <net/icmp.h>
  41. #include <net/tcp.h>
  42. #include <net/netlabel.h>
  43. #include <net/cipso_ipv4.h>
  44. #include <asm/bug.h>
  45. struct cipso_v4_domhsh_entry {
  46. char *domain;
  47. u32 valid;
  48. struct list_head list;
  49. struct rcu_head rcu;
  50. };
  51. /* List of available DOI definitions */
  52. /* XXX - Updates should be minimal so having a single lock for the
  53. * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
  54. * okay. */
  55. /* XXX - This currently assumes a minimal number of different DOIs in use,
  56. * if in practice there are a lot of different DOIs this list should
  57. * probably be turned into a hash table or something similar so we
  58. * can do quick lookups. */
  59. static DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
  60. static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list);
  61. /* Label mapping cache */
  62. int cipso_v4_cache_enabled = 1;
  63. int cipso_v4_cache_bucketsize = 10;
  64. #define CIPSO_V4_CACHE_BUCKETBITS 7
  65. #define CIPSO_V4_CACHE_BUCKETS (1 << CIPSO_V4_CACHE_BUCKETBITS)
  66. #define CIPSO_V4_CACHE_REORDERLIMIT 10
  67. struct cipso_v4_map_cache_bkt {
  68. spinlock_t lock;
  69. u32 size;
  70. struct list_head list;
  71. };
  72. struct cipso_v4_map_cache_entry {
  73. u32 hash;
  74. unsigned char *key;
  75. size_t key_len;
  76. struct netlbl_lsm_cache lsm_data;
  77. u32 activity;
  78. struct list_head list;
  79. };
  80. static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
  81. /* Restricted bitmap (tag #1) flags */
  82. int cipso_v4_rbm_optfmt = 0;
  83. int cipso_v4_rbm_strictvalid = 1;
  84. /*
  85. * Helper Functions
  86. */
  87. /**
  88. * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
  89. * @bitmap: the bitmap
  90. * @bitmap_len: length in bits
  91. * @offset: starting offset
  92. * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
  93. *
  94. * Description:
  95. * Starting at @offset, walk the bitmap from left to right until either the
  96. * desired bit is found or we reach the end. Return the bit offset, -1 if
  97. * not found, or -2 if error.
  98. */
  99. static int cipso_v4_bitmap_walk(const unsigned char *bitmap,
  100. u32 bitmap_len,
  101. u32 offset,
  102. u8 state)
  103. {
  104. u32 bit_spot;
  105. u32 byte_offset;
  106. unsigned char bitmask;
  107. unsigned char byte;
  108. /* gcc always rounds to zero when doing integer division */
  109. byte_offset = offset / 8;
  110. byte = bitmap[byte_offset];
  111. bit_spot = offset;
  112. bitmask = 0x80 >> (offset % 8);
  113. while (bit_spot < bitmap_len) {
  114. if ((state && (byte & bitmask) == bitmask) ||
  115. (state == 0 && (byte & bitmask) == 0))
  116. return bit_spot;
  117. bit_spot++;
  118. bitmask >>= 1;
  119. if (bitmask == 0) {
  120. byte = bitmap[++byte_offset];
  121. bitmask = 0x80;
  122. }
  123. }
  124. return -1;
  125. }
  126. /**
  127. * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
  128. * @bitmap: the bitmap
  129. * @bit: the bit
  130. * @state: if non-zero, set the bit (1) else clear the bit (0)
  131. *
  132. * Description:
  133. * Set a single bit in the bitmask. Returns zero on success, negative values
  134. * on error.
  135. */
  136. static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
  137. u32 bit,
  138. u8 state)
  139. {
  140. u32 byte_spot;
  141. u8 bitmask;
  142. /* gcc always rounds to zero when doing integer division */
  143. byte_spot = bit / 8;
  144. bitmask = 0x80 >> (bit % 8);
  145. if (state)
  146. bitmap[byte_spot] |= bitmask;
  147. else
  148. bitmap[byte_spot] &= ~bitmask;
  149. }
  150. /**
  151. * cipso_v4_doi_domhsh_free - Frees a domain list entry
  152. * @entry: the entry's RCU field
  153. *
  154. * Description:
  155. * This function is designed to be used as a callback to the call_rcu()
  156. * function so that the memory allocated to a domain list entry can be released
  157. * safely.
  158. *
  159. */
  160. static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
  161. {
  162. struct cipso_v4_domhsh_entry *ptr;
  163. ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
  164. kfree(ptr->domain);
  165. kfree(ptr);
  166. }
  167. /**
  168. * cipso_v4_cache_entry_free - Frees a cache entry
  169. * @entry: the entry to free
  170. *
  171. * Description:
  172. * This function frees the memory associated with a cache entry.
  173. *
  174. */
  175. static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
  176. {
  177. if (entry->lsm_data.free)
  178. entry->lsm_data.free(entry->lsm_data.data);
  179. kfree(entry->key);
  180. kfree(entry);
  181. }
  182. /**
  183. * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache
  184. * @key: the hash key
  185. * @key_len: the length of the key in bytes
  186. *
  187. * Description:
  188. * The CIPSO tag hashing function. Returns a 32-bit hash value.
  189. *
  190. */
  191. static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len)
  192. {
  193. return jhash(key, key_len, 0);
  194. }
  195. /*
  196. * Label Mapping Cache Functions
  197. */
  198. /**
  199. * cipso_v4_cache_init - Initialize the CIPSO cache
  200. *
  201. * Description:
  202. * Initializes the CIPSO label mapping cache, this function should be called
  203. * before any of the other functions defined in this file. Returns zero on
  204. * success, negative values on error.
  205. *
  206. */
  207. static int cipso_v4_cache_init(void)
  208. {
  209. u32 iter;
  210. cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS,
  211. sizeof(struct cipso_v4_map_cache_bkt),
  212. GFP_KERNEL);
  213. if (cipso_v4_cache == NULL)
  214. return -ENOMEM;
  215. for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
  216. spin_lock_init(&cipso_v4_cache[iter].lock);
  217. cipso_v4_cache[iter].size = 0;
  218. INIT_LIST_HEAD(&cipso_v4_cache[iter].list);
  219. }
  220. return 0;
  221. }
  222. /**
  223. * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
  224. *
  225. * Description:
  226. * Invalidates and frees any entries in the CIPSO cache. Returns zero on
  227. * success and negative values on failure.
  228. *
  229. */
  230. void cipso_v4_cache_invalidate(void)
  231. {
  232. struct cipso_v4_map_cache_entry *entry, *tmp_entry;
  233. u32 iter;
  234. for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
  235. spin_lock_bh(&cipso_v4_cache[iter].lock);
  236. list_for_each_entry_safe(entry,
  237. tmp_entry,
  238. &cipso_v4_cache[iter].list, list) {
  239. list_del(&entry->list);
  240. cipso_v4_cache_entry_free(entry);
  241. }
  242. cipso_v4_cache[iter].size = 0;
  243. spin_unlock_bh(&cipso_v4_cache[iter].lock);
  244. }
  245. return;
  246. }
  247. /**
  248. * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
  249. * @key: the buffer to check
  250. * @key_len: buffer length in bytes
  251. * @secattr: the security attribute struct to use
  252. *
  253. * Description:
  254. * This function checks the cache to see if a label mapping already exists for
  255. * the given key. If there is a match then the cache is adjusted and the
  256. * @secattr struct is populated with the correct LSM security attributes. The
  257. * cache is adjusted in the following manner if the entry is not already the
  258. * first in the cache bucket:
  259. *
  260. * 1. The cache entry's activity counter is incremented
  261. * 2. The previous (higher ranking) entry's activity counter is decremented
  262. * 3. If the difference between the two activity counters is geater than
  263. * CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped
  264. *
  265. * Returns zero on success, -ENOENT for a cache miss, and other negative values
  266. * on error.
  267. *
  268. */
  269. static int cipso_v4_cache_check(const unsigned char *key,
  270. u32 key_len,
  271. struct netlbl_lsm_secattr *secattr)
  272. {
  273. u32 bkt;
  274. struct cipso_v4_map_cache_entry *entry;
  275. struct cipso_v4_map_cache_entry *prev_entry = NULL;
  276. u32 hash;
  277. if (!cipso_v4_cache_enabled)
  278. return -ENOENT;
  279. hash = cipso_v4_map_cache_hash(key, key_len);
  280. bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
  281. spin_lock_bh(&cipso_v4_cache[bkt].lock);
  282. list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
  283. if (entry->hash == hash &&
  284. entry->key_len == key_len &&
  285. memcmp(entry->key, key, key_len) == 0) {
  286. entry->activity += 1;
  287. secattr->cache.free = entry->lsm_data.free;
  288. secattr->cache.data = entry->lsm_data.data;
  289. if (prev_entry == NULL) {
  290. spin_unlock_bh(&cipso_v4_cache[bkt].lock);
  291. return 0;
  292. }
  293. if (prev_entry->activity > 0)
  294. prev_entry->activity -= 1;
  295. if (entry->activity > prev_entry->activity &&
  296. entry->activity - prev_entry->activity >
  297. CIPSO_V4_CACHE_REORDERLIMIT) {
  298. __list_del(entry->list.prev, entry->list.next);
  299. __list_add(&entry->list,
  300. prev_entry->list.prev,
  301. &prev_entry->list);
  302. }
  303. spin_unlock_bh(&cipso_v4_cache[bkt].lock);
  304. return 0;
  305. }
  306. prev_entry = entry;
  307. }
  308. spin_unlock_bh(&cipso_v4_cache[bkt].lock);
  309. return -ENOENT;
  310. }
  311. /**
  312. * cipso_v4_cache_add - Add an entry to the CIPSO cache
  313. * @skb: the packet
  314. * @secattr: the packet's security attributes
  315. *
  316. * Description:
  317. * Add a new entry into the CIPSO label mapping cache. Add the new entry to
  318. * head of the cache bucket's list, if the cache bucket is out of room remove
  319. * the last entry in the list first. It is important to note that there is
  320. * currently no checking for duplicate keys. Returns zero on success,
  321. * negative values on failure.
  322. *
  323. */
  324. int cipso_v4_cache_add(const struct sk_buff *skb,
  325. const struct netlbl_lsm_secattr *secattr)
  326. {
  327. int ret_val = -EPERM;
  328. u32 bkt;
  329. struct cipso_v4_map_cache_entry *entry = NULL;
  330. struct cipso_v4_map_cache_entry *old_entry = NULL;
  331. unsigned char *cipso_ptr;
  332. u32 cipso_ptr_len;
  333. if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
  334. return 0;
  335. cipso_ptr = CIPSO_V4_OPTPTR(skb);
  336. cipso_ptr_len = cipso_ptr[1];
  337. entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
  338. if (entry == NULL)
  339. return -ENOMEM;
  340. entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC);
  341. if (entry->key == NULL) {
  342. ret_val = -ENOMEM;
  343. goto cache_add_failure;
  344. }
  345. memcpy(entry->key, cipso_ptr, cipso_ptr_len);
  346. entry->key_len = cipso_ptr_len;
  347. entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
  348. entry->lsm_data.free = secattr->cache.free;
  349. entry->lsm_data.data = secattr->cache.data;
  350. bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
  351. spin_lock_bh(&cipso_v4_cache[bkt].lock);
  352. if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
  353. list_add(&entry->list, &cipso_v4_cache[bkt].list);
  354. cipso_v4_cache[bkt].size += 1;
  355. } else {
  356. old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
  357. struct cipso_v4_map_cache_entry, list);
  358. list_del(&old_entry->list);
  359. list_add(&entry->list, &cipso_v4_cache[bkt].list);
  360. cipso_v4_cache_entry_free(old_entry);
  361. }
  362. spin_unlock_bh(&cipso_v4_cache[bkt].lock);
  363. return 0;
  364. cache_add_failure:
  365. if (entry)
  366. cipso_v4_cache_entry_free(entry);
  367. return ret_val;
  368. }
  369. /*
  370. * DOI List Functions
  371. */
  372. /**
  373. * cipso_v4_doi_search - Searches for a DOI definition
  374. * @doi: the DOI to search for
  375. *
  376. * Description:
  377. * Search the DOI definition list for a DOI definition with a DOI value that
  378. * matches @doi. The caller is responsibile for calling rcu_read_[un]lock().
  379. * Returns a pointer to the DOI definition on success and NULL on failure.
  380. */
  381. static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
  382. {
  383. struct cipso_v4_doi *iter;
  384. list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
  385. if (iter->doi == doi && iter->valid)
  386. return iter;
  387. return NULL;
  388. }
  389. /**
  390. * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
  391. * @doi_def: the DOI structure
  392. *
  393. * Description:
  394. * The caller defines a new DOI for use by the CIPSO engine and calls this
  395. * function to add it to the list of acceptable domains. The caller must
  396. * ensure that the mapping table specified in @doi_def->map meets all of the
  397. * requirements of the mapping type (see cipso_ipv4.h for details). Returns
  398. * zero on success and non-zero on failure.
  399. *
  400. */
  401. int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
  402. {
  403. if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
  404. return -EINVAL;
  405. doi_def->valid = 1;
  406. INIT_RCU_HEAD(&doi_def->rcu);
  407. INIT_LIST_HEAD(&doi_def->dom_list);
  408. rcu_read_lock();
  409. if (cipso_v4_doi_search(doi_def->doi) != NULL)
  410. goto doi_add_failure_rlock;
  411. spin_lock(&cipso_v4_doi_list_lock);
  412. if (cipso_v4_doi_search(doi_def->doi) != NULL)
  413. goto doi_add_failure_slock;
  414. list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
  415. spin_unlock(&cipso_v4_doi_list_lock);
  416. rcu_read_unlock();
  417. return 0;
  418. doi_add_failure_slock:
  419. spin_unlock(&cipso_v4_doi_list_lock);
  420. doi_add_failure_rlock:
  421. rcu_read_unlock();
  422. return -EEXIST;
  423. }
  424. /**
  425. * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
  426. * @doi: the DOI value
  427. * @audit_secid: the LSM secid to use in the audit message
  428. * @callback: the DOI cleanup/free callback
  429. *
  430. * Description:
  431. * Removes a DOI definition from the CIPSO engine, @callback is called to
  432. * free any memory. The NetLabel routines will be called to release their own
  433. * LSM domain mappings as well as our own domain list. Returns zero on
  434. * success and negative values on failure.
  435. *
  436. */
  437. int cipso_v4_doi_remove(u32 doi,
  438. u32 audit_secid,
  439. void (*callback) (struct rcu_head * head))
  440. {
  441. struct cipso_v4_doi *doi_def;
  442. struct cipso_v4_domhsh_entry *dom_iter;
  443. rcu_read_lock();
  444. if (cipso_v4_doi_search(doi) != NULL) {
  445. spin_lock(&cipso_v4_doi_list_lock);
  446. doi_def = cipso_v4_doi_search(doi);
  447. if (doi_def == NULL) {
  448. spin_unlock(&cipso_v4_doi_list_lock);
  449. rcu_read_unlock();
  450. return -ENOENT;
  451. }
  452. doi_def->valid = 0;
  453. list_del_rcu(&doi_def->list);
  454. spin_unlock(&cipso_v4_doi_list_lock);
  455. list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
  456. if (dom_iter->valid)
  457. netlbl_domhsh_remove(dom_iter->domain,
  458. audit_secid);
  459. cipso_v4_cache_invalidate();
  460. rcu_read_unlock();
  461. call_rcu(&doi_def->rcu, callback);
  462. return 0;
  463. }
  464. rcu_read_unlock();
  465. return -ENOENT;
  466. }
  467. /**
  468. * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
  469. * @doi: the DOI value
  470. *
  471. * Description:
  472. * Searches for a valid DOI definition and if one is found it is returned to
  473. * the caller. Otherwise NULL is returned. The caller must ensure that
  474. * rcu_read_lock() is held while accessing the returned definition.
  475. *
  476. */
  477. struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
  478. {
  479. return cipso_v4_doi_search(doi);
  480. }
  481. /**
  482. * cipso_v4_doi_walk - Iterate through the DOI definitions
  483. * @skip_cnt: skip past this number of DOI definitions, updated
  484. * @callback: callback for each DOI definition
  485. * @cb_arg: argument for the callback function
  486. *
  487. * Description:
  488. * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
  489. * For each entry call @callback, if @callback returns a negative value stop
  490. * 'walking' through the list and return. Updates the value in @skip_cnt upon
  491. * return. Returns zero on success, negative values on failure.
  492. *
  493. */
  494. int cipso_v4_doi_walk(u32 *skip_cnt,
  495. int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
  496. void *cb_arg)
  497. {
  498. int ret_val = -ENOENT;
  499. u32 doi_cnt = 0;
  500. struct cipso_v4_doi *iter_doi;
  501. rcu_read_lock();
  502. list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
  503. if (iter_doi->valid) {
  504. if (doi_cnt++ < *skip_cnt)
  505. continue;
  506. ret_val = callback(iter_doi, cb_arg);
  507. if (ret_val < 0) {
  508. doi_cnt--;
  509. goto doi_walk_return;
  510. }
  511. }
  512. doi_walk_return:
  513. rcu_read_unlock();
  514. *skip_cnt = doi_cnt;
  515. return ret_val;
  516. }
  517. /**
  518. * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
  519. * @doi_def: the DOI definition
  520. * @domain: the domain to add
  521. *
  522. * Description:
  523. * Adds the @domain to the the DOI specified by @doi_def, this function
  524. * should only be called by external functions (i.e. NetLabel). This function
  525. * does allocate memory. Returns zero on success, negative values on failure.
  526. *
  527. */
  528. int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
  529. {
  530. struct cipso_v4_domhsh_entry *iter;
  531. struct cipso_v4_domhsh_entry *new_dom;
  532. new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
  533. if (new_dom == NULL)
  534. return -ENOMEM;
  535. if (domain) {
  536. new_dom->domain = kstrdup(domain, GFP_KERNEL);
  537. if (new_dom->domain == NULL) {
  538. kfree(new_dom);
  539. return -ENOMEM;
  540. }
  541. }
  542. new_dom->valid = 1;
  543. INIT_RCU_HEAD(&new_dom->rcu);
  544. rcu_read_lock();
  545. spin_lock(&cipso_v4_doi_list_lock);
  546. list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
  547. if (iter->valid &&
  548. ((domain != NULL && iter->domain != NULL &&
  549. strcmp(iter->domain, domain) == 0) ||
  550. (domain == NULL && iter->domain == NULL))) {
  551. spin_unlock(&cipso_v4_doi_list_lock);
  552. rcu_read_unlock();
  553. kfree(new_dom->domain);
  554. kfree(new_dom);
  555. return -EEXIST;
  556. }
  557. list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
  558. spin_unlock(&cipso_v4_doi_list_lock);
  559. rcu_read_unlock();
  560. return 0;
  561. }
  562. /**
  563. * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
  564. * @doi_def: the DOI definition
  565. * @domain: the domain to remove
  566. *
  567. * Description:
  568. * Removes the @domain from the DOI specified by @doi_def, this function
  569. * should only be called by external functions (i.e. NetLabel). Returns zero
  570. * on success and negative values on error.
  571. *
  572. */
  573. int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
  574. const char *domain)
  575. {
  576. struct cipso_v4_domhsh_entry *iter;
  577. rcu_read_lock();
  578. spin_lock(&cipso_v4_doi_list_lock);
  579. list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
  580. if (iter->valid &&
  581. ((domain != NULL && iter->domain != NULL &&
  582. strcmp(iter->domain, domain) == 0) ||
  583. (domain == NULL && iter->domain == NULL))) {
  584. iter->valid = 0;
  585. list_del_rcu(&iter->list);
  586. spin_unlock(&cipso_v4_doi_list_lock);
  587. rcu_read_unlock();
  588. call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
  589. return 0;
  590. }
  591. spin_unlock(&cipso_v4_doi_list_lock);
  592. rcu_read_unlock();
  593. return -ENOENT;
  594. }
  595. /*
  596. * Label Mapping Functions
  597. */
  598. /**
  599. * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
  600. * @doi_def: the DOI definition
  601. * @level: the level to check
  602. *
  603. * Description:
  604. * Checks the given level against the given DOI definition and returns a
  605. * negative value if the level does not have a valid mapping and a zero value
  606. * if the level is defined by the DOI.
  607. *
  608. */
  609. static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
  610. {
  611. switch (doi_def->type) {
  612. case CIPSO_V4_MAP_PASS:
  613. return 0;
  614. case CIPSO_V4_MAP_STD:
  615. if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
  616. return 0;
  617. break;
  618. }
  619. return -EFAULT;
  620. }
  621. /**
  622. * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network
  623. * @doi_def: the DOI definition
  624. * @host_lvl: the host MLS level
  625. * @net_lvl: the network/CIPSO MLS level
  626. *
  627. * Description:
  628. * Perform a label mapping to translate a local MLS level to the correct
  629. * CIPSO level using the given DOI definition. Returns zero on success,
  630. * negative values otherwise.
  631. *
  632. */
  633. static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
  634. u32 host_lvl,
  635. u32 *net_lvl)
  636. {
  637. switch (doi_def->type) {
  638. case CIPSO_V4_MAP_PASS:
  639. *net_lvl = host_lvl;
  640. return 0;
  641. case CIPSO_V4_MAP_STD:
  642. if (host_lvl < doi_def->map.std->lvl.local_size) {
  643. *net_lvl = doi_def->map.std->lvl.local[host_lvl];
  644. return 0;
  645. }
  646. break;
  647. }
  648. return -EINVAL;
  649. }
  650. /**
  651. * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host
  652. * @doi_def: the DOI definition
  653. * @net_lvl: the network/CIPSO MLS level
  654. * @host_lvl: the host MLS level
  655. *
  656. * Description:
  657. * Perform a label mapping to translate a CIPSO level to the correct local MLS
  658. * level using the given DOI definition. Returns zero on success, negative
  659. * values otherwise.
  660. *
  661. */
  662. static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
  663. u32 net_lvl,
  664. u32 *host_lvl)
  665. {
  666. struct cipso_v4_std_map_tbl *map_tbl;
  667. switch (doi_def->type) {
  668. case CIPSO_V4_MAP_PASS:
  669. *host_lvl = net_lvl;
  670. return 0;
  671. case CIPSO_V4_MAP_STD:
  672. map_tbl = doi_def->map.std;
  673. if (net_lvl < map_tbl->lvl.cipso_size &&
  674. map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) {
  675. *host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
  676. return 0;
  677. }
  678. break;
  679. }
  680. return -EINVAL;
  681. }
  682. /**
  683. * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid
  684. * @doi_def: the DOI definition
  685. * @bitmap: category bitmap
  686. * @bitmap_len: bitmap length in bytes
  687. *
  688. * Description:
  689. * Checks the given category bitmap against the given DOI definition and
  690. * returns a negative value if any of the categories in the bitmap do not have
  691. * a valid mapping and a zero value if all of the categories are valid.
  692. *
  693. */
  694. static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
  695. const unsigned char *bitmap,
  696. u32 bitmap_len)
  697. {
  698. int cat = -1;
  699. u32 bitmap_len_bits = bitmap_len * 8;
  700. u32 cipso_cat_size = doi_def->map.std->cat.cipso_size;
  701. u32 *cipso_array = doi_def->map.std->cat.cipso;
  702. switch (doi_def->type) {
  703. case CIPSO_V4_MAP_PASS:
  704. return 0;
  705. case CIPSO_V4_MAP_STD:
  706. for (;;) {
  707. cat = cipso_v4_bitmap_walk(bitmap,
  708. bitmap_len_bits,
  709. cat + 1,
  710. 1);
  711. if (cat < 0)
  712. break;
  713. if (cat >= cipso_cat_size ||
  714. cipso_array[cat] >= CIPSO_V4_INV_CAT)
  715. return -EFAULT;
  716. }
  717. if (cat == -1)
  718. return 0;
  719. break;
  720. }
  721. return -EFAULT;
  722. }
  723. /**
  724. * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
  725. * @doi_def: the DOI definition
  726. * @host_cat: the category bitmap in host format
  727. * @host_cat_len: the length of the host's category bitmap in bytes
  728. * @net_cat: the zero'd out category bitmap in network/CIPSO format
  729. * @net_cat_len: the length of the CIPSO bitmap in bytes
  730. *
  731. * Description:
  732. * Perform a label mapping to translate a local MLS category bitmap to the
  733. * correct CIPSO bitmap using the given DOI definition. Returns the minimum
  734. * size in bytes of the network bitmap on success, negative values otherwise.
  735. *
  736. */
  737. static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
  738. const unsigned char *host_cat,
  739. u32 host_cat_len,
  740. unsigned char *net_cat,
  741. u32 net_cat_len)
  742. {
  743. int host_spot = -1;
  744. u32 net_spot;
  745. u32 net_spot_max = 0;
  746. u32 host_clen_bits = host_cat_len * 8;
  747. u32 net_clen_bits = net_cat_len * 8;
  748. u32 host_cat_size = doi_def->map.std->cat.local_size;
  749. u32 *host_cat_array = doi_def->map.std->cat.local;
  750. switch (doi_def->type) {
  751. case CIPSO_V4_MAP_PASS:
  752. net_spot_max = host_cat_len - 1;
  753. while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
  754. net_spot_max--;
  755. if (net_spot_max > net_cat_len)
  756. return -EINVAL;
  757. memcpy(net_cat, host_cat, net_spot_max);
  758. return net_spot_max;
  759. case CIPSO_V4_MAP_STD:
  760. for (;;) {
  761. host_spot = cipso_v4_bitmap_walk(host_cat,
  762. host_clen_bits,
  763. host_spot + 1,
  764. 1);
  765. if (host_spot < 0)
  766. break;
  767. if (host_spot >= host_cat_size)
  768. return -EPERM;
  769. net_spot = host_cat_array[host_spot];
  770. if (net_spot >= net_clen_bits)
  771. return -ENOSPC;
  772. cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
  773. if (net_spot > net_spot_max)
  774. net_spot_max = net_spot;
  775. }
  776. if (host_spot == -2)
  777. return -EFAULT;
  778. if (++net_spot_max % 8)
  779. return net_spot_max / 8 + 1;
  780. return net_spot_max / 8;
  781. }
  782. return -EINVAL;
  783. }
  784. /**
  785. * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
  786. * @doi_def: the DOI definition
  787. * @net_cat: the category bitmap in network/CIPSO format
  788. * @net_cat_len: the length of the CIPSO bitmap in bytes
  789. * @host_cat: the zero'd out category bitmap in host format
  790. * @host_cat_len: the length of the host's category bitmap in bytes
  791. *
  792. * Description:
  793. * Perform a label mapping to translate a CIPSO bitmap to the correct local
  794. * MLS category bitmap using the given DOI definition. Returns the minimum
  795. * size in bytes of the host bitmap on success, negative values otherwise.
  796. *
  797. */
  798. static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
  799. const unsigned char *net_cat,
  800. u32 net_cat_len,
  801. unsigned char *host_cat,
  802. u32 host_cat_len)
  803. {
  804. u32 host_spot;
  805. u32 host_spot_max = 0;
  806. int net_spot = -1;
  807. u32 net_clen_bits = net_cat_len * 8;
  808. u32 host_clen_bits = host_cat_len * 8;
  809. u32 net_cat_size = doi_def->map.std->cat.cipso_size;
  810. u32 *net_cat_array = doi_def->map.std->cat.cipso;
  811. switch (doi_def->type) {
  812. case CIPSO_V4_MAP_PASS:
  813. if (net_cat_len > host_cat_len)
  814. return -EINVAL;
  815. memcpy(host_cat, net_cat, net_cat_len);
  816. return net_cat_len;
  817. case CIPSO_V4_MAP_STD:
  818. for (;;) {
  819. net_spot = cipso_v4_bitmap_walk(net_cat,
  820. net_clen_bits,
  821. net_spot + 1,
  822. 1);
  823. if (net_spot < 0)
  824. break;
  825. if (net_spot >= net_cat_size ||
  826. net_cat_array[net_spot] >= CIPSO_V4_INV_CAT)
  827. return -EPERM;
  828. host_spot = net_cat_array[net_spot];
  829. if (host_spot >= host_clen_bits)
  830. return -ENOSPC;
  831. cipso_v4_bitmap_setbit(host_cat, host_spot, 1);
  832. if (host_spot > host_spot_max)
  833. host_spot_max = host_spot;
  834. }
  835. if (net_spot == -2)
  836. return -EFAULT;
  837. if (++host_spot_max % 8)
  838. return host_spot_max / 8 + 1;
  839. return host_spot_max / 8;
  840. }
  841. return -EINVAL;
  842. }
  843. /*
  844. * Protocol Handling Functions
  845. */
  846. #define CIPSO_V4_HDR_LEN 6
  847. /**
  848. * cipso_v4_gentag_hdr - Generate a CIPSO option header
  849. * @doi_def: the DOI definition
  850. * @len: the total tag length in bytes
  851. * @buf: the CIPSO option buffer
  852. *
  853. * Description:
  854. * Write a CIPSO header into the beginning of @buffer. Return zero on success,
  855. * negative values on failure.
  856. *
  857. */
  858. static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
  859. u32 len,
  860. unsigned char *buf)
  861. {
  862. if (CIPSO_V4_HDR_LEN + len > 40)
  863. return -ENOSPC;
  864. buf[0] = IPOPT_CIPSO;
  865. buf[1] = CIPSO_V4_HDR_LEN + len;
  866. *(u32 *)&buf[2] = htonl(doi_def->doi);
  867. return 0;
  868. }
  869. #define CIPSO_V4_TAG1_CAT_LEN 30
  870. /**
  871. * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
  872. * @doi_def: the DOI definition
  873. * @secattr: the security attributes
  874. * @buffer: the option buffer
  875. * @buffer_len: length of buffer in bytes
  876. *
  877. * Description:
  878. * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The
  879. * actual buffer length may be larger than the indicated size due to
  880. * translation between host and network category bitmaps. Returns zero on
  881. * success, negative values on failure.
  882. *
  883. */
  884. static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
  885. const struct netlbl_lsm_secattr *secattr,
  886. unsigned char **buffer,
  887. u32 *buffer_len)
  888. {
  889. int ret_val = -EPERM;
  890. unsigned char *buf = NULL;
  891. u32 buf_len;
  892. u32 level;
  893. if (secattr->mls_cat) {
  894. buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN,
  895. GFP_ATOMIC);
  896. if (buf == NULL)
  897. return -ENOMEM;
  898. ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
  899. secattr->mls_cat,
  900. secattr->mls_cat_len,
  901. &buf[CIPSO_V4_HDR_LEN + 4],
  902. CIPSO_V4_TAG1_CAT_LEN);
  903. if (ret_val < 0)
  904. goto gentag_failure;
  905. /* This will send packets using the "optimized" format when
  906. * possibile as specified in section 3.4.2.6 of the
  907. * CIPSO draft. */
  908. if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10))
  909. ret_val = 10;
  910. buf_len = 4 + ret_val;
  911. } else {
  912. buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC);
  913. if (buf == NULL)
  914. return -ENOMEM;
  915. buf_len = 4;
  916. }
  917. ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);
  918. if (ret_val != 0)
  919. goto gentag_failure;
  920. ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf);
  921. if (ret_val != 0)
  922. goto gentag_failure;
  923. buf[CIPSO_V4_HDR_LEN] = 0x01;
  924. buf[CIPSO_V4_HDR_LEN + 1] = buf_len;
  925. buf[CIPSO_V4_HDR_LEN + 3] = level;
  926. *buffer = buf;
  927. *buffer_len = CIPSO_V4_HDR_LEN + buf_len;
  928. return 0;
  929. gentag_failure:
  930. kfree(buf);
  931. return ret_val;
  932. }
  933. /**
  934. * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag
  935. * @doi_def: the DOI definition
  936. * @tag: the CIPSO tag
  937. * @secattr: the security attributes
  938. *
  939. * Description:
  940. * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security
  941. * attributes in @secattr. Return zero on success, negatives values on
  942. * failure.
  943. *
  944. */
  945. static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
  946. const unsigned char *tag,
  947. struct netlbl_lsm_secattr *secattr)
  948. {
  949. int ret_val;
  950. u8 tag_len = tag[1];
  951. u32 level;
  952. ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
  953. if (ret_val != 0)
  954. return ret_val;
  955. secattr->mls_lvl = level;
  956. secattr->mls_lvl_vld = 1;
  957. if (tag_len > 4) {
  958. switch (doi_def->type) {
  959. case CIPSO_V4_MAP_PASS:
  960. secattr->mls_cat_len = tag_len - 4;
  961. break;
  962. case CIPSO_V4_MAP_STD:
  963. secattr->mls_cat_len =
  964. doi_def->map.std->cat.local_size;
  965. break;
  966. }
  967. secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC);
  968. if (secattr->mls_cat == NULL)
  969. return -ENOMEM;
  970. ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
  971. &tag[4],
  972. tag_len - 4,
  973. secattr->mls_cat,
  974. secattr->mls_cat_len);
  975. if (ret_val < 0) {
  976. kfree(secattr->mls_cat);
  977. return ret_val;
  978. }
  979. secattr->mls_cat_len = ret_val;
  980. }
  981. return 0;
  982. }
  983. /**
  984. * cipso_v4_validate - Validate a CIPSO option
  985. * @option: the start of the option, on error it is set to point to the error
  986. *
  987. * Description:
  988. * This routine is called to validate a CIPSO option, it checks all of the
  989. * fields to ensure that they are at least valid, see the draft snippet below
  990. * for details. If the option is valid then a zero value is returned and
  991. * the value of @option is unchanged. If the option is invalid then a
  992. * non-zero value is returned and @option is adjusted to point to the
  993. * offending portion of the option. From the IETF draft ...
  994. *
  995. * "If any field within the CIPSO options, such as the DOI identifier, is not
  996. * recognized the IP datagram is discarded and an ICMP 'parameter problem'
  997. * (type 12) is generated and returned. The ICMP code field is set to 'bad
  998. * parameter' (code 0) and the pointer is set to the start of the CIPSO field
  999. * that is unrecognized."
  1000. *
  1001. */
  1002. int cipso_v4_validate(unsigned char **option)
  1003. {
  1004. unsigned char *opt = *option;
  1005. unsigned char *tag;
  1006. unsigned char opt_iter;
  1007. unsigned char err_offset = 0;
  1008. u8 opt_len;
  1009. u8 tag_len;
  1010. struct cipso_v4_doi *doi_def = NULL;
  1011. u32 tag_iter;
  1012. /* caller already checks for length values that are too large */
  1013. opt_len = opt[1];
  1014. if (opt_len < 8) {
  1015. err_offset = 1;
  1016. goto validate_return;
  1017. }
  1018. rcu_read_lock();
  1019. doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2])));
  1020. if (doi_def == NULL) {
  1021. err_offset = 2;
  1022. goto validate_return_locked;
  1023. }
  1024. opt_iter = 6;
  1025. tag = opt + opt_iter;
  1026. while (opt_iter < opt_len) {
  1027. for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
  1028. if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
  1029. ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
  1030. err_offset = opt_iter;
  1031. goto validate_return_locked;
  1032. }
  1033. tag_len = tag[1];
  1034. if (tag_len > (opt_len - opt_iter)) {
  1035. err_offset = opt_iter + 1;
  1036. goto validate_return_locked;
  1037. }
  1038. switch (tag[0]) {
  1039. case CIPSO_V4_TAG_RBITMAP:
  1040. if (tag_len < 4) {
  1041. err_offset = opt_iter + 1;
  1042. goto validate_return_locked;
  1043. }
  1044. /* We are already going to do all the verification
  1045. * necessary at the socket layer so from our point of
  1046. * view it is safe to turn these checks off (and less
  1047. * work), however, the CIPSO draft says we should do
  1048. * all the CIPSO validations here but it doesn't
  1049. * really specify _exactly_ what we need to validate
  1050. * ... so, just make it a sysctl tunable. */
  1051. if (cipso_v4_rbm_strictvalid) {
  1052. if (cipso_v4_map_lvl_valid(doi_def,
  1053. tag[3]) < 0) {
  1054. err_offset = opt_iter + 3;
  1055. goto validate_return_locked;
  1056. }
  1057. if (tag_len > 4 &&
  1058. cipso_v4_map_cat_rbm_valid(doi_def,
  1059. &tag[4],
  1060. tag_len - 4) < 0) {
  1061. err_offset = opt_iter + 4;
  1062. goto validate_return_locked;
  1063. }
  1064. }
  1065. break;
  1066. default:
  1067. err_offset = opt_iter;
  1068. goto validate_return_locked;
  1069. }
  1070. tag += tag_len;
  1071. opt_iter += tag_len;
  1072. }
  1073. validate_return_locked:
  1074. rcu_read_unlock();
  1075. validate_return:
  1076. *option = opt + err_offset;
  1077. return err_offset;
  1078. }
  1079. /**
  1080. * cipso_v4_error - Send the correct reponse for a bad packet
  1081. * @skb: the packet
  1082. * @error: the error code
  1083. * @gateway: CIPSO gateway flag
  1084. *
  1085. * Description:
  1086. * Based on the error code given in @error, send an ICMP error message back to
  1087. * the originating host. From the IETF draft ...
  1088. *
  1089. * "If the contents of the CIPSO [option] are valid but the security label is
  1090. * outside of the configured host or port label range, the datagram is
  1091. * discarded and an ICMP 'destination unreachable' (type 3) is generated and
  1092. * returned. The code field of the ICMP is set to 'communication with
  1093. * destination network administratively prohibited' (code 9) or to
  1094. * 'communication with destination host administratively prohibited'
  1095. * (code 10). The value of the code is dependent on whether the originator
  1096. * of the ICMP message is acting as a CIPSO host or a CIPSO gateway. The
  1097. * recipient of the ICMP message MUST be able to handle either value. The
  1098. * same procedure is performed if a CIPSO [option] can not be added to an
  1099. * IP packet because it is too large to fit in the IP options area."
  1100. *
  1101. * "If the error is triggered by receipt of an ICMP message, the message is
  1102. * discarded and no response is permitted (consistent with general ICMP
  1103. * processing rules)."
  1104. *
  1105. */
  1106. void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
  1107. {
  1108. if (skb->nh.iph->protocol == IPPROTO_ICMP || error != -EACCES)
  1109. return;
  1110. if (gateway)
  1111. icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
  1112. else
  1113. icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
  1114. }
  1115. /**
  1116. * cipso_v4_socket_setattr - Add a CIPSO option to a socket
  1117. * @sock: the socket
  1118. * @doi_def: the CIPSO DOI to use
  1119. * @secattr: the specific security attributes of the socket
  1120. *
  1121. * Description:
  1122. * Set the CIPSO option on the given socket using the DOI definition and
  1123. * security attributes passed to the function. This function requires
  1124. * exclusive access to @sock->sk, which means it either needs to be in the
  1125. * process of being created or locked via lock_sock(sock->sk). Returns zero on
  1126. * success and negative values on failure.
  1127. *
  1128. */
  1129. int cipso_v4_socket_setattr(const struct socket *sock,
  1130. const struct cipso_v4_doi *doi_def,
  1131. const struct netlbl_lsm_secattr *secattr)
  1132. {
  1133. int ret_val = -EPERM;
  1134. u32 iter;
  1135. unsigned char *buf = NULL;
  1136. u32 buf_len = 0;
  1137. u32 opt_len;
  1138. struct ip_options *opt = NULL;
  1139. struct sock *sk;
  1140. struct inet_sock *sk_inet;
  1141. struct inet_connection_sock *sk_conn;
  1142. /* In the case of sock_create_lite(), the sock->sk field is not
  1143. * defined yet but it is not a problem as the only users of these
  1144. * "lite" PF_INET sockets are functions which do an accept() call
  1145. * afterwards so we will label the socket as part of the accept(). */
  1146. sk = sock->sk;
  1147. if (sk == NULL)
  1148. return 0;
  1149. /* XXX - This code assumes only one tag per CIPSO option which isn't
  1150. * really a good assumption to make but since we only support the MAC
  1151. * tags right now it is a safe assumption. */
  1152. iter = 0;
  1153. do {
  1154. switch (doi_def->tags[iter]) {
  1155. case CIPSO_V4_TAG_RBITMAP:
  1156. ret_val = cipso_v4_gentag_rbm(doi_def,
  1157. secattr,
  1158. &buf,
  1159. &buf_len);
  1160. break;
  1161. default:
  1162. ret_val = -EPERM;
  1163. goto socket_setattr_failure;
  1164. }
  1165. iter++;
  1166. } while (ret_val != 0 &&
  1167. iter < CIPSO_V4_TAG_MAXCNT &&
  1168. doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
  1169. if (ret_val != 0)
  1170. goto socket_setattr_failure;
  1171. /* We can't use ip_options_get() directly because it makes a call to
  1172. * ip_options_get_alloc() which allocates memory with GFP_KERNEL and
  1173. * we can't block here. */
  1174. opt_len = (buf_len + 3) & ~3;
  1175. opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
  1176. if (opt == NULL) {
  1177. ret_val = -ENOMEM;
  1178. goto socket_setattr_failure;
  1179. }
  1180. memcpy(opt->__data, buf, buf_len);
  1181. opt->optlen = opt_len;
  1182. opt->is_data = 1;
  1183. kfree(buf);
  1184. buf = NULL;
  1185. ret_val = ip_options_compile(opt, NULL);
  1186. if (ret_val != 0)
  1187. goto socket_setattr_failure;
  1188. sk_inet = inet_sk(sk);
  1189. if (sk_inet->is_icsk) {
  1190. sk_conn = inet_csk(sk);
  1191. if (sk_inet->opt)
  1192. sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
  1193. sk_conn->icsk_ext_hdr_len += opt->optlen;
  1194. sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
  1195. }
  1196. opt = xchg(&sk_inet->opt, opt);
  1197. kfree(opt);
  1198. return 0;
  1199. socket_setattr_failure:
  1200. kfree(buf);
  1201. kfree(opt);
  1202. return ret_val;
  1203. }
  1204. /**
  1205. * cipso_v4_sock_getattr - Get the security attributes from a sock
  1206. * @sk: the sock
  1207. * @secattr: the security attributes
  1208. *
  1209. * Description:
  1210. * Query @sk to see if there is a CIPSO option attached to the sock and if
  1211. * there is return the CIPSO security attributes in @secattr. This function
  1212. * requires that @sk be locked, or privately held, but it does not do any
  1213. * locking itself. Returns zero on success and negative values on failure.
  1214. *
  1215. */
  1216. int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
  1217. {
  1218. int ret_val = -ENOMSG;
  1219. struct inet_sock *sk_inet;
  1220. unsigned char *cipso_ptr;
  1221. u32 doi;
  1222. struct cipso_v4_doi *doi_def;
  1223. sk_inet = inet_sk(sk);
  1224. if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0)
  1225. return -ENOMSG;
  1226. cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso -
  1227. sizeof(struct iphdr);
  1228. ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr);
  1229. if (ret_val == 0)
  1230. return ret_val;
  1231. doi = ntohl(*(u32 *)&cipso_ptr[2]);
  1232. rcu_read_lock();
  1233. doi_def = cipso_v4_doi_getdef(doi);
  1234. if (doi_def == NULL) {
  1235. rcu_read_unlock();
  1236. return -ENOMSG;
  1237. }
  1238. switch (cipso_ptr[6]) {
  1239. case CIPSO_V4_TAG_RBITMAP:
  1240. ret_val = cipso_v4_parsetag_rbm(doi_def,
  1241. &cipso_ptr[6],
  1242. secattr);
  1243. break;
  1244. }
  1245. rcu_read_unlock();
  1246. return ret_val;
  1247. }
  1248. /**
  1249. * cipso_v4_socket_getattr - Get the security attributes from a socket
  1250. * @sock: the socket
  1251. * @secattr: the security attributes
  1252. *
  1253. * Description:
  1254. * Query @sock to see if there is a CIPSO option attached to the socket and if
  1255. * there is return the CIPSO security attributes in @secattr. Returns zero on
  1256. * success and negative values on failure.
  1257. *
  1258. */
  1259. int cipso_v4_socket_getattr(const struct socket *sock,
  1260. struct netlbl_lsm_secattr *secattr)
  1261. {
  1262. int ret_val;
  1263. lock_sock(sock->sk);
  1264. ret_val = cipso_v4_sock_getattr(sock->sk, secattr);
  1265. release_sock(sock->sk);
  1266. return ret_val;
  1267. }
  1268. /**
  1269. * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
  1270. * @skb: the packet
  1271. * @secattr: the security attributes
  1272. *
  1273. * Description:
  1274. * Parse the given packet's CIPSO option and return the security attributes.
  1275. * Returns zero on success and negative values on failure.
  1276. *
  1277. */
  1278. int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
  1279. struct netlbl_lsm_secattr *secattr)
  1280. {
  1281. int ret_val = -ENOMSG;
  1282. unsigned char *cipso_ptr;
  1283. u32 doi;
  1284. struct cipso_v4_doi *doi_def;
  1285. if (!CIPSO_V4_OPTEXIST(skb))
  1286. return -ENOMSG;
  1287. cipso_ptr = CIPSO_V4_OPTPTR(skb);
  1288. if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0)
  1289. return 0;
  1290. doi = ntohl(*(u32 *)&cipso_ptr[2]);
  1291. rcu_read_lock();
  1292. doi_def = cipso_v4_doi_getdef(doi);
  1293. if (doi_def == NULL)
  1294. goto skbuff_getattr_return;
  1295. switch (cipso_ptr[6]) {
  1296. case CIPSO_V4_TAG_RBITMAP:
  1297. ret_val = cipso_v4_parsetag_rbm(doi_def,
  1298. &cipso_ptr[6],
  1299. secattr);
  1300. break;
  1301. }
  1302. skbuff_getattr_return:
  1303. rcu_read_unlock();
  1304. return ret_val;
  1305. }
  1306. /*
  1307. * Setup Functions
  1308. */
  1309. /**
  1310. * cipso_v4_init - Initialize the CIPSO module
  1311. *
  1312. * Description:
  1313. * Initialize the CIPSO module and prepare it for use. Returns zero on success
  1314. * and negative values on failure.
  1315. *
  1316. */
  1317. static int __init cipso_v4_init(void)
  1318. {
  1319. int ret_val;
  1320. ret_val = cipso_v4_cache_init();
  1321. if (ret_val != 0)
  1322. panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",
  1323. ret_val);
  1324. return 0;
  1325. }
  1326. subsys_initcall(cipso_v4_init);