]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
lib/fonts: Compare font data for equality with font_data_is_equal()
authorThomas Zimmermann <tzimmermann@suse.de>
Mon, 9 Mar 2026 14:14:52 +0000 (15:14 +0100)
committerHelge Deller <deller@gmx.de>
Mon, 9 Mar 2026 14:47:21 +0000 (15:47 +0100)
Add font_data_is_equal() and update consoles to use it.

Font data is equal if it has the same size and contains the same values
on all bytes. Only fbcon uses a crc32 checksum. If set in both operands
the checksums have to be equal.

The new helper also guarantees to not compare internal fonts against
fonts from user space. Internal fonts cannot be ref-counted, so making
them equal to user-space fonts with the same byte sequence results in
undefined behavior.

The test only compares data buffers. Their interpretation is up each
console. Therefore remove a width test in fbcon_set_font().

v3:
- rebase onto font_data_{get,put}()

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Helge Deller <deller@gmx.de>
drivers/video/console/newport_con.c
drivers/video/fbdev/core/fbcon.c
include/linux/font.h
lib/fonts/fonts.c

index dbbb787fc46efc728db8bd6e08d6d4287dd0034c..db0228bce00e83ed0f36a27c5612c39081d38424 100644 (file)
@@ -529,9 +529,7 @@ static int newport_set_font(int unit, const struct console_font *op,
 
        /* check if font is already used by other console */
        for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (font_data[i] != FONT_DATA
-                   && font_data_size(font_data[i]) == size
-                   && !memcmp(font_data[i], new_data, size)) {
+               if (font_data_is_equal(font_data[i], new_data)) {
                        font_data_put(new_data);
                        /* current font is the same as the new one */
                        if (i == unit)
index ac59480c98cb34dacb62720b9017f2ce0609627b..00255ac92e42834ba51aa2605c38c2c24942dc85 100644 (file)
@@ -2540,13 +2540,8 @@ static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
        FNTSUM(new_data) = csum;
        /* Check if the same font is on some other console already */
        for (i = first_fb_vc; i <= last_fb_vc; i++) {
-               struct vc_data *tmp = vc_cons[i].d;
-
                if (fb_display[i].fontdata &&
-                   FNTSUM(fb_display[i].fontdata) == csum &&
-                   font_data_size(fb_display[i].fontdata) == size &&
-                   tmp->vc_font.width == w &&
-                   !memcmp(fb_display[i].fontdata, new_data, size)) {
+                   font_data_is_equal(fb_display[i].fontdata, new_data)) {
                        font_data_get(fb_display[i].fontdata);
                        font_data_put(new_data);
                        new_data = fb_display[i].fontdata;
index dd319d0f0201e45840279f7f8d8d515c9557ab00..58bf3c64cabbf5ccf3454536d671051f8cf0a227 100644 (file)
@@ -57,6 +57,7 @@ static inline const unsigned char *font_data_buf(font_data_t *fd)
 void font_data_get(font_data_t *fd);
 bool font_data_put(font_data_t *fd);
 unsigned int font_data_size(font_data_t *fd);
+bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs);
 
 /*
  * Font description
index d25efd8d6c310e1c020500a8e4d0f03e82da8eb7..3fb76d1856475e688618ef778dddcb1bbc1ad2f0 100644 (file)
@@ -110,6 +110,32 @@ unsigned int font_data_size(font_data_t *fd)
 }
 EXPORT_SYMBOL_GPL(font_data_size);
 
+/**
+ * font_data_is_equal - Compares font data for equality
+ * @lhs: Left-hand side font data
+ * @rhs: Right-hand-size font data
+ *
+ * Font data is equal if is constain the same sequence of values. The
+ * helper also use the checksum, if both arguments contain it. Font data
+ * coming from different origins, internal or from user space, is never
+ * equal. Allowing this would break reference counting.
+ *
+ * Returns:
+ * True if the given font data is equal, false otherwise.
+ */
+bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
+{
+       if (font_data_is_internal(lhs) != font_data_is_internal(rhs))
+               return false;
+       if (font_data_size(lhs) != font_data_size(rhs))
+               return false;
+       if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs))
+               return false;
+
+       return !memcmp(lhs, rhs, FNTSIZE(lhs));
+}
+EXPORT_SYMBOL_GPL(font_data_is_equal);
+
 /*
  * Font lookup
  */