policy_module(veilor-firstboot, 1.0) # # veilor-os SELinux module — confine veilor-firstboot.service. # # The firstboot service runs once on TTY1 before SDDM, prompts for the # admin password, then enables SDDM and self-disables. It is privileged # (it must be — `passwd` writes /etc/shadow) but the surface is small and # bounded. This module narrows what the service is allowed to do so that a # bug or hostile env in firstboot.sh can't, e.g., dial out, scrape /home, # or load a kernel module. # # Build + load: # cd scripts/selinux # ./build-policy.sh # builds & loads all .te modules # # Verify: # semodule -l | grep veilor-firstboot # ls -Z /usr/local/sbin/veilor-firstboot # -> system_u:object_r:veilor_firstboot_exec_t:s0 # # Audit any denials with: # ausearch -m AVC -ts recent -c veilor-firstboot require { type init_t; type passwd_exec_t; type passwd_file_t; type shadow_t; type systemd_unit_file_t; type systemd_passwd_var_run_t; type sddm_unit_file_t; type sddm_var_lib_t; type tmp_t; type tty_device_t; type devtty_t; type self_runtime_t; type chkpwd_exec_t; type pam_var_run_t; type security_t; type fs_t; type usr_t; type bin_t; type lib_t; type etc_t; type proc_t; type unconfined_service_t; class file { read write create unlink getattr setattr open execute execute_no_trans map }; class dir { read write add_name remove_name search getattr open }; class chr_file { read write open getattr ioctl }; class capability { setuid setgid chown dac_override dac_read_search fowner fsetid }; class process { transition signal sigchld sigkill noatsecure rlimitinh siginh }; class service { start stop status enable disable }; class systemd { start }; class lnk_file { read getattr }; class filesystem { getattr }; } # --------------------------------------------------------------------- # 1. Define the firstboot domain + executable type # --------------------------------------------------------------------- type veilor_firstboot_t; type veilor_firstboot_exec_t; type veilor_firstboot_state_t; # /var/lib/veilor-firstboot.done init_daemon_domain(veilor_firstboot_t, veilor_firstboot_exec_t) files_type(veilor_firstboot_state_t) # Auto-transition: when init_t executes /usr/local/sbin/veilor-firstboot, # enter veilor_firstboot_t. domain_auto_trans(init_t, veilor_firstboot_exec_t, veilor_firstboot_t) # --------------------------------------------------------------------- # 2. Allow rules — what the service IS allowed to do # --------------------------------------------------------------------- # read /etc/passwd, /etc/group, /etc/shadow (passwd needs shadow write) allow veilor_firstboot_t passwd_file_t:file { read getattr open }; allow veilor_firstboot_t shadow_t:file { read write open getattr setattr }; # exec passwd(1) allow veilor_firstboot_t passwd_exec_t:file { read getattr open execute execute_no_trans map }; allow veilor_firstboot_t chkpwd_exec_t:file { read getattr open execute execute_no_trans map }; # capabilities passwd needs allow veilor_firstboot_t self:capability { setuid setgid chown dac_override dac_read_search fowner fsetid }; # write the state marker /var/lib/veilor-firstboot.done allow veilor_firstboot_t veilor_firstboot_state_t:file { create write open getattr setattr unlink }; allow veilor_firstboot_t veilor_firstboot_state_t:dir { search write add_name remove_name }; # write /etc/sddm.conf.d/ entries (autologin disable, theme, etc.) allow veilor_firstboot_t sddm_var_lib_t:dir { read write search add_name remove_name open }; allow veilor_firstboot_t sddm_var_lib_t:file { read write create open getattr setattr }; # start sddm.service via systemctl allow veilor_firstboot_t sddm_unit_file_t:file { read getattr open }; allow veilor_firstboot_t sddm_unit_file_t:service { start status enable disable }; allow veilor_firstboot_t init_t:system { start }; # tty1 I/O allow veilor_firstboot_t tty_device_t:chr_file { read write open getattr ioctl }; allow veilor_firstboot_t devtty_t:chr_file { read write open getattr ioctl }; # usual base reads allow veilor_firstboot_t bin_t:file { read getattr open execute execute_no_trans map }; allow veilor_firstboot_t lib_t:file { read getattr open execute execute_no_trans map }; allow veilor_firstboot_t usr_t:file { read getattr open }; allow veilor_firstboot_t etc_t:file { read getattr open }; allow veilor_firstboot_t etc_t:dir { read search getattr open }; allow veilor_firstboot_t fs_t:filesystem getattr; allow veilor_firstboot_t self:fifo_file { read write }; allow veilor_firstboot_t self:unix_stream_socket { create connect read write }; # --------------------------------------------------------------------- # 3. Deny rules — what the service is NOT allowed to do # --------------------------------------------------------------------- # no network — firstboot must never phone home neverallow veilor_firstboot_t self:tcp_socket *; neverallow veilor_firstboot_t self:udp_socket *; neverallow veilor_firstboot_t self:rawip_socket *; neverallow veilor_firstboot_t self:packet_socket *; neverallow veilor_firstboot_t self:netlink_route_socket *; # no kernel module load neverallow veilor_firstboot_t self:capability sys_module; # no /home access except the bits ferror-firstboot.sh writes (admin's # .config dir staging, if any). /home/admin general read = forbidden. neverallow veilor_firstboot_t home_root_t:dir { read write }; neverallow veilor_firstboot_t user_home_t:dir { read write search }; neverallow veilor_firstboot_t user_home_t:file { read write open }; # no ptrace, no /dev/mem, no /dev/kmem neverallow veilor_firstboot_t self:capability sys_ptrace; neverallow veilor_firstboot_t self:capability sys_rawio;