Bug 91582 - missing heap overflow detection for strcpy
Summary: missing heap overflow detection for strcpy
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 10.0
Assignee: Martin Sebor
URL:
Keywords: diagnostic, patch
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
 
Reported: 2019-08-28 14:47 UTC by Martin Sebor
Modified: 2023-12-30 21:16 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-08-28 00:00:00


Attachments
A proof-of-concept implementation of the overflow detection. (2.08 KB, patch)
2019-08-28 14:49 UTC, Martin Sebor
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2019-08-28 14:47:14 UTC
Both functions below overflow the destination buffer by a single byte yet neither is detected.

$ cat x.c && gcc -D_FORTIFY_SOURCE=2 -O2 -S -Wall -fdump-tree-optimized=/dev/stdout x.c
#include <stdlib.h>
#include <string.h>

void* f (void)
{
  const char a[] = "1234";
  char *t = (char*)malloc (strlen (a));
  strcpy (t, a);
  return t;
}

void* g (const char *s)
{ 
  char *t = (char*)malloc (strlen (s));
  strcpy (t, s);
  return t;
}


;; Function f (f, funcdef_no=27, decl_uid=2854, cgraph_uid=28, symbol_order=27)

f ()
{
  char * t;
  const char a[5];

  <bb 2> [local count: 1073741824]:
  a = "1234";
  t_5 = malloc (4);
  MEM <unsigned char[5]> [(char * {ref-all})t_5] = MEM <unsigned char[5]> [(char * {ref-all})&a];
  a ={v} {CLOBBER};
  return t_5;

}



;; Function g (g, funcdef_no=28, decl_uid=2859, cgraph_uid=29, symbol_order=28)

g (const char * s)
{
  char * t;
  long unsigned int _1;
  long unsigned int _6;

  <bb 2> [local count: 1073741824]:
  _1 = strlen (s_3(D));
  t_5 = malloc (_1);
  _6 = _1 + 1;
  __builtin_memcpy (t_5, s_3(D), _6);
  return t_5;

}
Comment 1 Martin Sebor 2019-08-28 14:49:32 UTC
Created attachment 46771 [details]
A proof-of-concept implementation of the overflow detection.

With the attached proof of concept GCC diagnoses the first overflow:

x.c: In function ‘f’:
x.c:8:3: warning: ‘strcpy’ writing 5 bytes into a region of size between 0 and 4 [-Wstringop-truncation]
    8 |   strcpy (t, a);
      |   ^~~~~~~~~~~~~
x.c:7:20: note: region allocated by ‘malloc’ here
    7 |   char *t = (char*)malloc (strlen (a));
      |                    ^~~~~~~~~~~~~~~~~~~
Comment 2 Martin Sebor 2019-08-28 14:50:15 UTC
Working on it.
Comment 3 Martin Sebor 2019-11-08 22:11:49 UTC
Patch: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00652.html
Comment 4 Martin Sebor 2019-12-05 01:28:42 UTC
Author: msebor
Date: Thu Dec  5 01:28:11 2019
New Revision: 278983

URL: https://gcc.gnu.org/viewcvs?rev=278983&root=gcc&view=rev
Log:
PR middle-end/91582 - missing heap overflow detection for strcpy

gcc/ChangeLog:

	PR middle-end/91582
	* builtins.c (gimple_call_alloc_size): New function.
	(compute_objsize): Add argument.  Call gimple_call_alloc_size.
	Handle variable offsets and indices.
	* builtins.h (gimple_call_alloc_size): Declare.
	(compute_objsize): Add argument.
	* gcc/gimple-ssa-warn-restrict.c: Remove assertions.
	* tree-ssa-strlen.c (handle_store): Handle calls to allocated objects.

gcc/testsuite/ChangeLog:

	PR middle-end/91582
	* c-c++-common/Wstringop-truncation.c: Remove xfails.
	* g++.dg/warn/Wstringop-overflow-4.C: New test.
	* g++.dg/ext/attr-alloc_size.C: Suppress -Warray-bounds.
	* gcc.dg/Warray-bounds-56.c: New test.
	* gcc.dg/Wstringop-overflow-22.c: New test.
	* gcc.dg/attr-alloc_size.c: Suppress -Warray-bounds.
	* gcc.dg/attr-copy-2.c: Same.
	* gcc.dg/builtin-stringop-chk-5.c: Remove xfails.
	* gcc.dg/builtin-stringop-chk-8.c: Same.  Correct the text of expected
	warnings.
	* gcc.target/i386/pr82002-2a.c: Prune expected warning.
	* gcc.target/i386/pr82002-2b.c: Same.


Added:
    trunk/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-56.c
    trunk/gcc/testsuite/gcc.dg/Wstringop-overflow-25.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/builtins.c
    trunk/gcc/builtins.h
    trunk/gcc/gimple-ssa-warn-restrict.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/c-c++-common/Wstringop-truncation.c
    trunk/gcc/testsuite/g++.dg/ext/attr-alloc_size.C
    trunk/gcc/testsuite/gcc.dg/attr-alloc_size.c
    trunk/gcc/testsuite/gcc.dg/attr-copy-2.c
    trunk/gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c
    trunk/gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c
    trunk/gcc/testsuite/gcc.target/i386/pr82002-2a.c
    trunk/gcc/testsuite/gcc.target/i386/pr82002-2b.c
    trunk/gcc/tree-ssa-strlen.c
Comment 5 Martin Sebor 2019-12-05 01:39:49 UTC
Part 2 of the patch series was committed in r278983.  Part 1 and part 3 are still waiting for review and approval:
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00429.html
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02340.html
Comment 6 Martin Sebor 2019-12-14 00:53:19 UTC
Author: msebor
Date: Sat Dec 14 00:52:46 2019
New Revision: 279392

URL: https://gcc.gnu.org/viewcvs?rev=279392&root=gcc&view=rev
Log:
PR middle-end/91582 - missing heap overflow detection for strcpy
PR middle-end/92868 - ICE: tree check: expected integer_cst, have ssa_name

gcc/ChangeLog:

	PR middle-end/91582
	PR middle-end/92868
	* builtins.c (addr_decl_size): New function.
	(gimple_call_alloc_size): Add arguments.
	(compute_objsize): Add an argument.  Set *PDECL even for allocated
	objects.
	Correct checking for negative wide_int.
	Correct handling of negative outer offsets into unknown regions
	or with unknown inner offsets.
	Extend offsets to at most sizetype precision.
	Only handle constant subobject sizes.
	* builtins.h (gimple_call_alloc_size): Add arguments.
	* tree.c (component_ref_size): Always return sizetype.
	* tree-ssa-strlen.c (strinfo::alloc): New member.
	(get_addr_stridx): Add argument.
	(get_stridx): Use ptrdiff_t.  Add argument.
	(new_strinfo): Set new member.
	(get_string_length): Handle alloca and VLA.
	(dump_strlen_info): Dump more state.
	(maybe_invalidate): Print more info.  Decrease indentation.
	(unshare_strinfo): Set new member.
	(valid_builtin_call): Handle alloca and VLA.
	(maybe_warn_overflow): Check and set no-warning bit.  Improve
	handling of offsets.  Print allocated objects.
	(handle_builtin_strlen): Handle strinfo records with null lengths.
	(handle_builtin_strcpy): Add argument.  Call maybe_warn_overflow.
	(is_strlen_related_p): Handle dynamically allocated objects.
	(get_range): Add argument.
	(handle_builtin_malloc): Rename...
	(handle_alloc): ...to this and handle all allocation functions.
	(handle_builtin_memset): Call maybe_warn_overflow.
	(count_nonzero_bytes): Handle more MEM_REF forms.
	(strlen_check_and_optimize_call): Call handle_alloc_call.  Pass
	arguments to more callees.
	(handle_integral_assign): Add argument.  Create strinfo entries
	for MEM_REF assignments.
	(check_and_optimize_stmt): Handle more MEM_REF forms.

gcc/testsuite/ChangeLog:

	PR middle-end/91582
	* c-c++-common/Wrestrict.c: Adjust expected warnings.
	* gcc/testsuite/c-c++-common/Wstringop-truncation-4.c: Enable more
	warnings.
	* gcc/testsuite/c-c++-common/Wstringop-truncation.c: Remove an xfail.
	* gcc.dg/Warray-bounds-46.c: Disable -Wstringop-overflow.
	* gcc.dg/Warray-bounds-47.c: Same.
	* gcc.dg/Warray-bounds-52.c: New test.
	* gcc.dg/Wstringop-overflow-27.c: New test.
	* gcc.dg/Wstringop-overflow-28.c: New test.
	* gcc.dg/Wstringop-overflow-29.c: New test.
	* gcc.dg/attr-alloc_size.c (test): Disable -Warray-bounds.
	* gcc.dg/attr-copy-2.c: Adjust expected warnings.
	* gcc.dg/builtin-stringop-chk-5.c: Adjust text of expected messages.
	* gcc.dg/strlenopt-86.c: Relax test.
	* gcc.target/i386/pr82002-1.c: Prune expected warnings.


Added:
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-52.c
    trunk/gcc/testsuite/gcc.dg/Wstringop-overflow-27.c
    trunk/gcc/testsuite/gcc.dg/Wstringop-overflow-28.c
    trunk/gcc/testsuite/gcc.dg/Wstringop-overflow-29.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/builtins.c
    trunk/gcc/builtins.h
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/c-c++-common/Wrestrict.c
    trunk/gcc/testsuite/c-c++-common/Wstringop-truncation-4.c
    trunk/gcc/testsuite/c-c++-common/Wstringop-truncation.c
    trunk/gcc/testsuite/g++.dg/warn/Wstringop-overflow-3.C
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-46.c
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-47.c
    trunk/gcc/testsuite/gcc.dg/attr-alloc_size.c
    trunk/gcc/testsuite/gcc.dg/attr-copy-2.c
    trunk/gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c
    trunk/gcc/testsuite/gcc.dg/strlenopt-86.c
    trunk/gcc/testsuite/gcc.target/i386/pr82002-1.c
    trunk/gcc/tree-ssa-strlen.c
    trunk/gcc/tree-ssa-strlen.h
    trunk/gcc/tree.c
Comment 7 Martin Sebor 2019-12-14 01:02:43 UTC
The last patch in the series has been committed in r279392.