0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <linux/types.h>
0021 #include <linux/rcupdate.h>
0022 #include <linux/list.h>
0023 #include <linux/slab.h>
0024 #include <linux/spinlock.h>
0025 #include <linux/in.h>
0026 #include <linux/in6.h>
0027 #include <linux/ip.h>
0028 #include <linux/ipv6.h>
0029 #include <net/ip.h>
0030 #include <net/ipv6.h>
0031
0032 #include "netport.h"
0033 #include "objsec.h"
0034
0035 #define SEL_NETPORT_HASH_SIZE 256
0036 #define SEL_NETPORT_HASH_BKT_LIMIT 16
0037
0038 struct sel_netport_bkt {
0039 int size;
0040 struct list_head list;
0041 };
0042
0043 struct sel_netport {
0044 struct netport_security_struct psec;
0045
0046 struct list_head list;
0047 struct rcu_head rcu;
0048 };
0049
0050
0051
0052
0053
0054
0055
0056 static DEFINE_SPINLOCK(sel_netport_lock);
0057 static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 static unsigned int sel_netport_hashfn(u16 pnum)
0069 {
0070 return (pnum & (SEL_NETPORT_HASH_SIZE - 1));
0071 }
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
0084 {
0085 unsigned int idx;
0086 struct sel_netport *port;
0087
0088 idx = sel_netport_hashfn(pnum);
0089 list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
0090 if (port->psec.port == pnum && port->psec.protocol == protocol)
0091 return port;
0092
0093 return NULL;
0094 }
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 static void sel_netport_insert(struct sel_netport *port)
0105 {
0106 unsigned int idx;
0107
0108
0109
0110 idx = sel_netport_hashfn(port->psec.port);
0111 list_add_rcu(&port->list, &sel_netport_hash[idx].list);
0112 if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
0113 struct sel_netport *tail;
0114 tail = list_entry(
0115 rcu_dereference_protected(
0116 list_tail_rcu(&sel_netport_hash[idx].list),
0117 lockdep_is_held(&sel_netport_lock)),
0118 struct sel_netport, list);
0119 list_del_rcu(&tail->list);
0120 kfree_rcu(tail, rcu);
0121 } else
0122 sel_netport_hash[idx].size++;
0123 }
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
0138 {
0139 int ret;
0140 struct sel_netport *port;
0141 struct sel_netport *new;
0142
0143 spin_lock_bh(&sel_netport_lock);
0144 port = sel_netport_find(protocol, pnum);
0145 if (port != NULL) {
0146 *sid = port->psec.sid;
0147 spin_unlock_bh(&sel_netport_lock);
0148 return 0;
0149 }
0150
0151 ret = security_port_sid(&selinux_state, protocol, pnum, sid);
0152 if (ret != 0)
0153 goto out;
0154 new = kzalloc(sizeof(*new), GFP_ATOMIC);
0155 if (new) {
0156 new->psec.port = pnum;
0157 new->psec.protocol = protocol;
0158 new->psec.sid = *sid;
0159 sel_netport_insert(new);
0160 }
0161
0162 out:
0163 spin_unlock_bh(&sel_netport_lock);
0164 if (unlikely(ret))
0165 pr_warn("SELinux: failure in %s(), unable to determine network port label\n",
0166 __func__);
0167 return ret;
0168 }
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
0184 {
0185 struct sel_netport *port;
0186
0187 rcu_read_lock();
0188 port = sel_netport_find(protocol, pnum);
0189 if (port != NULL) {
0190 *sid = port->psec.sid;
0191 rcu_read_unlock();
0192 return 0;
0193 }
0194 rcu_read_unlock();
0195
0196 return sel_netport_sid_slow(protocol, pnum, sid);
0197 }
0198
0199
0200
0201
0202
0203
0204
0205
0206 void sel_netport_flush(void)
0207 {
0208 unsigned int idx;
0209 struct sel_netport *port, *port_tmp;
0210
0211 spin_lock_bh(&sel_netport_lock);
0212 for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
0213 list_for_each_entry_safe(port, port_tmp,
0214 &sel_netport_hash[idx].list, list) {
0215 list_del_rcu(&port->list);
0216 kfree_rcu(port, rcu);
0217 }
0218 sel_netport_hash[idx].size = 0;
0219 }
0220 spin_unlock_bh(&sel_netport_lock);
0221 }
0222
0223 static __init int sel_netport_init(void)
0224 {
0225 int iter;
0226
0227 if (!selinux_enabled_boot)
0228 return 0;
0229
0230 for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
0231 INIT_LIST_HEAD(&sel_netport_hash[iter].list);
0232 sel_netport_hash[iter].size = 0;
0233 }
0234
0235 return 0;
0236 }
0237
0238 __initcall(sel_netport_init);