Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/selinux/netport.c
50754 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Network port table
4
*
5
* SELinux must keep a mapping of network ports to labels/SIDs. This
6
* mapping is maintained as part of the normal policy but a fast cache is
7
* needed to reduce the lookup overhead.
8
*
9
* Author: Paul Moore <[email protected]>
10
*
11
* This code is heavily based on the "netif" concept originally developed by
12
* James Morris <[email protected]>
13
* (see security/selinux/netif.c for more information)
14
*/
15
16
/*
17
* (c) Copyright Hewlett-Packard Development Company, L.P., 2008
18
*/
19
20
#include <linux/types.h>
21
#include <linux/rcupdate.h>
22
#include <linux/list.h>
23
#include <linux/slab.h>
24
#include <linux/spinlock.h>
25
#include <linux/in.h>
26
#include <linux/in6.h>
27
#include <linux/ip.h>
28
#include <linux/ipv6.h>
29
#include <net/ip.h>
30
#include <net/ipv6.h>
31
32
#include "initcalls.h"
33
#include "netport.h"
34
#include "objsec.h"
35
36
#define SEL_NETPORT_HASH_SIZE 256
37
#define SEL_NETPORT_HASH_BKT_LIMIT 16
38
39
struct sel_netport_bkt {
40
int size;
41
struct list_head list;
42
};
43
44
struct sel_netport {
45
struct netport_security_struct psec;
46
47
struct list_head list;
48
struct rcu_head rcu;
49
};
50
51
static DEFINE_SPINLOCK(sel_netport_lock);
52
static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
53
54
/**
55
* sel_netport_hashfn - Hashing function for the port table
56
* @pnum: port number
57
*
58
* Description:
59
* This is the hashing function for the port table, it returns the bucket
60
* number for the given port.
61
*
62
*/
63
static unsigned int sel_netport_hashfn(u16 pnum)
64
{
65
return (pnum & (SEL_NETPORT_HASH_SIZE - 1));
66
}
67
68
/**
69
* sel_netport_find - Search for a port record
70
* @protocol: protocol
71
* @pnum: port
72
*
73
* Description:
74
* Search the network port table and return the matching record. If an entry
75
* can not be found in the table return NULL.
76
*
77
*/
78
static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
79
{
80
unsigned int idx;
81
struct sel_netport *port;
82
83
idx = sel_netport_hashfn(pnum);
84
list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
85
if (port->psec.port == pnum && port->psec.protocol == protocol)
86
return port;
87
88
return NULL;
89
}
90
91
/**
92
* sel_netport_insert - Insert a new port into the table
93
* @port: the new port record
94
*
95
* Description:
96
* Add a new port record to the network address hash table.
97
*
98
*/
99
static void sel_netport_insert(struct sel_netport *port)
100
{
101
unsigned int idx;
102
103
/* we need to impose a limit on the growth of the hash table so check
104
* this bucket to make sure it is within the specified bounds */
105
idx = sel_netport_hashfn(port->psec.port);
106
list_add_rcu(&port->list, &sel_netport_hash[idx].list);
107
if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
108
struct sel_netport *tail;
109
tail = list_entry(
110
rcu_dereference_protected(
111
list_tail_rcu(&sel_netport_hash[idx].list),
112
lockdep_is_held(&sel_netport_lock)),
113
struct sel_netport, list);
114
list_del_rcu(&tail->list);
115
kfree_rcu(tail, rcu);
116
} else
117
sel_netport_hash[idx].size++;
118
}
119
120
/**
121
* sel_netport_sid_slow - Lookup the SID of a network address using the policy
122
* @protocol: protocol
123
* @pnum: port
124
* @sid: port SID
125
*
126
* Description:
127
* This function determines the SID of a network port by querying the security
128
* policy. The result is added to the network port table to speedup future
129
* queries. Returns zero on success, negative values on failure.
130
*
131
*/
132
static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
133
{
134
int ret;
135
struct sel_netport *port;
136
struct sel_netport *new;
137
138
spin_lock_bh(&sel_netport_lock);
139
port = sel_netport_find(protocol, pnum);
140
if (port != NULL) {
141
*sid = port->psec.sid;
142
spin_unlock_bh(&sel_netport_lock);
143
return 0;
144
}
145
146
ret = security_port_sid(protocol, pnum, sid);
147
if (ret != 0)
148
goto out;
149
150
/* If this memory allocation fails still return 0. The SID
151
* is valid, it just won't be added to the cache.
152
*/
153
new = kmalloc(sizeof(*new), GFP_ATOMIC);
154
if (new) {
155
new->psec.port = pnum;
156
new->psec.protocol = protocol;
157
new->psec.sid = *sid;
158
sel_netport_insert(new);
159
}
160
161
out:
162
spin_unlock_bh(&sel_netport_lock);
163
if (unlikely(ret))
164
pr_warn("SELinux: failure in %s(), unable to determine network port label\n",
165
__func__);
166
return ret;
167
}
168
169
/**
170
* sel_netport_sid - Lookup the SID of a network port
171
* @protocol: protocol
172
* @pnum: port
173
* @sid: port SID
174
*
175
* Description:
176
* This function determines the SID of a network port using the fastest method
177
* possible. First the port table is queried, but if an entry can't be found
178
* then the policy is queried and the result is added to the table to speedup
179
* future queries. Returns zero on success, negative values on failure.
180
*
181
*/
182
int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
183
{
184
struct sel_netport *port;
185
186
rcu_read_lock();
187
port = sel_netport_find(protocol, pnum);
188
if (likely(port != NULL)) {
189
*sid = port->psec.sid;
190
rcu_read_unlock();
191
return 0;
192
}
193
rcu_read_unlock();
194
195
return sel_netport_sid_slow(protocol, pnum, sid);
196
}
197
198
/**
199
* sel_netport_flush - Flush the entire network port table
200
*
201
* Description:
202
* Remove all entries from the network address table.
203
*
204
*/
205
void sel_netport_flush(void)
206
{
207
unsigned int idx;
208
struct sel_netport *port, *port_tmp;
209
210
spin_lock_bh(&sel_netport_lock);
211
for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
212
list_for_each_entry_safe(port, port_tmp,
213
&sel_netport_hash[idx].list, list) {
214
list_del_rcu(&port->list);
215
kfree_rcu(port, rcu);
216
}
217
sel_netport_hash[idx].size = 0;
218
}
219
spin_unlock_bh(&sel_netport_lock);
220
}
221
222
int __init sel_netport_init(void)
223
{
224
int iter;
225
226
if (!selinux_enabled_boot)
227
return 0;
228
229
for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
230
INIT_LIST_HEAD(&sel_netport_hash[iter].list);
231
sel_netport_hash[iter].size = 0;
232
}
233
234
return 0;
235
}
236
237