The attached patch is a revised version of memcached permissions. The 'calculate' permission has gone, and INCR/DECR requires us both of 'read' and 'write' permissions. It means we should switch domain of the client process when we need special treatments to unaccessable items; something like trusted procedures. Rest of the patch is not changed. (2010/08/05 9:20), KaiGai Kohei wrote: > (2010/08/04 10:25), Kelvin Edmison wrote: >> I'm still not sure how allowing a 'calculate' permission would be helpful in >> this case. Incr and decr allow for incrementing and decrementing by any >> amount. There does not seem to be any real difference between that and >> 'write' to me. >> > INCR and DECR allow users to set a numerical value according to arithmetic > rule, although SET allows to set a fully arbitrary value. > If administrator want to allow users to modify a value in a limited way, > he can grant 'calculate' permission, instead of 'write' permission. > > If we would be talking about RDBMS, it is possible to switch client's > privileges during execution of a certain stored procedure. > However, memcached does not have such a feature, so we need to consider > more fine grained permissions. > > BTW, I noticed a different viewpoint, although I didn't reach the idea before. > Since memcached does not have stored procedure, it might be a correct answer > that the client switches its privileges when it tries to modify read-only > values. Like set-uid programs in unix, SELinux has a feature to switch > privileges of process on execve(2) time. It allows a small number of trusted > programs to write values, but prevents to modify items by others. > >> If a strict security partitioning is desired, then perhaps a single >> reference counter isn't feasible. Would it not be better, from a security >> point of view, to have individual counters for the different clients? >> The clients would have 'create|read|write' permissions, and any overall >> administrative app could have read-only permissions on all those counters to >> collect and sum (or otherwise report) them? >> > If a strict security partitioning environment, it seems to me what you introduced > is reasonable. > > Thanks, > >> Kelvin >> >> On 02/08/10 1:45 AM, "KaiGai Kohei"<kaigai@xxxxxxxxxxxxx> wrote: >> >>> (2010/07/30 22:55), Kelvin Edmison wrote: >>>> While I haven't yet read the patch, I would like to understand why there is >>>> a need for a Calculate permission. Why would someone be granted 'calculate' >>>> permission but not 'write' permission? >>>> >>>> Kelvin >>>> >>> The issue depends on individual user's requirement of security. >>> If they want not to leak anything over the security domains, >>> they should grant the 'calculate' permission on everybody who >>> already have both 'read' and 'write' permissions. >>> It it equivalent to these permissions. >>> However, it may lack flexibility in configuration of access >>> controls, if users don't consider 'INCR' and 'DECR' are risk >>> information leaks/manipulations. >>> For example, it is not a rare case that we don't want to expose >>> individual client's items, but want to control a shared reference >>> counter. >>> >>> Ideally, I'd like to define more fine grained permissions to >>> distinguish a security sensitive operations and others. >>> But here is limitation of protocol. We cannot automatically >>> determine what is security sensitive data and what is not. >>> >>> Thanks, >>> >>>> On 30/07/10 12:49 AM, "KaiGai Kohei"<kaigai@xxxxxxxxxxxxx> wrote: >>>> >>>>> I'll mainly submit the patch and message to SELinux community, >>>>> but please don't hesitate to comment anything from memcached >>>>> community. >>>>> -------- >>>>> >>>>> The attached patch adds policies to support access controls >>>>> on key-value items managed by memcached with SELinux engine. >>>>> >>>>> Nowadays, various kind of key-value-stores support memcached >>>>> compatible protocol as a de-facto standard. So, it will be a >>>>> reasonable start to consider the protocol to control accesses >>>>> from clients; typically web applications. >>>>> >>>>> http://github.com/memcached/memcached/blob/master/doc/protocol.txt >>>>> >>>>> 1) new permissions >>>>> >>>>> This patch adds 'kv_item' class with the following permissions >>>>> - create >>>>> - getattr >>>>> - setattr >>>>> - remove >>>>> - relabelfrom >>>>> - relabelto >>>>> - read >>>>> - write >>>>> - append >>>>> - calculate >>>>> >>>>> Most of permission works as literal. >>>>> On the 'SET' or 'CAS' operations, it creates a new item when here >>>>> is no items with same kye. In this case, 'create' permission shall >>>>> be checked. Elsewhere, 'write' permission shall be checked on the >>>>> existing items. >>>>> >>>>> When an item get expired, it shall be unlinked internally. In this >>>>> case, no permissions are checked, because it does not work according >>>>> to the user's request. >>>>> >>>>> On the 'FLUSH_ALL' operation, it unlinks any items older than >>>>> a certain watermark. In this case, 'remove' permission shall be >>>>> checked on the items to be unlinked. If violated, it skips to >>>>> unlink this item. >>>>> >>>>> On 'INCR' or 'DECR' operation, 'calculate' permission shall be checked. >>>>> Is it necessary to distinguish between 'INCR' and 'DECR' here? >>>>> E.g, an item which can be incremented, but unavailable to decrement. >>>>> >>>>> 2) new types >>>>> - memcached_db_t >>>>> Some of modular memcached engines support on-disk storage, not only >>>>> volatile ram. The selinux_engine.so allows us to use a certain file >>>>> as a backend storage, but existing policy does not have definition >>>>> of data file type. This type allows memcached_t read/write accesses. >>>>> >>>>> - memcached_item_t (default of unconfined domain) >>>>> - memcached_ro_item_t >>>>> - memcached_secret_item_t >>>>> - user_memcached_item_t (default of rbac domain) >>>>> - unpriv_memcached_item_t (default of unprivileged domain) >>>>> These are types of individual key-value items. >>>>> The three default types are read-writable for its domains, >>>>> memcached_ro_item_t is read-only for confined domains, and >>>>> memcached_secret_t is invisible from confined domains. >>>>> >>>>> 3) supplemental policies >>>>> - This patch also adds permission on memcached_t to communicate with >>>>> SELinux using netlink socket and selinuxfs. >>>>> - This patch also adds permission on memcached_t to write out audit >>>>> logs onto auditd daemon, although it is not implemented yet. >>>>> >>>>> Thanks, Any comments please. >>>> >> >> > > -- KaiGai Kohei <kaigai@xxxxxxxxxxxxx>
diff --git a/policy/flask/access_vectors b/policy/flask/access_vectors index 6760c95..f6b82a2 100644 --- a/policy/flask/access_vectors +++ b/policy/flask/access_vectors @@ -816,3 +816,16 @@ inherits x_device class x_keyboard inherits x_device + +class kv_item +{ + create + getattr + setattr + remove + relabelfrom + relabelto + read + write + append +} diff --git a/policy/flask/security_classes b/policy/flask/security_classes index fa65db2..9ace105 100644 --- a/policy/flask/security_classes +++ b/policy/flask/security_classes @@ -125,4 +125,7 @@ class tun_socket class x_pointer # userspace class x_keyboard # userspace +# key-value-store, such as memcached +class kv_item # userspace + # FLASK diff --git a/policy/mcs b/policy/mcs index af90ef2..0d762fa 100644 --- a/policy/mcs +++ b/policy/mcs @@ -132,4 +132,13 @@ mlsconstrain db_procedure { drop getattr setattr execute install } mlsconstrain db_blob { drop getattr setattr relabelfrom read write import export } ( h1 dom h2 ); +# +# MCS policy for key-value items with SELinux support +# +mlsconstrain kv_item { create relabelto } + (( h1 dom h2 ) and ( l2 eq h2 )); + +mlsconstrain kv_item { getattr setattr remove read write append } + ( h1 dom h2 ); + ') dnl end enable_mcs diff --git a/policy/mls b/policy/mls index b9f0a3e..9b9e955 100644 --- a/policy/mls +++ b/policy/mls @@ -827,4 +827,42 @@ mlsvalidatetrans { db_database db_table db_procedure db_column db_tuple db_blob (( t3 == mlsdbdowngrade ) and ( h1 dom h2 )) or (( t3 == mlsdbdowngrade ) and ( h1 incomp h2 )))); +# +# MLS policy for key-value store +# + +# make sure kv_item has single level +mlsconstrain { kv_item } { create relabelto } + ( l2 eq h2 ); + +# new label must be dominated by the subjects clearance +mlsconstrain { kv_item } { relabelto } + ( h1 dom h2 ); + +# the key-value item "read" operations +mlsconstrain { kv_item } { getattr read } + (( l1 dom l2 ) or + (( t1 == mlsdbreadtoclr ) and ( h1 dom l2 )) or + ( t1 == mlsdbread ) or + ( t2 == mlstrustedobject )); + +# the key-value item "write" operations +mlsconstrain { kv_item } { create remove setattr write append } + (( l1 eq l2 ) or + (( t1 == mlsdbwritetoclr ) and ( h1 dom l2 ) and ( l1 domby l2 )) or + (( t2 == mlsdbwriteinrange ) and ( l1 dom l2 ) and ( h1 domby h2 )) or + ( t1 == mlsdbwrite ) or + ( t2 == mlstrustedobject )); + +# the key-value item upgrade/downgrade rule +mlsvalidatetrans { kv_item } + ((( l1 eq l2 ) or + (( t3 == mlsdbupgrade ) and ( l1 domby l2 )) or + (( t3 == mlsdbdowngrade ) and ( l1 dom l2 )) or + (( t3 == mlsdbdowngrade ) and ( l1 incomp l2 ))) and + (( l1 eq h2 ) or + (( t3 == mlsdbupgrade ) and ( h1 domby h2 )) or + (( t3 == mlsdbdowngrade ) and ( h1 dom h2 )) or + (( t3 == mlsdbdowngrade ) and ( h1 incomp h2 )))); + ') dnl end enable_mls diff --git a/policy/modules/roles/staff.te b/policy/modules/roles/staff.te index a589c55..cfde531 100644 --- a/policy/modules/roles/staff.te +++ b/policy/modules/roles/staff.te @@ -23,6 +23,10 @@ optional_policy(` ') optional_policy(` + memcached_role(staff_r, staff_t) +') + +optional_policy(` postgresql_role(staff_r, staff_t) ') diff --git a/policy/modules/roles/unprivuser.te b/policy/modules/roles/unprivuser.te index e8a507d..dae1d40 100644 --- a/policy/modules/roles/unprivuser.te +++ b/policy/modules/roles/unprivuser.te @@ -17,6 +17,10 @@ optional_policy(` ') optional_policy(` + memcached_role(user_r, user_t) +') + +optional_policy(` screen_role_template(user, user_r, user_t) ') diff --git a/policy/modules/services/apache.if b/policy/modules/services/apache.if index c9e1a44..05cee50 100644 --- a/policy/modules/services/apache.if +++ b/policy/modules/services/apache.if @@ -175,6 +175,14 @@ template(`apache_content_template',` ') optional_policy(` + memcached_unpriv_client(httpd_$1_script_t) + + tunable_policy(`httpd_enable_cgi && httpd_can_network_connect_db',` + memcached_tcp_connect(httpd_$1_script_t) + ') + ') + + optional_policy(` tunable_policy(`httpd_enable_cgi && allow_ypbind',` nis_use_ypbind_uncond(httpd_$1_script_t) ') diff --git a/policy/modules/services/apache.te b/policy/modules/services/apache.te index e33b9cd..da1b513 100644 --- a/policy/modules/services/apache.te +++ b/policy/modules/services/apache.te @@ -570,6 +570,16 @@ optional_policy(` ') optional_policy(` + # Allow httpd to work with memcached + memcached_stream_connect(httpd_t) + memcached_unpriv_client(httpd_t) + + tunable_policy(`httpd_can_network_connect_db',` + memcached_tcp_connect(httpd_t) + ') +') + +optional_policy(` openca_domtrans(httpd_t) openca_signal(httpd_t) openca_sigstop(httpd_t) diff --git a/policy/modules/services/memcached.if b/policy/modules/services/memcached.if index db4fd6f..6e410c2 100644 --- a/policy/modules/services/memcached.if +++ b/policy/modules/services/memcached.if @@ -71,3 +71,148 @@ interface(`memcached_admin',` admin_pattern($1, memcached_var_run_t) ') + +######################################## +## <summary> +## Marks as a memcached key/value item type +## </summary> +## <param name="type"> +## <summary> +## Type marked as a memcached key/value item type. +## </summary> +## </param> +# +interface(`memcached_item_object',` + gen_require(` + attribute memcached_item_type; + ') + + typeattribute $1 memcached_item_type; +') + +######################################## +## <summary> +## Allow the specified domain to connect to memcached with a tcp socket. +## </summary> +## <param name="domain"> +## <summary> +## Domain allowed access. +## </summary> +## </param> +# +interface(`memcached_tcp_connect',` + gen_require(` + type memcached_t; + ') + + corenet_tcp_recvfrom_labeled($1, memcached_t) + corenet_tcp_sendrecv_memcache_port($1) + corenet_tcp_connect_memcache_port($1) + corenet_sendrecv_memcache_client_packets($1) +') + +######################################## +## <summary> +## Allow the specified domain to connect to memcached with a unix socket. +## </summary> +## <param name="domain"> +## <summary> +## Domain allowed access. +## </summary> +## </param> +## <rolecap/> +# +interface(`memcached_stream_connect',` + gen_require(` + type memcached_t; + type memcached_var_run_t; + ') + + files_search_pids($1) + allow $1 memcached_t:unix_stream_socket connectto; + # we recommend to put the sock file in /var/run/memcached + rw_sock_files_pattern($1, memcached_var_run_t, memcached_var_run_t) +') + +######################################## +## <summary> +## Allow the specified domain unconfined accesses to any memcached items. +## </summary> +## <param name="domain"> +## <summary> +## Domain allowed access. +## </summary> +## </param> +# +interface(`memcached_unconfined',` + gen_require(` + attribute memcached_unconfined_type; + ') + typeattribute $1 memcached_unconfined_type; +') + +####################################### +## <summary> +## Role access to memcached with SELinux suport +## </summary> +## <param name="user_role"> +## <summary> +## The role associated with the user domain. +## </summary> +## </param> +## <param name="user_domain"> +## <summary> +## The type of the user domain. +## </summary> +## </param> +# +interface(`memcached_role',` + gen_require(` + class kv_item all_kv_item_perms; + + attribute memcached_client_type; + type memcached_t; + type user_memcached_item_t; + ') + + ######################################## + # + # Client local policy + # + typeattribute $2 memcached_client_type; + + type_transition $2 memcached_t:kv_item user_memcached_item_t; + + allow $2 user_memcached_item_t:kv_item { create getattr setattr remove read write append }; +') + +######################################## +## <summary> +## Allow the specified domain unprivileged accesses to unifined key-value +## items managed by memcached with SELinux support. +## </summary> +## <param name="domain"> +## <summary> +## Domain allowed access. +## </summary> +## </param> +# +interface(`memcached_unpriv_client',` + gen_require(` + class kv_item all_kv_item_perms; + + attribute memcached_client_type; + type memcached_t; + type unpriv_memcached_item_t; + ') + + ######################################## + # + # Client local policy + # + typeattribute $1 memcached_client_type; + + type_transition $1 memcached_t:kv_item unpriv_memcached_item_t; + + allow $1 unpriv_memcached_item_t:kv_item { create getattr setattr remove read write }; +') diff --git a/policy/modules/services/memcached.te b/policy/modules/services/memcached.te index b681608..5e7e763 100644 --- a/policy/modules/services/memcached.te +++ b/policy/modules/services/memcached.te @@ -15,6 +15,33 @@ init_script_file(memcached_initrc_exec_t) type memcached_var_run_t; files_pid_file(memcached_var_run_t) +type memcached_db_t; +files_type(memcached_db_t) + +# memcached clients +attribute memcached_client_type; +attribute memcached_unconfined_type; + +# memcached key/value items +attribute memcached_item_type; + +type memcached_item_t; +memcached_item_object(memcached_item_t) + +type memcached_ro_item_t; +memcached_item_object(memcached_ro_item_t) + +type memcached_secret_item_t; +memcached_item_object(memcached_secret_item_t) + +type user_memcached_item_t; +typealias user_memcached_item_t alias { staff_memcached_item_t sysadm_memcached_item_t }; +typealias user_memcached_item_t alias { auditadm_memcached_item_t secadm_memcached_item_t }; +memcached_item_object(user_memcached_item_t) + +type unpriv_memcached_item_t; +memcached_item_object(unpriv_memcached_item_t) + ######################################## # # memcached local policy @@ -27,6 +54,7 @@ allow memcached_t self:tcp_socket create_stream_socket_perms; allow memcached_t self:udp_socket { create_socket_perms listen }; allow memcached_t self:fifo_file rw_fifo_file_perms; allow memcached_t self:unix_stream_socket create_stream_socket_perms; +allow memcached_t self:netlink_selinux_socket create_socket_perms; corenet_all_recvfrom_unlabeled(memcached_t) corenet_udp_sendrecv_generic_if(memcached_t) @@ -42,17 +70,41 @@ corenet_udp_bind_memcache_port(memcached_t) manage_dirs_pattern(memcached_t, memcached_var_run_t, memcached_var_run_t) manage_files_pattern(memcached_t, memcached_var_run_t, memcached_var_run_t) +manage_sock_files_pattern(memcached_t, memcached_var_run_t, memcached_var_run_t) files_pid_filetrans(memcached_t, memcached_var_run_t, { file dir }) +manage_files_pattern(memcached_t, memcached_db_t, memcached_db_t) + kernel_read_kernel_sysctls(memcached_t) kernel_read_system_state(memcached_t) files_read_etc_files(memcached_t) +selinux_get_enforce_mode(memcached_t) +selinux_validate_context(memcached_t) +selinux_compute_access_vector(memcached_t) +selinux_compute_create_context(memcached_t) +selinux_compute_relabel_context(memcached_t) + term_dontaudit_use_all_ptys(memcached_t) term_dontaudit_use_all_ttys(memcached_t) term_dontaudit_use_console(memcached_t) auth_use_nsswitch(memcached_t) +logging_send_audit_msgs(memcached_t) + miscfiles_read_localization(memcached_t) + +######################################## +# +# Rules to managed items by memcached with SELinux support +# +gen_require(` + class kv_item all_kv_item_perms; +') + +allow memcached_client_type memcached_item_t:kv_item { getattr setattr read write append }; +allow memcached_client_type memcached_ro_item_t:kv_item { getattr read }; +type_transition memcached_unconfined_type memcached_t:kv_item memcached_item_t; +allow memcached_unconfined_type memcached_item_type:kv_item *; diff --git a/policy/modules/system/unconfined.if b/policy/modules/system/unconfined.if index 416e668..01bec5d 100644 --- a/policy/modules/system/unconfined.if +++ b/policy/modules/system/unconfined.if @@ -77,6 +77,10 @@ interface(`unconfined_domain_noaudit',` ') optional_policy(` + memcached_unconfined($1) + ') + + optional_policy(` nscd_unconfined($1) ') diff --git a/policy/modules/system/userdomain.if b/policy/modules/system/userdomain.if index 8b4f6d8..ce33925 100644 --- a/policy/modules/system/userdomain.if +++ b/policy/modules/system/userdomain.if @@ -626,6 +626,11 @@ template(`userdom_common_user_template',` locate_read_lib_files($1_t) ') + optional_policy(` + memcached_stream_connect($1_t) + memcached_tcp_connect($1_t) + ') + # for running depmod as part of the kernel packaging process optional_policy(` modutils_read_module_config($1_t) @@ -1159,6 +1164,10 @@ template(`userdom_admin_user_template',` ') optional_policy(` + memcached_unconfined($1_t) + ') + + optional_policy(` postgresql_unconfined($1_t) ')