netport.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * Network port table
  3. *
  4. * SELinux must keep a mapping of network ports to labels/SIDs. This
  5. * mapping is maintained as part of the normal policy but a fast cache is
  6. * needed to reduce the lookup overhead.
  7. *
  8. * Author: Paul Moore <paul.moore@hp.com>
  9. *
  10. * This code is heavily based on the "netif" concept originally developed by
  11. * James Morris <jmorris@redhat.com>
  12. * (see security/selinux/netif.c for more information)
  13. *
  14. */
  15. /*
  16. * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
  17. *
  18. * This program is free software: you can redistribute it and/or modify
  19. * it under the terms of version 2 of the GNU General Public License as
  20. * published by the Free Software Foundation.
  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 the
  25. * GNU General Public License for more details.
  26. *
  27. */
  28. #include <linux/types.h>
  29. #include <linux/rcupdate.h>
  30. #include <linux/list.h>
  31. #include <linux/spinlock.h>
  32. #include <linux/in.h>
  33. #include <linux/in6.h>
  34. #include <linux/ip.h>
  35. #include <linux/ipv6.h>
  36. #include <net/ip.h>
  37. #include <net/ipv6.h>
  38. #include "netport.h"
  39. #include "objsec.h"
  40. #define SEL_NETPORT_HASH_SIZE 256
  41. #define SEL_NETPORT_HASH_BKT_LIMIT 16
  42. struct sel_netport_bkt {
  43. int size;
  44. struct list_head list;
  45. };
  46. struct sel_netport {
  47. struct netport_security_struct psec;
  48. struct list_head list;
  49. struct rcu_head rcu;
  50. };
  51. /* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
  52. * for this is that I suspect most users will not make heavy use of both
  53. * address families at the same time so one table will usually end up wasted,
  54. * if this becomes a problem we can always add a hash table for each address
  55. * family later */
  56. static LIST_HEAD(sel_netport_list);
  57. static DEFINE_SPINLOCK(sel_netport_lock);
  58. static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
  59. /**
  60. * sel_netport_free - Frees a port entry
  61. * @p: the entry's RCU field
  62. *
  63. * Description:
  64. * This function is designed to be used as a callback to the call_rcu()
  65. * function so that memory allocated to a hash table port entry can be
  66. * released safely.
  67. *
  68. */
  69. static void sel_netport_free(struct rcu_head *p)
  70. {
  71. struct sel_netport *port = container_of(p, struct sel_netport, rcu);
  72. kfree(port);
  73. }
  74. /**
  75. * sel_netport_hashfn - Hashing function for the port table
  76. * @pnum: port number
  77. *
  78. * Description:
  79. * This is the hashing function for the port table, it returns the bucket
  80. * number for the given port.
  81. *
  82. */
  83. static unsigned int sel_netport_hashfn(u16 pnum)
  84. {
  85. return (pnum & (SEL_NETPORT_HASH_SIZE - 1));
  86. }
  87. /**
  88. * sel_netport_find - Search for a port record
  89. * @protocol: protocol
  90. * @port: pnum
  91. *
  92. * Description:
  93. * Search the network port table and return the matching record. If an entry
  94. * can not be found in the table return NULL.
  95. *
  96. */
  97. static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
  98. {
  99. unsigned int idx;
  100. struct sel_netport *port;
  101. idx = sel_netport_hashfn(pnum);
  102. list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
  103. if (port->psec.port == pnum && port->psec.protocol == protocol)
  104. return port;
  105. return NULL;
  106. }
  107. /**
  108. * sel_netport_insert - Insert a new port into the table
  109. * @port: the new port record
  110. *
  111. * Description:
  112. * Add a new port record to the network address hash table.
  113. *
  114. */
  115. static void sel_netport_insert(struct sel_netport *port)
  116. {
  117. unsigned int idx;
  118. /* we need to impose a limit on the growth of the hash table so check
  119. * this bucket to make sure it is within the specified bounds */
  120. idx = sel_netport_hashfn(port->psec.port);
  121. list_add_rcu(&port->list, &sel_netport_hash[idx].list);
  122. if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
  123. struct sel_netport *tail;
  124. tail = list_entry(
  125. rcu_dereference(sel_netport_hash[idx].list.prev),
  126. struct sel_netport, list);
  127. list_del_rcu(&tail->list);
  128. call_rcu(&tail->rcu, sel_netport_free);
  129. } else
  130. sel_netport_hash[idx].size++;
  131. }
  132. /**
  133. * sel_netport_sid_slow - Lookup the SID of a network address using the policy
  134. * @protocol: protocol
  135. * @pnum: port
  136. * @sid: port SID
  137. *
  138. * Description:
  139. * This function determines the SID of a network port by quering the security
  140. * policy. The result is added to the network port table to speedup future
  141. * queries. Returns zero on success, negative values on failure.
  142. *
  143. */
  144. static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
  145. {
  146. int ret = -ENOMEM;
  147. struct sel_netport *port;
  148. struct sel_netport *new = NULL;
  149. spin_lock_bh(&sel_netport_lock);
  150. port = sel_netport_find(protocol, pnum);
  151. if (port != NULL) {
  152. *sid = port->psec.sid;
  153. spin_unlock_bh(&sel_netport_lock);
  154. return 0;
  155. }
  156. new = kzalloc(sizeof(*new), GFP_ATOMIC);
  157. if (new == NULL)
  158. goto out;
  159. ret = security_port_sid(protocol, pnum, sid);
  160. if (ret != 0)
  161. goto out;
  162. new->psec.port = pnum;
  163. new->psec.protocol = protocol;
  164. new->psec.sid = *sid;
  165. sel_netport_insert(new);
  166. out:
  167. spin_unlock_bh(&sel_netport_lock);
  168. if (unlikely(ret)) {
  169. printk(KERN_WARNING
  170. "SELinux: failure in sel_netport_sid_slow(),"
  171. " unable to determine network port label\n");
  172. kfree(new);
  173. }
  174. return ret;
  175. }
  176. /**
  177. * sel_netport_sid - Lookup the SID of a network port
  178. * @protocol: protocol
  179. * @pnum: port
  180. * @sid: port SID
  181. *
  182. * Description:
  183. * This function determines the SID of a network port using the fastest method
  184. * possible. First the port table is queried, but if an entry can't be found
  185. * then the policy is queried and the result is added to the table to speedup
  186. * future queries. Returns zero on success, negative values on failure.
  187. *
  188. */
  189. int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
  190. {
  191. struct sel_netport *port;
  192. rcu_read_lock();
  193. port = sel_netport_find(protocol, pnum);
  194. if (port != NULL) {
  195. *sid = port->psec.sid;
  196. rcu_read_unlock();
  197. return 0;
  198. }
  199. rcu_read_unlock();
  200. return sel_netport_sid_slow(protocol, pnum, sid);
  201. }
  202. /**
  203. * sel_netport_flush - Flush the entire network port table
  204. *
  205. * Description:
  206. * Remove all entries from the network address table.
  207. *
  208. */
  209. static void sel_netport_flush(void)
  210. {
  211. unsigned int idx;
  212. struct sel_netport *port, *port_tmp;
  213. spin_lock_bh(&sel_netport_lock);
  214. for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
  215. list_for_each_entry_safe(port, port_tmp,
  216. &sel_netport_hash[idx].list, list) {
  217. list_del_rcu(&port->list);
  218. call_rcu(&port->rcu, sel_netport_free);
  219. }
  220. sel_netport_hash[idx].size = 0;
  221. }
  222. spin_unlock_bh(&sel_netport_lock);
  223. }
  224. static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid,
  225. u16 class, u32 perms, u32 *retained)
  226. {
  227. if (event == AVC_CALLBACK_RESET) {
  228. sel_netport_flush();
  229. synchronize_net();
  230. }
  231. return 0;
  232. }
  233. static __init int sel_netport_init(void)
  234. {
  235. int iter;
  236. int ret;
  237. if (!selinux_enabled)
  238. return 0;
  239. for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
  240. INIT_LIST_HEAD(&sel_netport_hash[iter].list);
  241. sel_netport_hash[iter].size = 0;
  242. }
  243. ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET,
  244. SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
  245. if (ret != 0)
  246. panic("avc_add_callback() failed, error %d\n", ret);
  247. return ret;
  248. }
  249. __initcall(sel_netport_init);