From patchwork Mon Dec 9 09:55:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1206090 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-515488-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="dTrsErxx"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="XmpFfbau"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47WdqZ5rbfz9sNH for ; Mon, 9 Dec 2019 20:55:52 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=aFznBNfNnzbBjl33Ou0CWj8+9WVGYcv6IwCPqsofFX26Wqzjoeros Xn49zehRtD7NE9L746NA2DZe1HkWjd3Cp0jzzk8yBX0vvYv5TRVbfVfeY3AfwnZg HGk0ff3qIiIOY4U9ys6OUGgKWTrxXkk/Zene7vg7uN+dq+gLo4mj/k= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=Vjiyaxg4KLkWodgnk0An/X5653Y=; b=dTrsErxxvRq6TSVn2+1K Xw/6S3eTVuZAWhCb7VRuBPqLe2zz3hyeQDoIhyV8ZrVXqHZnuVkvKZGRJDVdLpTJ FH+MrQfiYbws5QQt2KjMemW3h3HiikK+d94gs/uncaEIX+y8BsranHhqWwWvuRZH NHUmzfkB6w9m9WmgWnnOQqY= Received: (qmail 92927 invoked by alias); 9 Dec 2019 09:55:40 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 92869 invoked by uid 89); 9 Dec 2019 09:55:40 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-17.4 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT autolearn=unavailable version=3.3.1 spammy= X-HELO: us-smtp-delivery-1.mimecast.com Received: from us-smtp-1.mimecast.com (HELO us-smtp-delivery-1.mimecast.com) (205.139.110.61) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 09 Dec 2019 09:55:38 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1575885337; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=N19Al9y6R4tqW5L9mZ1SQComMgK7IALbYL+LiWvup0g=; b=XmpFfbauIwxawd55qKrvEfHgEfn/z/54MpASDcPNaT+Ws5wlCfnOPh2i33kkOJmTVFOpYO J4ADygHR8LghAbhUHqk02f8T624wZk1EUf86kYStKj3goz1az/B7hi2PAKERWI/O3xh0B9 irr2DZLsxQsP2CZNmx38FAvb2pKKi5c= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-276-yWD4_XASOzOdxqsCoh9OuQ-1; Mon, 09 Dec 2019 04:55:32 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id E4F571005514; Mon, 9 Dec 2019 09:55:31 +0000 (UTC) Received: from localhost (unknown [10.33.36.41]) by smtp.corp.redhat.com (Postfix) with ESMTP id 931985D9D6; Mon, 9 Dec 2019 09:55:31 +0000 (UTC) Date: Mon, 9 Dec 2019 09:55:30 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++: fix buffer overflow in path::operator+= (PR92853) Message-ID: <20191209095530.GA1835487@redhat.com> MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.1 (2019-06-15) X-Mimecast-Spam-Score: 0 Content-Disposition: inline When concatenating a path ending in a root-directory onto another path, we added an empty filename to the end of the path twice, but only reserved space for one. That meant the second write went past the end of the allocated buffer. PR libstdc++/92853 * src/c++17/fs_path.cc (filesystem::path::operator+=(const path&)): Do not process a trailing directory separator twice. * testsuite/27_io/filesystem/path/concat/92853.cc: New test. * testsuite/27_io/filesystem/path/concat/path.cc: Test more cases. Tested powerpc64le-linux, committed to trunk. I'll backport to gcc-9-branch too. commit ac0d55229433ddd9609684e56474ed2335dd98d8 Author: Jonathan Wakely Date: Mon Dec 9 09:12:26 2019 +0000 libstdc++: fix buffer overflow in path::operator+= (PR92853) When concatenating a path ending in a root-directory onto another path, we added an empty filename to the end of the path twice, but only reserved space for one. That meant the second write went past the end of the allocated buffer. PR libstdc++/92853 * src/c++17/fs_path.cc (filesystem::path::operator+=(const path&)): Do not process a trailing directory separator twice. * testsuite/27_io/filesystem/path/concat/92853.cc: New test. * testsuite/27_io/filesystem/path/concat/path.cc: Test more cases. diff --git a/libstdc++-v3/src/c++17/fs_path.cc b/libstdc++-v3/src/c++17/fs_path.cc index 5fba971fef6..3aefef271fa 100644 --- a/libstdc++-v3/src/c++17/fs_path.cc +++ b/libstdc++-v3/src/c++17/fs_path.cc @@ -975,16 +975,7 @@ path::operator+=(const path& p) } if (it != last && it->_M_type() == _Type::_Root_dir) - { - ++it; - if (it == last) - { - // This root-dir becomes a trailing slash - auto pos = _M_pathname.length() + p._M_pathname.length(); - ::new(output++) _Cmpt({}, _Type::_Filename, pos); - ++_M_cmpts._M_impl->_M_size; - } - } + ++it; while (it != last) { diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/92853.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/92853.cc new file mode 100644 index 00000000000..62bde05c3ad --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/92853.cc @@ -0,0 +1,61 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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, or (at your option) +// any later version. + +// This library 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 library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17" } +// { dg-do run { target c++17 } } + +#include +#include + +void +test01() +{ + // PR libstdc++/92853 + using std::filesystem::path; + path p1{ "." }, p2{ "/" }; + p1 += p2; // corrupts heap + path p3{ p1 }; // CRASH! + __gnu_test::compare_paths( p3, "./" ); +} + +void +test02() +{ + using std::filesystem::path; + path p1{ "." }, p2{ "////" }; + p1 += p2; + path p3{ p1 }; + __gnu_test::compare_paths( p3, ".////" ); +} + +void +test03() +{ + using std::filesystem::path; + path p1{ "./" }, p2{ "/" }; + p1 += p2; + path p3{ p1 }; + __gnu_test::compare_paths( p3, ".//" ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc index 9f534e64cb7..16e668c0163 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc @@ -55,6 +55,8 @@ test02() path x("//blah/di/blah"); p += x; VERIFY( p.native() == prior_native + x.native() ); + path copy(p); + compare_paths( copy, p ); } } @@ -66,10 +68,28 @@ test03() compare_paths(p, "a//b"); } +void +test04() +{ + // Concat every test path onto every test path. + for (path p : __gnu_test::test_paths) + { + for (path x : __gnu_test::test_paths) + { + auto prior_native = p.native(); + p += x; + VERIFY( p.native() == prior_native + x.native() ); + path copy(p); // PR libstdc++/98523 + compare_paths( copy, p ); + } + } +} + int main() { test01(); test02(); test03(); + test04(); }