Skip to content

Commit

Permalink
SELinuxInterface: new parser
Browse files Browse the repository at this point in the history
Signed-off-by: Masatake YAMATO <[email protected]>
  • Loading branch information
masatake committed Jan 8, 2025
1 parent 1f657af commit 3fd32e8
Show file tree
Hide file tree
Showing 10 changed files with 377 additions and 0 deletions.
1 change: 1 addition & 0 deletions Tmain/list-subparsers-all.d/stdout-expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
2 changes: 2 additions & 0 deletions Units/parser-selinux-interface.r/simple.d/args.ctags
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--sort=no
--fields=+e
3 changes: 3 additions & 0 deletions Units/parser-selinux-interface.r/simple.d/expected.tags
Original file line number Diff line number Diff line change
@@ -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
221 changes: 221 additions & 0 deletions Units/parser-selinux-interface.r/simple.d/input.if
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
###
### Taoken from selinux-policy-0113b35519369e628e7fcd87af000cfcd4b1fa6c/policy/modules/admin/su.if
###

## <summary>Run shells with substitute user and group</summary>

#######################################
## <summary>
## Restricted su domain template.
## </summary>
## <desc>
## <p>
## This template creates a derived domain which is allowed
## to change the linux user id, to run shells as a different
## user.
## </p>
## </desc>
## <param name="userdomain_prefix">
## <summary>
## The prefix of the user domain (e.g., user
## is the prefix for user_t).
## </summary>
## </param>
## <param name="user_domain">
## <summary>
## The type of the user domain.
## </summary>
## </param>
## <param name="user_role">
## <summary>
## The role associated with the user domain.
## </summary>
## </param>
#
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)
')
')

#######################################
## <summary>
## The role template for the su module.
## </summary>
## <param name="role_prefix">
## <summary>
## The prefix of the user role (e.g., user
## is the prefix for user_r).
## </summary>
## </param>
## <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>
#
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)

')

#######################################
## <summary>
## Execute su in the caller domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`su_exec',`
gen_require(`
type su_exec_t;
')

corecmd_search_bin($1)
can_exec($1, su_exec_t)
')
1 change: 1 addition & 0 deletions docs/news/HEAD.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ New parsers

* TOML *peg/packcc*
* Cargo *TOML based subparser*
* SELinuxIntefae *M4 based subparser*

Changes about parser specific kinds, roles, fields, and extras
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
1 change: 1 addition & 0 deletions main/parsers_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
S4ClassParser, \
SchemeParser, \
SCSSParser, \
SELinuxInterfaceParser, \
ShParser, \
SlangParser, \
SmlParser, \
Expand Down
143 changes: 143 additions & 0 deletions parsers/selinux-interface.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* 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 <string.h>

#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 bool probeLanguage (m4Subparser *m4 CTAGS_ATTR_UNUSED, const char* token)
{
return strncmp (token, "interface", 9) == 0
|| strncmp (token, "template", 8) == 0;
}

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 = probeLanguage,
.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;
}
Loading

0 comments on commit 3fd32e8

Please sign in to comment.