1 |
/* |
2 |
* security/ccsecurity/autobind.c |
3 |
* |
4 |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
5 |
* |
6 |
* Version: 1.7.0 2009/10/01 |
7 |
* |
8 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
9 |
* See README.ccs for ChangeLog. |
10 |
* |
11 |
*/ |
12 |
|
13 |
#include "internal.h" |
14 |
|
15 |
/* The list for "struct ccs_reserved_entry". */ |
16 |
LIST_HEAD(ccs_reservedport_list); |
17 |
|
18 |
static u8 ccs_reserved_port_map[8192]; |
19 |
|
20 |
/** |
21 |
* ccs_update_reserved_entry - Update "struct ccs_reserved_entry" list. |
22 |
* |
23 |
* @min_port: Start of port number range. |
24 |
* @max_port: End of port number range. |
25 |
* @is_delete: True if it is a delete request. |
26 |
* |
27 |
* Returns 0 on success, negative value otherwise. |
28 |
*/ |
29 |
static int ccs_update_reserved_entry(const u16 min_port, const u16 max_port, |
30 |
const bool is_delete) |
31 |
{ |
32 |
struct ccs_reserved_entry *ptr; |
33 |
struct ccs_reserved_entry e = { |
34 |
.min_port = min_port, |
35 |
.max_port = max_port |
36 |
}; |
37 |
int error = -ENOMEM; |
38 |
u8 *ccs_tmp_map = kzalloc(8192, GFP_KERNEL); |
39 |
struct ccs_reserved_entry *entry = kmalloc(sizeof(e), GFP_KERNEL); |
40 |
if (!ccs_tmp_map || !entry) { |
41 |
kfree(entry); |
42 |
kfree(ccs_tmp_map); |
43 |
return -ENOMEM; |
44 |
} |
45 |
if (is_delete) |
46 |
error = -ENOENT; |
47 |
mutex_lock(&ccs_policy_lock); |
48 |
list_for_each_entry_rcu(ptr, &ccs_reservedport_list, list) { |
49 |
if (ptr->min_port != min_port || ptr->max_port != max_port) |
50 |
continue; |
51 |
ptr->is_deleted = is_delete; |
52 |
error = 0; |
53 |
break; |
54 |
} |
55 |
if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) { |
56 |
list_add_tail_rcu(&entry->list, &ccs_reservedport_list); |
57 |
entry = NULL; |
58 |
error = 0; |
59 |
} |
60 |
list_for_each_entry_rcu(ptr, &ccs_reservedport_list, list) { |
61 |
unsigned int port; |
62 |
if (ptr->is_deleted) |
63 |
continue; |
64 |
for (port = ptr->min_port; port <= ptr->max_port; port++) |
65 |
ccs_tmp_map[port >> 8] |= 1 << (port & 7); |
66 |
} |
67 |
memmove(ccs_reserved_port_map, ccs_tmp_map, |
68 |
sizeof(ccs_reserved_port_map)); |
69 |
mutex_unlock(&ccs_policy_lock); |
70 |
kfree(entry); |
71 |
kfree(ccs_tmp_map); |
72 |
return error; |
73 |
} |
74 |
|
75 |
/** |
76 |
* ccs_lport_reserved - Check permission for bind()'s automatic port number selection. |
77 |
* |
78 |
* @port: Port number. |
79 |
* |
80 |
* Returns true on success, false otherwise. |
81 |
*/ |
82 |
bool ccs_lport_reserved(const u16 port) |
83 |
{ |
84 |
return ccs_reserved_port_map[port >> 8] & (1 << (port & 7)) |
85 |
? true : false; |
86 |
} |
87 |
EXPORT_SYMBOL(ccs_lport_reserved); /* for net/ipv4/ and net/ipv6/ */ |
88 |
|
89 |
/** |
90 |
* ccs_write_reserved_port_policy - Write "struct ccs_reserved_entry" list. |
91 |
* |
92 |
* @data: String to parse. |
93 |
* @is_delete: True if it is a delete request. |
94 |
* |
95 |
* Returns 0 on success, negative value otherwise. |
96 |
*/ |
97 |
int ccs_write_reserved_port_policy(char *data, const bool is_delete) |
98 |
{ |
99 |
unsigned int from; |
100 |
unsigned int to; |
101 |
if (strchr(data, ' ')) |
102 |
goto out; |
103 |
if (sscanf(data, "%u-%u", &from, &to) == 2) { |
104 |
if (from <= to && to < 65536) |
105 |
return ccs_update_reserved_entry(from, to, is_delete); |
106 |
} else if (sscanf(data, "%u", &from) == 1) { |
107 |
if (from < 65536) |
108 |
return ccs_update_reserved_entry(from, from, is_delete); |
109 |
} |
110 |
out: |
111 |
return -EINVAL; |
112 |
} |
113 |
|
114 |
/** |
115 |
* ccs_read_reserved_port_policy - Read "struct ccs_reserved_entry" list. |
116 |
* |
117 |
* @head: Pointer to "struct ccs_io_buffer". |
118 |
* |
119 |
* Returns true on success, false otherwise. |
120 |
* |
121 |
* Caller holds ccs_read_lock(). |
122 |
*/ |
123 |
bool ccs_read_reserved_port_policy(struct ccs_io_buffer *head) |
124 |
{ |
125 |
struct list_head *pos; |
126 |
char buffer[16]; |
127 |
memset(buffer, 0, sizeof(buffer)); |
128 |
list_for_each_cookie(pos, head->read_var2, &ccs_reservedport_list) { |
129 |
u16 min_port; |
130 |
u16 max_port; |
131 |
struct ccs_reserved_entry *ptr; |
132 |
ptr = list_entry(pos, struct ccs_reserved_entry, list); |
133 |
if (ptr->is_deleted) |
134 |
continue; |
135 |
min_port = ptr->min_port; |
136 |
max_port = ptr->max_port; |
137 |
snprintf(buffer, sizeof(buffer) - 1, "%u%c%u", min_port, |
138 |
min_port != max_port ? '-' : '\0', max_port); |
139 |
if (!ccs_io_printf(head, CCS_KEYWORD_DENY_AUTOBIND "%s\n", |
140 |
buffer)) |
141 |
return false; |
142 |
} |
143 |
return true; |
144 |
} |