15 |
/* Lock for protecting ccs_profile->comment */ |
/* Lock for protecting ccs_profile->comment */ |
16 |
static DEFINE_SPINLOCK(ccs_profile_comment_lock); |
static DEFINE_SPINLOCK(ccs_profile_comment_lock); |
17 |
|
|
18 |
static bool ccs_profile_entry_used[CCS_MAX_CONTROL_INDEX + |
/* String table for functionality that takes 2 modes. */ |
19 |
CCS_MAX_CAPABILITY_INDEX + 1]; |
static const char *ccs_mode_2[2] = { |
20 |
|
"disabled", "enabled" |
21 |
|
}; |
22 |
|
|
23 |
/* String table for functionality that takes 4 modes. */ |
static const char *ccs_keyword_mode[4] = { |
24 |
static const char *ccs_mode_4[4] = { |
"MAC_MODE_DISABLED", "MAC_MODE_LEARNING", |
25 |
"disabled", "learning", "permissive", "enforcing" |
"MAC_MODE_PERMISSIVE", "MAC_MODE_ENFORCING" |
26 |
}; |
}; |
27 |
/* String table for functionality that takes 2 modes. */ |
|
28 |
static const char *ccs_mode_2[4] = { |
static const char *ccs_keyword_capability_mode[4] = { |
29 |
"disabled", "enabled", "enabled", "enabled" |
"MAC_MODE_CAPABILITY_DISABLED", "MAC_MODE_CAPABILITY_LEARNING", |
30 |
|
"MAC_MODE_CAPABILITY_PERMISSIVE", "MAC_MODE_CAPABILITY_ENFORCING" |
31 |
|
}; |
32 |
|
|
33 |
|
static const char *ccs_mac_keywords[CCS_MAX_MAC_INDEX] = { |
34 |
|
[CCS_MAC_EXECUTE] = "execute", |
35 |
|
[CCS_MAC_OPEN] = "open", |
36 |
|
[CCS_MAC_CREATE] = "create", |
37 |
|
[CCS_MAC_UNLINK] = "unlink", |
38 |
|
[CCS_MAC_MKDIR] = "mkdir", |
39 |
|
[CCS_MAC_RMDIR] = "rmdir", |
40 |
|
[CCS_MAC_MKFIFO] = "mkfifo", |
41 |
|
[CCS_MAC_MKSOCK] = "mksock", |
42 |
|
[CCS_MAC_TRUNCATE] = "truncate", |
43 |
|
[CCS_MAC_SYMLINK] = "symlink", |
44 |
|
[CCS_MAC_REWRITE] = "rewrite", |
45 |
|
[CCS_MAC_MKBLOCK] = "mkblock", |
46 |
|
[CCS_MAC_MKCHAR] = "mkchar", |
47 |
|
[CCS_MAC_LINK] = "link", |
48 |
|
[CCS_MAC_RENAME] = "rename", |
49 |
|
[CCS_MAC_CHMOD] = "chmod", |
50 |
|
[CCS_MAC_CHOWN] = "chown", |
51 |
|
[CCS_MAC_CHGRP] = "chgrp", |
52 |
|
[CCS_MAC_IOCTL] = "ioctl", |
53 |
|
[CCS_MAC_CHROOT] = "chroot", |
54 |
|
[CCS_MAC_MOUNT] = "mount", |
55 |
|
[CCS_MAC_UMOUNT] = "umount", |
56 |
|
[CCS_MAC_PIVOT_ROOT] = "pivot_root", |
57 |
|
[CCS_MAC_ENVIRON] = "env", |
58 |
|
[CCS_MAC_NETWORK] = "network", |
59 |
|
[CCS_MAC_SIGNAL] = "signal" |
60 |
}; |
}; |
61 |
|
|
62 |
/* Table for profile. */ |
/* Table for profile. */ |
65 |
unsigned int current_value; |
unsigned int current_value; |
66 |
const unsigned int max_value; |
const unsigned int max_value; |
67 |
} ccs_control_array[CCS_MAX_CONTROL_INDEX] = { |
} ccs_control_array[CCS_MAX_CONTROL_INDEX] = { |
|
[CCS_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 }, |
|
68 |
[CCS_AUTOLEARN_EXEC_REALPATH] = { "AUTOLEARN_EXEC_REALPATH", 0, 1 }, |
[CCS_AUTOLEARN_EXEC_REALPATH] = { "AUTOLEARN_EXEC_REALPATH", 0, 1 }, |
69 |
[CCS_AUTOLEARN_EXEC_ARGV0] = { "AUTOLEARN_EXEC_ARGV0", 0, 1 }, |
[CCS_AUTOLEARN_EXEC_ARGV0] = { "AUTOLEARN_EXEC_ARGV0", 0, 1 }, |
|
[CCS_MAC_FOR_IOCTL] = { "MAC_FOR_IOCTL", 0, 3 }, |
|
|
[CCS_MAC_FOR_FILEATTR] = { "MAC_FOR_FILEATTR", 0, 3 }, |
|
|
[CCS_MAC_FOR_ENV] = { "MAC_FOR_ENV", 0, 3 }, |
|
|
[CCS_MAC_FOR_NETWORK] = { "MAC_FOR_NETWORK", 0, 3 }, |
|
|
[CCS_MAC_FOR_SIGNAL] = { "MAC_FOR_SIGNAL", 0, 3 }, |
|
|
[CCS_MAC_FOR_NAMESPACE] = { "MAC_FOR_NAMESPACE", 0, 3 }, |
|
70 |
[CCS_RESTRICT_AUTOBIND] = { "RESTRICT_AUTOBIND", 0, 1 }, |
[CCS_RESTRICT_AUTOBIND] = { "RESTRICT_AUTOBIND", 0, 1 }, |
71 |
[CCS_MAX_ACCEPT_ENTRY] |
[CCS_MAX_ACCEPT_ENTRY] |
72 |
= { "MAX_ACCEPT_ENTRY", CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY, INT_MAX }, |
= { "MAX_ACCEPT_ENTRY", CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY, INT_MAX }, |
151 |
ptr = entry; |
ptr = entry; |
152 |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) |
153 |
ptr->value[i] = ccs_control_array[i].current_value; |
ptr->value[i] = ccs_control_array[i].current_value; |
|
/* |
|
|
* Needn't to initialize "ptr->capability_value" |
|
|
* because they are always 0. |
|
|
*/ |
|
154 |
mb(); /* Avoid out-of-order execution. */ |
mb(); /* Avoid out-of-order execution. */ |
155 |
ccs_profile_ptr[profile] = ptr; |
ccs_profile_ptr[profile] = ptr; |
156 |
entry = NULL; |
entry = NULL; |
172 |
char *data = head->write_buf; |
char *data = head->write_buf; |
173 |
unsigned int i; |
unsigned int i; |
174 |
unsigned int value; |
unsigned int value; |
175 |
|
int mode; |
176 |
char *cp; |
char *cp; |
177 |
struct ccs_profile *ccs_profile; |
struct ccs_profile *ccs_profile; |
178 |
i = simple_strtoul(data, &cp, 10); |
i = simple_strtoul(data, &cp, 10); |
200 |
spin_unlock(&ccs_profile_comment_lock); |
spin_unlock(&ccs_profile_comment_lock); |
201 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
202 |
ccs_put_name(old_comment); |
ccs_put_name(old_comment); |
|
ccs_profile_entry_used[0] = true; |
|
203 |
return 0; |
return 0; |
204 |
} |
} |
205 |
if (ccs_str_starts(&data, CCS_KEYWORD_MAC_FOR_CAPABILITY)) { |
for (mode = 0; mode < 4; mode++) { |
206 |
if (sscanf(cp + 1, "%u", &value) != 1) { |
if (strcmp(data, ccs_keyword_mode[mode])) |
207 |
for (i = 0; i < 4; i++) { |
continue; |
208 |
if (strcmp(cp + 1, ccs_mode_4[i])) |
cp++; |
209 |
|
while (1) { |
210 |
|
char *cp2 = strchr(cp, ' '); |
211 |
|
if (cp2) |
212 |
|
*cp2 = '\0'; |
213 |
|
for (i = 0; i < CCS_MAX_MAC_INDEX; i++) { |
214 |
|
if (strcmp(cp, ccs_mac_keywords[i])) |
215 |
continue; |
continue; |
216 |
value = i; |
ccs_profile->mac_mode[i] = mode; |
|
break; |
|
217 |
} |
} |
218 |
if (i == 4) |
if (!cp2) |
219 |
return -EINVAL; |
break; |
220 |
|
cp = cp2 + 1; |
221 |
} |
} |
222 |
if (value > 3) |
return 0; |
223 |
value = 3; |
} |
224 |
for (i = 0; i < CCS_MAX_CAPABILITY_INDEX; i++) { |
for (mode = 0; mode < 4; mode++) { |
225 |
if (strcmp(data, ccs_capability_control_keyword[i])) |
if (strcmp(data, ccs_keyword_capability_mode[mode])) |
226 |
continue; |
continue; |
227 |
ccs_profile->capability_value[i] = value; |
cp++; |
228 |
ccs_profile_entry_used[i + 1 + CCS_MAX_CONTROL_INDEX] |
while (1) { |
229 |
= true; |
char *cp2 = strchr(cp, ' '); |
230 |
return 0; |
if (cp2) |
231 |
|
*cp2 = '\0'; |
232 |
|
for (i = 0; i < CCS_MAX_CAPABILITY_INDEX; i++) { |
233 |
|
if (strcmp(cp, ccs_capability_list[i])) |
234 |
|
continue; |
235 |
|
ccs_profile->mac_capability_mode[i] = mode; |
236 |
|
} |
237 |
|
if (!cp2) |
238 |
|
break; |
239 |
|
cp = cp2 + 1; |
240 |
} |
} |
241 |
return -EINVAL; |
return 0; |
242 |
} |
} |
243 |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) { |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) { |
244 |
if (strcmp(data, ccs_control_array[i].keyword)) |
if (strcmp(data, ccs_control_array[i].keyword)) |
245 |
continue; |
continue; |
246 |
if (sscanf(cp + 1, "%u", &value) != 1) { |
if (sscanf(cp + 1, "%u", &value) != 1) { |
247 |
int j; |
int j; |
248 |
const char **modes; |
for (j = 0; j < 2; j++) { |
249 |
switch (i) { |
if (strcmp(cp + 1, ccs_mode_2[j])) |
|
case CCS_AUTOLEARN_EXEC_REALPATH: |
|
|
case CCS_AUTOLEARN_EXEC_ARGV0: |
|
|
case CCS_RESTRICT_AUTOBIND: |
|
|
case CCS_VERBOSE: |
|
|
modes = ccs_mode_2; |
|
|
break; |
|
|
default: |
|
|
modes = ccs_mode_4; |
|
|
break; |
|
|
} |
|
|
for (j = 0; j < 4; j++) { |
|
|
if (strcmp(cp + 1, modes[j])) |
|
250 |
continue; |
continue; |
251 |
value = j; |
value = j; |
252 |
break; |
break; |
257 |
value = ccs_control_array[i].max_value; |
value = ccs_control_array[i].max_value; |
258 |
} |
} |
259 |
ccs_profile->value[i] = value; |
ccs_profile->value[i] = value; |
|
ccs_profile_entry_used[i + 1] = true; |
|
260 |
return 0; |
return 0; |
261 |
} |
} |
262 |
return -EINVAL; |
return -EINVAL; |
263 |
} |
} |
264 |
|
|
265 |
|
static bool ccs_print_mac_mode(struct ccs_io_buffer *head, u8 index) |
266 |
|
{ |
267 |
|
const int pos = head->read_avail; |
268 |
|
int i; |
269 |
|
int mode; |
270 |
|
const struct ccs_profile *ccs_profile = ccs_profile_ptr[index]; |
271 |
|
for (mode = 0; mode < 4; mode++) { |
272 |
|
if (!ccs_io_printf(head, "%u-%s={", index, ccs_keyword_mode[mode])) |
273 |
|
goto out; |
274 |
|
for (i = 0; i < CCS_MAX_MAC_INDEX; i++) { |
275 |
|
if (ccs_profile->mac_mode[i] != mode) |
276 |
|
continue; |
277 |
|
if (!ccs_io_printf(head, " %s", ccs_mac_keywords[i])) |
278 |
|
goto out; |
279 |
|
} |
280 |
|
if (!ccs_io_printf(head, " }\n")) |
281 |
|
goto out; |
282 |
|
} |
283 |
|
return true; |
284 |
|
out: |
285 |
|
head->read_avail = pos; |
286 |
|
return false; |
287 |
|
} |
288 |
|
|
289 |
|
static bool ccs_print_capability_mode(struct ccs_io_buffer *head, u8 index) |
290 |
|
{ |
291 |
|
const int pos = head->read_avail; |
292 |
|
int i; |
293 |
|
int mode; |
294 |
|
const struct ccs_profile *ccs_profile = ccs_profile_ptr[index]; |
295 |
|
for (mode = 0; mode < 4; mode++) { |
296 |
|
if (!ccs_io_printf(head, "%u-%s={", index, ccs_keyword_capability_mode[mode])) |
297 |
|
goto out; |
298 |
|
for (i = 0; i < CCS_MAX_CAPABILITY_INDEX; i++) { |
299 |
|
if (ccs_profile->mac_capability_mode[i] != mode) |
300 |
|
continue; |
301 |
|
if (!ccs_io_printf(head, " %s", ccs_capability_list[i])) |
302 |
|
goto out; |
303 |
|
} |
304 |
|
if (!ccs_io_printf(head, " }\n")) |
305 |
|
goto out; |
306 |
|
} |
307 |
|
return true; |
308 |
|
out: |
309 |
|
head->read_avail = pos; |
310 |
|
return false; |
311 |
|
} |
312 |
|
|
313 |
/** |
/** |
314 |
* ccs_read_profile - Read profile table. |
* ccs_read_profile - Read profile table. |
315 |
* |
* |
319 |
*/ |
*/ |
320 |
static int ccs_read_profile(struct ccs_io_buffer *head) |
static int ccs_read_profile(struct ccs_io_buffer *head) |
321 |
{ |
{ |
322 |
static const int ccs_total |
static const int ccs_total = CCS_MAX_CONTROL_INDEX + 2; |
|
= CCS_MAX_CONTROL_INDEX + CCS_MAX_CAPABILITY_INDEX + 1; |
|
323 |
int step; |
int step; |
324 |
if (head->read_eof) |
if (head->read_eof) |
325 |
return 0; |
return 0; |
331 |
head->read_step = step; |
head->read_step = step; |
332 |
if (!ccs_profile) |
if (!ccs_profile) |
333 |
continue; |
continue; |
|
if (!ccs_profile_entry_used[type]) |
|
|
continue; |
|
334 |
if (!type) { /* Print profile' comment tag. */ |
if (!type) { /* Print profile' comment tag. */ |
335 |
bool done; |
bool done; |
336 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
343 |
if (!done) |
if (!done) |
344 |
break; |
break; |
345 |
continue; |
continue; |
346 |
} |
} else if (type == 1) { |
347 |
type--; |
if (!ccs_print_mac_mode(head, index)) |
348 |
if (type >= CCS_MAX_CONTROL_INDEX) { |
break; |
349 |
const int i = type - CCS_MAX_CONTROL_INDEX; |
continue; |
350 |
const u8 value = ccs_profile->capability_value[i]; |
} else if (type == 2) { |
351 |
if (!ccs_io_printf(head, |
if (!ccs_print_capability_mode(head, index)) |
|
"%u-" CCS_KEYWORD_MAC_FOR_CAPABILITY |
|
|
"%s=%s\n", index, |
|
|
ccs_capability_control_keyword[i], |
|
|
ccs_mode_4[value])) |
|
352 |
break; |
break; |
353 |
} else { |
continue; |
354 |
|
} |
355 |
|
type -= 3; |
356 |
|
{ |
357 |
const unsigned int value = ccs_profile->value[type]; |
const unsigned int value = ccs_profile->value[type]; |
|
const char **modes = NULL; |
|
358 |
const char *keyword = ccs_control_array[type].keyword; |
const char *keyword = ccs_control_array[type].keyword; |
359 |
switch (ccs_control_array[type].max_value) { |
if (ccs_control_array[type].max_value == 1) { |
|
case 3: |
|
|
modes = ccs_mode_4; |
|
|
break; |
|
|
case 1: |
|
|
modes = ccs_mode_2; |
|
|
break; |
|
|
} |
|
|
if (modes) { |
|
360 |
if (!ccs_io_printf(head, "%u-%s=%s\n", index, |
if (!ccs_io_printf(head, "%u-%s=%s\n", index, |
361 |
keyword, modes[value])) |
keyword, ccs_mode_2[value])) |
362 |
break; |
break; |
363 |
} else { |
} else { |
364 |
if (!ccs_io_printf(head, "%u-%s=%u\n", index, |
if (!ccs_io_printf(head, "%u-%s=%u\n", index, |
387 |
{ |
{ |
388 |
struct ccs_policy_manager_entry *entry = NULL; |
struct ccs_policy_manager_entry *entry = NULL; |
389 |
struct ccs_policy_manager_entry *ptr; |
struct ccs_policy_manager_entry *ptr; |
390 |
const struct ccs_path_info *saved_manager; |
struct ccs_policy_manager_entry e = { }; |
391 |
int error = is_delete ? -ENOENT : -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
|
bool is_domain = false; |
|
392 |
if (ccs_is_domain_def(manager)) { |
if (ccs_is_domain_def(manager)) { |
393 |
if (!ccs_is_correct_domain(manager)) |
if (!ccs_is_correct_domain(manager)) |
394 |
return -EINVAL; |
return -EINVAL; |
395 |
is_domain = true; |
e.is_domain = true; |
396 |
} else { |
} else { |
397 |
if (!ccs_is_correct_path(manager, 1, -1, -1)) |
if (!ccs_is_correct_path(manager, 1, -1, -1)) |
398 |
return -EINVAL; |
return -EINVAL; |
399 |
} |
} |
400 |
saved_manager = ccs_get_name(manager); |
e.manager = ccs_get_name(manager); |
401 |
if (!saved_manager) |
if (!e.manager) |
402 |
return -ENOMEM; |
return -ENOMEM; |
403 |
if (!is_delete) |
if (!is_delete) |
404 |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
entry = kmalloc(sizeof(e), GFP_KERNEL); |
405 |
mutex_lock(&ccs_policy_lock); |
mutex_lock(&ccs_policy_lock); |
406 |
list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) { |
list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) { |
407 |
if (ptr->manager != saved_manager) |
if (ptr->manager != e.manager) |
408 |
continue; |
continue; |
409 |
ptr->is_deleted = is_delete; |
ptr->is_deleted = is_delete; |
410 |
error = 0; |
error = 0; |
411 |
break; |
break; |
412 |
} |
} |
413 |
if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) { |
if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) { |
|
entry->manager = saved_manager; |
|
|
saved_manager = NULL; |
|
|
entry->is_domain = is_domain; |
|
414 |
list_add_tail_rcu(&entry->list, &ccs_policy_manager_list); |
list_add_tail_rcu(&entry->list, &ccs_policy_manager_list); |
415 |
entry = NULL; |
entry = NULL; |
416 |
error = 0; |
error = 0; |
417 |
} |
} |
418 |
mutex_unlock(&ccs_policy_lock); |
mutex_unlock(&ccs_policy_lock); |
419 |
ccs_put_name(saved_manager); |
ccs_put_name(e.manager); |
420 |
kfree(entry); |
kfree(entry); |
421 |
return error; |
return error; |
422 |
} |
} |
607 |
return true; |
return true; |
608 |
} |
} |
609 |
|
|
610 |
|
static int ccs_write_domain_policy2(char *data, struct ccs_domain_info *domain, |
611 |
|
struct ccs_condition *cond, |
612 |
|
const bool is_delete) |
613 |
|
{ |
614 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CAPABILITY)) |
615 |
|
return ccs_write_capability_policy(data, domain, cond, |
616 |
|
is_delete); |
617 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_NETWORK)) |
618 |
|
return ccs_write_network_policy(data, domain, cond, is_delete); |
619 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_SIGNAL)) |
620 |
|
return ccs_write_signal_policy(data, domain, cond, is_delete); |
621 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_ENV)) |
622 |
|
return ccs_write_env_policy(data, domain, cond, is_delete); |
623 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_MOUNT)) |
624 |
|
return ccs_write_mount_policy(data, domain, cond, is_delete); |
625 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_UNMOUNT)) |
626 |
|
return ccs_write_umount_policy(data, domain, cond, is_delete); |
627 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CHROOT)) |
628 |
|
return ccs_write_chroot_policy(data, domain, cond, is_delete); |
629 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_PIVOT_ROOT)) |
630 |
|
return ccs_write_pivot_root_policy(data, domain, cond, |
631 |
|
is_delete); |
632 |
|
return ccs_write_file_policy(data, domain, cond, is_delete); |
633 |
|
} |
634 |
|
|
635 |
/** |
/** |
636 |
* ccs_write_domain_policy - Write domain policy. |
* ccs_write_domain_policy - Write domain policy. |
637 |
* |
* |
692 |
if (!cond) |
if (!cond) |
693 |
return -EINVAL; |
return -EINVAL; |
694 |
} |
} |
695 |
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CAPABILITY)) |
error = ccs_write_domain_policy2(data, domain, cond, is_delete); |
|
error = ccs_write_capability_policy(data, domain, cond, |
|
|
is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_NETWORK)) |
|
|
error = ccs_write_network_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_SIGNAL)) |
|
|
error = ccs_write_signal_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_ENV)) |
|
|
error = ccs_write_env_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_MOUNT)) |
|
|
error = ccs_write_mount_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_UNMOUNT)) |
|
|
error = ccs_write_umount_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CHROOT)) |
|
|
error = ccs_write_chroot_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_PIVOT_ROOT)) |
|
|
error = ccs_write_pivot_root_policy(data, domain, cond, |
|
|
is_delete); |
|
|
else |
|
|
error = ccs_write_file_policy(data, domain, cond, is_delete); |
|
696 |
if (cond) |
if (cond) |
697 |
ccs_put_condition(cond); |
ccs_put_condition(cond); |
698 |
return error; |
return error; |
762 |
} |
} |
763 |
} |
} |
764 |
|
|
765 |
static bool ccs_print_number_union(struct ccs_io_buffer *head, |
bool ccs_print_number_union(struct ccs_io_buffer *head, |
766 |
const struct ccs_number_union *ptr) |
const struct ccs_number_union *ptr) |
767 |
{ |
{ |
768 |
return ccs_print_number_union_common(head, ptr, true); |
return ccs_print_number_union_common(head, ptr, true); |
769 |
} |
} |
886 |
} |
} |
887 |
|
|
888 |
/** |
/** |
889 |
* ccs_print_single_path_acl - Print a single path ACL entry. |
* ccs_print_path_acl - Print a single path ACL entry. |
890 |
* |
* |
891 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
892 |
* @ptr: Pointer to "struct ccs_single_path_acl_record". |
* @ptr: Pointer to "struct ccs_path_acl". |
893 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
894 |
* |
* |
895 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
896 |
*/ |
*/ |
897 |
static bool ccs_print_single_path_acl(struct ccs_io_buffer *head, |
static bool ccs_print_path_acl(struct ccs_io_buffer *head, |
898 |
struct ccs_single_path_acl_record *ptr, |
struct ccs_path_acl *ptr, |
899 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
900 |
{ |
{ |
901 |
int pos; |
int pos; |
902 |
u8 bit; |
u8 bit; |
903 |
const u16 perm = ptr->perm; |
const u16 perm = ptr->perm; |
904 |
for (bit = head->read_bit; bit < CCS_MAX_SINGLE_PATH_OPERATION; bit++) { |
for (bit = head->read_bit; bit < CCS_MAX_PATH_OPERATION; bit++) { |
|
const char *msg; |
|
905 |
if (!(perm & (1 << bit))) |
if (!(perm & (1 << bit))) |
906 |
continue; |
continue; |
907 |
if (head->read_execute_only && bit != CCS_TYPE_EXECUTE_ACL) |
if (head->read_execute_only && bit != CCS_TYPE_EXECUTE) |
908 |
continue; |
continue; |
909 |
/* Print "read/write" instead of "read" and "write". */ |
/* Print "read/write" instead of "read" and "write". */ |
910 |
if ((bit == CCS_TYPE_READ_ACL || bit == CCS_TYPE_WRITE_ACL) |
if ((bit == CCS_TYPE_READ || bit == CCS_TYPE_WRITE) |
911 |
&& (perm & (1 << CCS_TYPE_READ_WRITE_ACL))) |
&& (perm & (1 << CCS_TYPE_READ_WRITE))) |
912 |
continue; |
continue; |
|
msg = ccs_sp2keyword(bit); |
|
913 |
pos = head->read_avail; |
pos = head->read_avail; |
914 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", ccs_path2keyword(bit)) || |
915 |
!ccs_print_name_union(head, &ptr->name) || |
!ccs_print_name_union(head, &ptr->name) || |
916 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
917 |
goto out; |
head->read_bit = bit; |
918 |
|
head->read_avail = pos; |
919 |
|
return false; |
920 |
|
} |
921 |
} |
} |
922 |
head->read_bit = 0; |
head->read_bit = 0; |
923 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
924 |
} |
} |
925 |
|
|
926 |
/** |
/** |
927 |
* ccs_print_mkdev_acl - Print a mkdev ACL entry. |
* ccs_print_path_number_number_acl - Print a path_number_number ACL entry. |
928 |
* |
* |
929 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
930 |
* @ptr: Pointer to "struct ccs_mkdev_acl_record". |
* @ptr: Pointer to "struct ccs_path_number_number_acl". |
931 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
932 |
* |
* |
933 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
934 |
*/ |
*/ |
935 |
static bool ccs_print_mkdev_acl(struct ccs_io_buffer *head, |
static bool ccs_print_path_number_number_acl(struct ccs_io_buffer *head, |
936 |
struct ccs_mkdev_acl_record *ptr, |
struct ccs_path_number_number_acl *ptr, |
937 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
938 |
{ |
{ |
939 |
int pos; |
int pos; |
940 |
u8 bit; |
u8 bit; |
941 |
const u16 perm = ptr->perm; |
const u16 perm = ptr->perm; |
942 |
for (bit = head->read_bit; bit < CCS_MAX_MKDEV_OPERATION; bit++) { |
for (bit = head->read_bit; bit < CCS_MAX_PATH_NUMBER_NUMBER_OPERATION; |
943 |
const char *msg; |
bit++) { |
944 |
if (!(perm & (1 << bit))) |
if (!(perm & (1 << bit))) |
945 |
continue; |
continue; |
|
msg = ccs_mkdev2keyword(bit); |
|
946 |
pos = head->read_avail; |
pos = head->read_avail; |
947 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", |
948 |
|
ccs_path_number_number2keyword(bit)) || |
949 |
!ccs_print_name_union(head, &ptr->name) || |
!ccs_print_name_union(head, &ptr->name) || |
950 |
!ccs_print_number_union(head, &ptr->major) || |
!ccs_print_number_union(head, &ptr->major) || |
951 |
!ccs_print_number_union(head, &ptr->minor) || |
!ccs_print_number_union(head, &ptr->minor) || |
952 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
953 |
goto out; |
head->read_bit = bit; |
954 |
|
head->read_avail = pos; |
955 |
|
return false; |
956 |
|
} |
957 |
} |
} |
958 |
head->read_bit = 0; |
head->read_bit = 0; |
959 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
960 |
} |
} |
961 |
|
|
962 |
/** |
/** |
963 |
* ccs_print_double_path_acl - Print a double path ACL entry. |
* ccs_print_path_path_acl - Print a double path ACL entry. |
964 |
* |
* |
965 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
966 |
* @ptr: Pointer to "struct ccs_double_path_acl_record". |
* @ptr: Pointer to "struct ccs_path_path_acl". |
967 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
968 |
* |
* |
969 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
970 |
*/ |
*/ |
971 |
static bool ccs_print_double_path_acl(struct ccs_io_buffer *head, |
static bool ccs_print_path_path_acl(struct ccs_io_buffer *head, |
972 |
struct ccs_double_path_acl_record *ptr, |
struct ccs_path_path_acl *ptr, |
973 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
974 |
{ |
{ |
975 |
int pos; |
int pos; |
976 |
u8 bit; |
u8 bit; |
977 |
const u8 perm = ptr->perm; |
const u8 perm = ptr->perm; |
978 |
for (bit = head->read_bit; bit < CCS_MAX_DOUBLE_PATH_OPERATION; bit++) { |
for (bit = head->read_bit; bit < CCS_MAX_PATH_PATH_OPERATION; bit++) { |
|
const char *msg; |
|
979 |
if (!(perm & (1 << bit))) |
if (!(perm & (1 << bit))) |
980 |
continue; |
continue; |
|
msg = ccs_dp2keyword(bit); |
|
981 |
pos = head->read_avail; |
pos = head->read_avail; |
982 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", |
983 |
|
ccs_path_path2keyword(bit)) || |
984 |
!ccs_print_name_union(head, &ptr->name1) || |
!ccs_print_name_union(head, &ptr->name1) || |
985 |
!ccs_print_name_union(head, &ptr->name2) || |
!ccs_print_name_union(head, &ptr->name2) || |
986 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
987 |
goto out; |
head->read_bit = bit; |
988 |
|
head->read_avail = pos; |
989 |
|
return false; |
990 |
|
} |
991 |
} |
} |
992 |
head->read_bit = 0; |
head->read_bit = 0; |
993 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
994 |
} |
} |
995 |
|
|
996 |
/** |
/** |
997 |
* ccs_print_path_number_acl - Print an ioctl/chmod/chown/chgrp ACL entry. |
* ccs_print_path_number_acl - Print an ioctl/chmod/chown/chgrp ACL entry. |
998 |
* |
* |
999 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1000 |
* @ptr: Pointer to "struct ccs_path_number_acl_record". |
* @ptr: Pointer to "struct ccs_path_number_acl". |
1001 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1002 |
* |
* |
1003 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1004 |
*/ |
*/ |
1005 |
static bool ccs_print_path_number_acl(struct ccs_io_buffer *head, |
static bool ccs_print_path_number_acl(struct ccs_io_buffer *head, |
1006 |
struct ccs_path_number_acl_record *ptr, |
struct ccs_path_number_acl *ptr, |
1007 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1008 |
{ |
{ |
1009 |
int pos; |
int pos; |
1010 |
u8 bit; |
u8 bit; |
1011 |
const u8 perm = ptr->perm; |
const u8 perm = ptr->perm; |
1012 |
for (bit = head->read_bit; bit < CCS_MAX_PATH_NUMBER_OPERATION; bit++) { |
for (bit = head->read_bit; bit < CCS_MAX_PATH_NUMBER_OPERATION; |
1013 |
const char *msg; |
bit++) { |
1014 |
if (!(perm & (1 << bit))) |
if (!(perm & (1 << bit))) |
1015 |
continue; |
continue; |
|
msg = ccs_path_number2keyword(bit); |
|
1016 |
pos = head->read_avail; |
pos = head->read_avail; |
1017 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", |
1018 |
|
ccs_path_number2keyword(bit)) || |
1019 |
!ccs_print_name_union(head, &ptr->name) || |
!ccs_print_name_union(head, &ptr->name) || |
1020 |
!ccs_print_number_union(head, &ptr->number) || |
!ccs_print_number_union(head, &ptr->number) || |
1021 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
1022 |
goto out; |
head->read_bit = bit; |
1023 |
|
head->read_avail = pos; |
1024 |
|
return false; |
1025 |
|
} |
1026 |
} |
} |
1027 |
head->read_bit = 0; |
head->read_bit = 0; |
1028 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1029 |
} |
} |
1030 |
|
|
1031 |
/** |
/** |
1032 |
* ccs_print_env_acl - Print an evironment variable name's ACL entry. |
* ccs_print_env_acl - Print an evironment variable name's ACL entry. |
1033 |
* |
* |
1034 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1035 |
* @ptr: Pointer to "struct ccs_env_acl_record". |
* @ptr: Pointer to "struct ccs_env_acl". |
1036 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1037 |
* |
* |
1038 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1039 |
*/ |
*/ |
1040 |
static bool ccs_print_env_acl(struct ccs_io_buffer *head, |
static bool ccs_print_env_acl(struct ccs_io_buffer *head, |
1041 |
struct ccs_env_acl_record *ptr, |
struct ccs_env_acl *ptr, |
1042 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1043 |
{ |
{ |
1044 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1045 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_ENV "%s", ptr->env->name)) |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_ENV "%s", ptr->env->name) || |
1046 |
goto out; |
!ccs_print_condition(head, cond)) { |
1047 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1048 |
goto out; |
return false; |
1049 |
|
} |
1050 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1051 |
} |
} |
1052 |
|
|
1053 |
/** |
/** |
1054 |
* ccs_print_capability_acl - Print a capability ACL entry. |
* ccs_print_capability_acl - Print a capability ACL entry. |
1055 |
* |
* |
1056 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1057 |
* @ptr: Pointer to "struct ccs_capability_acl_record". |
* @ptr: Pointer to "struct ccs_capability_acl". |
1058 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1059 |
* |
* |
1060 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1061 |
*/ |
*/ |
1062 |
static bool ccs_print_capability_acl(struct ccs_io_buffer *head, |
static bool ccs_print_capability_acl(struct ccs_io_buffer *head, |
1063 |
struct ccs_capability_acl_record *ptr, |
struct ccs_capability_acl *ptr, |
1064 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1065 |
{ |
{ |
1066 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1067 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CAPABILITY "%s", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CAPABILITY "%s", |
1068 |
ccs_cap2keyword(ptr->operation))) |
ccs_cap2keyword(ptr->operation)) || |
1069 |
goto out; |
!ccs_print_condition(head, cond)) { |
1070 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1071 |
goto out; |
return false; |
1072 |
|
} |
1073 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1074 |
} |
} |
1075 |
|
|
1076 |
/** |
/** |
1077 |
* ccs_print_ipv4_entry - Print IPv4 address of a network ACL entry. |
* ccs_print_ipv4_entry - Print IPv4 address of a network ACL entry. |
1078 |
* |
* |
1079 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1080 |
* @ptr: Pointer to "struct ccs_ip_network_acl_record". |
* @ptr: Pointer to "struct ccs_ip_network_acl". |
1081 |
* |
* |
1082 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1083 |
*/ |
*/ |
1084 |
static bool ccs_print_ipv4_entry(struct ccs_io_buffer *head, |
static bool ccs_print_ipv4_entry(struct ccs_io_buffer *head, |
1085 |
struct ccs_ip_network_acl_record *ptr) |
struct ccs_ip_network_acl *ptr) |
1086 |
{ |
{ |
1087 |
const u32 min_address = ptr->address.ipv4.min; |
const u32 min_address = ptr->address.ipv4.min; |
1088 |
const u32 max_address = ptr->address.ipv4.max; |
const u32 max_address = ptr->address.ipv4.max; |
1098 |
* ccs_print_ipv6_entry - Print IPv6 address of a network ACL entry. |
* ccs_print_ipv6_entry - Print IPv6 address of a network ACL entry. |
1099 |
* |
* |
1100 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1101 |
* @ptr: Pointer to "struct ccs_ip_network_acl_record". |
* @ptr: Pointer to "struct ccs_ip_network_acl". |
1102 |
* |
* |
1103 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1104 |
*/ |
*/ |
1105 |
static bool ccs_print_ipv6_entry(struct ccs_io_buffer *head, |
static bool ccs_print_ipv6_entry(struct ccs_io_buffer *head, |
1106 |
struct ccs_ip_network_acl_record *ptr) |
struct ccs_ip_network_acl *ptr) |
1107 |
{ |
{ |
1108 |
char buf[64]; |
char buf[64]; |
1109 |
const struct in6_addr *min_address = ptr->address.ipv6.min; |
const struct in6_addr *min_address = ptr->address.ipv6.min; |
1123 |
* ccs_print_network_acl - Print a network ACL entry. |
* ccs_print_network_acl - Print a network ACL entry. |
1124 |
* |
* |
1125 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1126 |
* @ptr: Pointer to "struct ccs_ip_network_acl_record". |
* @ptr: Pointer to "struct ccs_ip_network_acl". |
1127 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1128 |
* |
* |
1129 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1130 |
*/ |
*/ |
1131 |
static bool ccs_print_network_acl(struct ccs_io_buffer *head, |
static bool ccs_print_network_acl(struct ccs_io_buffer *head, |
1132 |
struct ccs_ip_network_acl_record *ptr, |
struct ccs_ip_network_acl *ptr, |
1133 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1134 |
{ |
{ |
1135 |
int pos = head->read_avail; |
int pos; |
1136 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_NETWORK "%s ", |
u8 bit; |
1137 |
ccs_net2keyword(ptr->operation_type))) |
const u16 perm = ptr->perm; |
1138 |
goto out; |
for (bit = head->read_bit; bit < CCS_MAX_NETWORK_OPERATION; bit++) { |
1139 |
switch (ptr->record_type) { |
if (!(perm & (1 << bit))) |
1140 |
case CCS_IP_RECORD_TYPE_ADDRESS_GROUP: |
continue; |
1141 |
if (!ccs_io_printf(head, "@%s", |
pos = head->read_avail; |
1142 |
ptr->address.group->group_name->name)) |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_NETWORK "%s ", |
1143 |
goto out; |
ccs_net2keyword(bit))) |
|
break; |
|
|
case CCS_IP_RECORD_TYPE_IPv4: |
|
|
if (!ccs_print_ipv4_entry(head, ptr)) |
|
1144 |
goto out; |
goto out; |
1145 |
break; |
switch (ptr->address_type) { |
1146 |
case CCS_IP_RECORD_TYPE_IPv6: |
case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP: |
1147 |
if (!ccs_print_ipv6_entry(head, ptr)) |
if (!ccs_io_printf(head, "@%s", ptr->address.group-> |
1148 |
|
group_name->name)) |
1149 |
|
goto out; |
1150 |
|
break; |
1151 |
|
case CCS_IP_ADDRESS_TYPE_IPv4: |
1152 |
|
if (!ccs_print_ipv4_entry(head, ptr)) |
1153 |
|
goto out; |
1154 |
|
break; |
1155 |
|
case CCS_IP_ADDRESS_TYPE_IPv6: |
1156 |
|
if (!ccs_print_ipv6_entry(head, ptr)) |
1157 |
|
goto out; |
1158 |
|
break; |
1159 |
|
} |
1160 |
|
if (!ccs_print_number_union(head, &ptr->port) || |
1161 |
|
!ccs_print_condition(head, cond)) |
1162 |
goto out; |
goto out; |
|
break; |
|
1163 |
} |
} |
1164 |
if (!ccs_print_number_union(head, &ptr->port) || |
head->read_bit = 0; |
|
!ccs_print_condition(head, cond)) |
|
|
goto out; |
|
1165 |
return true; |
return true; |
1166 |
out: |
out: |
1167 |
|
head->read_bit = bit; |
1168 |
head->read_avail = pos; |
head->read_avail = pos; |
1169 |
return false; |
return false; |
1170 |
} |
} |
1173 |
* ccs_print_signal_acl - Print a signal ACL entry. |
* ccs_print_signal_acl - Print a signal ACL entry. |
1174 |
* |
* |
1175 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1176 |
* @ptr: Pointer to "struct signale_acl_record". |
* @ptr: Pointer to "struct signale_acl". |
1177 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1178 |
* |
* |
1179 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1180 |
*/ |
*/ |
1181 |
static bool ccs_print_signal_acl(struct ccs_io_buffer *head, |
static bool ccs_print_signal_acl(struct ccs_io_buffer *head, |
1182 |
struct ccs_signal_acl_record *ptr, |
struct ccs_signal_acl *ptr, |
1183 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1184 |
{ |
{ |
1185 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1186 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_SIGNAL "%u %s", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_SIGNAL "%u %s", |
1187 |
ptr->sig, ptr->domainname->name)) |
ptr->sig, ptr->domainname->name) || |
1188 |
goto out; |
!ccs_print_condition(head, cond)) { |
1189 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1190 |
goto out; |
return false; |
1191 |
|
} |
1192 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1193 |
} |
} |
1194 |
|
|
1195 |
/** |
/** |
1213 |
* ccs_print_mount_acl - Print a mount ACL entry. |
* ccs_print_mount_acl - Print a mount ACL entry. |
1214 |
* |
* |
1215 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1216 |
* @ptr: Pointer to "struct ccs_mount_acl_record". |
* @ptr: Pointer to "struct ccs_mount_acl". |
1217 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1218 |
* |
* |
1219 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1220 |
*/ |
*/ |
1221 |
static bool ccs_print_mount_acl(struct ccs_io_buffer *head, |
static bool ccs_print_mount_acl(struct ccs_io_buffer *head, |
1222 |
struct ccs_mount_acl_record *ptr, |
struct ccs_mount_acl *ptr, |
1223 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1224 |
{ |
{ |
1225 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1226 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_MOUNT) || |
1227 |
ptr->dev_name->name, ptr->dir_name->name, |
!ccs_print_name_union(head, &ptr->dev_name) || |
1228 |
ptr->fs_type->name, ptr->flags)) |
!ccs_print_name_union(head, &ptr->dir_name) || |
1229 |
goto out; |
!ccs_print_name_union(head, &ptr->fs_type) || |
1230 |
if (!ccs_print_condition(head, cond)) |
!ccs_print_number_union(head, &ptr->flags) || |
1231 |
goto out; |
!ccs_print_condition(head, cond)) { |
1232 |
|
head->read_avail = pos; |
1233 |
|
return false; |
1234 |
|
} |
1235 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1236 |
} |
} |
1237 |
|
|
1238 |
/** |
/** |
1239 |
* ccs_print_umount_acl - Print a mount ACL entry. |
* ccs_print_umount_acl - Print a mount ACL entry. |
1240 |
* |
* |
1241 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1242 |
* @ptr: Pointer to "struct ccs_umount_acl_record". |
* @ptr: Pointer to "struct ccs_umount_acl". |
1243 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1244 |
* |
* |
1245 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1246 |
*/ |
*/ |
1247 |
static bool ccs_print_umount_acl(struct ccs_io_buffer *head, |
static bool ccs_print_umount_acl(struct ccs_io_buffer *head, |
1248 |
struct ccs_umount_acl_record *ptr, |
struct ccs_umount_acl *ptr, |
1249 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1250 |
{ |
{ |
1251 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1252 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_UNMOUNT "%s\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_UNMOUNT) || |
1253 |
ptr->dir->name)) |
!ccs_print_name_union(head, &ptr->dir) || |
1254 |
goto out; |
!ccs_print_condition(head, cond)) { |
1255 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1256 |
goto out; |
return false; |
1257 |
|
} |
1258 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1259 |
} |
} |
1260 |
|
|
1261 |
/** |
/** |
1262 |
* ccs_print_chroot_acl - Print a chroot ACL entry. |
* ccs_print_chroot_acl - Print a chroot ACL entry. |
1263 |
* |
* |
1264 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1265 |
* @ptr: Pointer to "struct ccs_chroot_acl_record". |
* @ptr: Pointer to "struct ccs_chroot_acl". |
1266 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1267 |
* |
* |
1268 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1269 |
*/ |
*/ |
1270 |
static bool ccs_print_chroot_acl(struct ccs_io_buffer *head, |
static bool ccs_print_chroot_acl(struct ccs_io_buffer *head, |
1271 |
struct ccs_chroot_acl_record *ptr, |
struct ccs_chroot_acl *ptr, |
1272 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1273 |
{ |
{ |
1274 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1275 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CHROOT "%s\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CHROOT) || |
1276 |
ptr->dir->name)) |
!ccs_print_name_union(head, &ptr->dir) || |
1277 |
goto out; |
!ccs_print_condition(head, cond)) { |
1278 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1279 |
goto out; |
return false; |
1280 |
|
} |
1281 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1282 |
} |
} |
1283 |
|
|
1284 |
/** |
/** |
1285 |
* ccs_print_pivot_root_acl - Print a pivot_root ACL entry. |
* ccs_print_pivot_root_acl - Print a pivot_root ACL entry. |
1286 |
* |
* |
1287 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1288 |
* @ptr: Pointer to "struct ccs_pivot_root_acl_record". |
* @ptr: Pointer to "struct ccs_pivot_root_acl". |
1289 |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1290 |
* |
* |
1291 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1292 |
*/ |
*/ |
1293 |
static bool ccs_print_pivot_root_acl(struct ccs_io_buffer *head, |
static bool ccs_print_pivot_root_acl(struct ccs_io_buffer *head, |
1294 |
struct ccs_pivot_root_acl_record *ptr, |
struct ccs_pivot_root_acl *ptr, |
1295 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1296 |
{ |
{ |
1297 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1298 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_PIVOT_ROOT "%s %s\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_PIVOT_ROOT) || |
1299 |
ptr->new_root->name, ptr->old_root->name)) |
!ccs_print_name_union(head, &ptr->new_root) || |
1300 |
goto out; |
!ccs_print_name_union(head, &ptr->old_root) || |
1301 |
if (!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
1302 |
goto out; |
head->read_avail = pos; |
1303 |
|
return false; |
1304 |
|
} |
1305 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1306 |
} |
} |
1307 |
|
|
1308 |
/** |
/** |
1317 |
struct ccs_acl_info *ptr) |
struct ccs_acl_info *ptr) |
1318 |
{ |
{ |
1319 |
const struct ccs_condition *cond = ptr->cond; |
const struct ccs_condition *cond = ptr->cond; |
1320 |
const u8 acl_type = ccs_acl_type2(ptr); |
const u8 acl_type = ptr->type; |
1321 |
if (acl_type & CCS_ACL_DELETED) |
if (ptr->is_deleted) |
1322 |
return true; |
return true; |
1323 |
if (acl_type == CCS_TYPE_SINGLE_PATH_ACL) { |
if (acl_type == CCS_TYPE_PATH_ACL) { |
1324 |
struct ccs_single_path_acl_record *acl |
struct ccs_path_acl *acl |
1325 |
= container_of(ptr, struct ccs_single_path_acl_record, |
= container_of(ptr, struct ccs_path_acl, |
1326 |
head); |
head); |
1327 |
return ccs_print_single_path_acl(head, acl, cond); |
return ccs_print_path_acl(head, acl, cond); |
1328 |
} |
} |
1329 |
if (acl_type == CCS_TYPE_EXECUTE_HANDLER) { |
if (acl_type == CCS_TYPE_EXECUTE_HANDLER) { |
1330 |
struct ccs_execute_handler_record *acl |
struct ccs_execute_handler_record *acl |
1342 |
} |
} |
1343 |
if (head->read_execute_only) |
if (head->read_execute_only) |
1344 |
return true; |
return true; |
1345 |
if (acl_type == CCS_TYPE_MKDEV_ACL) { |
if (acl_type == CCS_TYPE_PATH_NUMBER_NUMBER_ACL) { |
1346 |
struct ccs_mkdev_acl_record *acl |
struct ccs_path_number_number_acl *acl |
1347 |
= container_of(ptr, struct ccs_mkdev_acl_record, head); |
= container_of(ptr, struct ccs_path_number_number_acl, head); |
1348 |
return ccs_print_mkdev_acl(head, acl, cond); |
return ccs_print_path_number_number_acl(head, acl, cond); |
1349 |
} |
} |
1350 |
if (acl_type == CCS_TYPE_DOUBLE_PATH_ACL) { |
if (acl_type == CCS_TYPE_PATH_PATH_ACL) { |
1351 |
struct ccs_double_path_acl_record *acl |
struct ccs_path_path_acl *acl |
1352 |
= container_of(ptr, struct ccs_double_path_acl_record, |
= container_of(ptr, struct ccs_path_path_acl, |
1353 |
head); |
head); |
1354 |
return ccs_print_double_path_acl(head, acl, cond); |
return ccs_print_path_path_acl(head, acl, cond); |
1355 |
} |
} |
1356 |
if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) { |
if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) { |
1357 |
struct ccs_path_number_acl_record *acl |
struct ccs_path_number_acl *acl |
1358 |
= container_of(ptr, struct ccs_path_number_acl_record, |
= container_of(ptr, struct ccs_path_number_acl, |
1359 |
head); |
head); |
1360 |
return ccs_print_path_number_acl(head, acl, cond); |
return ccs_print_path_number_acl(head, acl, cond); |
1361 |
} |
} |
1362 |
if (acl_type == CCS_TYPE_ENV_ACL) { |
if (acl_type == CCS_TYPE_ENV_ACL) { |
1363 |
struct ccs_env_acl_record *acl |
struct ccs_env_acl *acl |
1364 |
= container_of(ptr, struct ccs_env_acl_record, head); |
= container_of(ptr, struct ccs_env_acl, head); |
1365 |
return ccs_print_env_acl(head, acl, cond); |
return ccs_print_env_acl(head, acl, cond); |
1366 |
} |
} |
1367 |
if (acl_type == CCS_TYPE_CAPABILITY_ACL) { |
if (acl_type == CCS_TYPE_CAPABILITY_ACL) { |
1368 |
struct ccs_capability_acl_record *acl |
struct ccs_capability_acl *acl |
1369 |
= container_of(ptr, struct ccs_capability_acl_record, |
= container_of(ptr, struct ccs_capability_acl, |
1370 |
head); |
head); |
1371 |
return ccs_print_capability_acl(head, acl, cond); |
return ccs_print_capability_acl(head, acl, cond); |
1372 |
} |
} |
1373 |
if (acl_type == CCS_TYPE_IP_NETWORK_ACL) { |
if (acl_type == CCS_TYPE_IP_NETWORK_ACL) { |
1374 |
struct ccs_ip_network_acl_record *acl |
struct ccs_ip_network_acl *acl |
1375 |
= container_of(ptr, struct ccs_ip_network_acl_record, |
= container_of(ptr, struct ccs_ip_network_acl, |
1376 |
head); |
head); |
1377 |
return ccs_print_network_acl(head, acl, cond); |
return ccs_print_network_acl(head, acl, cond); |
1378 |
} |
} |
1379 |
if (acl_type == CCS_TYPE_SIGNAL_ACL) { |
if (acl_type == CCS_TYPE_SIGNAL_ACL) { |
1380 |
struct ccs_signal_acl_record *acl |
struct ccs_signal_acl *acl |
1381 |
= container_of(ptr, struct ccs_signal_acl_record, head); |
= container_of(ptr, struct ccs_signal_acl, head); |
1382 |
return ccs_print_signal_acl(head, acl, cond); |
return ccs_print_signal_acl(head, acl, cond); |
1383 |
} |
} |
1384 |
if (acl_type == CCS_TYPE_MOUNT_ACL) { |
if (acl_type == CCS_TYPE_MOUNT_ACL) { |
1385 |
struct ccs_mount_acl_record *acl |
struct ccs_mount_acl *acl |
1386 |
= container_of(ptr, struct ccs_mount_acl_record, head); |
= container_of(ptr, struct ccs_mount_acl, head); |
1387 |
return ccs_print_mount_acl(head, acl, cond); |
return ccs_print_mount_acl(head, acl, cond); |
1388 |
} |
} |
1389 |
if (acl_type == CCS_TYPE_UMOUNT_ACL) { |
if (acl_type == CCS_TYPE_UMOUNT_ACL) { |
1390 |
struct ccs_umount_acl_record *acl |
struct ccs_umount_acl *acl |
1391 |
= container_of(ptr, struct ccs_umount_acl_record, head); |
= container_of(ptr, struct ccs_umount_acl, head); |
1392 |
return ccs_print_umount_acl(head, acl, cond); |
return ccs_print_umount_acl(head, acl, cond); |
1393 |
} |
} |
1394 |
if (acl_type == CCS_TYPE_CHROOT_ACL) { |
if (acl_type == CCS_TYPE_CHROOT_ACL) { |
1395 |
struct ccs_chroot_acl_record *acl |
struct ccs_chroot_acl *acl |
1396 |
= container_of(ptr, struct ccs_chroot_acl_record, head); |
= container_of(ptr, struct ccs_chroot_acl, head); |
1397 |
return ccs_print_chroot_acl(head, acl, cond); |
return ccs_print_chroot_acl(head, acl, cond); |
1398 |
} |
} |
1399 |
if (acl_type == CCS_TYPE_PIVOT_ROOT_ACL) { |
if (acl_type == CCS_TYPE_PIVOT_ROOT_ACL) { |
1400 |
struct ccs_pivot_root_acl_record *acl |
struct ccs_pivot_root_acl *acl |
1401 |
= container_of(ptr, struct ccs_pivot_root_acl_record, |
= container_of(ptr, struct ccs_pivot_root_acl, |
1402 |
head); |
head); |
1403 |
return ccs_print_pivot_root_acl(head, acl, cond); |
return ccs_print_pivot_root_acl(head, acl, cond); |
1404 |
} |
} |
|
/* Workaround for gcc 3.2.2's inline bug. */ |
|
|
if (acl_type & CCS_ACL_DELETED) |
|
|
return true; |
|
1405 |
BUG(); /* This must not happen. */ |
BUG(); /* This must not happen. */ |
1406 |
return false; |
return false; |
1407 |
} |
} |
1738 |
return 0; |
return 0; |
1739 |
} |
} |
1740 |
|
|
1741 |
|
/** |
1742 |
|
* ccs_get_argv0 - Get argv[0]. |
1743 |
|
* |
1744 |
|
* @ee: Pointer to "struct ccs_execve_entry". |
1745 |
|
* |
1746 |
|
* Returns true on success, false otherwise. |
1747 |
|
*/ |
1748 |
|
static bool ccs_get_argv0(struct ccs_execve_entry *ee) |
1749 |
|
{ |
1750 |
|
struct linux_binprm *bprm = ee->bprm; |
1751 |
|
char *arg_ptr = ee->tmp; |
1752 |
|
int arg_len = 0; |
1753 |
|
unsigned long pos = bprm->p; |
1754 |
|
int offset = pos % PAGE_SIZE; |
1755 |
|
bool done = false; |
1756 |
|
if (!bprm->argc) |
1757 |
|
goto out; |
1758 |
|
while (1) { |
1759 |
|
if (!ccs_dump_page(bprm, pos, &ee->dump)) |
1760 |
|
goto out; |
1761 |
|
pos += PAGE_SIZE - offset; |
1762 |
|
/* Read. */ |
1763 |
|
while (offset < PAGE_SIZE) { |
1764 |
|
const char *kaddr = ee->dump.data; |
1765 |
|
const unsigned char c = kaddr[offset++]; |
1766 |
|
if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) { |
1767 |
|
if (c == '\\') { |
1768 |
|
arg_ptr[arg_len++] = '\\'; |
1769 |
|
arg_ptr[arg_len++] = '\\'; |
1770 |
|
} else if (c == '/') { |
1771 |
|
arg_len = 0; |
1772 |
|
} else if (c > ' ' && c < 127) { |
1773 |
|
arg_ptr[arg_len++] = c; |
1774 |
|
} else { |
1775 |
|
arg_ptr[arg_len++] = '\\'; |
1776 |
|
arg_ptr[arg_len++] = (c >> 6) + '0'; |
1777 |
|
arg_ptr[arg_len++] |
1778 |
|
= ((c >> 3) & 7) + '0'; |
1779 |
|
arg_ptr[arg_len++] = (c & 7) + '0'; |
1780 |
|
} |
1781 |
|
} else { |
1782 |
|
arg_ptr[arg_len] = '\0'; |
1783 |
|
done = true; |
1784 |
|
break; |
1785 |
|
} |
1786 |
|
} |
1787 |
|
offset = 0; |
1788 |
|
if (done) |
1789 |
|
break; |
1790 |
|
} |
1791 |
|
return true; |
1792 |
|
out: |
1793 |
|
return false; |
1794 |
|
} |
1795 |
|
|
1796 |
|
static struct ccs_condition *ccs_get_execute_condition(struct ccs_execve_entry |
1797 |
|
*ee) |
1798 |
|
{ |
1799 |
|
struct ccs_condition *cond; |
1800 |
|
char *buf; |
1801 |
|
int len = 256; |
1802 |
|
char *realpath = NULL; |
1803 |
|
char *argv0 = NULL; |
1804 |
|
if (ccs_check_flags(NULL, CCS_AUTOLEARN_EXEC_REALPATH)) { |
1805 |
|
struct file *file = ee->bprm->file; |
1806 |
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
1807 |
|
struct path path = { file->f_vfsmnt, file->f_dentry }; |
1808 |
|
realpath = ccs_realpath_from_path(&path); |
1809 |
|
#else |
1810 |
|
realpath = ccs_realpath_from_path(&file->f_path); |
1811 |
|
#endif |
1812 |
|
if (realpath) |
1813 |
|
len += strlen(realpath) + 17; |
1814 |
|
} |
1815 |
|
if (ccs_check_flags(NULL, CCS_AUTOLEARN_EXEC_REALPATH)) { |
1816 |
|
if (ccs_get_argv0(ee)) { |
1817 |
|
argv0 = ee->tmp; |
1818 |
|
len += strlen(argv0) + 16; |
1819 |
|
} |
1820 |
|
} |
1821 |
|
buf = kmalloc(len, GFP_KERNEL); |
1822 |
|
if (!buf) |
1823 |
|
return NULL; |
1824 |
|
snprintf(buf, len - 1, "if"); |
1825 |
|
if (current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER) { |
1826 |
|
const int pos = strlen(buf); |
1827 |
|
snprintf(buf + pos, len - pos - 1, |
1828 |
|
" task.type=execute_handler"); |
1829 |
|
} |
1830 |
|
if (realpath) { |
1831 |
|
const int pos = strlen(buf); |
1832 |
|
snprintf(buf + pos, len - pos - 1, " exec.realpath=\"%s\"", |
1833 |
|
realpath); |
1834 |
|
kfree(realpath); |
1835 |
|
} |
1836 |
|
if (argv0) { |
1837 |
|
const int pos = strlen(buf); |
1838 |
|
snprintf(buf + pos, len - pos - 1, " exec.argv[0]=\"%s\"", |
1839 |
|
argv0); |
1840 |
|
} |
1841 |
|
cond = ccs_get_condition(buf); |
1842 |
|
kfree(buf); |
1843 |
|
return cond; |
1844 |
|
} |
1845 |
|
|
1846 |
/* Wait queue for ccs_query_list. */ |
/* Wait queue for ccs_query_list. */ |
1847 |
static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait); |
static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait); |
1848 |
|
|
1874 |
* Returns 0 if the supervisor decided to permit the access request which |
* Returns 0 if the supervisor decided to permit the access request which |
1875 |
* violated the policy in enforcing mode, 1 if the supervisor decided to |
* violated the policy in enforcing mode, 1 if the supervisor decided to |
1876 |
* retry the access request which violated the policy in enforcing mode, |
* retry the access request which violated the policy in enforcing mode, |
1877 |
* -EPERM otherwise. |
* 0 if it is not in enforcing mode, -EPERM otherwise. |
1878 |
*/ |
*/ |
1879 |
int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
1880 |
{ |
{ |
1888 |
char *header; |
char *header; |
1889 |
if (!r->domain) |
if (!r->domain) |
1890 |
r->domain = ccs_current_domain(); |
r->domain = ccs_current_domain(); |
1891 |
|
switch (r->mode) { |
1892 |
|
char *buffer; |
1893 |
|
struct ccs_condition *cond; |
1894 |
|
case 1: |
1895 |
|
if (!ccs_domain_quota_ok(r)) |
1896 |
|
return 0; |
1897 |
|
va_start(args, fmt); |
1898 |
|
len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; |
1899 |
|
va_end(args); |
1900 |
|
buffer = kmalloc(len, GFP_KERNEL); |
1901 |
|
if (!buffer) |
1902 |
|
return 0; |
1903 |
|
va_start(args, fmt); |
1904 |
|
vsnprintf(buffer, len - 1, fmt, args); |
1905 |
|
va_end(args); |
1906 |
|
ccs_normalize_line(buffer); |
1907 |
|
if (r->ee && !strncmp(buffer, "allow_execute ", 14)) |
1908 |
|
cond = ccs_get_execute_condition(r->ee); |
1909 |
|
else if ((current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)) { |
1910 |
|
char str[] = "if task.type=execute_handler"; |
1911 |
|
cond = ccs_get_condition(str); |
1912 |
|
} else |
1913 |
|
cond = NULL; |
1914 |
|
ccs_write_domain_policy2(buffer, r->domain, cond, false); |
1915 |
|
ccs_put_condition(cond); |
1916 |
|
kfree(buffer); |
1917 |
|
/* fall through */ |
1918 |
|
case 2: |
1919 |
|
return 0; |
1920 |
|
} |
1921 |
if (!atomic_read(&ccs_query_observers)) { |
if (!atomic_read(&ccs_query_observers)) { |
1922 |
int i; |
int i; |
1923 |
if (current->ccs_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) |
if (current->ccs_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) |
1938 |
ccs_query_entry = kzalloc(sizeof(*ccs_query_entry), GFP_KERNEL); |
ccs_query_entry = kzalloc(sizeof(*ccs_query_entry), GFP_KERNEL); |
1939 |
if (!ccs_query_entry) |
if (!ccs_query_entry) |
1940 |
goto out; |
goto out; |
1941 |
|
len = ccs_round2(len); |
1942 |
ccs_query_entry->query = kzalloc(len, GFP_KERNEL); |
ccs_query_entry->query = kzalloc(len, GFP_KERNEL); |
1943 |
if (!ccs_query_entry->query) |
if (!ccs_query_entry->query) |
1944 |
goto out; |
goto out; |