msg: sanitize term title and block C1 controls and DEL

Expose the terminal output sanitizer as mp_msg_sanitize() and use it in
term_osd_update_title() to sanitize the property-expanded term-title
string before it reaches mp_msg_set_term_title(). Without this, a
crafted media tag can break out of the OSC-0 sequence via embedded BEL
or ESC bytes when --term-title includes property expansions like
${media-title}.

Extend the sanitizer to cover two gaps:

- UTF-8 encoded C1 controls (U+0080-U+009F, bytes C2 80..C2 9F). xterm
  in UTF-8 mode interprets these codepoints as C1 control functions
  (U+009B as CSI, U+009D as OSC, U+009C as ST), allowing escape
  sequence injection without any ESC or BEL bytes.

- DEL (0x7F), which was not previously filtered.
This commit is contained in:
rabbit
2026-04-18 20:12:12 +00:00
committed by Kacper Michajłow
parent 4d0666670a
commit d4ae20b7a3
3 changed files with 21 additions and 4 deletions
+14 -3
View File
@@ -559,7 +559,7 @@ static void write_term_msg(struct mp_log *log, int lev, bstr text, bstr *out)
}
}
static void sanitize(bstr *text)
void mp_msg_sanitize(bstr *text)
{
for (size_t i = 0; i < text->len; i++) {
unsigned char ch = text->start[i];
@@ -587,9 +587,20 @@ static void sanitize(bstr *text)
text->start[i] = '?';
}
// Allow only printable > 0x20 and 0x08-0x0D (backspace, tab, newline, ...)
else if (ch < 0x08 || (ch > 0x0D && ch < 0x20)) {
else if (ch < 0x08 || (ch > 0x0D && ch < 0x20) || ch == 0x7F) {
text->start[i] = '?';
}
// Block UTF-8 encoded C1 controls (U+0080-U+009F = bytes C2 80..C2 9F).
// xterm interprets these as C1 control functions (CSI, OSC, DCS, ST, ...),
// which allows bypassing the ESC/BEL filter above.
else if (ch == 0xC2 && i + 1 < text->len &&
(unsigned char)text->start[i + 1] >= 0x80 &&
(unsigned char)text->start[i + 1] <= 0x9F)
{
text->start[i] = '?';
text->start[i + 1] = '?';
i++;
}
}
}
@@ -613,7 +624,7 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va)
bstr_xappend(root, &root->buffer, bstr0(format));
}
sanitize(&root->buffer);
mp_msg_sanitize(&root->buffer);
// Remember last status message and restore it to ensure that it is
// always displayed
+4
View File
@@ -67,6 +67,10 @@ static inline bool mp_msg_test(struct mp_log *log, int lev)
void mp_msg_set_max_level(struct mp_log *log, int lev);
// Sanitize text for terminal output.
struct bstr;
void mp_msg_sanitize(struct bstr *text);
// Convenience macros.
#define mp_fatal(log, ...) mp_msg(log, MSGL_FATAL, __VA_ARGS__)
#define mp_err(log, ...) mp_msg(log, MSGL_ERR, __VA_ARGS__)
+3 -1
View File
@@ -108,7 +108,9 @@ static void term_osd_update_title(struct MPContext *mpctx)
return;
char *s = mp_property_expand_escaped_string(mpctx, mpctx->opts->term_title);
if (bstr_equals(bstr0(s), bstr0(mpctx->term_osd_title))) {
bstr title = bstr0(s);
mp_msg_sanitize(&title);
if (bstr_equals(title, bstr0(mpctx->term_osd_title))) {
talloc_free(s);
return;
}