1
+ import sys
2
+
3
+ sys .path .insert (0 , ".." )
4
+
5
+ import logging
6
+ from dataclasses import dataclass
7
+ import os , signal
8
+ from pathlib import Path
9
+ import click
10
+ import re
11
+ import requests
12
+ from profiles_and_symbols_builders .base import (
13
+ Container ,
14
+ VolBuild ,
15
+ get_project_base_path ,
16
+ )
17
+
18
+ # CTRL-C instant killer
19
+ def handler (signum , frame ):
20
+ os .kill (os .getpid (), signal .SIGKILL )
21
+
22
+
23
+ signal .signal (signal .SIGINT , handler )
24
+
25
+ logging .basicConfig (
26
+ level = logging .INFO , format = "%(asctime)s [%(levelname)s] %(message)s"
27
+ )
28
+
29
+
30
+ @dataclass
31
+ class Generator :
32
+ kernel : str
33
+ destination_path : Path
34
+
35
+ def __post_init__ (self ):
36
+ self .version = self .kernel .split (".el" )[0 ]
37
+ self .release = self .kernel .split ("el" )[1 ].split ("." )[0 ].replace ("_" ,"." )
38
+ self .arch = self .kernel .split ("." )[- 1 ]
39
+ self .profile_name = f"AlmaLinux_{ self .kernel } .zip"
40
+ self .isf_name = f"AlmaLinux_{ self .kernel } .json.xz"
41
+ self .image_name = "almalinux-volatility"
42
+ self .volatility_builder_path = "/tmp/volatility/tools/linux"
43
+ self .container_name = f"almalinux-volatility-{ self .kernel } "
44
+ self .container_obj = Container (
45
+ self .image_name ,
46
+ self .container_name ,
47
+ get_project_base_path () / "AlmaLinux/Dockerfile-almalinux" ,
48
+ )
49
+ self .vol_obj = VolBuild (
50
+ self .destination_path ,
51
+ self .kernel ,
52
+ self .kernel ,
53
+ self .profile_name ,
54
+ self .isf_name ,
55
+ self .volatility_builder_path ,
56
+ self .container_obj ,
57
+ )
58
+
59
+ self .base_repo_url_vol = [
60
+ f"https://repo.almalinux.org/almalinux/{ self .release } /BaseOS/{ self .arch } /os/Packages/" ,
61
+ f"https://repo.almalinux.org/almalinux/{ self .release } /AppStream/{ self .arch } /os/Packages/" ,
62
+ f"https://repo.almalinux.org/almalinux/{ self .release } /devel/{ self .arch } /os/Packages/" ,
63
+ f"https://repo.almalinux.org/vault/{ self .release } /BaseOS/debug/{ self .arch } /Packages/" ,
64
+ ]
65
+
66
+ # (package_name, exit_on_error)
67
+ self .vol2_packages = [
68
+ ("kernel-core" , True ),
69
+ ("kernel-devel" , True ),
70
+ ("kernel-modules" , True ),
71
+ ("kernel-modules-core" , False ),
72
+ ]
73
+
74
+ self .vol3_packages = [
75
+ ("kernel-debuginfo" , True ),
76
+ ]
77
+
78
+ def check_profile_existence (self ):
79
+ return (self .destination_path / self .profile_name ).exists ()
80
+
81
+ def check_isf_existence (self ):
82
+ return (self .destination_path / self .isf_name ).exists ()
83
+
84
+ def container_init (self ):
85
+ self .container_obj .build_image ()
86
+ self .container_obj .kill_container ()
87
+ self .container_obj .remove_container ()
88
+ self .container_obj .create_container ()
89
+
90
+ def check_rpms (self , target ):
91
+ if target == "vol2" :
92
+ packages = self .vol2_packages
93
+ elif target == "vol3" :
94
+ packages = self .vol3_packages
95
+ else :
96
+ raise Exception ("Invalid target" )
97
+
98
+ full_packages = []
99
+ for package in packages :
100
+ package_name , exit_on_error = package
101
+ print (package_name )
102
+ package_url = None
103
+
104
+ for base_repo_url in self .base_repo_url_vol :
105
+ try :
106
+ r = requests .get (base_repo_url ).text
107
+ package_url = re .findall (f'"({ package_name } -{ self .kernel } .rpm)"' , r )[0 ]
108
+ full_packages .append (
109
+ (package_url .split ("/" )[- 1 ], f"{ base_repo_url } { package_url } " )
110
+ )
111
+ break # Exit the loop if the package is found
112
+ except Exception as e :
113
+ continue # Try the next base_repo_url if the package is not found
114
+
115
+ if package_url is None and exit_on_error :
116
+ raise Exception (
117
+ f'Error while fetching package url for "{ package_name } " : Package not found in any repositories.'
118
+ )
119
+
120
+ if target == "vol2" :
121
+ self .vol2_packages = full_packages
122
+ elif target == "vol3" :
123
+ self .vol3_packages = full_packages
124
+
125
+ def download_rpms (self , target ):
126
+ if target == "vol2" :
127
+ packages = self .vol2_packages
128
+
129
+ elif target == "vol3" :
130
+ packages = self .vol3_packages
131
+
132
+ else :
133
+ raise Exception ("Invalid target" )
134
+
135
+ logging .info (f"[{ self .kernel } ][{ target } ] Downloading rpms..." )
136
+
137
+ for package in packages :
138
+ package_name , package_url = package
139
+ print (package_name )
140
+ package_dl = self .container_obj .docker_exec (f"wget { package_url } " )
141
+ if package_dl .returncode != 0 :
142
+ raise Exception (
143
+ f"Error while fetching { package_name } : { package_dl .stderr .decode ()} "
144
+ )
145
+
146
+ def install_rpms (self , target : str ):
147
+ if target == "vol2" :
148
+ packages = self .vol2_packages
149
+
150
+ elif target == "vol3" :
151
+ packages = self .vol3_packages
152
+ else :
153
+ raise Exception ("Invalid target" )
154
+
155
+ logging .info (f"[{ self .kernel } ][{ target } ] Installing rpms..." )
156
+ for package in packages :
157
+ package_name , package_url = package
158
+ print (package_name )
159
+ rpm_cmd = f"rpm -i --nodeps { package_name } "
160
+ package_install = self .container_obj .docker_exec (rpm_cmd )
161
+ if package_install .returncode != 0 :
162
+ raise Exception (
163
+ f"Error while installing { package_name } : { package_install .stderr .decode ()} "
164
+ )
165
+
166
+ def __del__ (self ):
167
+ self .container_obj .kill_container ()
168
+ self .container_obj .remove_container ()
169
+
170
+
171
+ @click .command ()
172
+ @click .option (
173
+ "-k" ,
174
+ "--kernel" ,
175
+ type = str ,
176
+ help = "AlmaLinux kernel to generate profile against (ex: 4.18.0-477.10.1.el8_8.x86_64)" ,
177
+ required = True ,
178
+ )
179
+ @click .option (
180
+ "-o" ,
181
+ "--output-dir" ,
182
+ type = click .Path (writable = True , readable = True , exists = True ),
183
+ help = "Output directory for profiles and symbols" ,
184
+ required = True ,
185
+ )
186
+ def main (kernel , output_dir : Path ):
187
+ gen_obj = Generator (kernel .strip (), Path (output_dir ))
188
+
189
+ if not gen_obj .check_isf_existence () or not gen_obj .check_profile_existence ():
190
+ logging .info (f"[{ gen_obj .kernel } ] Initializing variables..." )
191
+ gen_obj .container_init ()
192
+
193
+ if not gen_obj .check_isf_existence ():
194
+ try :
195
+ gen_obj .check_rpms ("vol3" )
196
+ gen_obj .download_rpms ("vol3" )
197
+ gen_obj .install_rpms ("vol3" )
198
+ gen_obj .vol_obj .vol3_build_isf ("/usr/lib/" )
199
+ except Exception as e :
200
+ logging .error (f"[{ gen_obj .kernel } ] Vol3 build failed : { e } " )
201
+
202
+ if not gen_obj .check_profile_existence ():
203
+ try :
204
+ gen_obj .check_rpms ("vol2" )
205
+ gen_obj .download_rpms ("vol2" )
206
+ gen_obj .install_rpms ("vol2" )
207
+ gen_obj .vol_obj .vol2_build_profile ()
208
+ except Exception as e :
209
+ logging .error (f"[{ gen_obj .kernel } ] Vol2 build failed : { e } " )
210
+
211
+ if __name__ == "__main__" :
212
+ main ()
0 commit comments