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