aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/netport.c
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2008-04-25 15:03:39 -0400
committerJames Morris <jmorris@namei.org>2008-04-27 19:36:27 -0400
commitc9b7b9793764b171a118d049d4b721a7f5d8ac82 (patch)
treed9b0bf6c44a6672f6c3e08da340f6544056932e5 /security/selinux/netport.c
parenta639e7ca8e8282b75be2724a28bfc788aa3bb156 (diff)
SELinux: Fix a RCU free problem with the netport cache
The netport cache doesn't free resources in a manner which is safe or orderly. This patch fixes this by adding in a missing call to rcu_dereference() in sel_netport_insert() as well as some general cleanup throughout the file. Signed-off-by: Paul Moore <paul.moore@hp.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/netport.c')
-rw-r--r--security/selinux/netport.c40
1 files changed, 18 insertions, 22 deletions
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 68ede3c498ab..90b4cff7c350 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -114,8 +114,7 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
114 114
115 idx = sel_netport_hashfn(pnum); 115 idx = sel_netport_hashfn(pnum);
116 list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) 116 list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
117 if (port->psec.port == pnum && 117 if (port->psec.port == pnum && port->psec.protocol == protocol)
118 port->psec.protocol == protocol)
119 return port; 118 return port;
120 119
121 return NULL; 120 return NULL;
@@ -126,11 +125,10 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
126 * @port: the new port record 125 * @port: the new port record
127 * 126 *
128 * Description: 127 * Description:
129 * Add a new port record to the network address hash table. Returns zero on 128 * Add a new port record to the network address hash table.
130 * success, negative values on failure.
131 * 129 *
132 */ 130 */
133static int sel_netport_insert(struct sel_netport *port) 131static void sel_netport_insert(struct sel_netport *port)
134{ 132{
135 unsigned int idx; 133 unsigned int idx;
136 134
@@ -140,13 +138,13 @@ static int sel_netport_insert(struct sel_netport *port)
140 list_add_rcu(&port->list, &sel_netport_hash[idx].list); 138 list_add_rcu(&port->list, &sel_netport_hash[idx].list);
141 if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { 139 if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
142 struct sel_netport *tail; 140 struct sel_netport *tail;
143 tail = list_entry(port->list.prev, struct sel_netport, list); 141 tail = list_entry(
144 list_del_rcu(port->list.prev); 142 rcu_dereference(sel_netport_hash[idx].list.prev),
143 struct sel_netport, list);
144 list_del_rcu(&tail->list);
145 call_rcu(&tail->rcu, sel_netport_free); 145 call_rcu(&tail->rcu, sel_netport_free);
146 } else 146 } else
147 sel_netport_hash[idx].size++; 147 sel_netport_hash[idx].size++;
148
149 return 0;
150} 148}
151 149
152/** 150/**
@@ -163,7 +161,7 @@ static int sel_netport_insert(struct sel_netport *port)
163 */ 161 */
164static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) 162static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
165{ 163{
166 int ret; 164 int ret = -ENOMEM;
167 struct sel_netport *port; 165 struct sel_netport *port;
168 struct sel_netport *new = NULL; 166 struct sel_netport *new = NULL;
169 167
@@ -171,23 +169,20 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
171 port = sel_netport_find(protocol, pnum); 169 port = sel_netport_find(protocol, pnum);
172 if (port != NULL) { 170 if (port != NULL) {
173 *sid = port->psec.sid; 171 *sid = port->psec.sid;
174 ret = 0; 172 spin_unlock_bh(&sel_netport_lock);
175 goto out; 173 return 0;
176 } 174 }
177 new = kzalloc(sizeof(*new), GFP_ATOMIC); 175 new = kzalloc(sizeof(*new), GFP_ATOMIC);
178 if (new == NULL) { 176 if (new == NULL)
179 ret = -ENOMEM;
180 goto out; 177 goto out;
181 } 178 ret = security_port_sid(protocol, pnum, sid);
182 ret = security_port_sid(protocol, pnum, &new->psec.sid);
183 if (ret != 0) 179 if (ret != 0)
184 goto out; 180 goto out;
181
185 new->psec.port = pnum; 182 new->psec.port = pnum;
186 new->psec.protocol = protocol; 183 new->psec.protocol = protocol;
187 ret = sel_netport_insert(new); 184 new->psec.sid = *sid;
188 if (ret != 0) 185 sel_netport_insert(new);
189 goto out;
190 *sid = new->psec.sid;
191 186
192out: 187out:
193 spin_unlock_bh(&sel_netport_lock); 188 spin_unlock_bh(&sel_netport_lock);
@@ -239,11 +234,12 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
239static void sel_netport_flush(void) 234static void sel_netport_flush(void)
240{ 235{
241 unsigned int idx; 236 unsigned int idx;
242 struct sel_netport *port; 237 struct sel_netport *port, *port_tmp;
243 238
244 spin_lock_bh(&sel_netport_lock); 239 spin_lock_bh(&sel_netport_lock);
245 for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { 240 for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
246 list_for_each_entry(port, &sel_netport_hash[idx].list, list) { 241 list_for_each_entry_safe(port, port_tmp,
242 &sel_netport_hash[idx].list, list) {
247 list_del_rcu(&port->list); 243 list_del_rcu(&port->list);
248 call_rcu(&port->rcu, sel_netport_free); 244 call_rcu(&port->rcu, sel_netport_free);
249 } 245 }