From 3e880530377fcda5b203b3abfb8b58b7db867cc7 Mon Sep 17 00:00:00 2001
From: Olivier Gayot <olivier.gayot@sigexec.com>
Date: Fri, 7 Apr 2023 10:32:07 +0200
Subject: [PATCH] localed: fix invalid free after shifting pointers using
 strstrip

After manually editing /etc/locale.gen, calling localectl set-locale
sometimes fails. When it fails, the systemd journal shows:
systemd-localed: free() / invalid pointer.

It turned out that it only fails if some of the uncommented lines in
/etc/locale.gen have leading spaces, as in:

  * C.UTF-8       <= OK
  * en_US.UTF-8   <= OK
  *  fr_FR.UTF-8  <= NOK

After parsing a line from /etc/locale.gen, we use strstrip() to obtain
the "trimmed" line (without leading or trailing spaces).

However, we store the result of strstrip() in the original pointer
containing the untrimmed line. This pointer is later passed to free
(this is done automatically using _cleanup_free_).

This is a problem because if any leading space is present, the pointer
will essentially be shifted from its original value. This will result in
an invalid free upon cleanup.

The same issue is present in the locale_gen_locale_supported function.

Fixed by storing the result of strstrip() in a different pointer.

(cherry picked from commit b24b10592d74b73529817813ff33f7e28e79ca41)
(cherry picked from commit d18037b8ff43a1d7310708a50786f92c1291ce80)
(cherry picked from commit fcd9ec3effc9cad63f73cba024697011c5963766)

Conflict:NA
Reference:https://github.com/systemd/systemd-stable/commit/3e880530377fcda5b203b3abfb8b58b7db867cc7
---
 src/locale/keymap-util.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c
index 2d1b9826d0..77035d6584 100644
--- a/src/locale/keymap-util.c
+++ b/src/locale/keymap-util.c
@@ -784,6 +784,7 @@ static int locale_gen_locale_supported(const char *locale_entry) {
 
         for (;;) {
                 _cleanup_free_ char *line = NULL;
+                char *l;
 
                 r = read_line(f, LONG_LINE_MAX, &line);
                 if (r < 0)
@@ -791,8 +792,8 @@ static int locale_gen_locale_supported(const char *locale_entry) {
                 if (r == 0)
                         return 0;
 
-                line = strstrip(line);
-                if (strcaseeq_ptr(line, locale_entry))
+                l = strstrip(line);
+                if (strcaseeq_ptr(l, locale_entry))
                         return 1;
         }
 }
@@ -870,14 +871,13 @@ int locale_gen_enable_locale(const char *locale) {
                                 continue;
                         }
 
-                        line = strstrip(line);
-                        if (isempty(line)) {
+                        line_locale = strstrip(line);
+                        if (isempty(line_locale)) {
                                 fputc('\n', fw);
                                 first_line = false;
                                 continue;
                         }
 
-                        line_locale = line;
                         if (line_locale[0] == '#')
                                 line_locale = strstrip(line_locale + 1);
                         else if (strcaseeq_ptr(line_locale, locale_entry))
-- 
2.33.0

