From: Ismail Ramzi <[email protected]> parse_ls_color stores color_indicator[C_LINK].string as a pointer into the color_buf buffer, then frees color_buf on the unparsable-value path. The "ln=target" check after the parse loop still read that freed buffer, e.g. with LS_COLORS='ln=target:x'. Skip it on the failure path, where color output is disabled anyway and the buffer is gone. * src/ls.c (parse_ls_color): Return after freeing color_buf on failure, so the color_indicator[C_LINK] check only runs when the buffer is live. * tests/ls/color-symlink-target.sh: New test. * tests/local.mk (all_tests): Add it. * NEWS: Mention the fix.
Link: https://github.com/coreutils/coreutils/pull/352 --- NEWS | 4 ++++ src/ls.c | 1 + tests/local.mk | 1 + tests/ls/color-symlink-target.sh | 33 ++++++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100755 tests/ls/color-symlink-target.sh diff --git a/NEWS b/NEWS index 8d1ccb2e3..fd6582dea 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,10 @@ GNU coreutils NEWS -*- outline -*- 'head' and 'tail' now quote names in file headers when needed. [This bug was present in "the beginning".] + 'ls --color' no longer reads freed memory when LS_COLORS sets "ln=target" + and later becomes unparsable, e.g., LS_COLORS='ln=target:x'. + [This bug was present in "the beginning".] + 'mv' now warns when copying extended attributes fails with ENOTSUP, e.g., when moving files to a file system that does not support them. [bug introduced in coreutils-7.3] diff --git a/src/ls.c b/src/ls.c index 7f3b53541..9536209a5 100644 --- a/src/ls.c +++ b/src/ls.c @@ -2845,6 +2845,7 @@ parse_ls_color (void) free (e2); } print_with_color = false; + return; } else { diff --git a/tests/local.mk b/tests/local.mk index d91589355..e21c1116d 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -721,6 +721,7 @@ all_tests = \ tests/ls/color-norm.sh \ tests/ls/color-term.sh \ tests/ls/color-ext.sh \ + tests/ls/color-symlink-target.sh \ tests/ls/dangle.sh \ tests/ls/dired.sh \ tests/ls/file-type.sh \ diff --git a/tests/ls/color-symlink-target.sh b/tests/ls/color-symlink-target.sh new file mode 100755 index 000000000..fcbe2f1ef --- /dev/null +++ b/tests/ls/color-symlink-target.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# An invalid LS_COLORS that appears after a valid "ln=target" entry +# used to make ls read the freed color buffer (heap-use-after-free). +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ ls + +# "ln=target" stores a pointer into the color buffer, +# Until v9.12 this buffer was free'd then accessed +# after a subsequent parsing failure. +LS_COLORS='ln=target:x' ls --color=always . >/dev/null 2>err || fail=1 + +cat <<\EOF > exp-err || framework_failure_ +ls: unparsable value for LS_COLORS environment variable +EOF + +compare exp-err err || fail=1 + +Exit $fail -- 2.55.0
