diff --git a/Tmain/list-map-extensions.d/stdout-expected.txt b/Tmain/list-map-extensions.d/stdout-expected.txt index c2b58ae8b9..27df8a22bc 100644 --- a/Tmain/list-map-extensions.d/stdout-expected.txt +++ b/Tmain/list-map-extensions.d/stdout-expected.txt @@ -1,9 +1,9 @@ ## all|grep LdScript -#LANGUAGE EXTENSION -LdScript lds -LdScript scr -LdScript ld -LdScript ldi +#LANGUAGE EXTENSION +LdScript lds +LdScript scr +LdScript ld +LdScript ldi ## LdScript #EXTENSION lds diff --git a/Tmain/list-subparsers-all.d/stdout-expected.txt b/Tmain/list-subparsers-all.d/stdout-expected.txt index 19d66aed86..b2da4ec69a 100644 --- a/Tmain/list-subparsers-all.d/stdout-expected.txt +++ b/Tmain/list-subparsers-all.d/stdout-expected.txt @@ -26,6 +26,7 @@ RSpec Ruby base => sub {shared} Rake Ruby base <= sub {dedicated} RelaxNG XML base <> sub {bidirectional} S4Class R base <> sub {bidirectional} +SELinuxInterface M4 base <= sub {dedicated} SVG XML base <> sub {bidirectional} SystemdUnit Iniconf base <= sub {dedicated} TclOO Tcl base <> sub {bidirectional} diff --git a/Units/parser-selinux-interface.r/simple.d/args.ctags b/Units/parser-selinux-interface.r/simple.d/args.ctags new file mode 100644 index 0000000000..a60a455e15 --- /dev/null +++ b/Units/parser-selinux-interface.r/simple.d/args.ctags @@ -0,0 +1,2 @@ +--sort=no +--fields=+e diff --git a/Units/parser-selinux-interface.r/simple.d/expected.tags b/Units/parser-selinux-interface.r/simple.d/expected.tags new file mode 100644 index 0000000000..0b34a14af6 --- /dev/null +++ b/Units/parser-selinux-interface.r/simple.d/expected.tags @@ -0,0 +1,3 @@ +su_restricted_domain_template input.if /^template(`su_restricted_domain_template', `$/;" t end:140 +su_role_template input.if /^template(`su_role_template',`$/;" t end:202 +su_exec input.if /^interface(`su_exec',`$/;" i end:221 diff --git a/Units/parser-selinux-interface.r/simple.d/input.if b/Units/parser-selinux-interface.r/simple.d/input.if new file mode 100644 index 0000000000..4d64586b85 --- /dev/null +++ b/Units/parser-selinux-interface.r/simple.d/input.if @@ -0,0 +1,223 @@ +### +### Taoken from selinux-policy-0113b35519369e628e7fcd87af000cfcd4b1fa6c/policy/modules/admin/su.if +### + +## Run shells with substitute user and group + +####################################### +## +## Restricted su domain template. +## +## +## +## This template creates a derived domain which is allowed +## to change the linux user id, to run shells as a different +## user. +## +## +## +## +## The prefix of the user domain (e.g., user +## is the prefix for user_t). +## +## +## +## +## The type of the user domain. +## +## +## +## +## The role associated with the user domain. +## +## +# +template(`su_restricted_domain_template', ` + gen_require(` + type su_exec_t; + ') + + type $1_su_t; + domain_entry_file($1_su_t, su_exec_t) + domain_type($1_su_t) + domain_interactive_fd($1_su_t) + role $3 types $1_su_t; + + allow $2 $1_su_t:process signal; + + allow $1_su_t self:capability { audit_control audit_write setuid setgid net_bind_service chown dac_read_search fowner sys_nice sys_resource }; + dontaudit $1_su_t self:capability sys_tty_config; + allow $1_su_t self:key { search write }; + allow $1_su_t self:process { setexec setsched setrlimit }; + allow $1_su_t self:fifo_file rw_fifo_file_perms; + allow $1_su_t self:netlink_audit_socket { nlmsg_relay create_netlink_socket_perms }; + allow $1_su_t self:unix_stream_socket create_stream_socket_perms; + allow $1_su_t self:netlink_selinux_socket create_socket_perms; + + # Transition from the user domain to this domain. + domtrans_pattern($2, su_exec_t, $1_su_t) + + # By default, revert to the calling domain when a shell is executed. + corecmd_shell_domtrans($1_su_t,$2) + allow $2 $1_su_t:fd use; + allow $2 $1_su_t:fifo_file rw_file_perms; + allow $2 $1_su_t:process sigchld; + + kernel_getattr_core_if($1_su_t) + kernel_read_system_state($1_su_t) + kernel_read_kernel_sysctls($1_su_t) + kernel_search_key($1_su_t) + kernel_link_key($1_su_t) + + # for SSP + dev_read_urand($1_su_t) + + files_read_etc_files($1_su_t) + files_read_etc_runtime_files($1_su_t) + files_search_var_lib($1_su_t) + files_dontaudit_getattr_tmp_dirs($1_su_t) + + # for the rootok check + selinux_compute_access_vector($1_su_t) + + auth_domtrans_chk_passwd($1_su_t) + auth_dontaudit_read_shadow($1_su_t) + auth_use_nsswitch($1_su_t) + auth_rw_faillog($1_su_t) + + domain_use_interactive_fds($1_su_t) + + init_dontaudit_use_fds($1_su_t) + init_dontaudit_use_script_ptys($1_su_t) + # Write to utmp. + init_rw_utmp($1_su_t) + init_search_script_keys($1_su_t) + init_getattr_initctl($1_su_t) + + logging_send_syslog_msg($1_su_t) + + + ifdef(`distro_redhat',` + # RHEL5 and possibly newer releases incl. Fedora + auth_domtrans_upd_passwd($1_su_t) + + optional_policy(` + locallogin_search_keys($1_su_t) + ') + ') + + ifdef(`distro_rhel4',` + domain_role_change_exemption($1_su_t) + domain_subj_id_change_exemption($1_su_t) + domain_obj_id_change_exemption($1_su_t) + + selinux_get_fs_mount($1_su_t) + selinux_validate_context($1_su_t) + selinux_compute_access_vector($1_su_t) + selinux_compute_create_context($1_su_t) + selinux_compute_relabel_context($1_su_t) + selinux_compute_user_contexts($1_su_t) + + seutil_read_config($1_su_t) + seutil_read_default_contexts($1_su_t) + + # Only allow transitions to unprivileged user domains. + userdom_spec_domtrans_unpriv_users($1_su_t) + ') + + optional_policy(` + cron_read_pipes($1_su_t) + ') + + optional_policy(` + kerberos_use($1_su_t) + ') + + optional_policy(` + # used when the password has expired + usermanage_read_crack_db($1_su_t) + ') +') + +####################################### +## +## The role template for the su module. +## +## +## +## The prefix of the user role (e.g., user +## is the prefix for user_r). +## +## +## +## +## The role associated with the user domain. +## +## +## +## +## The type of the user domain. +## +## +# +template(`su_role_template',` + gen_require(` + attribute su_domain_type; + type su_exec_t; + bool secure_mode; + ') + + type $1_su_t, su_domain_type; + userdom_user_application_domain($1_su_t, su_exec_t) + domain_interactive_fd($1_su_t) + role $2 types $1_su_t; + + allow $1_su_t self:netlink_selinux_socket create_socket_perms; + + allow $3 $1_su_t:process signal; + allow $1_su_t $3:key search; + + # Transition from the user domain to this domain. + domtrans_pattern($3, su_exec_t, $1_su_t) + + ps_process_pattern($3, $1_su_t) + + # By default, revert to the calling domain when a shell is executed. + corecmd_shell_domtrans($1_su_t, $3) + allow $3 $1_su_t:fd use; + allow $3 $1_su_t:fifo_file rw_file_perms; + allow $3 $1_su_t:process sigchld; + + kernel_read_system_state($1_su_t) + kernel_dontaudit_getattr_core_if($1_su_t) + + auth_use_pam($1_su_t) + + init_dontaudit_getattr_initctl($1_su_t) + + mls_file_write_all_levels($1_su_t) + + logging_send_syslog_msg($1_su_t) + +') + +####################################### +## +## Execute su in the caller domain. +## +## +## +## Domain allowed access. +## +## +# +interface(`su_exec',` + gen_require(` + type su_exec_t; + ') + + corecmd_search_bin($1) + can_exec($1, su_exec_t) +') + +dummy(`dont_tag_me',`') diff --git a/Units/parser-selinux-type-enforcement.r/modules.d/args.ctags b/Units/parser-selinux-type-enforcement.r/modules.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/modules.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-selinux-type-enforcement.r/modules.d/expected.tags b/Units/parser-selinux-type-enforcement.r/modules.d/expected.tags new file mode 100644 index 0000000000..628f1ddc97 --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/modules.d/expected.tags @@ -0,0 +1,2 @@ +bind input.te /^module bind 1.0.0;$/;" m +bootloader input-0.te /^policy_module(bootloader, 1.14.0)$/;" m diff --git a/Units/parser-selinux-type-enforcement.r/modules.d/input-0.te b/Units/parser-selinux-type-enforcement.r/modules.d/input-0.te new file mode 100644 index 0000000000..c0c85f8c57 --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/modules.d/input-0.te @@ -0,0 +1,2 @@ +# selinux-policy-0113b35519369e628e7fcd87af000cfcd4b1fa6c/policy/modules/admin/bootloader.te +policy_module(bootloader, 1.14.0) diff --git a/Units/parser-selinux-type-enforcement.r/modules.d/input.te b/Units/parser-selinux-type-enforcement.r/modules.d/input.te new file mode 100644 index 0000000000..af4bcc15ed --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/modules.d/input.te @@ -0,0 +1,2 @@ +# https://github.com/SELinuxProject/selinux-notebook/blob/main/src/modular_policy_statements.md#modular-policy-support-statements +module bind 1.0.0; diff --git a/Units/parser-selinux-type-enforcement.r/simple.d/args.ctags b/Units/parser-selinux-type-enforcement.r/simple.d/args.ctags new file mode 100644 index 0000000000..5ee5f79f70 --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/simple.d/args.ctags @@ -0,0 +1 @@ +--sort=no diff --git a/Units/parser-selinux-type-enforcement.r/simple.d/expected.tags b/Units/parser-selinux-type-enforcement.r/simple.d/expected.tags new file mode 100644 index 0000000000..a3a29c065f --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/simple.d/expected.tags @@ -0,0 +1,26 @@ +dbus input.te /^policy_module(dbus, 1.19.0)$/;" m +dbusd_unconfined input.te /^attribute dbusd_unconfined;$/;" T +system_bus_type input.te /^attribute system_bus_type;$/;" T +dbusd_etc_t input.te /^type dbusd_etc_t;$/;" t +dbusd_exec_t input.te /^type dbusd_exec_t;$/;" t +system_dbusd_exec_t input.te /^typealias dbusd_exec_t alias system_dbusd_exec_t;$/;" a +session_dbusd_tmp_t input.te /^type session_dbusd_tmp_t;$/;" t +user_dbusd_tmp_t input.te /^typealias session_dbusd_tmp_t alias { user_dbusd_tmp_t staff_dbusd_tmp_t sysadm_dbusd_tmp_t };$/;" a +staff_dbusd_tmp_t input.te /^typealias session_dbusd_tmp_t alias { user_dbusd_tmp_t staff_dbusd_tmp_t sysadm_dbusd_tmp_t };$/;" a +sysadm_dbusd_tmp_t input.te /^typealias session_dbusd_tmp_t alias { user_dbusd_tmp_t staff_dbusd_tmp_t sysadm_dbusd_tmp_t };$/;" a +auditadm_dbusd_tmp_t input.te /^typealias session_dbusd_tmp_t alias { auditadm_dbusd_tmp_t secadm_dbusd_tmp_t };$/;" a +secadm_dbusd_tmp_t input.te /^typealias session_dbusd_tmp_t alias { auditadm_dbusd_tmp_t secadm_dbusd_tmp_t };$/;" a +system_r input.te /^role system_r types system_bus_type;$/;" r +git_sys_content_t input.te /^type git_sys_content_t alias git_system_content_t;$/;" t +git_system_content_t input.te /^type git_sys_content_t alias git_system_content_t;$/;" a +kmod_t input.te /^type kmod_t alias { update_modules_t depmod_t insmod_t };$/;" t +update_modules_t input.te /^type kmod_t alias { update_modules_t depmod_t insmod_t };$/;" a +depmod_t input.te /^type kmod_t alias { update_modules_t depmod_t insmod_t };$/;" a +insmod_t input.te /^type kmod_t alias { update_modules_t depmod_t insmod_t };$/;" a +system_r input.te /^role system_r types anaconda_t;$/;" r +install_roles input.te /^attribute_role install_roles;$/;" R +antivirus_can_scan_system input.te /^gen_tunable(antivirus_can_scan_system, false)$/;" b +secure_mode_insmod input.te /^gen_bool(secure_mode_insmod, false)$/;" b +allow_daemons_use_tty input.te /^bool allow_daemons_use_tty true;$/;" b +xguest_u input.te /^gen_user(xguest_u, user, xguest_r, s0, s0)$/;" u +sysadm_u input.te /^user sysadm_u roles { sysadm_r } level s0 range s0-s15:c0.c255;$/;" u diff --git a/Units/parser-selinux-type-enforcement.r/simple.d/input.te b/Units/parser-selinux-type-enforcement.r/simple.d/input.te new file mode 100644 index 0000000000..d0fff02777 --- /dev/null +++ b/Units/parser-selinux-type-enforcement.r/simple.d/input.te @@ -0,0 +1,58 @@ +# +# Derrived from policy/modules/contrib/dbus.te +# +policy_module(dbus, 1.19.0) + +gen_require(` + class dbus all_dbus_perms; +') + +############################## +# +# Delcarations +# + +attribute dbusd_unconfined; +attribute system_bus_type; + +type dbusd_etc_t; +files_config_file(dbusd_etc_t) + +type dbusd_exec_t; +corecmd_executable_file(dbusd_exec_t) +typealias dbusd_exec_t alias system_dbusd_exec_t; + +type session_dbusd_tmp_t; +typealias session_dbusd_tmp_t alias { user_dbusd_tmp_t staff_dbusd_tmp_t sysadm_dbusd_tmp_t }; +typealias session_dbusd_tmp_t alias { auditadm_dbusd_tmp_t secadm_dbusd_tmp_t }; +userdom_user_tmp_file(session_dbusd_tmp_t) + +# ... + +######################################## +# +# system_bus_type rules +# +role system_r types system_bus_type; +dontaudit system_bus_type self:capability net_admin; + +# The next one should not be tagged. +gen_require(` + type ssh_keygen_t; +') + + +type git_sys_content_t alias git_system_content_t; +type kmod_t alias { update_modules_t depmod_t insmod_t }; + +role system_r types anaconda_t; +attribute_role install_roles; +roleattribute system_r install_roles; + +gen_tunable(antivirus_can_scan_system, false) +gen_bool(secure_mode_insmod, false) + +bool allow_daemons_use_tty true; + +gen_user(xguest_u, user, xguest_r, s0, s0) +user sysadm_u roles { sysadm_r } level s0 range s0-s15:c0.c255; diff --git a/docs/news/HEAD.rst b/docs/news/HEAD.rst index c209e7556e..b3b8cd4c7b 100644 --- a/docs/news/HEAD.rst +++ b/docs/news/HEAD.rst @@ -33,6 +33,8 @@ New parsers * TOML *peg/packcc* * Cargo *TOML based subparser* +* SELinuxIntefae *M4 based subparser* +* SELinuxTypeEnforcement *optlib* Changes about parser specific kinds, roles, fields, and extras ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/main/parsers_p.h b/main/parsers_p.h index 18365ca44e..09e181f3ff 100644 --- a/main/parsers_p.h +++ b/main/parsers_p.h @@ -170,6 +170,8 @@ S4ClassParser, \ SchemeParser, \ SCSSParser, \ + SELinuxInterfaceParser, \ + SELinuxTypeEnforcementParser, \ ShParser, \ SlangParser, \ SmlParser, \ diff --git a/optlib/selinux-type-enforcement.c b/optlib/selinux-type-enforcement.c new file mode 100644 index 0000000000..e06b874725 --- /dev/null +++ b/optlib/selinux-type-enforcement.c @@ -0,0 +1,177 @@ +/* + * Generated by ./misc/optlib2c from optlib/selinux-type-enforcement.ctags, Don't edit this manually. + */ +#include "general.h" +#include "parse.h" +#include "routines.h" +#include "field.h" +#include "xtag.h" + + +static void initializeSELinuxTypeEnforcementParser (const langType language) +{ + + addLanguageRegexTable (language, "main"); + addLanguageRegexTable (language, "typedef"); + addLanguageRegexTable (language, "alias"); + addLanguageRegexTable (language, "compoundalias"); + addLanguageRegexTable (language, "lit"); + + addLanguageTagMultiTableRegex (language, "main", + "^#[^\n]*", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^[[:space:]]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^`", + "", "", "{tenter=lit}", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^[^pmtarbgu[:space:]][a-zA-Z0-9_]*", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^policy_module\\([[:blank:]]*([^,[:space:]\\)]+)[^\\)]*\\)", + "\\1", "m", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^module[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;", + "\\1", "m", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^type[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*", + "\\1", "t", "{tenter=typedef}", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^typealias[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*", + "", "", "{tenter=typedef}", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^attribute[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;", + "\\1", "T", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^role[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;", + "\\1", "r", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^attribute_role[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;", + "\\1", "R", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^bool[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;", + "\\1", "b", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^gen_(tunable|bool)\\([[:blank:]]*([^,[:space:]\\)]+)[^\\)]*\\)", + "\\2", "b", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^user[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;", + "\\1", "u", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^gen_user\\([[:blank:]]*([^,[:space:]\\)]+)[^\\)]*\\)", + "\\1", "u", "", NULL); + addLanguageTagMultiTableRegex (language, "main", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "typedef", + "^[[:space:]]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "typedef", + "^alias[[:space:]]+", + "", "", "{tenter=alias}", NULL); + addLanguageTagMultiTableRegex (language, "typedef", + "^;", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "typedef", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "alias", + "^[[:space:]]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "alias", + "^([a-zA-Z0-9_]+)[[:space:]]*", + "\\1", "a", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "alias", + "^\\{[[:space:]]*", + "", "", "{tenter=compoundalias}", NULL); + addLanguageTagMultiTableRegex (language, "alias", + "^\\}[[:space:]]*", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "alias", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "compoundalias", + "^[[:space:]]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "compoundalias", + "^([a-zA-Z0-9_]+)[[:space:]]*", + "\\1", "a", "", NULL); + addLanguageTagMultiTableRegex (language, "compoundalias", + "^\\}[[:space:]]*", + "", "", "{tleave}{_advanceTo=0start}", NULL); + addLanguageTagMultiTableRegex (language, "compoundalias", + "^.", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "lit", + "^[^'`]+", + "", "", "", NULL); + addLanguageTagMultiTableRegex (language, "lit", + "^'", + "", "", "{tleave}", NULL); + addLanguageTagMultiTableRegex (language, "lit", + "^`", + "", "", "{tenter=lit}", NULL); + addLanguageTagMultiTableRegex (language, "lit", + "^.", + "", "", "", NULL); +} + +extern parserDefinition* SELinuxTypeEnforcementParser (void) +{ + static const char *const extensions [] = { + "te", + NULL + }; + + static const char *const aliases [] = { + NULL + }; + + static const char *const patterns [] = { + NULL + }; + + static kindDefinition SELinuxTypeEnforcementKindTable [] = { + { + true, 'm', "module", "policy modules", + }, + { + true, 't', "type", "types", + }, + { + true, 'a', "alias", "type aliases", + }, + { + true, 'T', "attr", "type attributes", + }, + { + true, 'r', "role", "roles", + }, + { + true, 'R', "rattr", "role attributes", + }, + { + true, 'b', "tunable", "tunables", + }, + { + true, 'u', "user", "users", + }, + }; + + parserDefinition* const def = parserNew ("SELinuxTypeEnforcement"); + + def->versionCurrent= 0; + def->versionAge = 0; + def->enabled = true; + def->extensions = extensions; + def->patterns = patterns; + def->aliases = aliases; + def->method = METHOD_NOT_CRAFTED|METHOD_REGEX; + def->kindTable = SELinuxTypeEnforcementKindTable; + def->kindCount = ARRAY_SIZE(SELinuxTypeEnforcementKindTable); + def->initialize = initializeSELinuxTypeEnforcementParser; + + return def; +} diff --git a/optlib/selinux-type-enforcement.ctags b/optlib/selinux-type-enforcement.ctags new file mode 100644 index 0000000000..384b4b9727 --- /dev/null +++ b/optlib/selinux-type-enforcement.ctags @@ -0,0 +1,88 @@ +# +# Copyright (c) 2025 Red Hat, Inc. +# Copyright (c) 2025 Masatake YAMATO +# +# This source code is released for free distribution under the terms of the +# GNU General Public License version 2 or (at your opinion) any later version. +# +# This module contains functions for generating tags for *.te files in SELinux policy definitions: +# +# https://github.com/SELinuxProject/selinux-notebook/blob/main/src/kernel_policy_language.md#kernel-policy-language +# +--langdef=SELinuxTypeEnforcement +--map-SELinuxTypeEnforcement=+.te + +--kinddef-SELinuxTypeEnforcement=m,module,policy modules +--kinddef-SELinuxTypeEnforcement=t,type,types +--kinddef-SELinuxTypeEnforcement=a,alias,type aliases +--kinddef-SELinuxTypeEnforcement=T,attr,type attributes +--kinddef-SELinuxTypeEnforcement=r,role,roles +--kinddef-SELinuxTypeEnforcement=R,rattr,role attributes +--kinddef-SELinuxTypeEnforcement=b,tunable,tunables +--kinddef-SELinuxTypeEnforcement=u,user,users +# TODO: sensitivity, category, sid, class + +--_tabledef-SELinuxTypeEnforcement=main +--_tabledef-SELinuxTypeEnforcement=typedef +--_tabledef-SELinuxTypeEnforcement=alias +--_tabledef-SELinuxTypeEnforcement=compoundalias +--_tabledef-SELinuxTypeEnforcement=lit + +# +# main +# +--_mtable-regex-SELinuxTypeEnforcement=main/#[^\n]*// +--_mtable-regex-SELinuxTypeEnforcement=main/[[:space:]]+// +--_mtable-regex-SELinuxTypeEnforcement=main/`//{tenter=lit} +--_mtable-regex-SELinuxTypeEnforcement=main/[^pmtarbgu[:space:]][a-zA-Z0-9_]*// + +--_mtable-regex-SELinuxTypeEnforcement=main/policy_module\([[:blank:]]*([^,[:space:]\)]+)[^\)]*\)/\1/m/ +--_mtable-regex-SELinuxTypeEnforcement=main/module[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;/\1/m/ + + --_mtable-regex-SELinuxTypeEnforcement=main/type[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*/\1/t/{tenter=typedef} +--_mtable-regex-SELinuxTypeEnforcement=main/typealias[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*//{tenter=typedef} +--_mtable-regex-SELinuxTypeEnforcement=main/attribute[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;/\1/T/ + +--_mtable-regex-SELinuxTypeEnforcement=main/role[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;/\1/r/ +--_mtable-regex-SELinuxTypeEnforcement=main/attribute_role[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;/\1/R/ + +--_mtable-regex-SELinuxTypeEnforcement=main/bool[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;/\1/b/ +--_mtable-regex-SELinuxTypeEnforcement=main/gen_(tunable|bool)\([[:blank:]]*([^,[:space:]\)]+)[^\)]*\)/\2/b/ + +--_mtable-regex-SELinuxTypeEnforcement=main/user[[:blank:]]+([a-zA-Z0-9_]+)[[:blank:]]*[^;]*;/\1/u/ +--_mtable-regex-SELinuxTypeEnforcement=main/gen_user\([[:blank:]]*([^,[:space:]\)]+)[^\)]*\)/\1/u/ + +--_mtable-regex-SELinuxTypeEnforcement=main/.// + +# +# typedef +# +--_mtable-regex-SELinuxTypeEnforcement=typedef/[[:space:]]+// +--_mtable-regex-SELinuxTypeEnforcement=typedef/alias[[:space:]]+//{tenter=alias} +--_mtable-regex-SELinuxTypeEnforcement=typedef/;//{tleave} +--_mtable-regex-SELinuxTypeEnforcement=typedef/.// + +# +# alias +# +--_mtable-regex-SELinuxTypeEnforcement=alias/[[:space:]]+// +--_mtable-regex-SELinuxTypeEnforcement=alias/([a-zA-Z0-9_]+)[[:space:]]*/\1/a/{tleave} +--_mtable-regex-SELinuxTypeEnforcement=alias/\{[[:space:]]*//{tenter=compoundalias} +--_mtable-regex-SELinuxTypeEnforcement=alias/\}[[:space:]]*//{tleave} +--_mtable-regex-SELinuxTypeEnforcement=alias/.// + +# +# compoundalias +# +--_mtable-regex-SELinuxTypeEnforcement=compoundalias/[[:space:]]+// +--_mtable-regex-SELinuxTypeEnforcement=compoundalias/([a-zA-Z0-9_]+)[[:space:]]*/\1/a/ +--_mtable-regex-SELinuxTypeEnforcement=compoundalias/\}[[:space:]]*//{tleave}{_advanceTo=0start} +--_mtable-regex-SELinuxTypeEnforcement=compoundalias/.// + +# +# lit +# +--_mtable-regex-SELinuxTypeEnforcement=lit/[^'`]+// +--_mtable-regex-SELinuxTypeEnforcement=lit/'//{tleave} +--_mtable-regex-SELinuxTypeEnforcement=lit/`//{tenter=lit} +--_mtable-regex-SELinuxTypeEnforcement=lit/.// diff --git a/parsers/selinux-interface.c b/parsers/selinux-interface.c new file mode 100644 index 0000000000..e75fc4edaf --- /dev/null +++ b/parsers/selinux-interface.c @@ -0,0 +1,137 @@ +/* +* Copyright (c) 2025 Masatake YAMATO +* Copyright (c) 2025 Red Hat, Inc. +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* This module contains functions for generating tags for *if files in SELinux policy definitions: +* +* https://github.com/SELinuxProject/refpolicy/blob/main/policy/support/loadable_module.spt +* +*/ + +#include "general.h" /* must always come first */ + +#include + +#include "x-m4.h" + +#include "debug.h" +#include "entry.h" +#include "read.h" +#include "keyword.h" +#include "kind.h" +#include "parse.h" + +typedef enum { + INTERFACE_KIND, + TEMPLATE_KIND, +} autoconfKind; + +static kindDefinition SELinuxInterfaceKinds[] = { + { true, 'i', "interface", "interfaces" }, + { true, 't', "template", "templates" }, +}; + +typedef enum { + KEYWORD_interface, + KEYWORD_template, +} selinuxInterfaceKeywordId; + +static const keywordTable selinuxInterfaceKeywordTable[] = { + { "interface", KEYWORD_interface, }, + { "template", KEYWORD_template, }, +}; + +static bool doesLineCommentStart (m4Subparser *m4 CTAGS_ATTR_UNUSED, int c, const char* token CTAGS_ATTR_UNUSED) +{ + return (c == '#'); +} + +static bool doesStringLiteralStart (m4Subparser *m4 CTAGS_ATTR_UNUSED, int c CTAGS_ATTR_UNUSED) +{ + // return (c == '"') || (c == '\'') || (c == '`'); + return false; +} + +static bool doesWantToParseInsideQuotes (m4Subparser *m4 CTAGS_ATTR_UNUSED, intArray *indexStack CTAGS_ATTR_UNUSED) +{ + return false; +} + +static int makeSELinuxInterfaceTag (int kind) +{ + int index = CORK_NIL; + vString * name; + + name = vStringNew(); + readM4MacroArgument(name); + if (vStringLength (name) > 0) + index = makeSimpleTag(name, kind); + vStringDelete (name); + + return index; +} + +static int newMacroCallback (m4Subparser *m4 CTAGS_ATTR_UNUSED, const char* token) +{ + int keyword; + int index = CORK_NIL; + + keyword = lookupKeyword (token, getInputLanguage ()); + + switch (keyword) + { + case KEYWORD_NONE: + break; + case KEYWORD_interface: + index = makeSELinuxInterfaceTag (INTERFACE_KIND); + break; + case KEYWORD_template: + index = makeSELinuxInterfaceTag (TEMPLATE_KIND); + break; + default: + AssertNotReached (); + } + return index; +} + +static void findSELinuxInterfaceTags(void) +{ + scheduleRunningBaseparser (0); +} + +extern parserDefinition* SELinuxInterfaceParser (void) +{ + static const char *const extensions [] = { "if", NULL }; + parserDefinition* const def = parserNew("SELinuxInterface"); + + static m4Subparser selinuxInterfaceSubparser = { + .subparser = { + .direction = SUBPARSER_SUB_RUNS_BASE, + }, + .probeLanguage = NULL, + .newMacroNotify = newMacroCallback, + .doesLineCommentStart = doesLineCommentStart, + .doesStringLiteralStart = doesStringLiteralStart, + .doesWantToParseInsideQuotes = doesWantToParseInsideQuotes, + }; + static parserDependency dependencies [] = { + [0] = { DEPTYPE_SUBPARSER, "M4", &selinuxInterfaceSubparser }, + }; + + def->dependencies = dependencies; + def->dependencyCount = ARRAY_SIZE (dependencies); + + def->kindTable = SELinuxInterfaceKinds; + def->kindCount = ARRAY_SIZE(SELinuxInterfaceKinds); + def->extensions = extensions; + def->parser = findSELinuxInterfaceTags; + def->useCork = CORK_QUEUE; + + def->keywordTable = selinuxInterfaceKeywordTable; + def->keywordCount = ARRAY_SIZE (selinuxInterfaceKeywordTable); + + return def; +} diff --git a/source.mak b/source.mak index 90eac8df08..ff373b0cee 100644 --- a/source.mak +++ b/source.mak @@ -243,6 +243,7 @@ OPTLIB2C_INPUT = \ optlib/puppetManifest.ctags \ optlib/qemuhx.ctags \ optlib/rpmMacros.ctags \ + optlib/selinux-type-enforcement.ctags \ optlib/scss.ctags \ optlib/systemtap.ctags \ optlib/terraform.ctags \ @@ -408,6 +409,7 @@ PARSER_SRCS = \ parsers/ruby.c \ parsers/rust.c \ parsers/scheme.c \ + parsers/selinux-interface.c \ parsers/sh.c \ parsers/slang.c \ parsers/sml.c \ diff --git a/win32/ctags_vs2013.vcxproj b/win32/ctags_vs2013.vcxproj index c18b1c5f31..8e64187bce 100644 --- a/win32/ctags_vs2013.vcxproj +++ b/win32/ctags_vs2013.vcxproj @@ -254,6 +254,7 @@ + @@ -360,6 +361,7 @@ + diff --git a/win32/ctags_vs2013.vcxproj.filters b/win32/ctags_vs2013.vcxproj.filters index 55019a0f9d..6c8b25fa30 100644 --- a/win32/ctags_vs2013.vcxproj.filters +++ b/win32/ctags_vs2013.vcxproj.filters @@ -285,6 +285,9 @@ Source Files\optlib + + Source Files\optlib + Source Files\optlib @@ -603,6 +606,9 @@ Source Files\parsers + + Source Files\parsers + Source Files\parsers
+## This template creates a derived domain which is allowed +## to change the linux user id, to run shells as a different +## user. +##