From patchwork Tue Jun 7 16:49:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1640049 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=vLMdo6V4; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LHbzW33Qlz9sFx for ; Wed, 8 Jun 2022 02:53:59 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 882D439484B4 for ; Tue, 7 Jun 2022 16:53:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 882D439484B4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1654620837; bh=DLAoIRlpaopYEWu6Q+B9dW/+si2ScgNgaF96L2KjI2Y=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=vLMdo6V40qxtLcyiHF29A4DDOow13XItxs6d7jzMi+mw45Di714Zbn3aJAFnAnu9u VZT+nnGfcJ5VVL/7/zZsvke0nU/Sm9qbfTIIMNb4ehjiS0C/75lSNaka+bI0StYwaY xZYp5d3peqnpbyp0Y93V84n5rEuubUvG/txib7Zs= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id B260439484B4 for ; Tue, 7 Jun 2022 16:49:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B260439484B4 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-97-IqpEWZD3Nmamhe8hD_ca7Q-1; Tue, 07 Jun 2022 12:49:49 -0400 X-MC-Unique: IqpEWZD3Nmamhe8hD_ca7Q-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1E07A1C3E985 for ; Tue, 7 Jun 2022 16:49:49 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.39.192.117]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 94549492C3B for ; Tue, 7 Jun 2022 16:49:48 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH v3 07/11] libio: Convert __vsprintf_internal to buffers In-Reply-To: References: X-From-Line: f980ea296f054ec117ee674794b3c1f70b7e411b Mon Sep 17 00:00:00 2001 Message-Id: Date: Tue, 07 Jun 2022 18:49:47 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" --- v3: Fix __sprintf_chk to fail earlier in case of buffer overruns. include/printf_buffer.h | 2 + libio/iovsprintf.c | 70 ++++++++---------------------- stdio-common/printf_buffer_flush.c | 4 ++ 3 files changed, 24 insertions(+), 52 deletions(-) diff --git a/include/printf_buffer.h b/include/printf_buffer.h index e89f984aca..92393399fb 100644 --- a/include/printf_buffer.h +++ b/include/printf_buffer.h @@ -44,7 +44,9 @@ enum __printf_buffer_mode { __printf_buffer_mode_failed, + __printf_buffer_mode_sprintf, __printf_buffer_mode_snprintf, + __printf_buffer_mode_sprintf_chk, __printf_buffer_mode_to_file, __printf_buffer_mode_strfmon, __printf_buffer_mode_fp, /* For __printf_fp_l_buffer. */ diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c index 72c67bf27b..7305d8e247 100644 --- a/libio/iovsprintf.c +++ b/libio/iovsprintf.c @@ -25,58 +25,18 @@ in files containing the exception. */ #include "libioP.h" -#include "strfile.h" -static int __THROW -_IO_str_chk_overflow (FILE *fp, int c) -{ - /* If we get here, the user-supplied buffer would be overrun by - further output. */ - __chk_fail (); -} - -static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable = -{ - JUMP_INIT_DUMMY, - JUMP_INIT(finish, _IO_str_finish), - JUMP_INIT(overflow, _IO_str_chk_overflow), - JUMP_INIT(underflow, _IO_str_underflow), - JUMP_INIT(uflow, _IO_default_uflow), - JUMP_INIT(pbackfail, _IO_str_pbackfail), - JUMP_INIT(xsputn, _IO_default_xsputn), - JUMP_INIT(xsgetn, _IO_default_xsgetn), - JUMP_INIT(seekoff, _IO_str_seekoff), - JUMP_INIT(seekpos, _IO_default_seekpos), - JUMP_INIT(setbuf, _IO_default_setbuf), - JUMP_INIT(sync, _IO_default_sync), - JUMP_INIT(doallocate, _IO_default_doallocate), - JUMP_INIT(read, _IO_default_read), - JUMP_INIT(write, _IO_default_write), - JUMP_INIT(seek, _IO_default_seek), - JUMP_INIT(close, _IO_default_close), - JUMP_INIT(stat, _IO_default_stat), - JUMP_INIT(showmanyc, _IO_default_showmanyc), - JUMP_INIT(imbue, _IO_default_imbue) -}; - -/* This function is called by regular vsprintf with maxlen set to -1, - and by vsprintf_chk with maxlen set to the size of the output - string. In the former case, _IO_str_chk_overflow will never be - called; in the latter case it will crash the program if the buffer - overflows. */ +#include +#include +#include int __vsprintf_internal (char *string, size_t maxlen, const char *format, va_list args, unsigned int mode_flags) { - _IO_strfile sf; - int ret; + struct __printf_buffer buf; -#ifdef _IO_MTSAFE_IO - sf._sbf._f._lock = NULL; -#endif - _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL); /* When called from fortified sprintf/vsprintf, erase the destination buffer and try to detect overflows. When called from regular sprintf/vsprintf, do not erase the destination buffer, because @@ -84,19 +44,25 @@ __vsprintf_internal (char *string, size_t maxlen, by ISO C), nor try to detect overflows. */ if ((mode_flags & PRINTF_CHK) != 0) { - _IO_JUMPS (&sf._sbf) = &_IO_str_chk_jumps; string[0] = '\0'; + __printf_buffer_init (&buf, string, maxlen, + __printf_buffer_mode_sprintf_chk); } else - _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; - _IO_str_init_static_internal (&sf, string, - (maxlen == -1) ? -1 : maxlen - 1, - string); + { + __printf_buffer_init (&buf, string, 0, __printf_buffer_mode_sprintf); + buf.write_end = (char *) ~(uintptr_t) 0; /* End of address space. */ + } + + __printf_buffer (&buf, format, args, mode_flags); - ret = __vfprintf_internal (&sf._sbf._f, format, args, mode_flags); + /* Write the NUL terminator if there is room. Do not use the putc + operation to avoid overflowing the character write count. */ + if ((mode_flags & PRINTF_CHK) != 0 && buf.write_ptr == buf.write_end) + __chk_fail (); + *buf.write_ptr = '\0'; - *sf._sbf._f._IO_write_ptr = '\0'; - return ret; + return __printf_buffer_done (&buf); } int diff --git a/stdio-common/printf_buffer_flush.c b/stdio-common/printf_buffer_flush.c index bfd1f9d733..f44c8b887f 100644 --- a/stdio-common/printf_buffer_flush.c +++ b/stdio-common/printf_buffer_flush.c @@ -38,10 +38,14 @@ __printf_buffer_do_flush (struct __printf_buffer *buf) switch (buf->mode) { case __printf_buffer_mode_failed: + case __printf_buffer_mode_sprintf: return; case __printf_buffer_mode_snprintf: __printf_buffer_flush_snprintf ((struct __printf_buffer_snprintf *) buf); return; + case __printf_buffer_mode_sprintf_chk: + __chk_fail (); + break; case __printf_buffer_mode_to_file: __printf_buffer_flush_to_file ((struct __printf_buffer_to_file *) buf); return;