diff options
| author | Edwin Mons <edwin.mons@isode.com> | 2018-10-24 13:37:33 (GMT) |
|---|---|---|
| committer | Edwin Mons <edwin.mons@isode.com> | 2018-10-24 16:15:21 (GMT) |
| commit | 1c71c5a77e037038c581a68774c96fad9a79030b (patch) | |
| tree | 3ee82bd0d84aa1d4c33d69948ca10952bda9cd35 /Swiften/IDN/UnitTest/IDNConverterTest.cpp | |
| parent | 0f4a77303fedfaa57977d6ca528799305eac9367 (diff) | |
| download | swift-1c71c5a77e037038c581a68774c96fad9a79030b.zip swift-1c71c5a77e037038c581a68774c96fad9a79030b.tar.bz2 | |
Fix buffer overrun in LibIDNConverter
When Swift::LibIDNConverter::getStringPrepared was called with an input
of 1024 or more characters, stringprep would be called on a memory
region that wasn't NUL-terminated. It also blindly trimmed the input to
1024 bytes, even though there may be input longer than that that still
results in a valid 1023 byte prepped string.
IDNConverterTest has been converted to gtest, as cppunit cannot deal
with testing for std::exceptions being thrown on at least macOS
Test-Information:
Unit tests pass on macOS 10.13 and Debian 9
Before fix, the newly added unit tests triggered an ASan abort due to a
buffer overrun.
After fix, all unit tests pass, even with ASan enabled.
Change-Id: Ia3e51a39f5db1de32b8f8bb388f81ca041136df7
Diffstat (limited to 'Swiften/IDN/UnitTest/IDNConverterTest.cpp')
| -rw-r--r-- | Swiften/IDN/UnitTest/IDNConverterTest.cpp | 114 |
1 files changed, 65 insertions, 49 deletions
diff --git a/Swiften/IDN/UnitTest/IDNConverterTest.cpp b/Swiften/IDN/UnitTest/IDNConverterTest.cpp index 508a28c..c5f94d0 100644 --- a/Swiften/IDN/UnitTest/IDNConverterTest.cpp +++ b/Swiften/IDN/UnitTest/IDNConverterTest.cpp | |||
| @@ -1,64 +1,80 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010-2016 Isode Limited. | 2 | * Copyright (c) 2010-2018 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | 8 | ||
| 9 | #include <cppunit/extensions/HelperMacros.h> | 9 | #include <gtest/gtest.h> |
| 10 | #include <cppunit/extensions/TestFactoryRegistry.h> | ||
| 11 | 10 | ||
| 12 | #include <Swiften/IDN/IDNConverter.h> | 11 | #include <Swiften/IDN/IDNConverter.h> |
| 13 | #include <Swiften/IDN/PlatformIDNConverter.h> | 12 | #include <Swiften/IDN/PlatformIDNConverter.h> |
| 14 | 13 | ||
| 15 | using namespace Swift; | 14 | using namespace Swift; |
| 16 | 15 | ||
| 17 | class IDNConverterTest : public CppUnit::TestFixture { | 16 | class IDNConverterTest : public ::testing::Test { |
| 18 | CPPUNIT_TEST_SUITE(IDNConverterTest); | 17 | |
| 19 | CPPUNIT_TEST(testStringPrep); | 18 | protected: |
| 20 | CPPUNIT_TEST(testStringPrep_Empty); | 19 | virtual void SetUp() { |
| 21 | CPPUNIT_TEST(testGetEncoded); | 20 | testling_ = std::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); |
| 22 | CPPUNIT_TEST(testGetEncoded_International); | 21 | } |
| 23 | CPPUNIT_TEST(testGetEncoded_Invalid); | 22 | |
| 24 | CPPUNIT_TEST_SUITE_END(); | 23 | std::shared_ptr<IDNConverter> testling_; |
| 25 | |||
| 26 | public: | ||
| 27 | void setUp() { | ||
| 28 | testling = std::shared_ptr<IDNConverter>(PlatformIDNConverter::create()); | ||
| 29 | } | ||
| 30 | |||
| 31 | void testStringPrep() { | ||
| 32 | std::string result = testling->getStringPrepared("tron\xc3\x87on", IDNConverter::NamePrep); | ||
| 33 | |||
| 34 | CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), result); | ||
| 35 | } | ||
| 36 | |||
| 37 | void testStringPrep_Empty() { | ||
| 38 | CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::NamePrep)); | ||
| 39 | CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::XMPPNodePrep)); | ||
| 40 | CPPUNIT_ASSERT_EQUAL(std::string(""), testling->getStringPrepared("", IDNConverter::XMPPResourcePrep)); | ||
| 41 | } | ||
| 42 | |||
| 43 | void testGetEncoded() { | ||
| 44 | boost::optional<std::string> result = testling->getIDNAEncoded("www.swift.im"); | ||
| 45 | CPPUNIT_ASSERT(!!result); | ||
| 46 | CPPUNIT_ASSERT_EQUAL(std::string("www.swift.im"), *result); | ||
| 47 | } | ||
| 48 | |||
| 49 | void testGetEncoded_International() { | ||
| 50 | boost::optional<std::string> result = testling->getIDNAEncoded("www.tron\xc3\x87on.com"); | ||
| 51 | CPPUNIT_ASSERT(!!result); | ||
| 52 | CPPUNIT_ASSERT_EQUAL(std::string("www.xn--tronon-zua.com"), *result); | ||
| 53 | } | ||
| 54 | |||
| 55 | void testGetEncoded_Invalid() { | ||
| 56 | boost::optional<std::string> result = testling->getIDNAEncoded("www.foo,bar.com"); | ||
| 57 | CPPUNIT_ASSERT(!result); | ||
| 58 | } | ||
| 59 | |||
| 60 | private: | ||
| 61 | std::shared_ptr<IDNConverter> testling; | ||
| 62 | }; | 24 | }; |
| 63 | 25 | ||
| 64 | CPPUNIT_TEST_SUITE_REGISTRATION(IDNConverterTest); | 26 | TEST_F(IDNConverterTest, testStringPrep) { |
| 27 | std::string result = testling_->getStringPrepared("tron\xc3\x87on", IDNConverter::NamePrep); | ||
| 28 | |||
| 29 | ASSERT_EQ(std::string("tron\xc3\xa7on"), result); | ||
| 30 | } | ||
| 31 | |||
| 32 | TEST_F(IDNConverterTest, testStringPrep_Empty) { | ||
| 33 | ASSERT_EQ(std::string(""), testling_->getStringPrepared("", IDNConverter::NamePrep)); | ||
| 34 | ASSERT_EQ(std::string(""), testling_->getStringPrepared("", IDNConverter::XMPPNodePrep)); | ||
| 35 | ASSERT_EQ(std::string(""), testling_->getStringPrepared("", IDNConverter::XMPPResourcePrep)); | ||
| 36 | } | ||
| 37 | |||
| 38 | TEST_F(IDNConverterTest, testStringPrep_MaximumOutputSize) { | ||
| 39 | const std::string input(1023, 'x'); | ||
| 40 | ASSERT_EQ(input, testling_->getStringPrepared(input, IDNConverter::NamePrep)); | ||
| 41 | ASSERT_EQ(input, testling_->getStringPrepared(input, IDNConverter::XMPPNodePrep)); | ||
| 42 | ASSERT_EQ(input, testling_->getStringPrepared(input, IDNConverter::XMPPResourcePrep)); | ||
| 43 | } | ||
| 44 | |||
| 45 | TEST_F(IDNConverterTest, testStringPrep_TooLong) { | ||
| 46 | const std::string input(1024, 'x'); | ||
| 47 | ASSERT_THROW(testling_->getStringPrepared(input, IDNConverter::NamePrep), std::exception); | ||
| 48 | ASSERT_THROW(testling_->getStringPrepared(input, IDNConverter::XMPPNodePrep), std::exception); | ||
| 49 | ASSERT_THROW(testling_->getStringPrepared(input, IDNConverter::XMPPResourcePrep), std::exception); | ||
| 50 | } | ||
| 51 | |||
| 52 | TEST_F(IDNConverterTest, testStringPrep_ShrinkingBelow1023) { | ||
| 53 | std::string input; | ||
| 54 | std::string expected; | ||
| 55 | // The four byte \u03b1\u0313 UTF-8 string will shrink to the three byte \u1f00 | ||
| 56 | for (auto i = 0; i < 300; ++i) { | ||
| 57 | input +="\xce\xb1\xcc\x93"; // UTF-8 repesentation of U+03B1 U+0313 | ||
| 58 | expected += "\xe1\xbc\x80"; // UTF-8 representation of U+1F00 | ||
| 59 | } | ||
| 60 | ASSERT_EQ(expected, testling_->getStringPrepared(input, IDNConverter::NamePrep)); | ||
| 61 | ASSERT_EQ(expected, testling_->getStringPrepared(input, IDNConverter::XMPPNodePrep)); | ||
| 62 | ASSERT_EQ(expected, testling_->getStringPrepared(input, IDNConverter::XMPPResourcePrep)); | ||
| 63 | } | ||
| 64 | |||
| 65 | TEST_F(IDNConverterTest, testGetEncoded) { | ||
| 66 | boost::optional<std::string> result = testling_->getIDNAEncoded("www.swift.im"); | ||
| 67 | ASSERT_TRUE(!!result); | ||
| 68 | ASSERT_EQ(std::string("www.swift.im"), *result); | ||
| 69 | } | ||
| 70 | |||
| 71 | TEST_F(IDNConverterTest, testGetEncoded_International) { | ||
| 72 | boost::optional<std::string> result = testling_->getIDNAEncoded("www.tron\xc3\x87on.com"); | ||
| 73 | ASSERT_TRUE(result); | ||
| 74 | ASSERT_EQ(std::string("www.xn--tronon-zua.com"), *result); | ||
| 75 | } | ||
| 76 | |||
| 77 | TEST_F(IDNConverterTest, testGetEncoded_Invalid) { | ||
| 78 | boost::optional<std::string> result = testling_->getIDNAEncoded("www.foo,bar.com"); | ||
| 79 | ASSERT_FALSE(result); | ||
| 80 | } | ||
Swift