1919#include <sys/utsname.h>
2020#include <unistd.h>
2121
22+ /* Un-randomized direct-map base — the reference for the direct map's
23+ * RANDOMIZE_MEMORY offset in the readout. x86_64-only; 0 elsewhere, where the
24+ * direct-map base promotion that uses it never fires (gated on
25+ * RANDOMIZE_MEMORY_ALIGN > 0). */
26+ #ifndef PAGE_OFFSET_BASE_L4
27+ #define PAGE_OFFSET_BASE_L4 0ul
28+ #endif
29+
2230/* Group key for "already printed" tracking. Sections are short, fixed
2331 * strings from region_info[].section_name — copy by pointer (those are
2432 * static literals owned by region_info.c). */
@@ -1170,24 +1178,25 @@ static void readout_guaranteed_window_row(unsigned long lo, unsigned long hi,
11701178 "" , lo , hi , c (C_DIM ), c (C_RESET ), bits , slots );
11711179}
11721180
1173- /* A concrete LIKELY base: the best-guess address, its slide (base - default,
1174- * inheriting the point's speculative grade), and the "likely (speculative)"
1175- * label. The label is right-padded so it lands in the same column as
1176- * "guaranteed" on the window row that follows: both rows share the
1177- * " <label> 0x<addr>" prefix, and this row's " slide " runs 15 columns short
1178- * of where the window row's " - 0x<addr> " puts "guaranteed", so pad the
1179- * slide value out to width 15. */
1181+ /* A concrete LIKELY base graded "likely (speculative)", annotated with its
1182+ * displacement from the un-randomized base: `disp` labelled `disp_label`
1183+ * ("slide" for the kernel image bases; "off" for the direct map's independent
1184+ * RANDOMIZE_MEMORY offset). The " <label> <value>" field is a fixed 24
1185+ * visible columns (the value padded to fill), so "likely (speculative)" lands
1186+ * in the column shared with "guaranteed" on the window row beneath — both rows
1187+ * share the " <label> 0x<addr>" prefix, and 24 columns matches where the
1188+ * window row's " - 0x<addr> " puts "guaranteed". */
11801189static void readout_likely_base_row (const char * label , unsigned long base ,
1181- long slide ) {
1182- unsigned long mag = slide < 0 ? (unsigned long )- slide : (unsigned long )slide ;
1183- char sb [24 ];
1184- int sn = snprintf (sb , sizeof (sb ), "%s0x%lx" , slide < 0 ? "-" : "+" , mag );
1185- int pad = 15 - sn ;
1190+ const char * disp_label , long disp ) {
1191+ unsigned long mag = disp < 0 ? (unsigned long )- disp : (unsigned long )disp ;
1192+ char vb [24 ];
1193+ int vn = snprintf (vb , sizeof (vb ), "%s0x%lx" , disp < 0 ? "-" : "+" , mag );
1194+ int pad = 20 - ( int ) strlen ( disp_label ) - vn ; /* " <label> " + value == 24 */
11861195 if (pad < 1 )
1187- pad = 1 ; /* keep one space if the slide is unexpectedly wide */
1188- printf (" %-19s %s0x%016lx%s slide %s%s%s%*s%slikely (speculative)%s\n" ,
1189- label , c (C_GREEN ), base , c (C_RESET ), c (C_CYAN ), sb , c (C_RESET ), pad ,
1190- "" , c (C_DIM ), c (C_RESET ));
1196+ pad = 1 ; /* keep one space if the value is unexpectedly wide */
1197+ printf (" %-19s %s0x%016lx%s %s %s%s%s%*s%slikely (speculative)%s\n" , label ,
1198+ c (C_GREEN ), base , c (C_RESET ), disp_label , c (C_CYAN ), vb , c (C_RESET ),
1199+ pad , "" , c (C_DIM ), c (C_RESET ));
11911200}
11921201
11931202static void render_readout (const struct summary * s ) {
@@ -1269,7 +1278,7 @@ static void render_readout(const struct summary *s) {
12691278 } else if (v_likely_base ) {
12701279 /* Concrete base + its slide, both graded likely; the proven window follows
12711280 * on the guaranteed row beneath. */
1272- readout_likely_base_row ("Virtual image base" , s -> kaslr .vtext ,
1281+ readout_likely_base_row ("Virtual image base" , s -> kaslr .vtext , "slide" ,
12731282 s -> kaslr .vslide );
12741283 if (s -> kaslr .vstext && s -> kaslr .vstext != s -> kaslr .vtext )
12751284 printf (" %-19s %s0x%016lx%s %slikely%s\n" , "Virtual _stext" ,
@@ -1295,7 +1304,7 @@ static void render_readout(const struct summary *s) {
12951304 printf (" %-19s %s0x%016lx%s\n" , "Physical _stext" , c (C_GREEN ),
12961305 s -> kaslr .pstext , c (C_RESET ));
12971306 } else if (p_likely_base ) {
1298- readout_likely_base_row ("Physical image base" , s -> kaslr .ptext ,
1307+ readout_likely_base_row ("Physical image base" , s -> kaslr .ptext , "slide" ,
12991308 s -> kaslr .pslide );
13001309 if (s -> kaslr .pstext && s -> kaslr .pstext != s -> kaslr .ptext )
13011310 printf (" %-19s %s0x%016lx%s %slikely%s\n" , "Physical _stext" ,
@@ -1320,28 +1329,52 @@ static void render_readout(const struct summary *s) {
13201329 {
13211330 unsigned long lo = s -> kaslr .virt_page_offset_min ;
13221331 unsigned long hi = s -> kaslr .virt_page_offset_max ;
1323- if (lo && hi && hi >= lo ) {
1324- unsigned long slots = s -> kaslr .virt_page_offset_slots ;
1325- int bits = slots > 0 ? ilog2_ul (slots ) : 0 ;
1326- readout_bound_row ("Direct map base" , lo , hi , slots , bits ,
1327- (unsigned long )RANDOMIZE_MEMORY_ALIGN );
1328- } else if (lo && !hi ) {
1329- printf (" %-19s >= %s0x%016lx%s\n" , "Direct map base" , c (C_CYAN ), lo ,
1330- c (C_RESET ));
1331- } else if (!lo && hi ) {
1332- printf (" %-19s <= %s0x%016lx%s\n" , "Direct map base" , c (C_CYAN ), hi ,
1333- c (C_RESET ));
1332+ unsigned long llo = s -> kaslr .virt_page_offset_likely_min ;
1333+ unsigned long lhi = s -> kaslr .virt_page_offset_likely_max ;
1334+ unsigned long align = (unsigned long )RANDOMIZE_MEMORY_ALIGN ;
1335+ unsigned long slots = s -> kaslr .virt_page_offset_slots ;
1336+ int bits = slots > 0 ? ilog2_ul (slots ) : 0 ;
1337+ /* A concrete likely base — a POS_BASE timing pin (prefetch_directmap)
1338+ * narrowed the likely window to a single-slot bracket at the base — is
1339+ * promoted to a graded headline with the guaranteed window beneath, the
1340+ * same form as the image bases. The best-guess base is the bracket's top
1341+ * (lhi); the slide-less row is used since the direct map has no default to
1342+ * slide from. A wider likely narrowing is not a base pin and stays a dim
1343+ * range sub-line under the plain bounded row. */
1344+ int likely_base =
1345+ lo && hi && hi >= lo && lhi && align && (lhi - llo ) <= align ;
1346+ if (likely_base ) {
1347+ readout_likely_base_row ("Direct map base" , lhi , "off" ,
1348+ (long )(lhi - PAGE_OFFSET_BASE_L4 ));
1349+ readout_guaranteed_window_row (lo , hi , slots , bits , align );
1350+ } else {
1351+ if (lo && hi && hi >= lo )
1352+ readout_bound_row ("Direct map base" , lo , hi , slots , bits , align );
1353+ else if (lo && !hi )
1354+ printf (" %-19s >= %s0x%016lx%s\n" , "Direct map base" , c (C_CYAN ), lo ,
1355+ c (C_RESET ));
1356+ else if (!lo && hi )
1357+ printf (" %-19s <= %s0x%016lx%s\n" , "Direct map base" , c (C_CYAN ), hi ,
1358+ c (C_RESET ));
1359+ readout_likely_row (llo , lhi );
13341360 }
1335- readout_likely_row (s -> kaslr .virt_page_offset_likely_min ,
1336- s -> kaslr .virt_page_offset_likely_max );
13371361 }
13381362
13391363 /* Coupling closes the bounds table as a single dim line: it is a static
13401364 * arch property (not a measured quantity), so it recedes from the green/
13411365 * magenta measured rows and explains why physical and virtual bases resolve
1342- * as separate (or shared) quantities above. */
1343- printf (" %-19s %s%s%s\n" , "Phys/Virt coupling" , c (C_DIM ), coupling_descr (),
1344- c (C_RESET ));
1366+ * as separate (or shared) quantities above. Its job is to relate the physical
1367+ * and virtual text bases, so it only earns its place when there is a physical
1368+ * dimension to relate to: always on coupled arches (where one leak yields
1369+ * both — the exploitation-relevant case), and on decoupled arches only when a
1370+ * physical image base row was actually rendered. Suppressed where no physical
1371+ * base is shown, so it never asserts a relationship the reader can't see. */
1372+ int phys_row_shown = (s -> kaslr .has_phys && ppin ) || p_likely_base ||
1373+ s -> kaslr .pslots > 0 || layout .phys_kaslr_text_min ||
1374+ layout .phys_kaslr_text_max ;
1375+ if (TEXT_TRACKS_DIRECTMAP || phys_row_shown )
1376+ printf (" %-19s %s%s%s\n" , "Phys/Virt coupling" , c (C_DIM ), coupling_descr (),
1377+ c (C_RESET ));
13451378 printf ("\n" );
13461379
13471380 readout_print_leaks ();
0 commit comments