diff --git a/0010-moving-executables.patch b/0010-moving-executables.patch new file mode 100644 index 0000000..46f1439 --- /dev/null +++ b/0010-moving-executables.patch @@ -0,0 +1,40 @@ +diff --git a/tools/frr.service b/tools/frr.service +index aa45f42..a3f0103 100644 +--- a/tools/frr.service ++++ b/tools/frr.service +@@ -17,9 +17,9 @@ WatchdogSec=60s + RestartSec=5 + Restart=on-abnormal + LimitNOFILE=1024 +-ExecStart=/usr/lib/frr/frrinit.sh start +-ExecStop=/usr/lib/frr/frrinit.sh stop +-ExecReload=/usr/lib/frr/frrinit.sh reload ++ExecStart=/usr/libexec/frr/frrinit.sh start ++ExecStop=/usr/libexec/frr/frrinit.sh stop ++ExecReload=/usr/libexec/frr/frrinit.sh reload + + [Install] + WantedBy=multi-user.target +diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in +index 9a144b2..a334d95 100644 +--- a/tools/frrcommon.sh.in ++++ b/tools/frrcommon.sh.in +@@ -59,6 +59,9 @@ chownfrr() { + [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1" + [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1" + [ -n "$FRR_CONFIG_MODE" ] && chmod "$FRR_CONFIG_MODE" "$1" ++ if [ -d "$1" ]; then ++ chmod gu+x "$1" ++ fi + } + + vtysh_b () { +@@ -152,7 +155,7 @@ daemon_start() { + daemon_prep "$daemon" "$inst" || return 1 + if test ! -d "$V_PATH"; then + mkdir -p "$V_PATH" +- chown frr "$V_PATH" ++ chownfrr "$V_PATH" + fi + + eval wrap="\$${daemon}_wrap" diff --git a/0011-reload-bfd-profile.patch b/0011-reload-bfd-profile.patch new file mode 100644 index 0000000..dcd6981 --- /dev/null +++ b/0011-reload-bfd-profile.patch @@ -0,0 +1,77 @@ +diff --git a/tools/frr-reload.py b/tools/frr-reload.py +index 9979c8b..1c24f90 100755 +--- a/tools/frr-reload.py ++++ b/tools/frr-reload.py +@@ -785,6 +785,48 @@ def line_exist(lines, target_ctx_keys, target_line, exact_match=True): + return True + return False + ++def delete_bgp_bfd(lines_to_add, lines_to_del): ++ """ ++ When 'neighbor bfd profile ' is present without a ++ 'neighbor bfd' line, FRR explicitily adds it to the running ++ configuration. When the new configuration drops the bfd profile ++ line, the user's intent is to delete any bfd configuration on the ++ peer. On reload, deleting the bfd profile line after the bfd line ++ will re-enable BFD with the default BFD profile. Move the bfd line ++ to the end, if it exists in the new configuration. ++ ++ Example: ++ ++ neighbor 10.0.0.1 bfd ++ neighbor 10.0.0.1 bfd profile bfd-profile-1 ++ ++ Move to end: ++ neighbor 10.0.0.1 bfd profile bfd-profile-1 ++ ... ++ ++ neighbor 10.0.0.1 bfd ++ ++ """ ++ lines_to_del_to_app = [] ++ for (ctx_keys, line) in lines_to_del: ++ if ( ++ ctx_keys[0].startswith("router bgp") ++ and line ++ and line.startswith("neighbor ") ++ ): ++ # 'no neighbor [peer] bfd>' ++ nb_bfd = "neighbor (\S+) .*bfd$" ++ re_nb_bfd = re.search(nb_bfd, line) ++ if re_nb_bfd: ++ lines_to_del_to_app.append((ctx_keys, line)) ++ ++ for (ctx_keys, line) in lines_to_del_to_app: ++ lines_to_del.remove((ctx_keys, line)) ++ lines_to_del.append((ctx_keys, line)) ++ ++ return (lines_to_add, lines_to_del) ++ ++ + def check_for_exit_vrf(lines_to_add, lines_to_del): + + # exit-vrf is a bit tricky. If the new config is missing it but we +@@ -1248,6 +1290,7 @@ def compare_context_objects(newconf, running): + for line in newconf_ctx.lines: + lines_to_add.append((newconf_ctx_keys, line)) + ++ (lines_to_add, lines_to_del) = delete_bgp_bfd(lines_to_add, lines_to_del) + (lines_to_add, lines_to_del) = check_for_exit_vrf(lines_to_add, lines_to_del) + (lines_to_add, lines_to_del) = ignore_delete_re_add_lines(lines_to_add, lines_to_del) + (lines_to_add, lines_to_del) = ignore_unconfigurable_lines(lines_to_add, lines_to_del) +diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c +index b566b0e..1bd6249 100644 +--- a/bgpd/bgp_bfd.c ++++ b/bgpd/bgp_bfd.c +@@ -686,9 +686,9 @@ void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr) + + if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG) + && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) { +- vty_out(vty, " neighbor %s bfd", addr); ++ vty_out(vty, " neighbor %s bfd\n", addr); + if (bfd_info->profile[0]) +- vty_out(vty, " profile %s", bfd_info->profile); ++ vty_out(vty, " neighbor %s bfd profile %s", addr, bfd_info->profile); + vty_out(vty, "\n"); + } + diff --git a/frr.fc b/frr.fc new file mode 100644 index 0000000..acc5508 --- /dev/null +++ b/frr.fc @@ -0,0 +1,28 @@ +/usr/libexec/frr(/.*)? gen_context(system_u:object_r:frr_exec_t,s0) + +/usr/lib/systemd/system/frr.* gen_context(system_u:object_r:frr_unit_file_t,s0) + +/etc/frr(/.*)? gen_context(system_u:object_r:frr_conf_t,s0) + +/var/log/frr(/.*)? gen_context(system_u:object_r:frr_log_t,s0) +/var/tmp/frr(/.*)? gen_context(system_u:object_r:frr_tmp_t,s0) + +/var/lock/subsys/bfdd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/bgpd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/eigrpd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/fabricd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/isisd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/nhrpd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/ospf6d -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/ospfd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/pbrd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/pimd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/ripd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/ripngd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/staticd -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/zebra -- gen_context(system_u:object_r:frr_lock_t,s0) +/var/lock/subsys/vrrpd -- gen_context(system_u:object_r:frr_lock_t,s0) + +/var/run/frr(/.*)? gen_context(system_u:object_r:frr_var_run_t,s0) + +/usr/bin/vtysh -- gen_context(system_u:object_r:frr_exec_t,s0) diff --git a/frr.if b/frr.if new file mode 100644 index 0000000..d96499d --- /dev/null +++ b/frr.if @@ -0,0 +1,162 @@ +## policy for frr + +######################################## +## +## Execute frr_exec_t in the frr domain. +## +## +## +## Domain allowed to transition. +## +## +# +interface(`frr_domtrans',` + gen_require(` + type frr_t, frr_exec_t; + ') + + corecmd_search_bin($1) + domtrans_pattern($1, frr_exec_t, frr_t) +') + +###################################### +## +## Execute frr in the caller domain. +## +## +## +## Domain allowed access. +## +## +# +interface(`frr_exec',` + gen_require(` + type frr_exec_t; + ') + + corecmd_search_bin($1) + can_exec($1, frr_exec_t) +') + +######################################## +## +## Read frr's log files. +## +## +## +## Domain allowed access. +## +## +## +# +interface(`frr_read_log',` + gen_require(` + type frr_log_t; + ') + + read_files_pattern($1, frr_log_t, frr_log_t) + optional_policy(` + logging_search_logs($1) + ') +') + +######################################## +## +## Append to frr log files. +## +## +## +## Domain allowed access. +## +## +# +interface(`frr_append_log',` + gen_require(` + type frr_log_t; + ') + + append_files_pattern($1, frr_log_t, frr_log_t) + optional_policy(` + logging_search_logs($1) + ') +') + +######################################## +## +## Manage frr log files +## +## +## +## Domain allowed access. +## +## +# +interface(`frr_manage_log',` + gen_require(` + type frr_log_t; + ') + + manage_dirs_pattern($1, frr_log_t, frr_log_t) + manage_files_pattern($1, frr_log_t, frr_log_t) + manage_lnk_files_pattern($1, frr_log_t, frr_log_t) + optional_policy(` + logging_search_logs($1) + ') +') + +######################################## +## +## Read frr PID files. +## +## +## +## Domain allowed access. +## +## +# +interface(`frr_read_pid_files',` + gen_require(` + type frr_var_run_t; + ') + + files_search_pids($1) + read_files_pattern($1, frr_var_run_t, frr_var_run_t) +') + +######################################## +## +## All of the rules required to administrate +## an frr environment +## +## +## +## Domain allowed access. +## +## +# +interface(`frr_admin',` + gen_require(` + type frr_t; + type frr_log_t; + type frr_var_run_t; + ') + + allow $1 frr_t:process { signal_perms }; + ps_process_pattern($1, frr_t) + + tunable_policy(`deny_ptrace',`',` + allow $1 frr_t:process ptrace; + ') + + admin_pattern($1, frr_log_t) + + files_search_pids($1) + admin_pattern($1, frr_var_run_t) + optional_policy(` + logging_search_logs($1) + ') + optional_policy(` + systemd_passwd_agent_exec($1) + systemd_read_fifo_file_passwd_run($1) + ') +') diff --git a/frr.spec b/frr.spec index b0e841f..f2f0adf 100644 --- a/frr.spec +++ b/frr.spec @@ -1,16 +1,21 @@ %global frrversion 7.5.1 -%global frr_libdir /usr/lib/frr +%global frr_libdir /usr/libexec/frr %global _hardened_build 1 +%global selinuxtype targeted +%bcond_without selinux Name: frr Version: 7.5.1 -Release: 1%{?checkout}%{?dist} +Release: 3%{?checkout}%{?dist} Summary: Routing daemon License: GPLv2+ URL: http://www.frrouting.org Source0: https://github.com/FRRouting/frr/releases/download/%{name}-%{frrversion}/%{name}-%{frrversion}.tar.gz Source1: %{name}-tmpfiles.conf +Source2: frr.fc +Source3: frr.te +Source4: frr.if BuildRequires: perl-generators BuildRequires: gcc BuildRequires: net-snmp-devel @@ -27,6 +32,11 @@ Requires(preun): systemd /sbin/install-info Requires(postun): systemd Requires: iproute Requires: initscripts + +%if 0%{?with_selinux} +Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) +%endif + Provides: routingdaemon = %{version}-%{release} Obsoletes: frr-sysvinit quagga frr-contrib @@ -39,6 +49,8 @@ Patch0006: 0006-CVE-2020-12831.patch Patch0007: 0007-frrinit.patch Patch0008: 0008-designated-router.patch Patch0009: 0009-routemap.patch +Patch0010: 0010-moving-executables.patch +Patch0011: 0011-reload-bfd-profile.patch %description FRRouting is free software that manages TCP/IP based routing protocols. It takes @@ -49,8 +61,25 @@ FRRouting supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM, NHRP, PBR, EIGRP FRRouting is a fork of Quagga. +%if 0%{?with_selinux} +%package selinux +Summary: Selinux policy for FRR +BuildArch: noarch +Requires: selinux-policy-%{selinuxtype} +Requires(post): selinux-policy-%{selinuxtype} +BuildRequires: selinux-policy-devel +%{?selinux_requires} + +%description selinux +SELinux policy modules for FRR package + +%endif + %prep %autosetup -S git +#SELinux +mkdir selinux +cp -p %{SOURCE2} %{SOURCE3} %{SOURCE4} selinux %build autoreconf -ivf @@ -85,6 +114,12 @@ pushd doc make info popd +#SELinux policy +%if 0%{?with_selinux} +make -C selinux -f %{_datadir}/selinux/devel/Makefile %{name}.pp +bzip2 -9 selinux/%{name}.pp +%endif + %install mkdir -p %{buildroot}/etc/{frr,rc.d/init.d,sysconfig,logrotate.d,pam.d,default} \ %{buildroot}/var/log/frr %{buildroot}%{_infodir} \ @@ -109,6 +144,12 @@ install -p -m 644 %{_builddir}/%{name}-%{frrversion}/redhat/frr.logrotate %{buil install -p -m 644 %{_builddir}/%{name}-%{frrversion}/redhat/frr.pam %{buildroot}/etc/pam.d/frr install -d -m 775 %{buildroot}/run/frr +%if 0%{?with_selinux} +install -D -m 644 selinux/%{name}.pp.bz2 \ + %{buildroot}%{_datadir}/selinux/packages/%{selinuxtype}/%{name}.pp.bz2 +install -D -m 644 selinux/%{name}.if %{buildroot}%{_datadir}/selinux/devel/include/distributed/%{name}.if +%endif + rm %{buildroot}%{_libdir}/frr/*.la rm %{buildroot}%{_libdir}/frr/modules/*.la @@ -124,6 +165,8 @@ getent passwd frr >/dev/null 2>&1 || useradd -M -r -g frr -s /sbin/nologin \ usermod -aG frrvty frr %post +#Because we move files to /usr/libexec, we need to reload .service files as well +/usr/bin/systemctl daemon-reload %systemd_post frr.service if [ -f %{_infodir}/%{name}.inf* ]; then @@ -163,6 +206,26 @@ fi %preun %systemd_preun frr.service +#SELinux +%if 0%{?with_selinux} +%pre selinux +%selinux_relabel_pre -s %{selinuxtype} + +%post selinux +%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{name}.pp.bz2 +%selinux_relabel_post -s %{selinuxtype} +#/var/tmp and /var/run need to be relabeled as well if FRR is running before upgrade +%{_sbindir}/restorecon -R /var/tmp/frr &> /dev/null +%{_sbindir}/restorecon -R /var/run/frr &> /dev/null + +%postun selinux +if [ $1 -eq 0 ]; then + %selinux_modules_uninstall -s %{selinuxtype} %{name} + %selinux_relabel_post -s %{selinuxtype} +fi + +%endif + %check make check PYTHON=%{__python3} @@ -198,7 +261,21 @@ make check PYTHON=%{__python3} /usr/share/yang/*.yang %{_tmpfilesdir}/%{name}.conf +%if 0%{?with_selinux} +%files selinux +%{_datadir}/selinux/packages/%{selinuxtype}/%{name}.pp.* +%{_datadir}/selinux/devel/include/distributed/%{name}.if +%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{name} +%endif + %changelog +* Thu Aug 25 2022 Michal Ruprich - 7.5.1-3 +- Resolves: #2054160 - FRR reloader does not disable BFD when unsetting BFD profile + +* Wed Aug 24 2022 Michal Ruprich - 7.5.1-2 +- Resolves: #1941765 - AVCs while running frr tests on RHEL 8.4.0 Beta-1.2 +- Resolves: #1714984 - SELinux policy (daemons) changes required for package + * Wed May 11 2022 Michal Ruprich - 7.5.1-1 - Resolves: #2018451 - Rebase of frr to version 7.5.1 - Resolves: #1975361 - the dynamic routing setup does not work any more diff --git a/frr.te b/frr.te new file mode 100644 index 0000000..fadfa8f --- /dev/null +++ b/frr.te @@ -0,0 +1,121 @@ +policy_module(frr, 1.0.0) + +######################################## +# +# Declarations +# + +type frr_t; +type frr_exec_t; +init_daemon_domain(frr_t, frr_exec_t) + +type frr_log_t; +logging_log_file(frr_log_t) + +type frr_tmp_t; +files_tmp_file(frr_tmp_t) + +type frr_lock_t; +files_lock_file(frr_lock_t) + +type frr_conf_t; +files_config_file(frr_conf_t) + +type frr_unit_file_t; +systemd_unit_file(frr_unit_file_t) + +type frr_var_run_t; +files_pid_file(frr_var_run_t) + +######################################## +# +# frr local policy +# +allow frr_t self:capability { fowner fsetid chown dac_override dac_read_search kill net_bind_service net_raw setgid setuid }; +allow frr_t self:netlink_route_socket rw_netlink_socket_perms; +allow frr_t self:packet_socket create; +allow frr_t self:process { setcap setpgid }; +allow frr_t self:rawip_socket create_socket_perms; +allow frr_t self:tcp_socket { connect connected_stream_socket_perms }; +allow frr_t self:udp_socket create_socket_perms; +allow frr_t self:unix_stream_socket connectto; + +allow frr_t frr_conf_t:dir list_dir_perms; +manage_files_pattern(frr_t, frr_conf_t, frr_conf_t) +read_lnk_files_pattern(frr_t, frr_conf_t, frr_conf_t) + +manage_dirs_pattern(frr_t, frr_log_t, frr_log_t) +manage_files_pattern(frr_t, frr_log_t, frr_log_t) +manage_lnk_files_pattern(frr_t, frr_log_t, frr_log_t) +logging_log_filetrans(frr_t, frr_log_t, { dir file lnk_file }) + +allow frr_t frr_tmp_t:file map; +manage_dirs_pattern(frr_t, frr_tmp_t, frr_tmp_t) +manage_files_pattern(frr_t, frr_tmp_t, frr_tmp_t) +files_tmp_filetrans(frr_t, frr_tmp_t, { file dir }) + +manage_files_pattern(frr_t, frr_lock_t, frr_lock_t) +manage_lnk_files_pattern(frr_t, frr_lock_t, frr_lock_t) +files_lock_filetrans(frr_t, frr_lock_t, { file lnk_file }) + +manage_dirs_pattern(frr_t, frr_var_run_t, frr_var_run_t) +manage_files_pattern(frr_t, frr_var_run_t, frr_var_run_t) +manage_lnk_files_pattern(frr_t, frr_var_run_t, frr_var_run_t) +manage_sock_files_pattern(frr_t, frr_var_run_t, frr_var_run_t) +files_pid_filetrans(frr_t, frr_var_run_t, { dir file lnk_file }) + +allow frr_t frr_exec_t:dir search_dir_perms; +can_exec(frr_t, frr_exec_t) + +kernel_read_network_state(frr_t) +kernel_read_net_sysctls(frr_t) +kernel_read_system_state(frr_t) + +auth_use_nsswitch(frr_t) + +corecmd_exec_bin(frr_t) + +corenet_tcp_bind_appswitch_emp_port(frr_t) +corenet_udp_bind_bfd_control_port(frr_t) +corenet_udp_bind_bfd_echo_port(frr_t) +corenet_tcp_bind_bgp_port(frr_t) +corenet_udp_bind_all_unreserved_ports(frr_t); +corenet_tcp_bind_generic_port(frr_t) +corenet_tcp_bind_firepower_port(frr_t) +corenet_tcp_bind_priority_e_com_port(frr_t) +corenet_udp_bind_router_port(frr_t) +corenet_tcp_bind_qpasa_agent_port(frr_t) +corenet_tcp_bind_smntubootstrap_port(frr_t) +corenet_tcp_bind_versa_tek_port(frr_t) +corenet_tcp_bind_zebra_port(frr_t) + +domain_use_interactive_fds(frr_t) + +fs_read_nsfs_files(frr_t) + +sysnet_exec_ifconfig(frr_t) + +userdom_read_admin_home_files(frr_t) + +init_signal(frr_t) +init_signal_script(frr_t) +init_signull_script(frr_t) + +optional_policy(` + logging_send_syslog_msg(frr_t) +') + +optional_policy(` + modutils_exec_kmod(frr_t) + modutils_getattr_module_deps(frr_t) + modutils_read_module_config(frr_t) + modutils_read_module_deps_files(frr_t) +') + +optional_policy(` + networkmanager_read_state(frr_t) +') + +optional_policy(` + userdom_admin_home_dir_filetrans(frr_t, frr_conf_t, file, ".history_frr") +')