[vte] parser: Reject mixed-control OSC and DCS sequences
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] parser: Reject mixed-control OSC and DCS sequences
- Date: Tue, 27 Mar 2018 17:46:55 +0000 (UTC)
commit 181752d26586c050204a56616255ac1473abff91
Author: Christian Persch <chpe src gnome org>
Date: Tue Mar 27 19:40:13 2018 +0200
parser: Reject mixed-control OSC and DCS sequences
Only accept OSC/DCS sequences where the introducer (OSC or DCS)
and the string terminator (ST) are either both C1 or C0.
Note that this doesn't regress bug 730154; we still parse the
sequences but return VTE_SEQ_IGNORE.
src/parser-test.cc | 50 +++++++++++++++++++++++++++++++++++++-------------
src/parser.cc | 36 ++++++++++++++++++++++++++++++++++++
src/parser.hh | 1 +
3 files changed, 74 insertions(+), 13 deletions(-)
---
diff --git a/src/parser-test.cc b/src/parser-test.cc
index 255abea..26d9ceb 100644
--- a/src/parser-test.cc
+++ b/src/parser-test.cc
@@ -1178,13 +1178,14 @@ static int
feed_parser_st(vte_seq_builder& b,
bool c1 = false,
ssize_t max_arg_str_len = -1,
+ u32SequenceBuilder::Introducer introducer = u32SequenceBuilder::Introducer::DEFAULT,
u32SequenceBuilder::ST st = u32SequenceBuilder::ST::DEFAULT)
{
std::u32string s;
- b.to_string(s, c1, max_arg_str_len, u32SequenceBuilder::Introducer::DEFAULT, st);
+ b.to_string(s, c1, max_arg_str_len, introducer, st);
auto rv = feed_parser(s);
- if (rv == VTE_SEQ_NONE)
+ if (rv != VTE_SEQ_OSC)
return rv;
switch (st) {
@@ -1213,12 +1214,13 @@ test_seq_osc(std::u32string const& str,
int expected_rv = VTE_SEQ_OSC,
bool c1 = true,
ssize_t max_arg_str_len = -1,
+ u32SequenceBuilder::Introducer introducer = u32SequenceBuilder::Introducer::DEFAULT,
u32SequenceBuilder::ST st = u32SequenceBuilder::ST::DEFAULT)
{
vte_seq_builder b{VTE_SEQ_OSC, str};
parser.reset();
- auto rv = feed_parser_st(b, c1, max_arg_str_len, st);
+ auto rv = feed_parser_st(b, c1, max_arg_str_len, introducer, st);
g_assert_cmpint(rv, ==, expected_rv);
#if 0
if (rv != VTE_SEQ_NONE)
@@ -1234,6 +1236,25 @@ test_seq_osc(std::u32string const& str,
g_assert_true(seq.string() == str.substr(0, max_arg_str_len));
}
+static int
+controls_match(bool c1,
+ u32SequenceBuilder::Introducer introducer,
+ u32SequenceBuilder::ST st,
+ bool allow_bel,
+ int expected_rv)
+{
+ if (introducer == u32SequenceBuilder::Introducer::DEFAULT)
+ introducer = c1 ? u32SequenceBuilder::Introducer::C1 : u32SequenceBuilder::Introducer::C0;
+ if (st == u32SequenceBuilder::ST::DEFAULT)
+ st = c1 ? u32SequenceBuilder::ST::C1 : u32SequenceBuilder::ST::C0;
+ if ((introducer == u32SequenceBuilder::Introducer::C0 &&
+ (st == u32SequenceBuilder::ST::C0 || (allow_bel && st == u32SequenceBuilder::ST::BEL))) ||
+ (introducer == u32SequenceBuilder::Introducer::C1 &&
+ st == u32SequenceBuilder::ST::C1))
+ return expected_rv;
+ return VTE_SEQ_IGNORE;
+}
+
static void
test_seq_osc(void)
{
@@ -1249,16 +1270,19 @@ test_seq_osc(void)
test_seq_osc(std::u32string(VTE_SEQ_STRING_MAX_CAPACITY + 1, 0x100000), VTE_SEQ_IGNORE);
/* Test all introducer/ST combinations */
- test_seq_osc(U"TEST"s, VTE_SEQ_NONE, false, -1, u32SequenceBuilder::ST::NONE);
- test_seq_osc(U"TEST"s, VTE_SEQ_NONE, true, -1, u32SequenceBuilder::ST::NONE);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, false, -1, u32SequenceBuilder::ST::DEFAULT);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, true, -1, u32SequenceBuilder::ST::DEFAULT);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, false, -1, u32SequenceBuilder::ST::C0);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, true, -1, u32SequenceBuilder::ST::C0);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, false, -1, u32SequenceBuilder::ST::C1);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, true, -1, u32SequenceBuilder::ST::C1);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, false, -1, u32SequenceBuilder::ST::BEL);
- test_seq_osc(U"TEST"s, VTE_SEQ_OSC, true, -1, u32SequenceBuilder::ST::BEL);
+ for (auto introducer : { u32SequenceBuilder::Introducer::DEFAULT,
+ u32SequenceBuilder::Introducer::C0,
+ u32SequenceBuilder::Introducer::C1 }) {
+ for (auto st : {u32SequenceBuilder::ST::DEFAULT,
+ u32SequenceBuilder::ST::C0,
+ u32SequenceBuilder::ST::C1,
+ u32SequenceBuilder::ST::BEL }) {
+ for (auto c1 : { false, true }) {
+ int expected_rv = controls_match(c1, introducer, st, true, VTE_SEQ_OSC);
+ test_seq_osc(U"TEST"s, expected_rv, c1, -1, introducer, st);
+ }
+ }
+ }
}
static void
diff --git a/src/parser.cc b/src/parser.cc
index dd4eb35..7c1bd7a 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -114,6 +114,21 @@
*/
#define _VTE_SEQ_CODE(f,i) (((f) - 0x40) | ((i) << 6))
+/*
+ * @introducer: either a C1 control, or the final in the equivalent ESC F sequence
+ * @terminator: either a C1 control, or the final in the equivalent ESC F sequence
+ *
+ * Checks whether the OSC/DCS @introducer and the ST @terminator
+ * are from the same control set, i.e. both C0 or both C1.
+ *
+ * For OSC, this check allows C0 OSC with BEL-as-ST to pass, too.
+ */
+static inline bool parser_check_matching_controls(uint32_t introducer,
+ uint32_t terminator)
+{
+ return ((introducer ^ terminator) & 0x80) == 0;
+}
+
static unsigned int vte_parse_host_control(const struct vte_seq *seq)
{
switch (seq->terminator) {
@@ -554,6 +569,9 @@ static inline int parser_clear(struct vte_parser *parser, uint32_t raw)
for (i = 0; i < VTE_PARSER_ARG_MAX; ++i)
parser->seq.args[i] = VTE_SEQ_ARG_INIT_DEFAULT;
+ /* We don't need to do this, since it's only used when it's been set */
+ /* parser->seq.introducer = 0; */
+
return VTE_SEQ_NONE;
}
@@ -672,6 +690,7 @@ static inline int parser_osc_start(struct vte_parser *parser, uint32_t raw)
vte_seq_string_reset(&parser->seq.arg_str);
+ parser->seq.introducer = raw;
return VTE_SEQ_NONE;
}
@@ -694,6 +713,7 @@ static int parser_dcs_start(struct vte_parser *parser, uint32_t raw)
vte_seq_string_reset(&parser->seq.arg_str);
+ parser->seq.introducer = raw;
return VTE_SEQ_NONE;
}
@@ -769,6 +789,13 @@ static int parser_osc(struct vte_parser *parser, uint32_t raw)
vte_seq_string_finish(&parser->seq.arg_str);
+ /* We only dispatch a DCS if the introducer and string
+ * terminator are from the same control set, i.e. both
+ * C0 or both C1; we discard sequences with mixed controls.
+ */
+ if (!parser_check_matching_controls(parser->seq.introducer, raw))
+ return VTE_SEQ_IGNORE;
+
parser->seq.type = VTE_SEQ_OSC;
parser->seq.command = VTE_CMD_OSC;
parser->seq.terminator = raw;
@@ -781,6 +808,15 @@ static int parser_dcs(struct vte_parser *parser, uint32_t raw)
{
/* parser->seq was already filled in parser_dcs_consume() */
+ vte_seq_string_finish(&parser->seq.arg_str);
+
+ /* We only dispatch a DCS if the introducer and string
+ * terminator are from the same control set, i.e. both
+ * C0 or both C1; we discard sequences with mixed controls.
+ */
+ if (!parser_check_matching_controls(parser->seq.introducer, raw))
+ return VTE_SEQ_IGNORE;
+
return parser->seq.type;
}
diff --git a/src/parser.hh b/src/parser.hh
index 94b5af4..2338f4a 100644
--- a/src/parser.hh
+++ b/src/parser.hh
@@ -174,6 +174,7 @@ struct vte_seq {
unsigned int n_final_args;
vte_seq_arg_t args[VTE_PARSER_ARG_MAX];
vte_seq_string_t arg_str;
+ uint32_t introducer;
};
struct vte_parser {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]