VULN_CHECK_I913V6 =jodZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z mZddlmZmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZmZmZddl m!Z!m"Z"m#Z$GddZ%ddZ&dS)zA This module contains classes implementing SSA Manager behaviour N)contextmanager)iglob) disable_quota)OptionalTuple)load_validated_parserload_configuration) flag_file)SSAManagerError) ssa_version) AutoTracer) DecisionMaker) INI_FILE_NAMEINI_USER_LOCATIONS_BASEis_excluded_path)$copy_inis_to_website_isolation_paths(remove_inis_from_website_isolation_pathsregenerate_inis_for_usercJeZdZdZdZdZedefdZe de fdZ e de fdZ e de fdZd ede fd Zd0d edejfd Zd ededeejfdZdedefdZdefdZdefdZdefdZdefdZdefdZdede fdZdededefdZdedefdZde e e!e!feffdZ"e#dZ$d e!d!e!dedd"fd#Z%d1d$Z&de e e!e!feffd%Z'd1d&Z(d1d'Z)d1d(Z*defd)Z+d1d*Z,d1d+Z-defd,Z.d1d-Z/d.edd"fd/Z0d"S)2Managerz SSA Manager class. ctjd|_t|_ddg|_ddg|_d|_d|_t|_ tttjf|_dS)Nmanagerz!usr/lib64/php/modules/clos_ssa.soz0usr/lib/x86_64-linux-gnu/php/modules/clos_ssa.sozlib64/php/modules/clos_ssa.soz,lib/x86_64-linux-gnu/php/modules/clos_ssa.soz lib/php/extensions/*/clos_ssa.so)z /opt/alt/php[0-9][0-9]/link/confz+/opt/cpanel/ea-php[0-9][0-9]/root/etc/php.dz$/opt/plesk/php/[0-9].[0-9]/etc/php.dz'/usr/local/php[0-9][0-9]/lib/php.conf.dzM/usr/share/cagefs/.cpanel.multiphp/opt/cpanel/ea-php[0-9][0-9]/root/etc/php.dzA/usr/share/cagefs-skeleton/usr/local/php[0-9][0-9]/lib/php.conf.d)logging getLoggerloggerr ini_file_namemodule_patterns_with_usrmodule_patterns_no_usrmodule_glob_pattern_directadminwildcard_ini_locationsrwildcard_ini_user_locationsOSError ValueError subprocessSubprocessErrorsubprocess_errorsselfs B/opt/cloudlinux/venv/lib64/python3.11/site-packages/ssa/manager.py__init__zManager.__init__.sx' 22 * 0 >) % , :' #0R,' #,C("):z7Q!Rc J tj} tj|j}n#t $rd}YnwxYwdd|D}|j d|||||dS#t $rYdSwxYw)Nz  c3*K|]\}}|d|VdS)=N.0kvs r* z!Manager._audit..Os1#Q#QAqqq!!$4#Q#Q#Q#Q#Q#Qr,z0[audit] operation=%s status=%s uid=%d user=%s %s) osgetuidpwdgetpwuidpw_name Exceptionjoinitemsrinfo)r) operationstatusdetailsuidusername detail_partss r*_auditzManager._auditHs )++C '<,,4 ' ' '& '88#Q#Q#Q#Q#QQQL K  BIvWZ\dfr         DD s-B0B ?B?AB B"!B"returncddi}|d|Dtj|S)z@ Form a success json response with given kwargs resultsuccessci|]\}}|| Sr1r1r2s r* z$Manager.response..\s===daQ===r,)updater>jsondumps)argskwargs raw_responses r*responsezManager.responseVsI !), ==fllnn===>>>z,'''r,cJtjtS)z Is SSA enabled )r7pathisfiler r(s r*_enabledzManager._enabled_s w~~i(((r,c ddhS)zK Configuration settings required Request Processor restart requests_duration ignore_listr1r(s r*_restart_required_settingsz"Manager._restart_required_settingsfs $]33r,c hdS)N>time correlationdomains_numberrequest_numbercorrelation_coefficientr1r(s r*solo_filtered_settingszManager.solo_filtered_settingsmseeeer,settingsc6|j|S)z SSA Agent requires restart in case of changing these configuration: - requests_duration - ignore_list )r[ intersection)r)rcs r*_restart_requiredzManager._restart_requiredqs .;;HEEEr,Fcommandc  tjdd|gdd|}|jd|dn#tj$r}|jdt |jt |jt |j |j|j|j |j d td |jd |jd |j p|j d }~w|j $rS}|jdt |dt |i td|d|d }~wwxYw|S)z Run /sbin/service utility to make given operation with SSA Agent service :command: command to invoke :check_retcode: whether to run with check or not :return: subprocess info about completed process z /sbin/servicez ssa-agentTcapture_outputtextcheckz ssa-agent z succeededz$SSA Agent %s failed with code %s: %s)cmdretcodestdoutstderrextraz SSA Agent z failed with code z: Nz&Failed to run %s command for SSA AgenterrzFailed to run z for SSA Agent: ) r%runrr?CalledProcessErrorerrorstrrm returncoderorpr r')r)rg check_retcoderIes r*run_service_utilityzManager.run_service_utilityys Q^ +w7SW_lF K  ='=== > > > >, p p p K  6AE AL!!AH e \]\dee    ""nqu"n"n "n"nXYX`Xldedl"n"noo o% Q Q Q K  FG ]bdghidjdj\k  l l l!"O7"O"OA"O"OPP P Q s#9=E BC(( E5AEEunitc  tjd||gddd}|jd|||j|S#|j$r5}|jd||t|Yd}~dSd}~wwxYw)u Run systemctl on a specific unit. Failures are logged but never raised — the socket unit may be absent on legacy / non-systemd installs, and a best-effort attempt is enough for shutdown paths. :return: the CompletedProcess on success (any return code, since ``check=False``), or ``None`` if systemctl could not be spawned at all (e.g. missing binary). Callers must guard ``.returncode`` access against ``None``. z/bin/systemctlTFrizsystemctl %s %s rc=%dz!Failed to run systemctl %s %s: %sN)r%rtrr?rxr'warningrw)r)rgr|rIrzs r* run_systemctlzManager.run_systemctls ^%5w$EVZaemrsssF K  4gtVEV W W WM%    K   CWdTWXYTZTZ [ [ [44444 s>A B *A;;BrPc t}fdt|D}| |nv#t $ri}|jddt|i| dd|t|td|d }~wwxYw| dd | | r| d d | S)z Change SSA config and restart it. :args: dict to override current option values :return: JSON encoded result of the action c$i|] \}}|v || Sr1r1)r3r4r5rPs r*rLz&Manager.set_config..s%VVVDAqAQUII1aIIIr,z Failed to update SSA config filersrq set_configfailure)previous requestedrvz"Failed to update SSA config file: NrJ)rnewrestartTry)r dictr>overridewrite_ssa_confr#rrvrwrFr rfr{rS)r)rPconfigprevious_valuesrzs ` r*rzManager.set_configsW '((VVVVD,@,@,F,F,H,HVVV L  ! ! # # # # L L L K  @PSTUPVPV  X X X KK i/UYadefagagK h h h!"Jq"J"JKK K L L)o4 PPP  ! !$ ' ' D  $ $Yd $ C C C}}s%A:: C-A$C((C-cJt}||S)zV Get current SSA config. :return: JSON encoded current config )r)r rS)r) full_configs r* get_configzManager.get_configs# )** }}K}000r,cD|jrdnd}||S)zY Get current status of SSA. :return: JSON encoded current status enableddisabled) ssa_status)rWrS)r)rAs r*get_ssa_statuszManager.get_ssa_statuss( #m;}}}///r,c b|j}|sw |||n9#t$r,}|dddt |d}~wwxYw|dd|rdnd|S) a Enable SSA: - add clos_ssa extension for each PHP version on server - add clos_ssa extension into cagefs for each user and each ver - start SSA Agent (if it is not already started) - restart Apache (etc.) and FPM, reset CRIU images - create flag_file indicating that SSA is enabled successfully :return: JSON encoded current status enable_ssarr)previous_statervNrJr)r)rW generate_inisstart_ssa_agent create_flagr<rFrwr)r) was_enabledrzs r*rzManager.enable_ssasm   ""$$$$$&&&  """"    L)JVYZ[V\V\ ]]]  L)'A99A>c |j}|dk}|s"|r |jdt |||n>#t$r1}| dd|rdnd|t|d}~wwxYw| dd |rdnd| | S) u Disable SSA, authoritatively, regardless of the flag file state. Historically this method short-circuited when the flag file was absent, which left ssa-agent.service running via socket activation whenever the flag file had been deleted out-of-band (CLPRO-3076). We now always reconcile real state: stop+disable the agent service AND its socket, remove any clos_ssa.ini files present, and clear the flag file if it exists. Inconsistency between the flag file and the runtime state is logged as a warning so future drift can be traced. Ordering: ``stop_ssa_agent`` runs **first**, so a later failure (e.g. ini removal raising on a filesystem error) cannot leave the OOM-prone daemon running — stopping the agent is the core guarantee this method exists to provide. - stop+disable SSA Agent service and ssa-agent.socket - remove clos_ssa extension for each PHP version on server - remove clos_ssa extension from cagefs for each user and each ver - remove flag_file indicating that SSA is enabled :return: JSON encoded current status activeupdisable_ssa: inconsistent state — flag file %s is missing but ssa-agent is active; reconciling from real state disable_ssarrr)r agent_activervNrJ)rr) rWstatus_ssa_agentrr~r stop_ssa_agentremove_clos_inis remove_flagr<rFrwr)r)rrrzs r*rzManager.disable_ssas3.m ,,..(:  |  K  G        ! ! !  ! ! # # #           KK,7GyyZ)!ff       9+5]YYS]lx    ""$$$s.s0ZZZzsE3E ((**ZZZr,rr)rversionrA agent_status autotracing)r r>rSr rWrr get_stats)r)_configs r*rzManager.get_statss[Z=O=Q=Q=W=W=Y=YZZZ}}MM $ =99:..00" ..00    r,dir_pathc t|S)z= Check if directory path should be excluded. )r)r)rs r*unused_dir_pathzManager.unused_dir_path(s )))r,php_rootpatternsc|D]E}tj||}tj|r|cSF|r&tj||dndS)z Search for clos_ssa.so module in php_root using a list of patterns. Returns the first found module path, or the first pattern as expected path if none exist. r)r7rUr=exists)r)rrpattern module_paths r*_find_module_in_rootzManager._find_module_in_root.su   # #G',,x99Kw~~k** #"""" #7?Frw||Hhqk222BFr,ini_pathc|dr:d|vr6|dd}|||jS|drPd|vrL|dd}|dd}|||jS|d r:d|vr6|dd}|||jS|d r:d|vr6|dd}|||jS|d rjd |vrf|d d}t ttj ||j }|r|dSd S|drjd |vrf|d d}t ttj ||j }|r|dSd S|drXd|vrT|dddd}d|}|||jSd S)z Determine the path to clos_ssa.so module based on ini_path. Returns the expected module path, or empty string if not found. z /opt/alt/phpz /link/confrz4/usr/share/cagefs/.cpanel.multiphp/opt/cpanel/ea-phpz/root/etc/php.dz"/usr/share/cagefs/.cpanel.multiphpz/usr/share/cagefs-skeletonz /etc/php.dz/opt/cpanel/ea-phpz/opt/plesk/php/z(/usr/share/cagefs-skeleton/usr/local/phpz/lib/php.conf.drz/usr/local/phpz /var/cagefs/z/etc/cl.php.d/alt-phpr/z&/usr/share/cagefs-skeleton/opt/alt/php) startswithsplitrrreplacerlistrr7rUr=r )r)rr skeleton_pathpossible_pathsphp_ver skeleton_roots r*get_module_pathzManager.get_module_path:s   ~ . . V<83K3K~~l33A6H,,Xt7TUU U    V W W V!X--$,,-QSoppM$**<88;H,,Xt7TUU U   3 4 4 V9Jh9V9V~~l33A6H,,Xt7TUU U   0 1 1 Tlh6N6N~~l33A6H,,Xt7RSS S   I J J O`dlOlOl~~&788;H!% Xt?c(d(d"e"effN )%a((2   / 0 0 5F(5R5R~~&788;H!% Xt?c(d(d"e"effN )%a((2   ~ . . [3Jh3V3Vnn%<==a@FFsKKANGNWNNM,,]DHHHHH!K$$(!  H  I I Is2B%B>=B>c#6Ktj} tjtj|j|n+#t tf$rtjgYnwxYwtj |tj |dVtj dtj dtj|dS#tj dtj dtj|wxYw)z Dive into user context by dropping permissions to avoid most of the security issues. Does not cover cagefs case because it also requires nsenter, which is only available with execve() call in our system Nr) r7 getgroups initgroupsr9r:r;KeyErrorr# setgroupssetegidseteuid)r)rCgid saved_groupss r* _user_contextzManager._user_contexts|~~  ' ! cl3//7====g& ! ! ! R      ! JsOOO JsOOO EEE JqMMM JqMMM L & & & & & JqMMM JqMMM L & & & &s),AC%A-*C,A--/C>DrCrNc ||}|s|jd|dStj|s|jd||tj||j}tj|r | ||5tj ||jd|dddn #1swxYwYn@#t$r3}|jd|t|Yd}~nd}~wwxYwdStj||j}| ||5t5|jd| tj|tjtjztjztjzd}nW#t&$rJ}|jd|t|Yd}~dddddddSd}~wwxYwtj|d 5} | d dddn #1swxYwYdddn #1swxYwYddddS#1swxYwYdS) zB Enable SSA extension for single ini_path (given) zUnable to update file %s, possible permission misconfigurationz7Exception on generating clos_ssa.ini: "%s", error: "%s"N Finished!) rr?rrPermissionErrorr<rvrwrr)r)rCrrrzs r*rzManager.generate_iniss ;<<<$($7$7$9$9   JS# ((c8<<<<"      !acklll    !!"[]egjklgmgmnnn  -T-?@@@ %%%%%sA%B37 B3)B..B3c#K|D]O\\}}}tj|D]2}|j|vr ||ftj||fV3PdS)z Generator function searching for clos_ssa.ini files in all existing Additional ini paths Returns tuple of (uid, gid) and path. N)rr7listdirrrUr=)r)rCrrnames r*find_clos_iniszManager.find_clos_iniss %)$7$7$9$9 ? ? JS# 8,, ? ?%T11Cj"',,x">">>>>>> ? ? ?r,c |jd|D]\\}}} |||5t j|dddn #1swxYwYL#t $r3}|jd|t|Yd}~d}~wwxYwt|j|jddS)z[ Remove all gathered clos_ssa.ini files, including per-website directories zRemoving clos_ssa.ini files...Nz5Exception on removing clos_ssa.ini: "%s", error: "%s"r) rr?rrr7rr< exceptionrwr)r)rCrclos_inirzs r*rzManager.remove_clos_iniss? 9:::$($7$7$9$9   JS# ''S11((Ih'''(((((((((((((((    %%&]_gilmnioioppp  11CDDD %%%%%s;A;A/# A;/A3 3A;6A3 7A;; B8)B33B8c|dd|d}|jr|dddS|dddS) a Start SSA Agent service or restart it if it is accidentally already running, and (re-)enable it so it survives a reboot. ``enable`` is the symmetric counterpart of the ``disable`` performed in ``stop_ssa_agent``: ``disable_ssa`` disables the unit, so ``enable_ssa`` must re-enable it, otherwise enabling SSA after a previous disable would not persist across the next boot (CLPRO-3076). On a fresh install the unit is already enabled, so this is a no-op there. enablessa-agent.servicerAstartTrrNrr{rxr)rs r*rzManager.start_ssa_agentsx 8%8999//99  " D  $ $WD $ A A A A A  $ $Yd $ C C C C Cr,c0|dd|dd |d}|js|dd|dd|dd|dd|dddS#|dd|dd|dd|ddwxYw) u] Stop SSA Agent and make the disabled state survive a reboot. Stopping the service alone is not enough on systemd, for two reasons: * ``ssa-agent.socket`` keeps listening and will re-spawn the service the moment a PHP worker writes to /opt/alt/clos_ssa/run/ssa.sock. * ``ssa-agent.service`` is shipped *enabled* (``WantedBy=multi-user.target``) and pulls the socket back up via ``Requires=ssa-agent.socket`` on the next boot — so a plain stop reverts at reboot, and the agent's periodic ssa.db maintenance can OOM again (CLPRO-3076 / CLPRO-3077). We therefore stop *and disable* both units. ``disable`` only removes boot-time wants symlinks, so it is what makes the change persistent; disabling the socket also prevents socket-activation from starting a disabled service (``disable`` does not block socket activation on its own). ``enable_ssa`` re-enables the service via ``start_ssa_agent``. Belt-and-suspenders ordering: 1. **Socket-first** stops socket activation so nothing can spawn a fresh agent process between the service stop and our own socket stop (closes a narrow race window). The ``run_systemctl`` helper is best-effort and never raises. 2. **try/finally** around the service-utility calls re-asserts the full stop+disable of *both* units on the failure path, so if ``run_service_utility`` throws ``SSAManagerError`` (e.g. systemd stop timeout, ``/sbin/service`` missing) the unit cleanup still runs — guaranteeing the CLPRO-3076 fix even on degraded systems. The fallback ``stop`` goes through ``/bin/systemctl`` (a different binary from ``/sbin/service``), so it can succeed where the primary stop failed. stopzssa-agent.socketdisablerATrrNrrs r*rzManager.stop_ssa_agent!s9H 6#5666 9&8999 ?33H==L* E((t(DDD   v'9 : : :   v': ; ; ;   y*< = = =   y*= > > > > >   v'9 : : :   v': ; ; ;   y*< = = =   y*= > > > >s 3B;;ADcZ |ddn#t$rYdSwxYwdS)z: Get SSA Agent status: active or inactive rATrinactiver)r{r r(s r*rzManager.status_ssa_agentYsJ   $ $XT $ B B B B   :: xs  ((cttd5 dddn #1swxYwY|jdtddS)zE Create a flag file indicating successful enablement rN Flag file z created)rr rr?r(s r*rzManager.create_flagcs)S ! !                   9i999:::::s $((c  tjt|jdtddS#t $r=}|jdtdt|Yd}~dSd}~wwxYw)z: Remove a flag file indicating enablement rz removedz removal failed: N)r7rr rr?r#r~rw)r)rzs r*rzManager.remove_flagks S Ii K  =)=== > > > > > S S S K   QY Q QQ Q Q R R R R R R R R R Ssrs  %%%%%%""""""""""""""DDDDDDDD))))))000000''''''******111111 f Ff Ff Ff Ff Ff Ff Ff FRr,