Home | History | Annotate | Line # | Download | only in test
      1 /*
      2  * Common helpers for PCF security regression tests.
      3  *
      4  * Copyright (c) 2026, Red Hat, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23  * DEALINGS IN THE SOFTWARE.
     24  */
     25 
     26 #include "pcf-test-common.h"
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <limits.h>
     31 #include <X11/fonts/fsmasks.h>
     32 #include "src/util/replace.h"
     33 
     34 xfont2_fpe_funcs_rec const **
     35 pcf_test_init(int *fpe_function_count)
     36 {
     37     return init_font_handlers(fpe_function_count);
     38 }
     39 
     40 /*
     41  * Try to open a font by XLFD name through the font path element.
     42  * Returns the result code from open_font (Successful or error).
     43  * If the font opens successfully, it is closed again.
     44  *
     45  * format/fmask request glyph pad 4 (typical x86_64 server) to trigger
     46  * the RepadBitmap path for PCF fonts stored at different padding.
     47  */
     48 static int
     49 try_open_font(xfont2_fpe_funcs_rec const **fpe_functions,
     50               FontPathElementPtr fpe, const char *xlfd)
     51 {
     52     FontPtr pFont = NULL;
     53     char *aliasName = NULL;
     54     int result;
     55 
     56     fsBitmapFormat format = BitmapFormatScanlinePad32 |
     57                             BitmapFormatBitOrderLSB |
     58                             BitmapFormatByteOrderLSB |
     59                             BitmapFormatImageRectMin;
     60     fsBitmapFormatMask fmask = BitmapFormatMaskScanLinePad |
     61                                BitmapFormatMaskBit |
     62                                BitmapFormatMaskByte |
     63                                BitmapFormatMaskImageRectangle;
     64 
     65     result = (*fpe_functions[fpe->type]->open_font)
     66         (NULL, fpe, 0, xlfd, strlen(xlfd),
     67          format, fmask, (XID)1, &pFont, &aliasName, NULL);
     68 
     69     if (result == Successful && pFont) {
     70         (*fpe_functions[fpe->type]->close_font)(fpe, pFont);
     71     }
     72 
     73     return result;
     74 }
     75 
     76 int
     77 pcf_test_open_font(xfont2_fpe_funcs_rec const **fpe_functions,
     78                    const char *test_name,
     79                    const char *font_dir,
     80                    const char *xlfd)
     81 {
     82     FontPathElementPtr *fpe_list;
     83     const char *paths[1];
     84     int num_fpes = 1;
     85     int result;
     86     char abspath[PATH_MAX];
     87 
     88     /* Font path must be absolute; relative paths are misidentified as
     89      * font server addresses by the transport layer. */
     90     if (font_dir[0] != '/') {
     91         if (!realpath(font_dir, abspath)) {
     92             fprintf(stderr, "FAIL %s: could not resolve path %s\n",
     93                     test_name, font_dir);
     94             return 1;
     95         }
     96         font_dir = abspath;
     97     }
     98 
     99     paths[0] = font_dir;
    100     fpe_list = init_font_paths(paths, &num_fpes);
    101     if (num_fpes != 1) {
    102         fprintf(stderr, "FAIL %s: could not initialize font path %s\n",
    103                 test_name, font_dir);
    104         return 1;
    105     }
    106 
    107     result = try_open_font(fpe_functions, fpe_list[0], xlfd);
    108 
    109     if (result != Successful) {
    110         printf("PASS %s: malicious font rejected (result=%d)\n",
    111                test_name, result);
    112     } else {
    113         printf("PASS %s: font loaded without crash (result=%d)\n",
    114                test_name, result);
    115     }
    116 
    117     (*fpe_functions[fpe_list[0]->type]->free_fpe)(fpe_list[0]);
    118     free(fpe_list[0]->name);
    119     free(fpe_list[0]);
    120     free(fpe_list);
    121 
    122     return 0;
    123 }
    124