1 |
/* |
/* |
2 |
* fs/ccs_common.c |
* fs/ccsecurity/util.c |
|
* |
|
|
* Common functions for SAKURA and TOMOYO. |
|
3 |
* |
* |
4 |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
5 |
* |
* |
6 |
* Version: 1.6.7-rc 2009/03/18 |
* Version: 1.7.0-pre 2009/07/03 |
7 |
* |
* |
8 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
9 |
* See README.ccs for ChangeLog. |
* See README.ccs for ChangeLog. |
29 |
#else |
#else |
30 |
static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE; |
static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE; |
31 |
#endif |
#endif |
|
#include <linux/realpath.h> |
|
|
#include <linux/ccs_common.h> |
|
|
#include <linux/ccs_proc.h> |
|
|
#include <linux/tomoyo.h> |
|
32 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) |
33 |
#include <linux/unistd.h> |
#include <linux/unistd.h> |
34 |
#endif |
#endif |
35 |
|
#include "internal.h" |
36 |
|
#include <linux/ccsecurity.h> |
37 |
|
|
38 |
/* To support PID namespace. */ |
/* To support PID namespace. */ |
39 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) |
41 |
#endif |
#endif |
42 |
|
|
43 |
/* Set default specified by the kernel config. */ |
/* Set default specified by the kernel config. */ |
44 |
#ifdef CONFIG_TOMOYO |
#define MAX_ACCEPT_ENTRY (CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY) |
45 |
#define MAX_ACCEPT_ENTRY (CONFIG_TOMOYO_MAX_ACCEPT_ENTRY) |
#define MAX_GRANT_LOG (CONFIG_CCSECURITY_MAX_GRANT_LOG) |
46 |
#define MAX_GRANT_LOG (CONFIG_TOMOYO_MAX_GRANT_LOG) |
#define MAX_REJECT_LOG (CONFIG_CCSECURITY_MAX_REJECT_LOG) |
47 |
#define MAX_REJECT_LOG (CONFIG_TOMOYO_MAX_REJECT_LOG) |
|
48 |
#else |
DEFINE_MUTEX(ccs_policy_lock); |
|
#define MAX_ACCEPT_ENTRY 0 |
|
|
#define MAX_GRANT_LOG 0 |
|
|
#define MAX_REJECT_LOG 0 |
|
|
#endif |
|
49 |
|
|
50 |
/* Has /sbin/init started? */ |
/* Has /sbin/init started? */ |
51 |
bool ccs_policy_loaded; |
bool ccs_policy_loaded; |
52 |
|
|
|
/* Log level for SAKURA's printk(). */ |
|
|
const char *ccs_log_level = KERN_DEBUG; |
|
|
|
|
53 |
/* String table for functionality that takes 4 modes. */ |
/* String table for functionality that takes 4 modes. */ |
54 |
static const char *ccs_mode_4[4] = { |
static const char *ccs_mode_4[4] = { |
55 |
"disabled", "learning", "permissive", "enforcing" |
"disabled", "learning", "permissive", "enforcing" |
71 |
[CCS_MAC_FOR_ENV] = { "MAC_FOR_ENV", 0, 3 }, |
[CCS_MAC_FOR_ENV] = { "MAC_FOR_ENV", 0, 3 }, |
72 |
[CCS_MAC_FOR_NETWORK] = { "MAC_FOR_NETWORK", 0, 3 }, |
[CCS_MAC_FOR_NETWORK] = { "MAC_FOR_NETWORK", 0, 3 }, |
73 |
[CCS_MAC_FOR_SIGNAL] = { "MAC_FOR_SIGNAL", 0, 3 }, |
[CCS_MAC_FOR_SIGNAL] = { "MAC_FOR_SIGNAL", 0, 3 }, |
74 |
[CCS_DENY_CONCEAL_MOUNT] = { "DENY_CONCEAL_MOUNT", 0, 3 }, |
[CCS_MAC_FOR_NAMESPACE] = { "MAC_FOR_NAMESPACE", 0, 3 }, |
|
[CCS_RESTRICT_CHROOT] = { "RESTRICT_CHROOT", 0, 3 }, |
|
|
[CCS_RESTRICT_MOUNT] = { "RESTRICT_MOUNT", 0, 3 }, |
|
|
[CCS_RESTRICT_UNMOUNT] = { "RESTRICT_UNMOUNT", 0, 3 }, |
|
|
[CCS_RESTRICT_PIVOT_ROOT] = { "RESTRICT_PIVOT_ROOT", 0, 3 }, |
|
75 |
[CCS_RESTRICT_AUTOBIND] = { "RESTRICT_AUTOBIND", 0, 1 }, |
[CCS_RESTRICT_AUTOBIND] = { "RESTRICT_AUTOBIND", 0, 1 }, |
76 |
[CCS_MAX_ACCEPT_ENTRY] |
[CCS_MAX_ACCEPT_ENTRY] |
77 |
= { "MAX_ACCEPT_ENTRY", MAX_ACCEPT_ENTRY, INT_MAX }, |
= { "MAX_ACCEPT_ENTRY", MAX_ACCEPT_ENTRY, INT_MAX }, |
78 |
#ifdef CONFIG_TOMOYO_AUDIT |
#ifdef CONFIG_CCSECURITY_AUDIT |
79 |
[CCS_MAX_GRANT_LOG] |
[CCS_MAX_GRANT_LOG] |
80 |
= { "MAX_GRANT_LOG", MAX_GRANT_LOG, INT_MAX }, |
= { "MAX_GRANT_LOG", MAX_GRANT_LOG, INT_MAX }, |
81 |
[CCS_MAX_REJECT_LOG] |
[CCS_MAX_REJECT_LOG] |
86 |
= { "SLEEP_PERIOD", 0, 3000 }, /* in 0.1 second */ |
= { "SLEEP_PERIOD", 0, 3000 }, /* in 0.1 second */ |
87 |
}; |
}; |
88 |
|
|
|
#ifdef CONFIG_TOMOYO |
|
89 |
/* Capability name used by domain policy. */ |
/* Capability name used by domain policy. */ |
90 |
static const char *ccs_capability_control_keyword[CCS_MAX_CAPABILITY_INDEX] |
static const char *ccs_capability_control_keyword[CCS_MAX_CAPABILITY_INDEX] |
91 |
= { |
= { |
120 |
[CCS_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD", |
[CCS_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD", |
121 |
[CCS_SYS_PIVOT_ROOT] = "SYS_PIVOT_ROOT", |
[CCS_SYS_PIVOT_ROOT] = "SYS_PIVOT_ROOT", |
122 |
[CCS_SYS_PTRACE] = "SYS_PTRACE", |
[CCS_SYS_PTRACE] = "SYS_PTRACE", |
123 |
|
[CCS_CONCEAL_MOUNT] = "conceal_mount", |
124 |
}; |
}; |
|
#endif |
|
125 |
|
|
|
#ifdef CONFIG_TOMOYO |
|
126 |
static bool ccs_profile_entry_used[CCS_MAX_CONTROL_INDEX + |
static bool ccs_profile_entry_used[CCS_MAX_CONTROL_INDEX + |
127 |
CCS_MAX_CAPABILITY_INDEX + 1]; |
CCS_MAX_CAPABILITY_INDEX + 1]; |
|
#else |
|
|
static bool ccs_profile_entry_used[CCS_MAX_CONTROL_INDEX + 1]; |
|
|
#endif |
|
128 |
|
|
129 |
/* Profile table. Memory is allocated as needed. */ |
/* Profile table. Memory is allocated as needed. */ |
130 |
static struct ccs_profile { |
static struct ccs_profile { |
131 |
unsigned int value[CCS_MAX_CONTROL_INDEX]; |
unsigned int value[CCS_MAX_CONTROL_INDEX]; |
132 |
const struct ccs_path_info *comment; |
const struct ccs_path_info *comment; |
|
#ifdef CONFIG_TOMOYO |
|
133 |
unsigned char capability_value[CCS_MAX_CAPABILITY_INDEX]; |
unsigned char capability_value[CCS_MAX_CAPABILITY_INDEX]; |
|
#endif |
|
134 |
} *ccs_profile_ptr[MAX_PROFILES]; |
} *ccs_profile_ptr[MAX_PROFILES]; |
135 |
|
|
136 |
|
/* Lock for protecting ccs_profile->comment */ |
137 |
|
static DEFINE_SPINLOCK(ccs_profile_comment_lock); |
138 |
|
|
139 |
/* Permit policy management by non-root user? */ |
/* Permit policy management by non-root user? */ |
140 |
static bool ccs_manage_by_non_root; |
static bool ccs_manage_by_non_root; |
141 |
|
|
142 |
/* Utility functions. */ |
/* Utility functions. */ |
143 |
|
|
|
#ifdef CONFIG_TOMOYO |
|
144 |
/** |
/** |
145 |
* ccs_quiet_setup - Set CCS_VERBOSE=0 by default. |
* ccs_quiet_setup - Set CCS_VERBOSE=0 by default. |
146 |
* |
* |
155 |
} |
} |
156 |
|
|
157 |
__setup("CCS_QUIET", ccs_quiet_setup); |
__setup("CCS_QUIET", ccs_quiet_setup); |
|
#endif |
|
158 |
|
|
159 |
/** |
/** |
160 |
* ccs_is_byte_range - Check whether the string isa \ooo style octal value. |
* ccs_is_byte_range - Check whether the string isa \ooo style octal value. |
254 |
* |
* |
255 |
* Returns nothing. |
* Returns nothing. |
256 |
*/ |
*/ |
257 |
static void ccs_normalize_line(unsigned char *buffer) |
void ccs_normalize_line(unsigned char *buffer) |
258 |
{ |
{ |
259 |
unsigned char *sp = buffer; |
unsigned char *sp = buffer; |
260 |
unsigned char *dp = buffer; |
unsigned char *dp = buffer; |
274 |
} |
} |
275 |
|
|
276 |
/** |
/** |
277 |
|
* ccs_tokenize - Tokenize string. |
278 |
|
* |
279 |
|
* @buffer: The line to tokenize. |
280 |
|
* @w: Pointer to "char *". |
281 |
|
* @size: Sizeof @w . |
282 |
|
* |
283 |
|
* Returns true on success, false otherwise. |
284 |
|
*/ |
285 |
|
bool ccs_tokenize(char *buffer, char *w[], size_t size) |
286 |
|
{ |
287 |
|
int count = size / sizeof(char *); |
288 |
|
int i; |
289 |
|
for (i = 0; i < count; i++) |
290 |
|
w[i] = ""; |
291 |
|
for (i = 0; i < count; i++) { |
292 |
|
char *cp = strchr(buffer, ' '); |
293 |
|
if (cp) |
294 |
|
*cp = '\0'; |
295 |
|
w[i] = buffer; |
296 |
|
if (!cp) |
297 |
|
break; |
298 |
|
buffer = cp + 1; |
299 |
|
} |
300 |
|
return i < count || !*buffer; |
301 |
|
} |
302 |
|
|
303 |
|
/** |
304 |
* ccs_is_correct_path - Validate a pathname. |
* ccs_is_correct_path - Validate a pathname. |
305 |
* @filename: The pathname to check. |
* @filename: The pathname to check. |
306 |
* @start_type: Should the pathname start with '/'? |
* @start_type: Should the pathname start with '/'? |
309 |
* 1 = must / -1 = must not / 0 = don't care |
* 1 = must / -1 = must not / 0 = don't care |
310 |
* @end_type: Should the pathname end with '/'? |
* @end_type: Should the pathname end with '/'? |
311 |
* 1 = must / -1 = must not / 0 = don't care |
* 1 = must / -1 = must not / 0 = don't care |
|
* @function: The name of function calling me. |
|
312 |
* |
* |
313 |
* Check whether the given filename follows the naming rules. |
* Check whether the given filename follows the naming rules. |
314 |
* Returns true if @filename follows the naming rules, false otherwise. |
* Returns true if @filename follows the naming rules, false otherwise. |
315 |
*/ |
*/ |
316 |
bool ccs_is_correct_path(const char *filename, const s8 start_type, |
bool ccs_is_correct_path(const char *filename, const s8 start_type, |
317 |
const s8 pattern_type, const s8 end_type, |
const s8 pattern_type, const s8 end_type) |
|
const char *function) |
|
318 |
{ |
{ |
319 |
bool contains_pattern = false; |
bool contains_pattern = false; |
320 |
unsigned char c; |
unsigned char c; |
388 |
} |
} |
389 |
return true; |
return true; |
390 |
out: |
out: |
391 |
printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, |
printk(KERN_DEBUG "Invalid pathname '%s'\n", original_filename); |
|
original_filename); |
|
392 |
return false; |
return false; |
393 |
} |
} |
394 |
|
|
395 |
/** |
/** |
396 |
* ccs_is_correct_domain - Check whether the given domainname follows the naming rules. |
* ccs_is_correct_domain - Check whether the given domainname follows the naming rules. |
397 |
* @domainname: The domainname to check. |
* @domainname: The domainname to check. |
|
* @function: The name of function calling me. |
|
398 |
* |
* |
399 |
* Returns true if @domainname follows the naming rules, false otherwise. |
* Returns true if @domainname follows the naming rules, false otherwise. |
400 |
*/ |
*/ |
401 |
bool ccs_is_correct_domain(const unsigned char *domainname, |
bool ccs_is_correct_domain(const unsigned char *domainname) |
|
const char *function) |
|
402 |
{ |
{ |
403 |
unsigned char c; |
unsigned char c; |
404 |
unsigned char d; |
unsigned char d; |
447 |
} while (*domainname); |
} while (*domainname); |
448 |
return true; |
return true; |
449 |
out: |
out: |
450 |
printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, |
printk(KERN_DEBUG "Invalid domainname '%s'\n", org_domainname); |
|
org_domainname); |
|
451 |
return false; |
return false; |
452 |
} |
} |
453 |
|
|
469 |
* @domainname: The domainname to find. |
* @domainname: The domainname to find. |
470 |
* |
* |
471 |
* Returns pointer to "struct ccs_domain_info" if found, NULL otherwise. |
* Returns pointer to "struct ccs_domain_info" if found, NULL otherwise. |
472 |
|
* |
473 |
|
* Caller holds ccs_read_lock(). |
474 |
*/ |
*/ |
475 |
struct ccs_domain_info *ccs_find_domain(const char *domainname) |
struct ccs_domain_info *ccs_find_domain(const char *domainname) |
476 |
{ |
{ |
477 |
struct ccs_domain_info *domain; |
struct ccs_domain_info *domain; |
478 |
struct ccs_path_info name; |
struct ccs_path_info name; |
479 |
|
ccs_check_read_lock(); |
480 |
name.name = domainname; |
name.name = domainname; |
481 |
ccs_fill_path_info(&name); |
ccs_fill_path_info(&name); |
482 |
list1_for_each_entry(domain, &ccs_domain_list, list) { |
list_for_each_entry_rcu(domain, &ccs_domain_list, list) { |
483 |
if (!domain->is_deleted && |
if (!domain->is_deleted && |
484 |
!ccs_pathcmp(&name, domain->domainname)) |
!ccs_pathcmp(&name, domain->domainname)) |
485 |
return domain; |
return domain; |
831 |
* |
* |
832 |
* Returns the ccs_realpath() of current process on success, NULL otherwise. |
* Returns the ccs_realpath() of current process on success, NULL otherwise. |
833 |
* |
* |
834 |
* This function uses ccs_alloc(), so the caller must ccs_free() |
* This function uses kzalloc(), so the caller must kfree() |
835 |
* if this function didn't return NULL. |
* if this function didn't return NULL. |
836 |
*/ |
*/ |
837 |
const char *ccs_get_exe(void) |
const char *ccs_get_exe(void) |
917 |
ccs_profile_ptr[profile]->value[index] : 0; |
ccs_profile_ptr[profile]->value[index] : 0; |
918 |
} |
} |
919 |
|
|
|
#ifdef CONFIG_TOMOYO |
|
920 |
/** |
/** |
921 |
* ccs_check_capability_flags - Check mode for specified capability. |
* ccs_check_capability_flags - Check mode for specified capability. |
922 |
* |
* |
951 |
? ccs_capability_control_keyword[operation] : NULL; |
? ccs_capability_control_keyword[operation] : NULL; |
952 |
} |
} |
953 |
|
|
|
#endif |
|
|
|
|
954 |
/** |
/** |
955 |
* ccs_init_request_info - Initialize "struct ccs_request_info" members. |
* ccs_init_request_info - Initialize "struct ccs_request_info" members. |
956 |
* |
* |
968 |
r->profile = domain->profile; |
r->profile = domain->profile; |
969 |
if (index < CCS_MAX_CONTROL_INDEX) |
if (index < CCS_MAX_CONTROL_INDEX) |
970 |
r->mode = ccs_check_flags(domain, index); |
r->mode = ccs_check_flags(domain, index); |
|
#ifdef CONFIG_TOMOYO |
|
971 |
else |
else |
972 |
r->mode = ccs_check_capability_flags(domain, index |
r->mode = ccs_check_capability_flags(domain, index |
973 |
- CCS_MAX_CONTROL_INDEX); |
- CCS_MAX_CONTROL_INDEX); |
|
#endif |
|
974 |
} |
} |
975 |
|
|
976 |
/** |
/** |
989 |
/** |
/** |
990 |
* ccs_domain_quota_ok - Check for domain's quota. |
* ccs_domain_quota_ok - Check for domain's quota. |
991 |
* |
* |
992 |
* @domain: Pointer to "struct ccs_domain_info". |
* @r: Pointer to "struct ccs_request_info". |
993 |
* |
* |
994 |
* Returns true if the domain is not exceeded quota, false otherwise. |
* Returns true if the domain is not exceeded quota, false otherwise. |
995 |
|
* |
996 |
|
* Caller holds ccs_read_lock(). |
997 |
*/ |
*/ |
998 |
bool ccs_domain_quota_ok(struct ccs_domain_info * const domain) |
bool ccs_domain_quota_ok(struct ccs_request_info *r) |
999 |
{ |
{ |
1000 |
unsigned int count = 0; |
unsigned int count = 0; |
1001 |
|
struct ccs_domain_info *domain = r->domain; |
1002 |
struct ccs_acl_info *ptr; |
struct ccs_acl_info *ptr; |
1003 |
|
ccs_check_read_lock(); |
1004 |
|
if (r->mode != 1) |
1005 |
|
return false; |
1006 |
if (!domain) |
if (!domain) |
1007 |
return true; |
return true; |
1008 |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
1009 |
if (ptr->type & ACL_DELETED) |
if (ptr->type & ACL_DELETED) |
1010 |
continue; |
continue; |
1011 |
switch (ccs_acl_type2(ptr)) { |
switch (ccs_acl_type2(ptr)) { |
1083 |
static struct ccs_profile *ccs_find_or_assign_new_profile(const unsigned int |
static struct ccs_profile *ccs_find_or_assign_new_profile(const unsigned int |
1084 |
profile) |
profile) |
1085 |
{ |
{ |
1086 |
static DEFINE_MUTEX(lock); |
struct ccs_profile *ptr; |
1087 |
struct ccs_profile *ptr = NULL; |
struct ccs_profile *entry; |
1088 |
mutex_lock(&lock); |
int i; |
1089 |
if (profile < MAX_PROFILES) { |
if (profile >= MAX_PROFILES) |
1090 |
ptr = ccs_profile_ptr[profile]; |
return NULL; |
1091 |
if (ptr) |
ptr = ccs_profile_ptr[profile]; |
1092 |
goto ok; |
if (ptr) |
1093 |
ptr = ccs_alloc_element(sizeof(*ptr)); |
return ptr; |
1094 |
if (ptr) { |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
1095 |
int i; |
mutex_lock(&ccs_policy_lock); |
1096 |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) |
ptr = ccs_profile_ptr[profile]; |
1097 |
ptr->value[i] |
if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) { |
1098 |
= ccs_control_array[i].current_value; |
ptr = entry; |
1099 |
/* |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) |
1100 |
* Needn't to initialize "ptr->capability_value" |
ptr->value[i] = ccs_control_array[i].current_value; |
1101 |
* because they are always 0. |
/* |
1102 |
*/ |
* Needn't to initialize "ptr->capability_value" |
1103 |
mb(); /* Avoid out-of-order execution. */ |
* because they are always 0. |
1104 |
ccs_profile_ptr[profile] = ptr; |
*/ |
1105 |
} |
mb(); /* Avoid out-of-order execution. */ |
1106 |
|
ccs_profile_ptr[profile] = ptr; |
1107 |
|
entry = NULL; |
1108 |
} |
} |
1109 |
ok: |
mutex_unlock(&ccs_policy_lock); |
1110 |
mutex_unlock(&lock); |
kfree(entry); |
1111 |
return ptr; |
return ptr; |
1112 |
} |
} |
1113 |
|
|
1138 |
if (!cp) |
if (!cp) |
1139 |
return -EINVAL; |
return -EINVAL; |
1140 |
*cp = '\0'; |
*cp = '\0'; |
|
ccs_update_counter(CCS_UPDATES_COUNTER_PROFILE); |
|
1141 |
if (!strcmp(data, "COMMENT")) { |
if (!strcmp(data, "COMMENT")) { |
1142 |
ccs_profile->comment = ccs_save_name(cp + 1); |
const struct ccs_path_info *new_comment |
1143 |
|
= ccs_get_name(cp + 1); |
1144 |
|
const struct ccs_path_info *old_comment; |
1145 |
|
/* Protect reader from ccs_put_name(). */ |
1146 |
|
/***** CRITICAL SECTION START *****/ |
1147 |
|
spin_lock(&ccs_profile_comment_lock); |
1148 |
|
old_comment = ccs_profile->comment; |
1149 |
|
ccs_profile->comment = new_comment; |
1150 |
|
spin_unlock(&ccs_profile_comment_lock); |
1151 |
|
/***** CRITICAL SECTION END *****/ |
1152 |
|
ccs_put_name(old_comment); |
1153 |
ccs_profile_entry_used[0] = true; |
ccs_profile_entry_used[0] = true; |
1154 |
return 0; |
return 0; |
1155 |
} |
} |
|
#ifdef CONFIG_TOMOYO |
|
1156 |
if (ccs_str_starts(&data, KEYWORD_MAC_FOR_CAPABILITY)) { |
if (ccs_str_starts(&data, KEYWORD_MAC_FOR_CAPABILITY)) { |
1157 |
if (sscanf(cp + 1, "%u", &value) != 1) { |
if (sscanf(cp + 1, "%u", &value) != 1) { |
1158 |
for (i = 0; i < 4; i++) { |
for (i = 0; i < 4; i++) { |
1176 |
} |
} |
1177 |
return -EINVAL; |
return -EINVAL; |
1178 |
} |
} |
|
#endif |
|
1179 |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) { |
for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) { |
1180 |
if (strcmp(data, ccs_control_array[i].keyword)) |
if (strcmp(data, ccs_control_array[i].keyword)) |
1181 |
continue; |
continue; |
1202 |
} else if (value > ccs_control_array[i].max_value) { |
} else if (value > ccs_control_array[i].max_value) { |
1203 |
value = ccs_control_array[i].max_value; |
value = ccs_control_array[i].max_value; |
1204 |
} |
} |
|
switch (i) { |
|
|
case CCS_DENY_CONCEAL_MOUNT: |
|
|
case CCS_RESTRICT_UNMOUNT: |
|
|
if (value == 1) |
|
|
value = 2; /* learning mode is not supported. */ |
|
|
} |
|
1205 |
ccs_profile->value[i] = value; |
ccs_profile->value[i] = value; |
1206 |
ccs_profile_entry_used[i + 1] = true; |
ccs_profile_entry_used[i + 1] = true; |
1207 |
return 0; |
return 0; |
1230 |
head->read_step = step; |
head->read_step = step; |
1231 |
if (!ccs_profile) |
if (!ccs_profile) |
1232 |
continue; |
continue; |
|
#if !defined(CONFIG_SAKURA) || !defined(CONFIG_TOMOYO) |
|
|
switch (type - 1) { |
|
|
#ifndef CONFIG_SAKURA |
|
|
case CCS_DENY_CONCEAL_MOUNT: |
|
|
case CCS_RESTRICT_CHROOT: |
|
|
case CCS_RESTRICT_MOUNT: |
|
|
case CCS_RESTRICT_UNMOUNT: |
|
|
case CCS_RESTRICT_PIVOT_ROOT: |
|
|
case CCS_RESTRICT_AUTOBIND: |
|
|
#endif |
|
|
#ifndef CONFIG_TOMOYO |
|
|
case CCS_MAC_FOR_FILE: |
|
|
case CCS_MAC_FOR_IOCTL: |
|
|
case CCS_MAC_FOR_ARGV0: |
|
|
case CCS_MAC_FOR_ENV: |
|
|
case CCS_MAC_FOR_NETWORK: |
|
|
case CCS_MAC_FOR_SIGNAL: |
|
|
case CCS_MAX_ACCEPT_ENTRY: |
|
|
case CCS_VERBOSE: |
|
|
#endif |
|
|
continue; |
|
|
} |
|
|
#endif |
|
1233 |
if (!ccs_profile_entry_used[type]) |
if (!ccs_profile_entry_used[type]) |
1234 |
continue; |
continue; |
1235 |
if (!type) { /* Print profile' comment tag. */ |
if (!type) { /* Print profile' comment tag. */ |
1236 |
if (!ccs_io_printf(head, "%u-COMMENT=%s\n", |
bool done; |
1237 |
index, ccs_profile->comment ? |
/***** CRITICAL SECTION START *****/ |
1238 |
ccs_profile->comment->name : "")) |
spin_lock(&ccs_profile_comment_lock); |
1239 |
|
done = ccs_io_printf(head, "%u-COMMENT=%s\n", |
1240 |
|
index, ccs_profile->comment ? |
1241 |
|
ccs_profile->comment->name : ""); |
1242 |
|
spin_unlock(&ccs_profile_comment_lock); |
1243 |
|
/***** CRITICAL SECTION END *****/ |
1244 |
|
if (!done) |
1245 |
break; |
break; |
1246 |
continue; |
continue; |
1247 |
} |
} |
1248 |
type--; |
type--; |
1249 |
if (type >= CCS_MAX_CONTROL_INDEX) { |
if (type >= CCS_MAX_CONTROL_INDEX) { |
|
#ifdef CONFIG_TOMOYO |
|
1250 |
const int i = type - CCS_MAX_CONTROL_INDEX; |
const int i = type - CCS_MAX_CONTROL_INDEX; |
1251 |
const u8 value = ccs_profile->capability_value[i]; |
const u8 value = ccs_profile->capability_value[i]; |
1252 |
if (!ccs_io_printf(head, |
if (!ccs_io_printf(head, |
1255 |
ccs_capability_control_keyword[i], |
ccs_capability_control_keyword[i], |
1256 |
ccs_mode_4[value])) |
ccs_mode_4[value])) |
1257 |
break; |
break; |
|
#endif |
|
1258 |
} else { |
} else { |
1259 |
const unsigned int value = ccs_profile->value[type]; |
const unsigned int value = ccs_profile->value[type]; |
1260 |
const char **modes = NULL; |
const char **modes = NULL; |
1283 |
return 0; |
return 0; |
1284 |
} |
} |
1285 |
|
|
|
/* Structure for policy manager. */ |
|
|
struct ccs_policy_manager_entry { |
|
|
struct list1_head list; |
|
|
/* A path to program or a domainname. */ |
|
|
const struct ccs_path_info *manager; |
|
|
bool is_domain; /* True if manager is a domainname. */ |
|
|
bool is_deleted; /* True if this entry is deleted. */ |
|
|
}; |
|
|
|
|
1286 |
/* The list for "struct ccs_policy_manager_entry". */ |
/* The list for "struct ccs_policy_manager_entry". */ |
1287 |
static LIST1_HEAD(ccs_policy_manager_list); |
LIST_HEAD(ccs_policy_manager_list); |
1288 |
|
|
1289 |
/** |
/** |
1290 |
* ccs_update_manager_entry - Add a manager entry. |
* ccs_update_manager_entry - Add a manager entry. |
1296 |
*/ |
*/ |
1297 |
static int ccs_update_manager_entry(const char *manager, const bool is_delete) |
static int ccs_update_manager_entry(const char *manager, const bool is_delete) |
1298 |
{ |
{ |
1299 |
struct ccs_policy_manager_entry *new_entry; |
struct ccs_policy_manager_entry *entry = NULL; |
1300 |
struct ccs_policy_manager_entry *ptr; |
struct ccs_policy_manager_entry *ptr; |
|
static DEFINE_MUTEX(lock); |
|
1301 |
const struct ccs_path_info *saved_manager; |
const struct ccs_path_info *saved_manager; |
1302 |
int error = -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
1303 |
bool is_domain = false; |
bool is_domain = false; |
1304 |
if (ccs_is_domain_def(manager)) { |
if (ccs_is_domain_def(manager)) { |
1305 |
if (!ccs_is_correct_domain(manager, __func__)) |
if (!ccs_is_correct_domain(manager)) |
1306 |
return -EINVAL; |
return -EINVAL; |
1307 |
is_domain = true; |
is_domain = true; |
1308 |
} else { |
} else { |
1309 |
if (!ccs_is_correct_path(manager, 1, -1, -1, __func__)) |
if (!ccs_is_correct_path(manager, 1, -1, -1)) |
1310 |
return -EINVAL; |
return -EINVAL; |
1311 |
} |
} |
1312 |
saved_manager = ccs_save_name(manager); |
saved_manager = ccs_get_name(manager); |
1313 |
if (!saved_manager) |
if (!saved_manager) |
1314 |
return -ENOMEM; |
return -ENOMEM; |
1315 |
mutex_lock(&lock); |
if (!is_delete) |
1316 |
list1_for_each_entry(ptr, &ccs_policy_manager_list, list) { |
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
1317 |
|
mutex_lock(&ccs_policy_lock); |
1318 |
|
list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) { |
1319 |
if (ptr->manager != saved_manager) |
if (ptr->manager != saved_manager) |
1320 |
continue; |
continue; |
1321 |
ptr->is_deleted = is_delete; |
ptr->is_deleted = is_delete; |
1322 |
error = 0; |
error = 0; |
1323 |
goto out; |
break; |
1324 |
} |
} |
1325 |
if (is_delete) { |
if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) { |
1326 |
error = -ENOENT; |
entry->manager = saved_manager; |
1327 |
goto out; |
saved_manager = NULL; |
1328 |
|
entry->is_domain = is_domain; |
1329 |
|
list_add_tail_rcu(&entry->list, &ccs_policy_manager_list); |
1330 |
|
entry = NULL; |
1331 |
|
error = 0; |
1332 |
} |
} |
1333 |
new_entry = ccs_alloc_element(sizeof(*new_entry)); |
mutex_unlock(&ccs_policy_lock); |
1334 |
if (!new_entry) |
ccs_put_name(saved_manager); |
1335 |
goto out; |
kfree(entry); |
|
new_entry->manager = saved_manager; |
|
|
new_entry->is_domain = is_domain; |
|
|
list1_add_tail_mb(&new_entry->list, &ccs_policy_manager_list); |
|
|
error = 0; |
|
|
out: |
|
|
mutex_unlock(&lock); |
|
|
if (!error) |
|
|
ccs_update_counter(CCS_UPDATES_COUNTER_MANAGER); |
|
1336 |
return error; |
return error; |
1337 |
} |
} |
1338 |
|
|
1360 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1361 |
* |
* |
1362 |
* Returns 0. |
* Returns 0. |
1363 |
|
* |
1364 |
|
* Caller holds ccs_read_lock(). |
1365 |
*/ |
*/ |
1366 |
static int ccs_read_manager_policy(struct ccs_io_buffer *head) |
static int ccs_read_manager_policy(struct ccs_io_buffer *head) |
1367 |
{ |
{ |
1368 |
struct list1_head *pos; |
struct list_head *pos; |
1369 |
|
ccs_check_read_lock(); |
1370 |
if (head->read_eof) |
if (head->read_eof) |
1371 |
return 0; |
return 0; |
1372 |
list1_for_each_cookie(pos, head->read_var2, &ccs_policy_manager_list) { |
list_for_each_cookie(pos, head->read_var2, &ccs_policy_manager_list) { |
1373 |
struct ccs_policy_manager_entry *ptr; |
struct ccs_policy_manager_entry *ptr; |
1374 |
ptr = list1_entry(pos, struct ccs_policy_manager_entry, list); |
ptr = list_entry(pos, struct ccs_policy_manager_entry, list); |
1375 |
if (ptr->is_deleted) |
if (ptr->is_deleted) |
1376 |
continue; |
continue; |
1377 |
if (!ccs_io_printf(head, "%s\n", ptr->manager->name)) |
if (!ccs_io_printf(head, "%s\n", ptr->manager->name)) |
1386 |
* |
* |
1387 |
* Returns true if the current process is permitted to modify policy |
* Returns true if the current process is permitted to modify policy |
1388 |
* via /proc/ccs/ interface. |
* via /proc/ccs/ interface. |
1389 |
|
* |
1390 |
|
* Caller holds ccs_read_lock(). |
1391 |
*/ |
*/ |
1392 |
static bool ccs_is_policy_manager(void) |
static bool ccs_is_policy_manager(void) |
1393 |
{ |
{ |
1397 |
const struct ccs_path_info *domainname |
const struct ccs_path_info *domainname |
1398 |
= ccs_current_domain()->domainname; |
= ccs_current_domain()->domainname; |
1399 |
bool found = false; |
bool found = false; |
1400 |
|
ccs_check_read_lock(); |
1401 |
if (!ccs_policy_loaded) |
if (!ccs_policy_loaded) |
1402 |
return true; |
return true; |
1403 |
if (task->ccs_flags & CCS_TASK_IS_POLICY_MANAGER) |
if (task->ccs_flags & CCS_TASK_IS_POLICY_MANAGER) |
1404 |
return true; |
return true; |
1405 |
if (!ccs_manage_by_non_root && (current_uid() || current_euid())) |
if (!ccs_manage_by_non_root && (current_uid() || current_euid())) |
1406 |
return false; |
return false; |
1407 |
list1_for_each_entry(ptr, &ccs_policy_manager_list, list) { |
list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) { |
1408 |
if (!ptr->is_deleted && ptr->is_domain |
if (!ptr->is_deleted && ptr->is_domain |
1409 |
&& !ccs_pathcmp(domainname, ptr->manager)) { |
&& !ccs_pathcmp(domainname, ptr->manager)) { |
1410 |
/* Set manager flag. */ |
/* Set manager flag. */ |
1415 |
exe = ccs_get_exe(); |
exe = ccs_get_exe(); |
1416 |
if (!exe) |
if (!exe) |
1417 |
return false; |
return false; |
1418 |
list1_for_each_entry(ptr, &ccs_policy_manager_list, list) { |
list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) { |
1419 |
if (!ptr->is_deleted && !ptr->is_domain |
if (!ptr->is_deleted && !ptr->is_domain |
1420 |
&& !strcmp(exe, ptr->manager->name)) { |
&& !strcmp(exe, ptr->manager->name)) { |
1421 |
found = true; |
found = true; |
1433 |
ccs_last_pid = pid; |
ccs_last_pid = pid; |
1434 |
} |
} |
1435 |
} |
} |
1436 |
ccs_free(exe); |
kfree(exe); |
1437 |
return found; |
return found; |
1438 |
} |
} |
1439 |
|
|
|
#ifdef CONFIG_TOMOYO |
|
|
|
|
1440 |
/** |
/** |
1441 |
* ccs_find_condition_part - Find condition part from the statement. |
* ccs_find_condition_part - Find condition part from the statement. |
1442 |
* |
* |
1471 |
* @data: String to parse. |
* @data: String to parse. |
1472 |
* |
* |
1473 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1474 |
|
* |
1475 |
|
* Caller holds ccs_read_lock(). |
1476 |
*/ |
*/ |
1477 |
static bool ccs_is_select_one(struct ccs_io_buffer *head, const char *data) |
static bool ccs_is_select_one(struct ccs_io_buffer *head, const char *data) |
1478 |
{ |
{ |
1479 |
unsigned int pid; |
unsigned int pid; |
1480 |
struct ccs_domain_info *domain = NULL; |
struct ccs_domain_info *domain = NULL; |
1481 |
|
ccs_check_read_lock(); |
1482 |
if (!strcmp(data, "allow_execute")) { |
if (!strcmp(data, "allow_execute")) { |
1483 |
head->read_execute_only = true; |
head->read_execute_only = true; |
1484 |
return true; |
return true; |
1508 |
if (domain) { |
if (domain) { |
1509 |
struct ccs_domain_info *d; |
struct ccs_domain_info *d; |
1510 |
head->read_var1 = NULL; |
head->read_var1 = NULL; |
1511 |
list1_for_each_entry(d, &ccs_domain_list, list) { |
list_for_each_entry_rcu(d, &ccs_domain_list, list) { |
1512 |
if (d == domain) |
if (d == domain) |
1513 |
break; |
break; |
1514 |
head->read_var1 = &d->list; |
head->read_var1 = &d->list; |
1535 |
struct ccs_domain_info *domain = head->write_var1; |
struct ccs_domain_info *domain = head->write_var1; |
1536 |
bool is_delete = false; |
bool is_delete = false; |
1537 |
bool is_select = false; |
bool is_select = false; |
|
bool is_undelete = false; |
|
1538 |
unsigned int profile; |
unsigned int profile; |
1539 |
const struct ccs_condition_list *cond = NULL; |
struct ccs_condition *cond = NULL; |
1540 |
char *cp; |
char *cp; |
1541 |
|
int error; |
1542 |
if (ccs_str_starts(&data, KEYWORD_DELETE)) |
if (ccs_str_starts(&data, KEYWORD_DELETE)) |
1543 |
is_delete = true; |
is_delete = true; |
1544 |
else if (ccs_str_starts(&data, KEYWORD_SELECT)) |
else if (ccs_str_starts(&data, KEYWORD_SELECT)) |
1545 |
is_select = true; |
is_select = true; |
|
else if (ccs_str_starts(&data, KEYWORD_UNDELETE)) |
|
|
is_undelete = true; |
|
1546 |
if (is_select && ccs_is_select_one(head, data)) |
if (is_select && ccs_is_select_one(head, data)) |
1547 |
return 0; |
return 0; |
1548 |
/* Don't allow updating policies by non manager programs. */ |
/* Don't allow updating policies by non manager programs. */ |
1554 |
ccs_delete_domain(data); |
ccs_delete_domain(data); |
1555 |
else if (is_select) |
else if (is_select) |
1556 |
domain = ccs_find_domain(data); |
domain = ccs_find_domain(data); |
|
else if (is_undelete) |
|
|
domain = ccs_undelete_domain(data); |
|
1557 |
else |
else |
1558 |
domain = ccs_find_or_assign_new_domain(data, 0); |
domain = ccs_find_or_assign_new_domain(data, 0); |
1559 |
head->write_var1 = domain; |
head->write_var1 = domain; |
|
ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY); |
|
1560 |
return 0; |
return 0; |
1561 |
} |
} |
1562 |
if (!domain) |
if (!domain) |
1569 |
return 0; |
return 0; |
1570 |
} |
} |
1571 |
if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { |
if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { |
1572 |
ccs_set_domain_flag(domain, is_delete, |
domain->ignore_global_allow_read = !is_delete; |
|
DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ); |
|
1573 |
return 0; |
return 0; |
1574 |
} |
} |
1575 |
if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV)) { |
if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV)) { |
1576 |
ccs_set_domain_flag(domain, is_delete, |
domain->ignore_global_allow_env = !is_delete; |
|
DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV); |
|
1577 |
return 0; |
return 0; |
1578 |
} |
} |
1579 |
cp = ccs_find_condition_part(data); |
cp = ccs_find_condition_part(data); |
1580 |
if (cp) { |
if (cp) { |
1581 |
cond = ccs_find_or_assign_new_condition(cp); |
cond = ccs_get_condition(cp); |
1582 |
if (!cond) |
if (!cond) |
1583 |
return -EINVAL; |
return -EINVAL; |
1584 |
} |
} |
1585 |
if (ccs_str_starts(&data, KEYWORD_ALLOW_CAPABILITY)) |
if (ccs_str_starts(&data, KEYWORD_ALLOW_CAPABILITY)) |
1586 |
return ccs_write_capability_policy(data, domain, cond, |
error = ccs_write_capability_policy(data, domain, cond, |
1587 |
is_delete); |
is_delete); |
1588 |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_NETWORK)) |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_NETWORK)) |
1589 |
return ccs_write_network_policy(data, domain, cond, is_delete); |
error = ccs_write_network_policy(data, domain, cond, is_delete); |
1590 |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_SIGNAL)) |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_SIGNAL)) |
1591 |
return ccs_write_signal_policy(data, domain, cond, is_delete); |
error = ccs_write_signal_policy(data, domain, cond, is_delete); |
1592 |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_ARGV0)) |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_ARGV0)) |
1593 |
return ccs_write_argv0_policy(data, domain, cond, is_delete); |
error = ccs_write_argv0_policy(data, domain, cond, is_delete); |
1594 |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_ENV)) |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_ENV)) |
1595 |
return ccs_write_env_policy(data, domain, cond, is_delete); |
error = ccs_write_env_policy(data, domain, cond, is_delete); |
1596 |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_IOCTL)) |
else if (ccs_str_starts(&data, KEYWORD_ALLOW_IOCTL)) |
1597 |
return ccs_write_ioctl_policy(data, domain, cond, is_delete); |
error = ccs_write_ioctl_policy(data, domain, cond, is_delete); |
1598 |
|
else if (ccs_str_starts(&data, KEYWORD_ALLOW_MOUNT)) |
1599 |
|
error = ccs_write_mount_policy(data, domain, cond, is_delete); |
1600 |
|
else if (ccs_str_starts(&data, KEYWORD_ALLOW_UNMOUNT)) |
1601 |
|
error = ccs_write_umount_policy(data, domain, cond, is_delete); |
1602 |
|
else if (ccs_str_starts(&data, KEYWORD_ALLOW_CHROOT)) |
1603 |
|
error = ccs_write_chroot_policy(data, domain, cond, is_delete); |
1604 |
|
else if (ccs_str_starts(&data, KEYWORD_ALLOW_PIVOT_ROOT)) |
1605 |
|
error = ccs_write_pivot_root_policy(data, domain, cond, |
1606 |
|
is_delete); |
1607 |
else |
else |
1608 |
return ccs_write_file_policy(data, domain, cond, is_delete); |
error = ccs_write_file_policy(data, domain, cond, is_delete); |
1609 |
|
if (cond) |
1610 |
|
ccs_put_condition(cond); |
1611 |
|
return error; |
1612 |
} |
} |
1613 |
|
|
1614 |
/** |
/** |
1616 |
* |
* |
1617 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1618 |
* @ptr: Pointer to "struct ccs_single_path_acl_record". |
* @ptr: Pointer to "struct ccs_single_path_acl_record". |
1619 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1620 |
* |
* |
1621 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1622 |
*/ |
*/ |
1623 |
static bool ccs_print_single_path_acl(struct ccs_io_buffer *head, |
static bool ccs_print_single_path_acl(struct ccs_io_buffer *head, |
1624 |
struct ccs_single_path_acl_record *ptr, |
struct ccs_single_path_acl_record *ptr, |
1625 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1626 |
{ |
{ |
1627 |
int pos; |
int pos; |
1628 |
u8 bit; |
u8 bit; |
1661 |
} |
} |
1662 |
|
|
1663 |
/** |
/** |
1664 |
|
* ccs_print_mkdev_acl - Print a mkdev ACL entry. |
1665 |
|
* |
1666 |
|
* @head: Pointer to "struct ccs_io_buffer". |
1667 |
|
* @ptr: Pointer to "struct ccs_mkdev_acl_record". |
1668 |
|
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1669 |
|
* |
1670 |
|
* Returns true on success, false otherwise. |
1671 |
|
*/ |
1672 |
|
static bool ccs_print_mkdev_acl(struct ccs_io_buffer *head, |
1673 |
|
struct ccs_mkdev_acl_record *ptr, |
1674 |
|
const struct ccs_condition *cond) |
1675 |
|
{ |
1676 |
|
int pos; |
1677 |
|
u8 bit; |
1678 |
|
const char *atmark = ""; |
1679 |
|
const char *filename; |
1680 |
|
const u16 perm = ptr->perm; |
1681 |
|
if (ptr->u_is_group) { |
1682 |
|
atmark = "@"; |
1683 |
|
filename = ptr->u.group->group_name->name; |
1684 |
|
} else { |
1685 |
|
filename = ptr->u.filename->name; |
1686 |
|
} |
1687 |
|
for (bit = head->read_bit; bit < MAX_MKDEV_OPERATION; bit++) { |
1688 |
|
const char *msg; |
1689 |
|
const unsigned int min_major = ptr->min_major; |
1690 |
|
const unsigned int max_major = ptr->max_major; |
1691 |
|
const unsigned int min_minor = ptr->min_minor; |
1692 |
|
const unsigned int max_minor = ptr->max_minor; |
1693 |
|
if (!(perm & (1 << bit))) |
1694 |
|
continue; |
1695 |
|
msg = ccs_mkdev2keyword(bit); |
1696 |
|
pos = head->read_avail; |
1697 |
|
if (!ccs_io_printf(head, "allow_%s %s%s %u", msg, atmark, |
1698 |
|
filename, min_major) || |
1699 |
|
(min_major != max_major && |
1700 |
|
!ccs_io_printf(head, "-%u", max_major)) || |
1701 |
|
!ccs_io_printf(head, " %u", min_minor) || |
1702 |
|
(min_minor != max_minor && |
1703 |
|
!ccs_io_printf(head, "-%u", max_minor)) || |
1704 |
|
!ccs_print_condition(head, cond)) |
1705 |
|
goto out; |
1706 |
|
} |
1707 |
|
head->read_bit = 0; |
1708 |
|
return true; |
1709 |
|
out: |
1710 |
|
head->read_bit = bit; |
1711 |
|
head->read_avail = pos; |
1712 |
|
return false; |
1713 |
|
} |
1714 |
|
|
1715 |
|
/** |
1716 |
* ccs_print_double_path_acl - Print a double path ACL entry. |
* ccs_print_double_path_acl - Print a double path ACL entry. |
1717 |
* |
* |
1718 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1719 |
* @ptr: Pointer to "struct ccs_double_path_acl_record". |
* @ptr: Pointer to "struct ccs_double_path_acl_record". |
1720 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1721 |
* |
* |
1722 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1723 |
*/ |
*/ |
1724 |
static bool ccs_print_double_path_acl(struct ccs_io_buffer *head, |
static bool ccs_print_double_path_acl(struct ccs_io_buffer *head, |
1725 |
struct ccs_double_path_acl_record *ptr, |
struct ccs_double_path_acl_record *ptr, |
1726 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1727 |
{ |
{ |
1728 |
int pos; |
int pos; |
1729 |
const char *atmark1 = ""; |
const char *atmark1 = ""; |
1768 |
* |
* |
1769 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1770 |
* @ptr: Pointer to "struct ccs_ioctl_acl_record". |
* @ptr: Pointer to "struct ccs_ioctl_acl_record". |
1771 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1772 |
* |
* |
1773 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1774 |
*/ |
*/ |
1775 |
static bool ccs_print_ioctl_acl(struct ccs_io_buffer *head, |
static bool ccs_print_ioctl_acl(struct ccs_io_buffer *head, |
1776 |
struct ccs_ioctl_acl_record *ptr, |
struct ccs_ioctl_acl_record *ptr, |
1777 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1778 |
{ |
{ |
1779 |
int pos = head->read_avail; |
int pos = head->read_avail; |
1780 |
const char *atmark = ""; |
const char *atmark = ""; |
1806 |
* |
* |
1807 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1808 |
* @ptr: Pointer to "struct ccs_argv0_acl_record". |
* @ptr: Pointer to "struct ccs_argv0_acl_record". |
1809 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1810 |
* |
* |
1811 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1812 |
*/ |
*/ |
1813 |
static bool ccs_print_argv0_acl(struct ccs_io_buffer *head, |
static bool ccs_print_argv0_acl(struct ccs_io_buffer *head, |
1814 |
struct ccs_argv0_acl_record *ptr, |
struct ccs_argv0_acl_record *ptr, |
1815 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1816 |
{ |
{ |
1817 |
int pos = head->read_avail; |
int pos = head->read_avail; |
1818 |
if (!ccs_io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s", |
if (!ccs_io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s", |
1831 |
* |
* |
1832 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1833 |
* @ptr: Pointer to "struct ccs_env_acl_record". |
* @ptr: Pointer to "struct ccs_env_acl_record". |
1834 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1835 |
* |
* |
1836 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1837 |
*/ |
*/ |
1838 |
static bool ccs_print_env_acl(struct ccs_io_buffer *head, |
static bool ccs_print_env_acl(struct ccs_io_buffer *head, |
1839 |
struct ccs_env_acl_record *ptr, |
struct ccs_env_acl_record *ptr, |
1840 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1841 |
{ |
{ |
1842 |
int pos = head->read_avail; |
int pos = head->read_avail; |
1843 |
if (!ccs_io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name)) |
if (!ccs_io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name)) |
1855 |
* |
* |
1856 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1857 |
* @ptr: Pointer to "struct ccs_capability_acl_record". |
* @ptr: Pointer to "struct ccs_capability_acl_record". |
1858 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1859 |
* |
* |
1860 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1861 |
*/ |
*/ |
1862 |
static bool ccs_print_capability_acl(struct ccs_io_buffer *head, |
static bool ccs_print_capability_acl(struct ccs_io_buffer *head, |
1863 |
struct ccs_capability_acl_record *ptr, |
struct ccs_capability_acl_record *ptr, |
1864 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1865 |
{ |
{ |
1866 |
int pos = head->read_avail; |
int pos = head->read_avail; |
1867 |
if (!ccs_io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", |
if (!ccs_io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", |
1946 |
* |
* |
1947 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1948 |
* @ptr: Pointer to "struct ccs_ip_network_acl_record". |
* @ptr: Pointer to "struct ccs_ip_network_acl_record". |
1949 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1950 |
* |
* |
1951 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1952 |
*/ |
*/ |
1953 |
static bool ccs_print_network_acl(struct ccs_io_buffer *head, |
static bool ccs_print_network_acl(struct ccs_io_buffer *head, |
1954 |
struct ccs_ip_network_acl_record *ptr, |
struct ccs_ip_network_acl_record *ptr, |
1955 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1956 |
{ |
{ |
1957 |
int pos = head->read_avail; |
int pos = head->read_avail; |
1958 |
if (!ccs_io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", |
if (!ccs_io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", |
1987 |
* |
* |
1988 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1989 |
* @ptr: Pointer to "struct signale_acl_record". |
* @ptr: Pointer to "struct signale_acl_record". |
1990 |
* @cond: Pointer to "struct ccs_condition_list". May be NULL. |
* @cond: Pointer to "struct ccs_condition". May be NULL. |
1991 |
* |
* |
1992 |
* Returns true on success, false otherwise. |
* Returns true on success, false otherwise. |
1993 |
*/ |
*/ |
1994 |
static bool ccs_print_signal_acl(struct ccs_io_buffer *head, |
static bool ccs_print_signal_acl(struct ccs_io_buffer *head, |
1995 |
struct ccs_signal_acl_record *ptr, |
struct ccs_signal_acl_record *ptr, |
1996 |
const struct ccs_condition_list *cond) |
const struct ccs_condition *cond) |
1997 |
{ |
{ |
1998 |
int pos = head->read_avail; |
int pos = head->read_avail; |
1999 |
if (!ccs_io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", |
if (!ccs_io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", |
2025 |
} |
} |
2026 |
|
|
2027 |
/** |
/** |
2028 |
|
* ccs_print_mount_acl - Print a mount ACL entry. |
2029 |
|
* |
2030 |
|
* @head: Pointer to "struct ccs_io_buffer". |
2031 |
|
* @ptr: Pointer to "struct ccs_mount_acl_record". |
2032 |
|
* @cond: Pointer to "struct ccs_condition". May be NULL. |
2033 |
|
* |
2034 |
|
* Returns true on success, false otherwise. |
2035 |
|
*/ |
2036 |
|
static bool ccs_print_mount_acl(struct ccs_io_buffer *head, |
2037 |
|
struct ccs_mount_acl_record *ptr, |
2038 |
|
const struct ccs_condition *cond) |
2039 |
|
{ |
2040 |
|
int pos = head->read_avail; |
2041 |
|
if (!ccs_io_printf(head, KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n", |
2042 |
|
ptr->dev_name->name, ptr->dir_name->name, |
2043 |
|
ptr->fs_type->name, ptr->flags)) |
2044 |
|
goto out; |
2045 |
|
if (!ccs_print_condition(head, cond)) |
2046 |
|
goto out; |
2047 |
|
return true; |
2048 |
|
out: |
2049 |
|
head->read_avail = pos; |
2050 |
|
return false; |
2051 |
|
} |
2052 |
|
|
2053 |
|
/** |
2054 |
|
* ccs_print_umount_acl - Print a mount ACL entry. |
2055 |
|
* |
2056 |
|
* @head: Pointer to "struct ccs_io_buffer". |
2057 |
|
* @ptr: Pointer to "struct ccs_umount_acl_record". |
2058 |
|
* @cond: Pointer to "struct ccs_condition". May be NULL. |
2059 |
|
* |
2060 |
|
* Returns true on success, false otherwise. |
2061 |
|
*/ |
2062 |
|
static bool ccs_print_umount_acl(struct ccs_io_buffer *head, |
2063 |
|
struct ccs_umount_acl_record *ptr, |
2064 |
|
const struct ccs_condition *cond) |
2065 |
|
{ |
2066 |
|
int pos = head->read_avail; |
2067 |
|
if (!ccs_io_printf(head, KEYWORD_ALLOW_UNMOUNT "%s\n", |
2068 |
|
ptr->dir->name)) |
2069 |
|
goto out; |
2070 |
|
if (!ccs_print_condition(head, cond)) |
2071 |
|
goto out; |
2072 |
|
return true; |
2073 |
|
out: |
2074 |
|
head->read_avail = pos; |
2075 |
|
return false; |
2076 |
|
} |
2077 |
|
|
2078 |
|
/** |
2079 |
|
* ccs_print_chroot_acl - Print a chroot ACL entry. |
2080 |
|
* |
2081 |
|
* @head: Pointer to "struct ccs_io_buffer". |
2082 |
|
* @ptr: Pointer to "struct ccs_chroot_acl_record". |
2083 |
|
* @cond: Pointer to "struct ccs_condition". May be NULL. |
2084 |
|
* |
2085 |
|
* Returns true on success, false otherwise. |
2086 |
|
*/ |
2087 |
|
static bool ccs_print_chroot_acl(struct ccs_io_buffer *head, |
2088 |
|
struct ccs_chroot_acl_record *ptr, |
2089 |
|
const struct ccs_condition *cond) |
2090 |
|
{ |
2091 |
|
int pos = head->read_avail; |
2092 |
|
if (!ccs_io_printf(head, KEYWORD_ALLOW_CHROOT "%s\n", |
2093 |
|
ptr->dir->name)) |
2094 |
|
goto out; |
2095 |
|
if (!ccs_print_condition(head, cond)) |
2096 |
|
goto out; |
2097 |
|
return true; |
2098 |
|
out: |
2099 |
|
head->read_avail = pos; |
2100 |
|
return false; |
2101 |
|
} |
2102 |
|
|
2103 |
|
/** |
2104 |
|
* ccs_print_pivot_root_acl - Print a pivot_root ACL entry. |
2105 |
|
* |
2106 |
|
* @head: Pointer to "struct ccs_io_buffer". |
2107 |
|
* @ptr: Pointer to "struct ccs_pivot_root_acl_record". |
2108 |
|
* @cond: Pointer to "struct ccs_condition". May be NULL. |
2109 |
|
* |
2110 |
|
* Returns true on success, false otherwise. |
2111 |
|
*/ |
2112 |
|
static bool ccs_print_pivot_root_acl(struct ccs_io_buffer *head, |
2113 |
|
struct ccs_pivot_root_acl_record *ptr, |
2114 |
|
const struct ccs_condition *cond) |
2115 |
|
{ |
2116 |
|
int pos = head->read_avail; |
2117 |
|
if (!ccs_io_printf(head, KEYWORD_ALLOW_PIVOT_ROOT "%s %s\n", |
2118 |
|
ptr->new_root->name, ptr->old_root->name)) |
2119 |
|
goto out; |
2120 |
|
if (!ccs_print_condition(head, cond)) |
2121 |
|
goto out; |
2122 |
|
return true; |
2123 |
|
out: |
2124 |
|
head->read_avail = pos; |
2125 |
|
return false; |
2126 |
|
} |
2127 |
|
|
2128 |
|
/** |
2129 |
* ccs_print_entry - Print an ACL entry. |
* ccs_print_entry - Print an ACL entry. |
2130 |
* |
* |
2131 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
2136 |
static bool ccs_print_entry(struct ccs_io_buffer *head, |
static bool ccs_print_entry(struct ccs_io_buffer *head, |
2137 |
struct ccs_acl_info *ptr) |
struct ccs_acl_info *ptr) |
2138 |
{ |
{ |
2139 |
const struct ccs_condition_list *cond = ccs_get_condition_part(ptr); |
const struct ccs_condition *cond = ptr->cond; |
2140 |
const u8 acl_type = ccs_acl_type2(ptr); |
const u8 acl_type = ccs_acl_type2(ptr); |
2141 |
if (acl_type & ACL_DELETED) |
if (acl_type & ACL_DELETED) |
2142 |
return true; |
return true; |
2162 |
} |
} |
2163 |
if (head->read_execute_only) |
if (head->read_execute_only) |
2164 |
return true; |
return true; |
2165 |
|
if (acl_type == TYPE_MKDEV_ACL) { |
2166 |
|
struct ccs_mkdev_acl_record *acl |
2167 |
|
= container_of(ptr, struct ccs_mkdev_acl_record, head); |
2168 |
|
return ccs_print_mkdev_acl(head, acl, cond); |
2169 |
|
} |
2170 |
if (acl_type == TYPE_DOUBLE_PATH_ACL) { |
if (acl_type == TYPE_DOUBLE_PATH_ACL) { |
2171 |
struct ccs_double_path_acl_record *acl |
struct ccs_double_path_acl_record *acl |
2172 |
= container_of(ptr, struct ccs_double_path_acl_record, |
= container_of(ptr, struct ccs_double_path_acl_record, |
2205 |
= container_of(ptr, struct ccs_signal_acl_record, head); |
= container_of(ptr, struct ccs_signal_acl_record, head); |
2206 |
return ccs_print_signal_acl(head, acl, cond); |
return ccs_print_signal_acl(head, acl, cond); |
2207 |
} |
} |
2208 |
|
if (acl_type == TYPE_MOUNT_ACL) { |
2209 |
|
struct ccs_mount_acl_record *acl |
2210 |
|
= container_of(ptr, struct ccs_mount_acl_record, head); |
2211 |
|
return ccs_print_mount_acl(head, acl, cond); |
2212 |
|
} |
2213 |
|
if (acl_type == TYPE_UMOUNT_ACL) { |
2214 |
|
struct ccs_umount_acl_record *acl |
2215 |
|
= container_of(ptr, struct ccs_umount_acl_record, head); |
2216 |
|
return ccs_print_umount_acl(head, acl, cond); |
2217 |
|
} |
2218 |
|
if (acl_type == TYPE_CHROOT_ACL) { |
2219 |
|
struct ccs_chroot_acl_record *acl |
2220 |
|
= container_of(ptr, struct ccs_chroot_acl_record, head); |
2221 |
|
return ccs_print_chroot_acl(head, acl, cond); |
2222 |
|
} |
2223 |
|
if (acl_type == TYPE_PIVOT_ROOT_ACL) { |
2224 |
|
struct ccs_pivot_root_acl_record *acl |
2225 |
|
= container_of(ptr, struct ccs_pivot_root_acl_record, |
2226 |
|
head); |
2227 |
|
return ccs_print_pivot_root_acl(head, acl, cond); |
2228 |
|
} |
2229 |
/* Workaround for gcc 3.2.2's inline bug. */ |
/* Workaround for gcc 3.2.2's inline bug. */ |
2230 |
if (acl_type & ACL_DELETED) |
if (acl_type & ACL_DELETED) |
2231 |
return true; |
return true; |
2239 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
2240 |
* |
* |
2241 |
* Returns 0. |
* Returns 0. |
2242 |
|
* |
2243 |
|
* Caller holds ccs_read_lock(). |
2244 |
*/ |
*/ |
2245 |
static int ccs_read_domain_policy(struct ccs_io_buffer *head) |
static int ccs_read_domain_policy(struct ccs_io_buffer *head) |
2246 |
{ |
{ |
2247 |
struct list1_head *dpos; |
struct list_head *dpos; |
2248 |
struct list1_head *apos; |
struct list_head *apos; |
2249 |
|
ccs_check_read_lock(); |
2250 |
if (head->read_eof) |
if (head->read_eof) |
2251 |
return 0; |
return 0; |
2252 |
if (head->read_step == 0) |
if (head->read_step == 0) |
2253 |
head->read_step = 1; |
head->read_step = 1; |
2254 |
list1_for_each_cookie(dpos, head->read_var1, &ccs_domain_list) { |
list_for_each_cookie(dpos, head->read_var1, &ccs_domain_list) { |
2255 |
struct ccs_domain_info *domain; |
struct ccs_domain_info *domain; |
2256 |
const char *quota_exceeded = ""; |
const char *quota_exceeded = ""; |
2257 |
const char *transition_failed = ""; |
const char *transition_failed = ""; |
2258 |
const char *ignore_global_allow_read = ""; |
const char *ignore_global_allow_read = ""; |
2259 |
const char *ignore_global_allow_env = ""; |
const char *ignore_global_allow_env = ""; |
2260 |
domain = list1_entry(dpos, struct ccs_domain_info, list); |
domain = list_entry(dpos, struct ccs_domain_info, list); |
2261 |
if (head->read_step != 1) |
if (head->read_step != 1) |
2262 |
goto acl_loop; |
goto acl_loop; |
2263 |
if (domain->is_deleted && !head->read_single_domain) |
if (domain->is_deleted && !head->read_single_domain) |
2265 |
/* Print domainname and flags. */ |
/* Print domainname and flags. */ |
2266 |
if (domain->quota_warned) |
if (domain->quota_warned) |
2267 |
quota_exceeded = "quota_exceeded\n"; |
quota_exceeded = "quota_exceeded\n"; |
2268 |
if (domain->flags & DOMAIN_FLAGS_TRANSITION_FAILED) |
if (domain->domain_transition_failed) |
2269 |
transition_failed = "transition_failed\n"; |
transition_failed = "transition_failed\n"; |
2270 |
if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) |
if (domain->ignore_global_allow_read) |
2271 |
ignore_global_allow_read |
ignore_global_allow_read |
2272 |
= KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
= KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
2273 |
if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV) |
if (domain->ignore_global_allow_env) |
2274 |
ignore_global_allow_env |
ignore_global_allow_env |
2275 |
= KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n"; |
= KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n"; |
2276 |
if (!ccs_io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n" |
if (!ccs_io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n" |
2285 |
if (head->read_step == 3) |
if (head->read_step == 3) |
2286 |
goto tail_mark; |
goto tail_mark; |
2287 |
/* Print ACL entries in the domain. */ |
/* Print ACL entries in the domain. */ |
2288 |
list1_for_each_cookie(apos, head->read_var2, |
list_for_each_cookie(apos, head->read_var2, |
2289 |
&domain->acl_info_list) { |
&domain->acl_info_list) { |
2290 |
struct ccs_acl_info *ptr |
struct ccs_acl_info *ptr |
2291 |
= list1_entry(apos, struct ccs_acl_info, list); |
= list_entry(apos, struct ccs_acl_info, list); |
2292 |
if (!ccs_print_entry(head, ptr)) |
if (!ccs_print_entry(head, ptr)) |
2293 |
return 0; |
return 0; |
2294 |
} |
} |
2304 |
return 0; |
return 0; |
2305 |
} |
} |
2306 |
|
|
|
#endif |
|
|
|
|
2307 |
/** |
/** |
2308 |
* ccs_write_domain_profile - Assign profile for specified domain. |
* ccs_write_domain_profile - Assign profile for specified domain. |
2309 |
* |
* |
2315 |
* |
* |
2316 |
* ( echo "select " $domainname; echo "use_profile " $profile ) | |
* ( echo "select " $domainname; echo "use_profile " $profile ) | |
2317 |
* /usr/lib/ccs/loadpolicy -d |
* /usr/lib/ccs/loadpolicy -d |
2318 |
|
* |
2319 |
|
* Caller holds ccs_read_lock(). |
2320 |
*/ |
*/ |
2321 |
static int ccs_write_domain_profile(struct ccs_io_buffer *head) |
static int ccs_write_domain_profile(struct ccs_io_buffer *head) |
2322 |
{ |
{ |
2324 |
char *cp = strchr(data, ' '); |
char *cp = strchr(data, ' '); |
2325 |
struct ccs_domain_info *domain; |
struct ccs_domain_info *domain; |
2326 |
unsigned int profile; |
unsigned int profile; |
2327 |
|
ccs_check_read_lock(); |
2328 |
if (!cp) |
if (!cp) |
2329 |
return -EINVAL; |
return -EINVAL; |
2330 |
*cp = '\0'; |
*cp = '\0'; |
|
domain = ccs_find_domain(cp + 1); |
|
2331 |
profile = simple_strtoul(data, NULL, 10); |
profile = simple_strtoul(data, NULL, 10); |
2332 |
if (domain && profile < MAX_PROFILES |
if (profile >= MAX_PROFILES) |
2333 |
&& (ccs_profile_ptr[profile] || !ccs_policy_loaded)) |
return -EINVAL; |
2334 |
|
domain = ccs_find_domain(cp + 1); |
2335 |
|
if (domain && (ccs_profile_ptr[profile] || !ccs_policy_loaded)) |
2336 |
domain->profile = (u8) profile; |
domain->profile = (u8) profile; |
|
ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY); |
|
2337 |
return 0; |
return 0; |
2338 |
} |
} |
2339 |
|
|
2350 |
* awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) |
* awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" ) |
2351 |
* domainname = $0; } else if ( $1 == "use_profile" ) { |
* domainname = $0; } else if ( $1 == "use_profile" ) { |
2352 |
* print $2 " " domainname; domainname = ""; } } ; ' |
* print $2 " " domainname; domainname = ""; } } ; ' |
2353 |
|
* |
2354 |
|
* Caller holds ccs_read_lock(). |
2355 |
*/ |
*/ |
2356 |
static int ccs_read_domain_profile(struct ccs_io_buffer *head) |
static int ccs_read_domain_profile(struct ccs_io_buffer *head) |
2357 |
{ |
{ |
2358 |
struct list1_head *pos; |
struct list_head *pos; |
2359 |
|
ccs_check_read_lock(); |
2360 |
if (head->read_eof) |
if (head->read_eof) |
2361 |
return 0; |
return 0; |
2362 |
list1_for_each_cookie(pos, head->read_var1, &ccs_domain_list) { |
list_for_each_cookie(pos, head->read_var1, &ccs_domain_list) { |
2363 |
struct ccs_domain_info *domain; |
struct ccs_domain_info *domain; |
2364 |
domain = list1_entry(pos, struct ccs_domain_info, list); |
domain = list_entry(pos, struct ccs_domain_info, list); |
2365 |
if (domain->is_deleted) |
if (domain->is_deleted) |
2366 |
continue; |
continue; |
2367 |
if (!ccs_io_printf(head, "%u %s\n", domain->profile, |
if (!ccs_io_printf(head, "%u %s\n", domain->profile, |
2393 |
* Returns the domainname which the specified PID is in or |
* Returns the domainname which the specified PID is in or |
2394 |
* process information of the specified PID on success, |
* process information of the specified PID on success, |
2395 |
* empty string otherwise. |
* empty string otherwise. |
2396 |
|
* |
2397 |
|
* Caller holds ccs_read_lock(). |
2398 |
*/ |
*/ |
2399 |
static int ccs_read_pid(struct ccs_io_buffer *head) |
static int ccs_read_pid(struct ccs_io_buffer *head) |
2400 |
{ |
{ |
2404 |
struct task_struct *p; |
struct task_struct *p; |
2405 |
struct ccs_domain_info *domain = NULL; |
struct ccs_domain_info *domain = NULL; |
2406 |
u32 ccs_flags = 0; |
u32 ccs_flags = 0; |
2407 |
|
ccs_check_read_lock(); |
2408 |
/* Accessing write_buf is safe because head->io_sem is held. */ |
/* Accessing write_buf is safe because head->io_sem is held. */ |
2409 |
if (!buf) |
if (!buf) |
2410 |
goto done; /* Do nothing if open(O_RDONLY). */ |
goto done; /* Do nothing if open(O_RDONLY). */ |
2442 |
return 0; |
return 0; |
2443 |
} |
} |
2444 |
|
|
|
#ifdef CONFIG_TOMOYO |
|
|
|
|
2445 |
/** |
/** |
2446 |
* ccs_write_exception_policy - Write exception policy. |
* ccs_write_exception_policy - Write exception policy. |
2447 |
* |
* |
2463 |
if (ccs_str_starts(&data, KEYWORD_NO_INITIALIZE_DOMAIN)) |
if (ccs_str_starts(&data, KEYWORD_NO_INITIALIZE_DOMAIN)) |
2464 |
return ccs_write_domain_initializer_policy(data, true, |
return ccs_write_domain_initializer_policy(data, true, |
2465 |
is_delete); |
is_delete); |
|
if (ccs_str_starts(&data, KEYWORD_ALIAS)) |
|
|
return ccs_write_alias_policy(data, is_delete); |
|
2466 |
if (ccs_str_starts(&data, KEYWORD_AGGREGATOR)) |
if (ccs_str_starts(&data, KEYWORD_AGGREGATOR)) |
2467 |
return ccs_write_aggregator_policy(data, is_delete); |
return ccs_write_aggregator_policy(data, is_delete); |
2468 |
if (ccs_str_starts(&data, KEYWORD_ALLOW_READ)) |
if (ccs_str_starts(&data, KEYWORD_ALLOW_READ)) |
2473 |
return ccs_write_pattern_policy(data, is_delete); |
return ccs_write_pattern_policy(data, is_delete); |
2474 |
if (ccs_str_starts(&data, KEYWORD_PATH_GROUP)) |
if (ccs_str_starts(&data, KEYWORD_PATH_GROUP)) |
2475 |
return ccs_write_path_group_policy(data, is_delete); |
return ccs_write_path_group_policy(data, is_delete); |
2476 |
|
if (ccs_str_starts(&data, KEYWORD_NUMBER_GROUP)) |
2477 |
|
return ccs_write_number_group_policy(data, is_delete); |
2478 |
if (ccs_str_starts(&data, KEYWORD_DENY_REWRITE)) |
if (ccs_str_starts(&data, KEYWORD_DENY_REWRITE)) |
2479 |
return ccs_write_no_rewrite_policy(data, is_delete); |
return ccs_write_no_rewrite_policy(data, is_delete); |
2480 |
if (ccs_str_starts(&data, KEYWORD_ADDRESS_GROUP)) |
if (ccs_str_starts(&data, KEYWORD_ADDRESS_GROUP)) |
2481 |
return ccs_write_address_group_policy(data, is_delete); |
return ccs_write_address_group_policy(data, is_delete); |
2482 |
|
if (ccs_str_starts(&data, KEYWORD_DENY_AUTOBIND)) |
2483 |
|
return ccs_write_reserved_port_policy(data, is_delete); |
2484 |
return -EINVAL; |
return -EINVAL; |
2485 |
} |
} |
2486 |
|
|
2490 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
2491 |
* |
* |
2492 |
* Returns 0 on success, -EINVAL otherwise. |
* Returns 0 on success, -EINVAL otherwise. |
2493 |
|
* |
2494 |
|
* Caller holds ccs_read_lock(). |
2495 |
*/ |
*/ |
2496 |
static int ccs_read_exception_policy(struct ccs_io_buffer *head) |
static int ccs_read_exception_policy(struct ccs_io_buffer *head) |
2497 |
{ |
{ |
2498 |
|
ccs_check_read_lock(); |
2499 |
if (!head->read_eof) { |
if (!head->read_eof) { |
2500 |
switch (head->read_step) { |
switch (head->read_step) { |
2501 |
case 0: |
case 0: |
2520 |
if (!ccs_read_domain_initializer_policy(head)) |
if (!ccs_read_domain_initializer_policy(head)) |
2521 |
break; |
break; |
2522 |
head->read_var2 = NULL; |
head->read_var2 = NULL; |
|
head->read_step = 5; |
|
|
case 5: |
|
|
if (!ccs_read_alias_policy(head)) |
|
|
break; |
|
|
head->read_var2 = NULL; |
|
2523 |
head->read_step = 6; |
head->read_step = 6; |
2524 |
case 6: |
case 6: |
2525 |
if (!ccs_read_aggregator_policy(head)) |
if (!ccs_read_aggregator_policy(head)) |
2543 |
head->read_var2 = NULL; |
head->read_var2 = NULL; |
2544 |
head->read_step = 10; |
head->read_step = 10; |
2545 |
case 10: |
case 10: |
2546 |
if (!ccs_read_address_group_policy(head)) |
if (!ccs_read_number_group_policy(head)) |
|
break; |
|
|
head->read_eof = true; |
|
|
break; |
|
|
default: |
|
|
return -EINVAL; |
|
|
} |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef CONFIG_SAKURA |
|
|
|
|
|
/** |
|
|
* ccs_write_system_policy - Write system policy. |
|
|
* |
|
|
* @head: Pointer to "struct ccs_io_buffer". |
|
|
* |
|
|
* Returns 0 on success, negative value otherwise. |
|
|
*/ |
|
|
static int ccs_write_system_policy(struct ccs_io_buffer *head) |
|
|
{ |
|
|
char *data = head->write_buf; |
|
|
bool is_delete = false; |
|
|
if (ccs_str_starts(&data, KEYWORD_DELETE)) |
|
|
is_delete = true; |
|
|
if (ccs_str_starts(&data, KEYWORD_ALLOW_MOUNT)) |
|
|
return ccs_write_mount_policy(data, is_delete); |
|
|
if (ccs_str_starts(&data, KEYWORD_DENY_UNMOUNT)) |
|
|
return ccs_write_no_umount_policy(data, is_delete); |
|
|
if (ccs_str_starts(&data, KEYWORD_ALLOW_CHROOT)) |
|
|
return ccs_write_chroot_policy(data, is_delete); |
|
|
if (ccs_str_starts(&data, KEYWORD_ALLOW_PIVOT_ROOT)) |
|
|
return ccs_write_pivot_root_policy(data, is_delete); |
|
|
if (ccs_str_starts(&data, KEYWORD_DENY_AUTOBIND)) |
|
|
return ccs_write_reserved_port_policy(data, is_delete); |
|
|
return -EINVAL; |
|
|
} |
|
|
|
|
|
/** |
|
|
* ccs_read_system_policy - Read system policy. |
|
|
* |
|
|
* @head: Pointer to "struct ccs_io_buffer". |
|
|
* |
|
|
* Returns 0 on success, -EINVAL otherwise. |
|
|
*/ |
|
|
static int ccs_read_system_policy(struct ccs_io_buffer *head) |
|
|
{ |
|
|
if (!head->read_eof) { |
|
|
switch (head->read_step) { |
|
|
case 0: |
|
|
head->read_var2 = NULL; |
|
|
head->read_step = 1; |
|
|
case 1: |
|
|
if (!ccs_read_mount_policy(head)) |
|
|
break; |
|
|
head->read_var2 = NULL; |
|
|
head->read_step = 2; |
|
|
case 2: |
|
|
if (!ccs_read_no_umount_policy(head)) |
|
|
break; |
|
|
head->read_var2 = NULL; |
|
|
head->read_step = 3; |
|
|
case 3: |
|
|
if (!ccs_read_chroot_policy(head)) |
|
2547 |
break; |
break; |
2548 |
|
head->read_var1 = NULL; |
2549 |
head->read_var2 = NULL; |
head->read_var2 = NULL; |
2550 |
head->read_step = 4; |
head->read_step = 11; |
2551 |
case 4: |
case 11: |
2552 |
if (!ccs_read_pivot_root_policy(head)) |
if (!ccs_read_address_group_policy(head)) |
2553 |
break; |
break; |
2554 |
head->read_var2 = NULL; |
head->read_var2 = NULL; |
2555 |
head->read_step = 5; |
head->read_step = 12; |
2556 |
case 5: |
case 12: |
2557 |
if (!ccs_read_reserved_port_policy(head)) |
if (!ccs_read_reserved_port_policy(head)) |
2558 |
break; |
break; |
2559 |
head->read_eof = true; |
head->read_eof = true; |
2565 |
return 0; |
return 0; |
2566 |
} |
} |
2567 |
|
|
|
#endif |
|
|
|
|
2568 |
/* Path to the policy loader. The default is /sbin/ccs-init. */ |
/* Path to the policy loader. The default is /sbin/ccs-init. */ |
2569 |
static const char *ccs_loader; |
static const char *ccs_loader; |
2570 |
|
|
2716 |
spin_unlock_irq(&task->sigmask_lock); |
spin_unlock_irq(&task->sigmask_lock); |
2717 |
} |
} |
2718 |
#endif |
#endif |
2719 |
#ifdef CONFIG_SAKURA |
printk(KERN_INFO "SAKURA: 1.7.0-pre 2009/07/03\n"); |
2720 |
printk(KERN_INFO "SAKURA: 1.6.7-rc 2009/03/18\n"); |
printk(KERN_INFO "TOMOYO: 1.7.0-pre 2009/07/03\n"); |
|
#endif |
|
|
#ifdef CONFIG_TOMOYO |
|
|
printk(KERN_INFO "TOMOYO: 1.6.7-rc 2009/03/18\n"); |
|
|
#endif |
|
2721 |
printk(KERN_INFO "Mandatory Access Control activated.\n"); |
printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2722 |
ccs_policy_loaded = true; |
ccs_policy_loaded = true; |
|
ccs_log_level = KERN_WARNING; |
|
2723 |
{ /* Check all profiles currently assigned to domains are defined. */ |
{ /* Check all profiles currently assigned to domains are defined. */ |
2724 |
struct ccs_domain_info *domain; |
struct ccs_domain_info *domain; |
2725 |
list1_for_each_entry(domain, &ccs_domain_list, list) { |
list_for_each_entry_rcu(domain, &ccs_domain_list, list) { |
2726 |
const u8 profile = domain->profile; |
const u8 profile = domain->profile; |
2727 |
if (ccs_profile_ptr[profile]) |
if (ccs_profile_ptr[profile]) |
2728 |
continue; |
continue; |
2773 |
int len; |
int len; |
2774 |
static unsigned int ccs_serial; |
static unsigned int ccs_serial; |
2775 |
struct ccs_query_entry *ccs_query_entry = NULL; |
struct ccs_query_entry *ccs_query_entry = NULL; |
2776 |
|
bool quota_exceeded = false; |
2777 |
char *header; |
char *header; |
2778 |
if (!r->domain) |
if (!r->domain) |
2779 |
r->domain = ccs_current_domain(); |
r->domain = ccs_current_domain(); |
2791 |
va_start(args, fmt); |
va_start(args, fmt); |
2792 |
len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; |
len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; |
2793 |
va_end(args); |
va_end(args); |
|
#ifdef CONFIG_TOMOYO |
|
2794 |
header = ccs_init_audit_log(&len, r); |
header = ccs_init_audit_log(&len, r); |
|
#else |
|
|
header = ccs_alloc(1, true); |
|
|
#endif |
|
2795 |
if (!header) |
if (!header) |
2796 |
goto out; |
goto out; |
2797 |
ccs_query_entry = ccs_alloc(sizeof(*ccs_query_entry), true); |
ccs_query_entry = kzalloc(sizeof(*ccs_query_entry), GFP_KERNEL); |
2798 |
if (!ccs_query_entry) |
if (!ccs_query_entry) |
2799 |
goto out; |
goto out; |
2800 |
ccs_query_entry->query = ccs_alloc(len, true); |
ccs_query_entry->query = kzalloc(len, GFP_KERNEL); |
2801 |
if (!ccs_query_entry->query) |
if (!ccs_query_entry->query) |
2802 |
goto out; |
goto out; |
2803 |
INIT_LIST_HEAD(&ccs_query_entry->list); |
INIT_LIST_HEAD(&ccs_query_entry->list); |
2804 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
2805 |
spin_lock(&ccs_query_list_lock); |
spin_lock(&ccs_query_list_lock); |
2806 |
ccs_query_entry->serial = ccs_serial++; |
if (ccs_quota_for_query && ccs_query_memory_size + len + |
2807 |
|
sizeof(*ccs_query_entry) >= ccs_quota_for_query) { |
2808 |
|
quota_exceeded = true; |
2809 |
|
} else { |
2810 |
|
ccs_query_memory_size += len + sizeof(*ccs_query_entry); |
2811 |
|
ccs_query_entry->serial = ccs_serial++; |
2812 |
|
} |
2813 |
spin_unlock(&ccs_query_list_lock); |
spin_unlock(&ccs_query_list_lock); |
2814 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
2815 |
|
if (quota_exceeded) |
2816 |
|
goto out; |
2817 |
pos = snprintf(ccs_query_entry->query, len - 1, "Q%u-%hu\n%s", |
pos = snprintf(ccs_query_entry->query, len - 1, "Q%u-%hu\n%s", |
2818 |
ccs_query_entry->serial, r->retry, header); |
ccs_query_entry->serial, r->retry, header); |
2819 |
ccs_free(header); |
kfree(header); |
2820 |
header = NULL; |
header = NULL; |
2821 |
va_start(args, fmt); |
va_start(args, fmt); |
2822 |
vsnprintf(ccs_query_entry->query + pos, len - 1 - pos, fmt, args); |
vsnprintf(ccs_query_entry->query + pos, len - 1 - pos, fmt, args); |
2827 |
list_add_tail(&ccs_query_entry->list, &ccs_query_list); |
list_add_tail(&ccs_query_entry->list, &ccs_query_list); |
2828 |
spin_unlock(&ccs_query_list_lock); |
spin_unlock(&ccs_query_list_lock); |
2829 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
|
ccs_update_counter(CCS_UPDATES_COUNTER_QUERY); |
|
2830 |
/* Give 10 seconds for supervisor's opinion. */ |
/* Give 10 seconds for supervisor's opinion. */ |
2831 |
for (ccs_query_entry->timer = 0; |
for (ccs_query_entry->timer = 0; |
2832 |
atomic_read(&ccs_query_observers) && ccs_query_entry->timer < 100; |
atomic_read(&ccs_query_observers) && ccs_query_entry->timer < 100; |
2837 |
if (ccs_query_entry->answer) |
if (ccs_query_entry->answer) |
2838 |
break; |
break; |
2839 |
} |
} |
|
ccs_update_counter(CCS_UPDATES_COUNTER_QUERY); |
|
2840 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
2841 |
spin_lock(&ccs_query_list_lock); |
spin_lock(&ccs_query_list_lock); |
2842 |
list_del(&ccs_query_entry->list); |
list_del(&ccs_query_entry->list); |
2843 |
|
ccs_query_memory_size -= len + sizeof(*ccs_query_entry); |
2844 |
spin_unlock(&ccs_query_list_lock); |
spin_unlock(&ccs_query_list_lock); |
2845 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
2846 |
switch (ccs_query_entry->answer) { |
switch (ccs_query_entry->answer) { |
2861 |
} |
} |
2862 |
out: |
out: |
2863 |
if (ccs_query_entry) |
if (ccs_query_entry) |
2864 |
ccs_free(ccs_query_entry->query); |
kfree(ccs_query_entry->query); |
2865 |
ccs_free(ccs_query_entry); |
kfree(ccs_query_entry); |
2866 |
ccs_free(header); |
kfree(header); |
2867 |
return error; |
return error; |
2868 |
} |
} |
2869 |
|
|
2920 |
if (head->read_avail) |
if (head->read_avail) |
2921 |
return 0; |
return 0; |
2922 |
if (head->read_buf) { |
if (head->read_buf) { |
2923 |
ccs_free(head->read_buf); |
kfree(head->read_buf); |
2924 |
head->read_buf = NULL; |
head->read_buf = NULL; |
2925 |
head->readbuf_size = 0; |
head->readbuf_size = 0; |
2926 |
} |
} |
2942 |
head->read_step = 0; |
head->read_step = 0; |
2943 |
return 0; |
return 0; |
2944 |
} |
} |
2945 |
buf = ccs_alloc(len, false); |
buf = kzalloc(len, GFP_KERNEL); |
2946 |
if (!buf) |
if (!buf) |
2947 |
return 0; |
return 0; |
2948 |
pos = 0; |
pos = 0; |
2971 |
head->read_buf = buf; |
head->read_buf = buf; |
2972 |
head->read_step++; |
head->read_step++; |
2973 |
} else { |
} else { |
2974 |
ccs_free(buf); |
kfree(buf); |
2975 |
} |
} |
2976 |
return 0; |
return 0; |
2977 |
} |
} |
3016 |
return 0; |
return 0; |
3017 |
} |
} |
3018 |
|
|
|
#if !defined(atomic_xchg) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) |
|
|
|
|
|
/* Policy updates counter. */ |
|
|
static unsigned int ccs_updates_counter[MAX_CCS_UPDATES_COUNTER]; |
|
|
|
|
|
/* Policy updates counter lock. */ |
|
|
static DEFINE_SPINLOCK(ccs_updates_counter_lock); |
|
|
|
|
|
/** |
|
|
* ccs_update_counter - Increment policy change counter. |
|
|
* |
|
|
* @index: Type of policy. |
|
|
* |
|
|
* Returns nothing. |
|
|
*/ |
|
|
void ccs_update_counter(const unsigned char index) |
|
|
{ |
|
|
/***** CRITICAL SECTION START *****/ |
|
|
spin_lock(&ccs_updates_counter_lock); |
|
|
if (index < MAX_CCS_UPDATES_COUNTER) |
|
|
ccs_updates_counter[index]++; |
|
|
spin_unlock(&ccs_updates_counter_lock); |
|
|
/***** CRITICAL SECTION END *****/ |
|
|
} |
|
|
|
|
|
/** |
|
|
* ccs_read_updates_counter - Check for policy change counter. |
|
|
* |
|
|
* @head: Pointer to "struct ccs_io_buffer". |
|
|
* |
|
|
* Returns how many times policy has changed since the previous check. |
|
|
*/ |
|
|
static int ccs_read_updates_counter(struct ccs_io_buffer *head) |
|
|
{ |
|
|
unsigned int counter[MAX_CCS_UPDATES_COUNTER]; |
|
|
if (head->read_eof) |
|
|
return 0; |
|
|
/***** CRITICAL SECTION START *****/ |
|
|
spin_lock(&ccs_updates_counter_lock); |
|
|
memmove(counter, ccs_updates_counter, sizeof(ccs_updates_counter)); |
|
|
memset(ccs_updates_counter, 0, sizeof(ccs_updates_counter)); |
|
|
spin_unlock(&ccs_updates_counter_lock); |
|
|
/***** CRITICAL SECTION END *****/ |
|
|
ccs_io_printf(head, |
|
|
"/proc/ccs/system_policy: %10u\n" |
|
|
"/proc/ccs/domain_policy: %10u\n" |
|
|
"/proc/ccs/exception_policy: %10u\n" |
|
|
"/proc/ccs/profile: %10u\n" |
|
|
"/proc/ccs/query: %10u\n" |
|
|
"/proc/ccs/manager: %10u\n" |
|
|
#ifdef CONFIG_TOMOYO_AUDIT |
|
|
"/proc/ccs/grant_log: %10u\n" |
|
|
"/proc/ccs/reject_log: %10u\n" |
|
|
#endif |
|
|
, counter[CCS_UPDATES_COUNTER_SYSTEM_POLICY] |
|
|
, counter[CCS_UPDATES_COUNTER_DOMAIN_POLICY] |
|
|
, counter[CCS_UPDATES_COUNTER_EXCEPTION_POLICY] |
|
|
, counter[CCS_UPDATES_COUNTER_PROFILE] |
|
|
, counter[CCS_UPDATES_COUNTER_QUERY] |
|
|
, counter[CCS_UPDATES_COUNTER_MANAGER] |
|
|
#ifdef CONFIG_TOMOYO_AUDIT |
|
|
, counter[CCS_UPDATES_COUNTER_GRANT_LOG] |
|
|
, counter[CCS_UPDATES_COUNTER_REJECT_LOG] |
|
|
#endif |
|
|
); |
|
|
head->read_eof = true; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
#else |
|
|
|
|
|
/* Policy updates counter. */ |
|
|
static atomic_t ccs_updates_counter[MAX_CCS_UPDATES_COUNTER]; |
|
|
|
|
|
/** |
|
|
* ccs_update_counter - Increment policy change counter. |
|
|
* |
|
|
* @index: Type of policy. |
|
|
* |
|
|
* Returns nothing. |
|
|
*/ |
|
|
void ccs_update_counter(const unsigned char index) |
|
|
{ |
|
|
if (index < MAX_CCS_UPDATES_COUNTER) |
|
|
atomic_inc(&ccs_updates_counter[index]); |
|
|
} |
|
|
|
|
|
/** |
|
|
* ccs_read_updates_counter - Check for policy change counter. |
|
|
* |
|
|
* @head: Pointer to "struct ccs_io_buffer". |
|
|
* |
|
|
* Returns how many times policy has changed since the previous check. |
|
|
*/ |
|
|
static int ccs_read_updates_counter(struct ccs_io_buffer *head) |
|
|
{ |
|
|
if (head->read_eof) |
|
|
return 0; |
|
|
ccs_io_printf(head, |
|
|
"/proc/ccs/system_policy: %10u\n" |
|
|
"/proc/ccs/domain_policy: %10u\n" |
|
|
"/proc/ccs/exception_policy: %10u\n" |
|
|
"/proc/ccs/profile: %10u\n" |
|
|
"/proc/ccs/query: %10u\n" |
|
|
"/proc/ccs/manager: %10u\n" |
|
|
#ifdef CONFIG_TOMOYO_AUDIT |
|
|
"/proc/ccs/grant_log: %10u\n" |
|
|
"/proc/ccs/reject_log: %10u\n" |
|
|
#endif |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_SYSTEM_POLICY], 0) |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_DOMAIN_POLICY], 0) |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_EXCEPTION_POLICY], 0) |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_PROFILE], 0) |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_QUERY], 0) |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_MANAGER], 0) |
|
|
#ifdef CONFIG_TOMOYO_AUDIT |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_GRANT_LOG], 0) |
|
|
, atomic_xchg(&ccs_updates_counter |
|
|
[CCS_UPDATES_COUNTER_REJECT_LOG], 0) |
|
|
#endif |
|
|
); |
|
|
head->read_eof = true; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
3019 |
/** |
/** |
3020 |
* ccs_read_version: Get version. |
* ccs_read_version: Get version. |
3021 |
* |
* |
3026 |
static int ccs_read_version(struct ccs_io_buffer *head) |
static int ccs_read_version(struct ccs_io_buffer *head) |
3027 |
{ |
{ |
3028 |
if (!head->read_eof) { |
if (!head->read_eof) { |
3029 |
ccs_io_printf(head, "1.6.7-rc"); |
ccs_io_printf(head, "1.7.0-pre"); |
3030 |
head->read_eof = true; |
head->read_eof = true; |
3031 |
} |
} |
3032 |
return 0; |
return 0; |
3064 |
*/ |
*/ |
3065 |
int ccs_open_control(const u8 type, struct file *file) |
int ccs_open_control(const u8 type, struct file *file) |
3066 |
{ |
{ |
3067 |
struct ccs_io_buffer *head = ccs_alloc(sizeof(*head), false); |
struct ccs_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); |
3068 |
if (!head) |
if (!head) |
3069 |
return -ENOMEM; |
return -ENOMEM; |
3070 |
mutex_init(&head->io_sem); |
mutex_init(&head->io_sem); |
3071 |
|
head->type = type; |
3072 |
switch (type) { |
switch (type) { |
|
#ifdef CONFIG_SAKURA |
|
|
case CCS_SYSTEMPOLICY: /* /proc/ccs/system_policy */ |
|
|
head->write = ccs_write_system_policy; |
|
|
head->read = ccs_read_system_policy; |
|
|
break; |
|
|
#endif |
|
|
#ifdef CONFIG_TOMOYO |
|
3073 |
case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */ |
case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */ |
3074 |
head->write = ccs_write_domain_policy; |
head->write = ccs_write_domain_policy; |
3075 |
head->read = ccs_read_domain_policy; |
head->read = ccs_read_domain_policy; |
3078 |
head->write = ccs_write_exception_policy; |
head->write = ccs_write_exception_policy; |
3079 |
head->read = ccs_read_exception_policy; |
head->read = ccs_read_exception_policy; |
3080 |
break; |
break; |
3081 |
#ifdef CONFIG_TOMOYO_AUDIT |
#ifdef CONFIG_CCSECURITY_AUDIT |
3082 |
case CCS_GRANTLOG: /* /proc/ccs/grant_log */ |
case CCS_GRANTLOG: /* /proc/ccs/grant_log */ |
3083 |
head->poll = ccs_poll_grant_log; |
head->poll = ccs_poll_grant_log; |
3084 |
head->read = ccs_read_grant_log; |
head->read = ccs_read_grant_log; |
3088 |
head->read = ccs_read_reject_log; |
head->read = ccs_read_reject_log; |
3089 |
break; |
break; |
3090 |
#endif |
#endif |
|
#endif |
|
3091 |
case CCS_SELFDOMAIN: /* /proc/ccs/self_domain */ |
case CCS_SELFDOMAIN: /* /proc/ccs/self_domain */ |
3092 |
head->read = ccs_read_self_domain; |
head->read = ccs_read_self_domain; |
3093 |
break; |
break; |
3098 |
case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */ |
case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */ |
3099 |
/* Allow execute_handler to read process's status. */ |
/* Allow execute_handler to read process's status. */ |
3100 |
if (!(current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)) { |
if (!(current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)) { |
3101 |
ccs_free(head); |
kfree(head); |
3102 |
return -EPERM; |
return -EPERM; |
3103 |
} |
} |
3104 |
/* fall through */ |
/* fall through */ |
3128 |
head->write = ccs_write_manager_policy; |
head->write = ccs_write_manager_policy; |
3129 |
head->read = ccs_read_manager_policy; |
head->read = ccs_read_manager_policy; |
3130 |
break; |
break; |
|
case CCS_UPDATESCOUNTER: /* /proc/ccs/.ccs_updates_counter */ |
|
|
head->read = ccs_read_updates_counter; |
|
|
break; |
|
3131 |
} |
} |
3132 |
if (!(file->f_mode & FMODE_READ)) { |
if (!(file->f_mode & FMODE_READ)) { |
3133 |
/* |
/* |
3136 |
*/ |
*/ |
3137 |
head->read = NULL; |
head->read = NULL; |
3138 |
head->poll = NULL; |
head->poll = NULL; |
3139 |
} else if (type != CCS_QUERY |
} else if (type != CCS_QUERY && |
3140 |
#ifdef CONFIG_TOMOYO_AUDIT |
type != CCS_GRANTLOG && type != CCS_REJECTLOG) { |
|
&& type != CCS_GRANTLOG && type != CCS_REJECTLOG |
|
|
#endif |
|
|
) { |
|
3141 |
/* |
/* |
3142 |
* Don't allocate buffer for reading if the file is one of |
* Don't allocate buffer for reading if the file is one of |
3143 |
* /proc/ccs/grant_log , /proc/ccs/reject_log , /proc/ccs/query. |
* /proc/ccs/grant_log , /proc/ccs/reject_log , /proc/ccs/query. |
3144 |
*/ |
*/ |
3145 |
if (!head->readbuf_size) |
if (!head->readbuf_size) |
3146 |
head->readbuf_size = 4096 * 2; |
head->readbuf_size = 4096 * 2; |
3147 |
head->read_buf = ccs_alloc(head->readbuf_size, false); |
head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); |
3148 |
if (!head->read_buf) { |
if (!head->read_buf) { |
3149 |
ccs_free(head); |
kfree(head); |
3150 |
return -ENOMEM; |
return -ENOMEM; |
3151 |
} |
} |
3152 |
} |
} |
3158 |
head->write = NULL; |
head->write = NULL; |
3159 |
} else if (head->write) { |
} else if (head->write) { |
3160 |
head->writebuf_size = 4096 * 2; |
head->writebuf_size = 4096 * 2; |
3161 |
head->write_buf = ccs_alloc(head->writebuf_size, false); |
head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); |
3162 |
if (!head->write_buf) { |
if (!head->write_buf) { |
3163 |
ccs_free(head->read_buf); |
kfree(head->read_buf); |
3164 |
ccs_free(head); |
kfree(head); |
3165 |
return -ENOMEM; |
return -ENOMEM; |
3166 |
} |
} |
3167 |
} |
} |
3168 |
|
if (type != CCS_QUERY && |
3169 |
|
type != CCS_GRANTLOG && type != CCS_REJECTLOG) |
3170 |
|
head->reader_idx = ccs_read_lock(); |
3171 |
file->private_data = head; |
file->private_data = head; |
3172 |
/* |
/* |
3173 |
* Call the handler now if the file is /proc/ccs/self_domain |
* Call the handler now if the file is /proc/ccs/self_domain |
3181 |
* The obserber counter is used by ccs_check_supervisor() to see if |
* The obserber counter is used by ccs_check_supervisor() to see if |
3182 |
* there is some process monitoring /proc/ccs/query. |
* there is some process monitoring /proc/ccs/query. |
3183 |
*/ |
*/ |
3184 |
else if (head->write == ccs_write_answer || |
else if (type == CCS_QUERY) |
|
head->read == ccs_read_query) |
|
3185 |
atomic_inc(&ccs_query_observers); |
atomic_inc(&ccs_query_observers); |
3186 |
return 0; |
return 0; |
3187 |
} |
} |
3271 |
return -EFAULT; |
return -EFAULT; |
3272 |
/* Don't allow updating policies by non manager programs. */ |
/* Don't allow updating policies by non manager programs. */ |
3273 |
if (head->write != ccs_write_pid && |
if (head->write != ccs_write_pid && |
|
#ifdef CONFIG_TOMOYO |
|
3274 |
head->write != ccs_write_domain_policy && |
head->write != ccs_write_domain_policy && |
|
#endif |
|
3275 |
!ccs_is_policy_manager()) |
!ccs_is_policy_manager()) |
3276 |
return -EPERM; |
return -EPERM; |
3277 |
if (mutex_lock_interruptible(&head->io_sem)) |
if (mutex_lock_interruptible(&head->io_sem)) |
3310 |
int ccs_close_control(struct file *file) |
int ccs_close_control(struct file *file) |
3311 |
{ |
{ |
3312 |
struct ccs_io_buffer *head = file->private_data; |
struct ccs_io_buffer *head = file->private_data; |
3313 |
|
const bool is_write = head->write_buf != NULL; |
3314 |
|
const u8 type = head->type; |
3315 |
/* |
/* |
3316 |
* If the file is /proc/ccs/query , decrement the observer counter. |
* If the file is /proc/ccs/query , decrement the observer counter. |
3317 |
*/ |
*/ |
3318 |
if (head->write == ccs_write_answer || head->read == ccs_read_query) |
if (type == CCS_QUERY) |
3319 |
atomic_dec(&ccs_query_observers); |
atomic_dec(&ccs_query_observers); |
3320 |
|
if (type != CCS_QUERY && |
3321 |
|
type != CCS_GRANTLOG && type != CCS_REJECTLOG) |
3322 |
|
ccs_read_unlock(head->reader_idx); |
3323 |
/* Release memory used for policy I/O. */ |
/* Release memory used for policy I/O. */ |
3324 |
ccs_free(head->read_buf); |
kfree(head->read_buf); |
3325 |
head->read_buf = NULL; |
head->read_buf = NULL; |
3326 |
ccs_free(head->write_buf); |
kfree(head->write_buf); |
3327 |
head->write_buf = NULL; |
head->write_buf = NULL; |
3328 |
ccs_free(head); |
kfree(head); |
3329 |
head = NULL; |
head = NULL; |
3330 |
file->private_data = NULL; |
file->private_data = NULL; |
3331 |
|
if (is_write) |
3332 |
|
ccs_run_gc(); |
3333 |
return 0; |
return 0; |
3334 |
} |
} |
|
|
|
|
/** |
|
|
* ccs_alloc_acl_element - Allocate permanent memory for ACL entry. |
|
|
* |
|
|
* @acl_type: Type of ACL entry. |
|
|
* @condition: Pointer to condition part of the ACL entry. May be NULL. |
|
|
* |
|
|
* Returns pointer to the ACL entry on success, NULL otherwise. |
|
|
*/ |
|
|
void *ccs_alloc_acl_element(const u8 acl_type, |
|
|
const struct ccs_condition_list *condition) |
|
|
{ |
|
|
int len; |
|
|
struct ccs_acl_info *ptr; |
|
|
switch (acl_type) { |
|
|
case TYPE_SINGLE_PATH_ACL: |
|
|
len = sizeof(struct ccs_single_path_acl_record); |
|
|
break; |
|
|
case TYPE_DOUBLE_PATH_ACL: |
|
|
len = sizeof(struct ccs_double_path_acl_record); |
|
|
break; |
|
|
case TYPE_IOCTL_ACL: |
|
|
len = sizeof(struct ccs_ioctl_acl_record); |
|
|
break; |
|
|
case TYPE_ARGV0_ACL: |
|
|
len = sizeof(struct ccs_argv0_acl_record); |
|
|
break; |
|
|
case TYPE_ENV_ACL: |
|
|
len = sizeof(struct ccs_env_acl_record); |
|
|
break; |
|
|
case TYPE_CAPABILITY_ACL: |
|
|
len = sizeof(struct ccs_capability_acl_record); |
|
|
break; |
|
|
case TYPE_IP_NETWORK_ACL: |
|
|
len = sizeof(struct ccs_ip_network_acl_record); |
|
|
break; |
|
|
case TYPE_SIGNAL_ACL: |
|
|
len = sizeof(struct ccs_signal_acl_record); |
|
|
break; |
|
|
case TYPE_EXECUTE_HANDLER: |
|
|
case TYPE_DENIED_EXECUTE_HANDLER: |
|
|
len = sizeof(struct ccs_execute_handler_record); |
|
|
break; |
|
|
default: |
|
|
return NULL; |
|
|
} |
|
|
/* |
|
|
* If the ACL doesn't have condition part, reduce memory usage |
|
|
* by eliminating sizeof(struct ccs_condition_list *). |
|
|
*/ |
|
|
if (!condition) |
|
|
len -= sizeof(ptr->access_me_via_ccs_get_condition_part); |
|
|
ptr = ccs_alloc_element(len); |
|
|
if (!ptr) |
|
|
return NULL; |
|
|
if (condition) { |
|
|
ptr->access_me_via_ccs_get_condition_part = condition; |
|
|
ptr->type = acl_type | ACL_WITH_CONDITION; |
|
|
return ptr; |
|
|
} |
|
|
/* |
|
|
* Substract sizeof(struct ccs_condition_list *) because I eliminated |
|
|
* sizeof(struct ccs_condition_list *) from "struct ccs_acl_info" |
|
|
* but I must return the start address of "struct ccs_acl_info". |
|
|
*/ |
|
|
ptr = (void *) (((u8 *) ptr) |
|
|
- sizeof(ptr->access_me_via_ccs_get_condition_part)); |
|
|
ptr->type = acl_type; |
|
|
return ptr; |
|
|
} |
|