From owner-freebsd-security Fri May 18 17:33:56 2001 Delivered-To: freebsd-security@freebsd.org Received: from virginia.yamato.ibm.co.jp (virginia.yamato.ibm.co.jp [203.141.89.165]) by hub.freebsd.org (Postfix) with ESMTP id E0F3237B42C for ; Fri, 18 May 2001 17:32:38 -0700 (PDT) (envelope-from etoh@trl.ibm.co.jp) Received: from ns.trl.ibm.com (ns.trl.ibm.com [9.116.48.18]) by virginia.yamato.ibm.co.jp (8.9.3/3.7W/GW3.3) with ESMTP id JAA10162 for ; Sat, 19 May 2001 09:32:28 +0900 Received: from localhost by ns.trl.ibm.com (AIX4.3/8.9.3/TRL4.5SRV) id JAA23958; Sat, 19 May 2001 09:32:27 +0900 To: security@FreeBSD.ORG Subject: Base system with gcc stack-smashing protector X-Mailer: Mew version 1.94b48 on Emacs 20.7 / Mule 4.0 (HANANOEN) Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="--Next_Part(Sat_May_19_09:32:24_2001_518)--" Content-Transfer-Encoding: 7bit Message-Id: <20010519093227T.etoh@trl.ibm.com> Date: Sat, 19 May 2001 09:32:27 +0900 From: Hiroaki Etoh X-Dispatcher: imput version 990813(IM119) Lines: 2686 Sender: owner-freebsd-security@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org ----Next_Part(Sat_May_19_09:32:24_2001_518)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit At last, I have completed GCC extension for protectiong applications against stack smashing attack. It works on Intel x86 processor and IBM powerpc. I also updated the patch for protecting FreeBSD 4.3 system from stack smashing attack. - support FreeBSD 4.3 - syslog output at the detection of stack smashing attack - kernel protection The attached file is a patch against the system 4.3-RELEASE. See http://www.trl.ibm.com/projects/security/ssp/buildfreebsd.html for details. (to be appered in the next week) Hiroaki Etoh, Tokyo Research Laboratory, IBM Japan ----Next_Part(Sat_May_19_09:32:24_2001_518)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="protector43.patch" ? contrib/gcc/protector.h ? contrib/gcc/protector.c ? lib/libc/.depend ? sys/libkern/stack_smash_handler.c Index: contrib/gcc/Makefile.in =================================================================== RCS file: /home/ncvs/src/contrib/gcc/Makefile.in,v retrieving revision 1.4.2.1 diff -c -r1.4.2.1 Makefile.in *** contrib/gcc/Makefile.in 2001/04/10 19:22:57 1.4.2.1 --- contrib/gcc/Makefile.in 2001/05/18 23:54:35 *************** *** 685,691 **** insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \ profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \ ! mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load --- 685,691 ---- insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \ insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \ profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \ ! mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o protector.o # GEN files are listed separately, so they can be built before doing parallel # makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load *************** *** 736,742 **** _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit \ ! _ctors _pure LIB2FUNCS_EH = _eh --- 736,742 ---- _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit \ ! _ctors _pure _stack_smash_handler LIB2FUNCS_EH = _eh *************** *** 1138,1144 **** if [ $${name}.asm = $${file} ]; then \ cp $${file} $${name}.s || exit 1; file=$${name}.s; \ else true; fi; \ ! $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${oname}$(objext); \ rm -f $${name}.s $${oname}$(objext); \ --- 1138,1144 ---- if [ $${name}.asm = $${file} ]; then \ cp $${file} $${name}.s || exit 1; file=$${name}.s; \ else true; fi; \ ! $(GCC_FOR_TARGET) -fno-stack-protector $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \ $(AR_FOR_TARGET) $(AR_FLAGS_FOR_TARGET) tmplibgcc2.a $${oname}$(objext); \ rm -f $${name}.s $${oname}$(objext); \ *************** *** 1465,1471 **** dwarf2out.h sdbout.h dbxout.h $(EXPR_H) $(BASIC_BLOCK_H) \ $(lang_options_files) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \ ! -DTARGET_NAME=\"$(target_alias)\" \ -c `echo $(srcdir)/toplev.c | sed 's,^\./,,'` rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h --- 1465,1471 ---- dwarf2out.h sdbout.h dbxout.h $(EXPR_H) $(BASIC_BLOCK_H) \ $(lang_options_files) $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \ ! -DSTACK_PROTECTOR -DTARGET_NAME=\"$(target_alias)\" \ -c `echo $(srcdir)/toplev.c | sed 's,^\./,,'` rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h Index: contrib/gcc/cse.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/cse.c,v retrieving revision 1.1.1.6.2.1 diff -c -r1.1.1.6.2.1 cse.c *** contrib/gcc/cse.c 2001/04/10 19:23:04 1.1.1.6.2.1 --- contrib/gcc/cse.c 2001/05/18 23:54:39 *************** *** 6483,6488 **** --- 6483,6492 ---- if (SET_DEST (x) == pc_rtx && GET_CODE (SET_SRC (x)) == LABEL_REF) ; + else if (x->volatil) { + make_new_qty (REGNO (SET_DEST (x))); + qty_mode[REG_QTY (REGNO (SET_DEST (x)))] = GET_MODE (SET_DEST (x)); + } /* Don't count call-insns, (set (reg 0) (call ...)), as a set. The hard function value register is used only once, to copy to Index: contrib/gcc/dbxout.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/dbxout.c,v retrieving revision 1.4 diff -c -r1.4 dbxout.c *** contrib/gcc/dbxout.c 1999/10/26 08:47:58 1.4 --- contrib/gcc/dbxout.c 2001/05/18 23:54:40 *************** *** 2253,2258 **** --- 2253,2261 ---- for (; parms; parms = TREE_CHAIN (parms)) if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) { + /* change the debug info of escaped argument for stack protection */ + update_debuginfo_using_escaped_arg_list (parms); + dbxout_prepare_symbol (parms); /* Perform any necessary register eliminations on the parameter's rtl, Index: contrib/gcc/expr.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/expr.c,v retrieving revision 1.1.1.4.2.2 diff -c -r1.1.1.4.2.2 expr.c *** contrib/gcc/expr.c 2001/04/10 19:23:06 1.1.1.4.2.2 --- contrib/gcc/expr.c 2001/05/18 23:54:45 *************** *** 41,46 **** --- 41,47 ---- #include "typeclass.h" #include "defaults.h" #include "toplev.h" + #include "protector.h" #define CEIL(x,y) (((x) + (y) - 1) / (y)) *************** *** 6316,6322 **** && modifier != EXPAND_MEMORY_USE_WO) return GEN_INT (TREE_STRING_POINTER (string)[i]); ! op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address (mode, op0); if (current_function_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp))) --- 6317,6323 ---- && modifier != EXPAND_MEMORY_USE_WO) return GEN_INT (TREE_STRING_POINTER (string)[i]); ! op0 = expand_expr (exp1, NULL_RTX, VOIDmode, flag_propolice_protection?ro_modifier:EXPAND_SUM); op0 = memory_address (mode, op0); if (current_function_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp))) *************** *** 8796,8802 **** mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, expand_expr (exp, NULL_RTX, ! ptr_mode, EXPAND_SUM))); RTX_UNCHANGING_P (mem) = TREE_READONLY (exp); --- 8797,8803 ---- mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, expand_expr (exp, NULL_RTX, ! ptr_mode, flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM))); RTX_UNCHANGING_P (mem) = TREE_READONLY (exp); Index: contrib/gcc/function.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/function.c,v retrieving revision 1.6.2.2 diff -c -r1.6.2.2 function.c *** contrib/gcc/function.c 2001/04/10 19:23:08 1.6.2.2 --- contrib/gcc/function.c 2001/05/18 23:54:47 *************** *** 60,65 **** --- 60,66 ---- #include "obstack.h" #include "toplev.h" #include "hash.h" + #include "protector.h" #ifndef TRAMPOLINE_ALIGNMENT #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY *************** *** 432,437 **** --- 433,440 ---- /* The size of the slot, including extra space for alignment. This info is for combine_temp_slots. */ HOST_WIDE_INT full_size; + /* Boundary mark of a character array and the others. This info is for ProPolice */ + int boundary_mark; }; /* List of all temporaries allocated, both available and in use. */ *************** *** 451,456 **** --- 454,464 ---- until no longer needed. CLEANUP_POINT_EXPRs define the lifetime of TARGET_EXPRs. */ int target_temp_slot_level; + + /* Current boundary mark for character arrays. */ + + int temp_boundary_mark; + /* This structure is used to record MEMs or pseudos used to replace VAR, any SUBREGs of VAR, and any MEMs containing VAR as an address. We need to *************** *** 933,938 **** --- 941,950 ---- int align; int alias_set; struct temp_slot *p, *best_p = 0; + int char_array = type && (TREE_TYPE (type)==char_type_node + || (TREE_TYPE (type) + && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE + && TYPE_PRECISION (TREE_TYPE (type)) == 8)); /* If SIZE is -1 it means that somebody tried to allocate a temporary of a variable size. */ *************** *** 965,971 **** && (!flag_strict_aliasing || (alias_set && p->alias_set == alias_set)) && (best_p == 0 || best_p->size > p->size ! || (best_p->size == p->size && best_p->align > p->align))) { if (p->align == align && p->size == size) { --- 977,984 ---- && (!flag_strict_aliasing || (alias_set && p->alias_set == alias_set)) && (best_p == 0 || best_p->size > p->size ! || (best_p->size == p->size && best_p->align > p->align)) ! && (! char_array || p->boundary_mark != 0)) { if (p->align == align && p->size == size) { *************** *** 1003,1008 **** --- 1016,1022 ---- p->align = best_p->align; p->address = 0; p->rtl_expr = 0; + p->boundary_mark = best_p->boundary_mark; p->next = temp_slots; temp_slots = p; *************** *** 1064,1069 **** --- 1078,1084 ---- p->full_size = frame_offset - frame_offset_old; #endif p->address = 0; + p->boundary_mark = char_array?++temp_boundary_mark:0; p->next = temp_slots; temp_slots = p; } *************** *** 1188,1201 **** int delete_q = 0; if (! q->in_use && GET_MODE (q->slot) == BLKmode) { ! if (p->base_offset + p->full_size == q->base_offset) { /* Q comes after P; combine Q into P. */ p->size += q->size; p->full_size += q->full_size; delete_q = 1; } ! else if (q->base_offset + q->full_size == p->base_offset) { /* P comes after Q; combine P into Q. */ q->size += p->size; --- 1203,1218 ---- int delete_q = 0; if (! q->in_use && GET_MODE (q->slot) == BLKmode) { ! if (p->base_offset + p->full_size == q->base_offset && ! p->boundary_mark == q->boundary_mark) { /* Q comes after P; combine Q into P. */ p->size += q->size; p->full_size += q->full_size; delete_q = 1; } ! else if (q->base_offset + q->full_size == p->base_offset && ! p->boundary_mark == q->boundary_mark) { /* P comes after Q; combine P into Q. */ q->size += p->size; *************** *** 1704,1710 **** if (regno < max_parm_reg) new = parm_reg_stack_loc[regno]; if (new == 0) ! new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0); } PUT_MODE (reg, decl_mode); --- 1721,1727 ---- if (regno < max_parm_reg) new = parm_reg_stack_loc[regno]; if (new == 0) ! new = assign_stack_local_for_pseudo_reg (decl_mode, GET_MODE_SIZE (decl_mode), 0); } PUT_MODE (reg, decl_mode); *************** *** 7035,7038 **** --- 7052,7061 ---- } } #endif /* HAVE_prologue or HAVE_epilogue */ + } + + tree + query_trampoline_list() + { + return trampoline_list; } Index: contrib/gcc/gcc.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/gcc.c,v retrieving revision 1.17.2.1 diff -c -r1.17.2.1 gcc.c *** contrib/gcc/gcc.c 2001/04/10 19:23:09 1.17.2.1 --- contrib/gcc/gcc.c 2001/05/18 23:54:49 *************** *** 768,774 **** %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\ %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ %{static:} %{L*} %D %o\ ! %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\ %{T*}\ \n }}}}}}"; --- 768,774 ---- %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\ %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ %{static:} %{L*} %D %o\ ! %{!nostdlib:%{!nodefaultlibs:%G %L %G %L}}\ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\ %{T*}\ \n }}}}}}"; Index: contrib/gcc/gcse.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/gcse.c,v retrieving revision 1.1.1.3 diff -c -r1.1.1.3 gcse.c *** contrib/gcc/gcse.c 1999/11/01 08:26:03 1.1.1.3 --- contrib/gcc/gcse.c 2001/05/18 23:54:51 *************** *** 3718,3724 **** /* Find an assignment that sets reg_used and is available at the start of the block. */ set = find_avail_set (regno, insn); ! if (! set) continue; pat = set->expr; --- 3718,3724 ---- /* Find an assignment that sets reg_used and is available at the start of the block. */ set = find_avail_set (regno, insn); ! if (! set || set->expr->volatil) continue; pat = set->expr; Index: contrib/gcc/integrate.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/integrate.c,v retrieving revision 1.1.1.3 diff -c -r1.1.1.3 integrate.c *** contrib/gcc/integrate.c 1999/10/16 06:05:22 1.1.1.3 --- contrib/gcc/integrate.c 2001/05/18 23:54:53 *************** *** 38,43 **** --- 38,44 ---- #include "function.h" #include "toplev.h" #include "intl.h" + #include "protector.h" #include "obstack.h" #define obstack_chunk_alloc xmalloc *************** *** 1503,1512 **** arg_vals[i] = convert_modes (GET_MODE (loc), TYPE_MODE (TREE_TYPE (arg)), expand_expr (arg, NULL_RTX, mode, ! EXPAND_SUM), TREE_UNSIGNED (TREE_TYPE (formal))); else ! arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM); } else arg_vals[i] = 0; --- 1504,1513 ---- arg_vals[i] = convert_modes (GET_MODE (loc), TYPE_MODE (TREE_TYPE (arg)), expand_expr (arg, NULL_RTX, mode, ! flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM), TREE_UNSIGNED (TREE_TYPE (formal))); else ! arg_vals[i] = expand_expr (arg, NULL_RTX, mode, flag_propolice_protection?EXPAND_NORMAL:EXPAND_SUM); } else arg_vals[i] = 0; Index: contrib/gcc/libgcc2.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/libgcc2.c,v retrieving revision 1.4 diff -c -r1.4 libgcc2.c *** contrib/gcc/libgcc2.c 1999/10/27 09:45:47 1.4 --- contrib/gcc/libgcc2.c 2001/05/18 23:54:54 *************** *** 4014,4016 **** --- 4014,4086 ---- __terminate (); } #endif + + #ifdef L_stack_smash_handler + #include + #include + #include + + #if defined(HAVE_SYSLOG) + #include + #include + #include + + #include + #ifndef _PATH_LOG + #define _PATH_LOG "/dev/log" + #endif + #endif + + char __guard[32] = {0,0,0,0,0,0,0,0}; + static void __guard_setup (void) __attribute__ ((constructor)) ; + static void __guard_setup (void) + { + int fd; + if (((int*)__guard)[0]!=0) return; + fd = open ("/dev/urandom", 0); + if (fd != -1) { + ssize_t size = read (fd, &__guard, sizeof(__guard)); + close (fd) ; + if (size == sizeof(__guard)) return; + } + /* If a random generator can't be used, the protector switches the guard + to the "terminator canary" */ + __guard[0] = 0; __guard[1] = 0; __guard[2] = '\n'; __guard[3] = 255; + } + void __stack_smash_handler (char func[], int damaged) + { + #if defined (__GNU_LIBRARY__) + extern char * __progname; + #endif + char message[] = ": stack smashing attack in function "; + int bufsz = 256, len; + char buf[bufsz]; + #if defined(HAVE_SYSLOG) + int LogFile; + struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ + #endif + + strcpy(buf, "<2>"); len=3; /* send LOG_CRIT */ + #if defined (__GNU_LIBRARY__) + strncat(buf, __progname, bufsz-len); len = strlen(buf); + #endif + if (bufsz>len) strncat(buf, message, bufsz-len); len = strlen(buf); + if (bufsz>len) strncat(buf, func, bufsz-len); len = strlen(buf); + + /* print error message */ + write (STDERR_FILENO, buf+3, len-3); + #if defined(HAVE_SYSLOG) + if ((LogFile = socket(AF_UNIX, SOCK_DGRAM, 0)) != -1) { + + /* + * Send "found" message to the "/dev/log" path + */ + SyslogAddr.sun_family = AF_UNIX; + (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, + sizeof SyslogAddr.sun_path); + sendto(LogFile, buf, strlen(buf), 0, (struct sockaddr *)&SyslogAddr, sizeof(SyslogAddr)); + } + #endif + abort(); + } + #endif Index: contrib/gcc/reload1.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/reload1.c,v retrieving revision 1.1.1.4.2.1 diff -c -r1.1.1.4.2.1 reload1.c *** contrib/gcc/reload1.c 2001/04/10 19:23:13 1.1.1.4.2.1 --- contrib/gcc/reload1.c 2001/05/18 23:54:58 *************** *** 39,44 **** --- 39,45 ---- #include "output.h" #include "real.h" #include "toplev.h" + #include "protector.h" #if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY #define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY *************** *** 2424,2430 **** if (from_reg == -1) { /* No known place to spill from => no slot to reuse. */ ! x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, inherent_size == total_size ? 0 : -1); if (BYTES_BIG_ENDIAN) /* Cancel the big-endian correction done in assign_stack_local. --- 2425,2431 ---- if (from_reg == -1) { /* No known place to spill from => no slot to reuse. */ ! x = assign_stack_local_for_pseudo_reg (GET_MODE (regno_reg_rtx[i]), total_size, inherent_size == total_size ? 0 : -1); if (BYTES_BIG_ENDIAN) /* Cancel the big-endian correction done in assign_stack_local. Index: contrib/gcc/toplev.c =================================================================== RCS file: /home/ncvs/src/contrib/gcc/toplev.c,v retrieving revision 1.6.2.3 diff -c -r1.6.2.3 toplev.c *** contrib/gcc/toplev.c 2001/04/10 19:23:16 1.6.2.3 --- contrib/gcc/toplev.c 2001/05/18 23:54:59 *************** *** 777,782 **** --- 777,789 ---- int flag_no_ident = 0; + #ifdef STACK_PROTECTOR + /* Nonzero means use ProPolice as a stack protection method */ + int flag_propolice_protection = 1; + #else + int flag_propolice_protection = 0; + #endif + /* Table of supported debugging formats. */ static struct { *************** *** 986,992 **** {"leading-underscore", &flag_leading_underscore, 1, "External symbols have a leading underscore" }, {"ident", &flag_no_ident, 0, ! "Process #ident directives"} }; #define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0])) --- 993,1003 ---- {"leading-underscore", &flag_leading_underscore, 1, "External symbols have a leading underscore" }, {"ident", &flag_no_ident, 0, ! "Process #ident directives"}, ! {"stack-protector", &flag_propolice_protection, 1, ! "Enables stack protection" }, ! {"no-stack-protector", &flag_propolice_protection, 0, ! "Disables stack protection" }, }; #define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0])) *************** *** 3652,3657 **** --- 3663,3670 ---- insns = get_insns (); + if (flag_propolice_protection) prepare_stack_protection (); + /* Dump the rtl code if we are dumping rtl. */ if (rtl_dump) Index: gnu/lib/libgcc/Makefile =================================================================== RCS file: /home/ncvs/src/gnu/lib/libgcc/Makefile,v retrieving revision 1.31.2.1 diff -c -r1.31.2.1 Makefile *** gnu/lib/libgcc/Makefile 2001/01/06 23:16:54 1.31.2.1 --- gnu/lib/libgcc/Makefile 2001/05/18 23:55:23 *************** *** 49,55 **** _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit _ctors \ ! _eh _pure # Library members defined in new1.cc. NEW1FUNCS= _op_new _op_newnt --- 49,55 ---- _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit _ctors \ ! _eh _pure _stack_smash_handler # Library members defined in new1.cc. NEW1FUNCS= _op_new _op_newnt *************** *** 65,70 **** --- 65,71 ---- .if ${OBJFORMAT} != aout CFLAGS+= -D_PTHREADS -fPIC -DGTHREAD_USE_WEAK .endif + CFLAGS+= -DHAVE_SYSLOG CXXFLAGS+= -I${GCCDIR}/cp/inc CXXFLAGS+= -nostdinc++ Index: gnu/usr.bin/cc/cc_int/Makefile =================================================================== RCS file: /home/ncvs/src/gnu/usr.bin/cc/cc_int/Makefile,v retrieving revision 1.25.2.1 diff -c -r1.25.2.1 Makefile *** gnu/usr.bin/cc/cc_int/Makefile 2000/07/04 05:41:39 1.25.2.1 --- gnu/usr.bin/cc/cc_int/Makefile 2001/05/18 23:55:26 *************** *** 22,28 **** toplev.c tree.c unroll.c varasm.c version.c xcoffout.c \ alias.c bitmap.c dwarf2out.c dyn-string.c except.c \ gcse.c genrtl.c profile.c regmove.c varray.c \ ! ${OUT_FILE} .if defined(USE_EGCS_HAIFA) && ${USE_EGCS_HAIFA} == 1 SRCS+= haifa-sched.c .else --- 22,28 ---- toplev.c tree.c unroll.c varasm.c version.c xcoffout.c \ alias.c bitmap.c dwarf2out.c dyn-string.c except.c \ gcse.c genrtl.c profile.c regmove.c varray.c \ ! ${OUT_FILE} protector.c .if defined(USE_EGCS_HAIFA) && ${USE_EGCS_HAIFA} == 1 SRCS+= haifa-sched.c .else Index: libexec/rtld-elf/Makefile =================================================================== RCS file: /home/ncvs/src/libexec/rtld-elf/Makefile,v retrieving revision 1.10.2.3 diff -c -r1.10.2.3 Makefile *** libexec/rtld-elf/Makefile 2000/07/20 11:16:05 1.10.2.3 --- libexec/rtld-elf/Makefile 2001/05/18 23:55:37 *************** *** 30,35 **** --- 30,49 ---- DPADD= ${LIBC} LDADD= -lc .else + + OBJS+= _stack_smash_handler.o + CLEANFILES+= tconfig.h tm.h + _stack_smash_handler.o: ${.CURDIR}/../../contrib/gcc/libgcc2.c + echo '#include "gansidecl.h"' > tconfig.h + echo '#include "${MACHINE_ARCH}/xm-${MACHINE_ARCH}.h"' >> tconfig.h + echo '#include "i386/i386.h"' > tm.h + echo '#include "i386/att.h"' >> tm.h + echo '#include "svr4.h"' >> tm.h + echo '#include ' >> tm.h + echo '#include "i386/freebsd.h"'>> tm.h + echo '#include "i386/perform.h"'>> tm.h + $(CC) $(CFLAGS) -DIN_GCC -DL_stack_smash_handler -I${.CURDIR}/../../contrib/gcc -I${.CURDIR}/../../contrib/gcc/config -I. -fexceptions -c $> -o $@ + CFLAGS+= -fpic -DPIC LDFLAGS+= -shared -Wl,-Bsymbolic DPADD= ${LIBC_PIC} Index: sys/boot/i386/loader/Makefile =================================================================== RCS file: /home/ncvs/src/sys/boot/i386/loader/Makefile,v retrieving revision 1.41.2.6 diff -c -r1.41.2.6 Makefile *** sys/boot/i386/loader/Makefile 2000/12/19 01:18:34 1.41.2.6 --- sys/boot/i386/loader/Makefile 2001/05/18 23:55:47 *************** *** 125,131 **** ${BASE}.sym: ${OBJS} ${LIBI386} ${LIBSTAND} ${LIBFICL} vers.o ${CC} ${LDFLAGS} -o ${.TARGET} ${BTXCRT} ${OBJS} vers.o \ ! ${LIBFICL} ${LIBI386} ${LIBSTAND} # If it's not there, don't consider it a target .if exists(${.CURDIR}/../../../i386/include) --- 125,131 ---- ${BASE}.sym: ${OBJS} ${LIBI386} ${LIBSTAND} ${LIBFICL} vers.o ${CC} ${LDFLAGS} -o ${.TARGET} ${BTXCRT} ${OBJS} vers.o \ ! ${LIBFICL} ${LIBI386} ${LIBSTAND} -lgcc -lc # If it's not there, don't consider it a target .if exists(${.CURDIR}/../../../i386/include) Index: sys/conf/files =================================================================== RCS file: /home/ncvs/src/sys/conf/files,v retrieving revision 1.340.2.51 diff -c -r1.340.2.51 files *** sys/conf/files 2001/03/05 05:33:20 1.340.2.51 --- sys/conf/files 2001/05/18 23:55:52 *************** *** 1223,1225 **** --- 1223,1226 ---- libkern/strtoq.c standard libkern/strtoul.c standard libkern/strtouq.c standard + libkern/stack_smash_handler.c standard *** /dev/null Sat May 19 03:36:36 2001 --- contrib/gcc/protector.h Tue May 15 18:39:54 2001 *************** *** 0 **** --- 1,46 ---- + /* Top level of GNU C compiler + Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc. + + This file is part of GNU CC. + + GNU CC 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 2, or (at your option) + any later version. + + GNU CC 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 GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + + /* declaration of GUARD variable */ + #define GUARD_m SImode + #define UNITS_PER_GUARD GET_MODE_SIZE (GUARD_m) + + + #ifndef L_stack_smash_handler + + /* insert a guard variable before a character buffer and change the order + of pointer variables, character buffers and pointer arguments */ + + extern void prepare_stack_protection PARAMS ((void)); + + /* allocate a local variable in the stack area before character buffers + to avoid the corruption of it */ + + extern rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int)); + + /* Update the debug information of the function argument pointed by 'old' */ + extern void set_debuginfo_of_escaped_arg PARAMS ((rtx new, rtx old)); + + + /* Nonzero means use propolice as a stack protection method */ + extern int flag_propolice_protection; + + #endif *** /dev/null Sat May 19 03:36:36 2001 --- contrib/gcc/protector.c Tue May 15 18:39:54 2001 *************** *** 0 **** --- 1,1877 ---- + /* Top level of GNU C compiler + Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc. + + This file is part of GNU CC. + + GNU CC 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 2, or (at your option) + any later version. + + GNU CC 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 GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + #include "config.h" + #include "system.h" + + #include "rtl.h" + #include "tree.h" + #include "regs.h" + #include "flags.h" + #include "insn-config.h" + #include "insn-flags.h" + #include "expr.h" + #include "output.h" + #include "recog.h" + #include "hard-reg-set.h" + #include "real.h" + #include "except.h" + #include "function.h" + #include "toplev.h" + #include "conditions.h" + #include "insn-attr.h" + #include "c-tree.h" + #include "protector.h" + + + rtx assign_stack_local_for_pseudo_reg PARAMS ((enum machine_mode, HOST_WIDE_INT, int)); + void set_debuginfo_of_escaped_arg PARAMS ((rtx old, rtx new)); + void update_debuginfo_using_escaped_arg_list PARAMS ((tree parms)); + + + /* Round a value to the lowest integer less than it that is a multiple of + the required alignment. Avoid using division in case the value is + negative. Assume the alignment is a power of two. */ + #define FLOOR_ROUND(VALUE,ALIGN) ((VALUE) & ~((ALIGN) - 1)) + + /* Similar, but round to the next highest integer that meets the + alignment. */ + #define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1)) + + + /* Nonzero means use propolice as a stack protection method */ + extern int flag_propolice_protection; + + /* List of trampolines */ + extern tree query_trampoline_list PARAMS ((void)); + + typedef struct { rtx original; rtx escaped; } arg_status; + + /* This file contains several memory arrangement functions to protect + the return address and the frame pointer of the stack + from a stack-smashing attack. It also + provides the function that protects pointer variables. */ + + /* Nonzero if function being compiled can define string buffers that may be + damaged by the stack-smash attack */ + static int current_function_defines_vulnerable_string; + static int current_function_has_variable_string; + + static rtx guard_area, _guard; + static rtx function_first_insn, prologue_insert_point; + + /* */ + static HOST_WIDE_INT sweep_frame_offset; + static arg_status* escaped_arg_list = 0; + static int escaped_arg_list_size = 0; + static int guard_has_legitimate_address; + + static int search_string_from_argsandvars PARAMS ((void)); + static int search_string_from_local_vars PARAMS ((tree block)); + static int search_string_def PARAMS ((tree names)); + static int search_pointer_def PARAMS ((tree names)); + static int search_func_pointer PARAMS ((tree type, int mark)); + static void reset_used_flags_for_insns PARAMS ((rtx insn)); + static void reset_used_flags_for_decls PARAMS ((tree block)); + static void reset_used_flags_of_plus PARAMS ((rtx x)); + static void rtl_prologue PARAMS ((rtx insn)); + static void rtl_epilogue PARAMS ((rtx fnlastinsn)); + static void arrange_var_order PARAMS ((tree blocks)); + static void copy_args_for_protection PARAMS ((void)); + static void sweep_string_variable PARAMS ((rtx sweep_var, int var_size)); + static void sweep_string_in_decls PARAMS ((tree block, int sweep_offset, int size)); + static void sweep_string_in_args PARAMS ((tree parms, int sweep_offset, int size)); + static void sweep_string_use_of_insns PARAMS ((rtx insn, int sweep_offset, int size)); + static void sweep_string_in_operand PARAMS ((rtx orig, int sweep_offset, int size)); + static void move_arg_location PARAMS ((rtx insn, rtx orig, rtx new, int var_size)); + static void change_arg_use_of_insns PARAMS ((rtx insn, rtx orig, rtx new, int size)); + static void change_arg_use_in_operand PARAMS ((rtx x, rtx orig, rtx new, int size)); + static void expand_value_return PARAMS ((rtx val)); + static int replace_return_reg PARAMS ((rtx insn, rtx return_save)); + + + #define SUSPICIOUS_BUF_SIZE 8 + + #define DEBUGGER_AUTO_BASEPTR(X) \ + (GET_CODE (X) == PLUS ? XEXP (X, 0) : X) + #define DEBUGGER_AUTO_OFFSET(X) \ + (GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) + #define PARM_PASSED_IN_MEMORY(PARM) \ + (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM) + + + + void + prepare_stack_protection (void) + { + tree blocks = DECL_INITIAL (current_function_decl); + current_function_has_variable_string = FALSE; + + /* + skip the protection if the function has no block or it is an inline function + */ + if (! blocks || DECL_INLINE (current_function_decl)) return; + + current_function_defines_vulnerable_string = search_string_from_argsandvars (); + + if (current_function_defines_vulnerable_string) + { + HOST_WIDE_INT previous_frame_offset, offset; + function_first_insn = get_insns (); + + if (query_trampoline_list ()) return; + + sweep_frame_offset = 0; + + #ifdef STACK_GROWS_DOWNWARD + /* + frame_offset: offset to end of allocated area of stack frame. + It is defined in the function.c + */ + previous_frame_offset = frame_offset; + + /* the location must be before buffers */ + guard_area = assign_stack_local (GUARD_m, UNITS_PER_GUARD, 0); + MEM_VOLATILE_P (guard_area) = 1; + + /* check if the address of the guard has legitimate address */ + guard_has_legitimate_address = 1; + GO_IF_LEGITIMATE_ADDRESS(GUARD_m, guard_area, has_legitimate_address); + guard_has_legitimate_address = 0; + has_legitimate_address: + + #ifndef FRAME_GROWS_DOWNWARD + sweep_frame_offset = frame_offset; + #endif + + /* For making room for guard value, scan all insns and fix the offset address + of the variable that is based on frame pointer. + Scan all declarations of variables and fix the offset address of the variable that + is based on the frame pointer */ + sweep_string_variable (guard_area, UNITS_PER_GUARD); + + + /* the location of guard area moves to the beginning of stack frame */ + offset = DEBUGGER_AUTO_OFFSET(XEXP (guard_area, 0)); + XEXP (XEXP (guard_area, 0), 1) = gen_rtx_CONST_INT (VOIDmode, sweep_frame_offset); + + + /* Insert prologue rtl instructions */ + rtl_prologue (function_first_insn); + + if (! current_function_has_variable_string) + { + /* Generate argument saving instruction */ + copy_args_for_protection (); + + #ifndef FRAME_GROWS_DOWNWARD + /* If frame grows upward, character string copied from an arg stays top of + the guard variable. So sweep the guard variable again */ + sweep_frame_offset = frame_offset; + sweep_string_variable (guard_area, UNITS_PER_GUARD); + #endif + } + #endif + + if (! current_function_has_variable_string + && guard_has_legitimate_address) + { + /* Arrange the order of local variables */ + arrange_var_order (blocks); + } + + #ifdef STACK_GROWS_DOWNWARD + /* Insert epilogue rtl instructions */ + rtl_epilogue (get_last_insn ()); + #endif + } + } + + + static int + search_string_from_argsandvars (void) + { + tree blocks, parms; + int string_p; + + /* + search a string variable from local variables + */ + blocks = DECL_INITIAL (current_function_decl); + string_p = search_string_from_local_vars (blocks); + if (string_p) return TRUE; + + + #ifdef FRAME_GROWS_DOWNWARD + /* + search a string variable from arguments + */ + parms = DECL_ARGUMENTS (current_function_decl); + + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) + { + string_p = search_string_def (TREE_TYPE(parms)); + if (string_p) return TRUE; + } + } + #endif + + return FALSE; + } + + + static int + search_string_from_local_vars (block) + tree block; + { + tree types; + int found = FALSE; + + while (block) + { + types = BLOCK_VARS(block); + + while (types) + { + /* skip the declaration that refers an external variable */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types) + && TREE_CODE (types) == VAR_DECL + && DECL_RTL (types) && GET_CODE (DECL_RTL (types)) == MEM) + { + + if (search_string_def (TREE_TYPE (types))) + { + rtx home = DECL_RTL (types); + + if (GET_CODE (home) == MEM + && (GET_CODE (XEXP (home, 0)) == MEM + || (GET_CODE (XEXP (home, 0)) == REG + && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM + #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM + #endif + ))) + /* If the value is indirect by memory or by a register + that isn't the frame pointer + then it means the object is variable-sized and address through + that register or stack slot. The protection has no way to hide pointer variables + behind the array, so all we can do is staying the order of variables and arguments. */ + { + current_function_has_variable_string = TRUE; + } + + found = TRUE; + } + } + + types = TREE_CHAIN(types); + } + + if (search_string_from_local_vars (BLOCK_SUBBLOCKS (block))) + { + found = TRUE; + } + + block = BLOCK_CHAIN (block); + } + + return found; + } + + static int + search_string_def (type) + tree type; + { + tree tem; + + /* Mark it as defined, so that if it is self-referent + we will not get into an infinite recursion of definitions. */ + + switch (TREE_CODE (type)) + { + case ARRAY_TYPE: + if (TREE_TYPE (type) == char_type_node + || (TREE_TYPE (type) + && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE + && TYPE_PRECISION (TREE_TYPE (type)) == 8)) + { + /* Check if the string is a variable string */ + if (TYPE_DOMAIN (type) == 0 || + TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == NOP_EXPR) + return TRUE; + + /* Check if the string size is greater than SUSPICIOUS_BUF_SIZE */ + if (TREE_INT_CST_LOW(TYPE_MAX_VALUE(TYPE_DOMAIN(type)))+1 >= SUSPICIOUS_BUF_SIZE) + return TRUE; + } + return search_string_def(TREE_TYPE(type)); + + case UNION_TYPE: + case QUAL_UNION_TYPE: + case RECORD_TYPE: + /* Output the name, type, position (in bits), size (in bits) of each + field. */ + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + /* Omit here local type decls until we know how to support them. */ + if ((TREE_CODE (tem) == TYPE_DECL) + || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem))) + continue; + + if (search_string_def(TREE_TYPE(tem))) return TRUE; + } + break; + + case POINTER_TYPE: + case REFERENCE_TYPE: + /* I'm not sure whether OFFSET_TYPE needs this treatment, + so I'll play safe and return 1. */ + case OFFSET_TYPE: + default: + break; + } + + return FALSE; + } + + + static int + search_pointer_def (type) + tree type; + { + tree tem; + + /* Mark it as defined, so that if it is self-referent + we will not get into an infinite recursion of definitions. */ + + switch (TREE_CODE (type)) + { + case UNION_TYPE: + case QUAL_UNION_TYPE: + case RECORD_TYPE: + /* Output the name, type, position (in bits), size (in bits) of each + field. */ + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + /* Omit here local type decls until we know how to support them. */ + if ((TREE_CODE (tem) == TYPE_DECL) + || (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem))) + continue; + + if (search_pointer_def (TREE_TYPE(tem))) return TRUE; + } + break; + + case ARRAY_TYPE: + return search_pointer_def (TREE_TYPE(type)); + + case POINTER_TYPE: + case REFERENCE_TYPE: + /* I'm not sure whether OFFSET_TYPE needs this treatment, + so I'll play safe and return 1. */ + case OFFSET_TYPE: + if (TYPE_READONLY (TREE_TYPE (type))) + { + int funcp = search_func_pointer (TREE_TYPE (type), 1); + /* Un-mark the type as having been visited already */ + search_func_pointer (TREE_TYPE (type), 0); + return funcp; + } + return TRUE; + + default: + break; + } + + return FALSE; + } + + + static int + search_func_pointer (type, mark) + tree type; + int mark; + { + tree tem; + + /* Mark it as defined, so that if it is self-referent + we will not get into an infinite recursion of definitions. */ + + switch (TREE_CODE (type)) + { + case UNION_TYPE: + case QUAL_UNION_TYPE: + case RECORD_TYPE: + if (TREE_ASM_WRITTEN (type) != mark) + { + /* mark the type as having been visited already */ + TREE_ASM_WRITTEN (type) = mark; + + /* Output the name, type, position (in bits), size (in bits) of + each field. */ + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + /* Omit here local type decls until we know how to support them. */ + if (TREE_CODE (tem) == FIELD_DECL + && search_func_pointer (TREE_TYPE(tem), mark)) return TRUE; + } + } + break; + + case ARRAY_TYPE: + return search_func_pointer (TREE_TYPE(type), mark); + + case POINTER_TYPE: + case REFERENCE_TYPE: + /* I'm not sure whether OFFSET_TYPE needs this treatment, + so I'll play safe and return 1. */ + case OFFSET_TYPE: + return TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE; + + default: + break; + } + + return FALSE; + } + + + static void + reset_used_flags_for_insns (insn) + rtx insn; + { + register int i, j; + register enum rtx_code code; + register const char *format_ptr; + + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + code = GET_CODE (insn); + insn->used = 0; + format_ptr = GET_RTX_FORMAT (code); + + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*format_ptr++) { + case 'e': + reset_used_flags_of_plus (XEXP (insn, i)); + break; + + case 'E': + for (j = 0; j < XVECLEN (insn, i); j++) + reset_used_flags_of_plus (XVECEXP (insn, i, j)); + break; + } + } + } + } + + static void + reset_used_flags_for_decls (block) + tree block; + { + tree types; + rtx home; + + while (block) + { + types = BLOCK_VARS(block); + + while (types) + { + /* skip the declaration that refers an external variable and + also skip an global variable */ + if (! DECL_EXTERNAL (types)) + { + home = DECL_RTL (types); + if (home == 0) goto next; + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == PLUS + && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) + { + XEXP (home, 0)->used = 0; + } + } + next: + types = TREE_CHAIN(types); + } + + reset_used_flags_for_decls (BLOCK_SUBBLOCKS (block)); + + block = BLOCK_CHAIN (block); + } + } + + /* Clear the USED bits only of type PLUS in X */ + + static void + reset_used_flags_of_plus (x) + rtx x; + { + register int i, j; + register enum rtx_code code; + register const char *format_ptr; + + if (x == 0) + return; + + code = GET_CODE (x); + + /* These types may be freely shared so we needn't do any resetting + for them. */ + + switch (code) + { + case REG: + case QUEUED: + case CONST_INT: + case CONST_DOUBLE: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + return; + + case INSN: + case JUMP_INSN: + case CALL_INSN: + case NOTE: + case LABEL_REF: + case BARRIER: + /* The chain of insns is not being copied. */ + return; + + case PLUS: + x->used = 0; + break; + + case CALL_PLACEHOLDER: + reset_used_flags_for_insns (XEXP (x, 0)); + reset_used_flags_for_insns (XEXP (x, 1)); + reset_used_flags_for_insns (XEXP (x, 2)); + break; + + default: + break; + } + + format_ptr = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++) + { + switch (*format_ptr++) + { + case 'e': + reset_used_flags_of_plus (XEXP (x, i)); + break; + + case 'E': + for (j = 0; j < XVECLEN (x, i); j++) + reset_used_flags_of_plus (XVECEXP (x, i, j)); + break; + } + } + } + + + static void + rtl_prologue (insn) + rtx insn; + { + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) + { + rtx _val; + + prologue_insert_point = NEXT_INSN (insn); /* mark the next insn of FUNCTION_BEG insn */ + + start_sequence (); + + _guard = gen_rtx_MEM (GUARD_m, gen_rtx_SYMBOL_REF (Pmode, "__guard")); + emit_move_insn ( guard_area, _guard); + + _val = gen_sequence (); + end_sequence (); + + emit_insn_before (_val, prologue_insert_point); + break; + } + } + + static void + rtl_epilogue (insn) + rtx insn; + { + /* Like STACK_BOUNDARY but in units of bytes, not bits. */ + #define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT) + + rtx if_false_label; + rtx _val, handler, funcname, addr; + tree funcstr; + HOST_WIDE_INT args_size; + enum machine_mode arg1mode; + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)), return_save; + + handler = gen_rtx_MEM (FUNCTION_MODE, gen_rtx (SYMBOL_REF, Pmode, "__stack_smash_handler")); + + start_sequence (); + + if (return_reg + && ! (current_function_returns_struct + || current_function_returns_pcc_struct)) + { + return_save = gen_reg_rtx (GET_MODE (return_reg)); + + if (! replace_return_reg (prologue_insert_point, return_save)) + emit_move_insn (return_save, return_reg); + } + + compare_from_rtx (guard_area, _guard, NE, 0, GUARD_m, 0, 0); /* if (guard_area != _guard) */ + + if_false_label = gen_label_rtx (); /* { */ + emit_jump_insn ( gen_beq(if_false_label)); + + /* + In the function force_const_mem in varasm.c of egcs-1.1.2-30, there is a + failure to assign the guard_area variable to eax register, which destroys + the return value of the function. + + The BUG preceding comment is an apropriate processes. + When the bug is fixed, removes the comment + */ + + /* generate string for the current function name */ + funcstr = build_string (strlen(current_function_name)+1, current_function_name); + TREE_TYPE (funcstr) = build_array_type (char_type_node, 0);/* = char_array_type_node;*/ + funcname = output_constant_def (funcstr); + + addr = gen_push_operand (); + emit_move_insn (gen_rtx_MEM (GUARD_m, addr), guard_area); /* push the value of guard area */ + + arg1mode = GET_MODE (XEXP (funcname, 0)); + addr = gen_push_operand (); + emit_move_insn (gen_rtx_MEM (arg1mode, addr), XEXP (funcname, 0)); /* push current_function_name */ + + /* calculate the stack size of two arguments */ + args_size = GET_MODE_SIZE (arg1mode) + GET_MODE_SIZE (GUARD_m); + #ifdef PUSH_ROUNDING + args_size = PUSH_ROUNDING (GET_MODE_SIZE (arg1mode)) + PUSH_ROUNDING (GET_MODE_SIZE (GUARD_m)); + #endif + #ifdef STACK_BOUNDARY + args_size = (((args_size + (STACK_BYTES - 1)) / STACK_BYTES) * STACK_BYTES); + #endif + + /* jump to the stack smash handler */ + emit_call_insn (gen_call (handler, GEN_INT (args_size), const0_rtx)); + + /* generate RTL to return from the current function */ + + emit_barrier (); /* } */ + emit_label (if_false_label); + + /* generate RTL to return from the current function */ + if (return_reg) + { + if (!current_function_returns_struct && !current_function_returns_pcc_struct) + expand_value_return (return_save); + + + /* If returning a structure, arrange to return the address of the value + in a place where debuggers expect to find it. + + If returning a structure PCC style, + the caller also depends on this value. + And current_function_returns_pcc_struct is not necessarily set. */ + else + { + rtx value_address = XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0); + tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); + #ifdef FUNCTION_OUTGOING_VALUE + rtx outgoing + = FUNCTION_OUTGOING_VALUE (build_pointer_type (type), + current_function_decl); + #else + rtx outgoing + = FUNCTION_VALUE (build_pointer_type (type), + current_function_decl); + #endif + + /* Mark this as a function return value so integrate will delete the + assignment and USE below when inlining this function. */ + REG_FUNCTION_VALUE_P (outgoing) = 1; + + emit_move_insn (outgoing, value_address); + use_variable (outgoing); + } + } + + _val = gen_sequence (); + end_sequence (); + + emit_insn_after (_val, insn); + } + + + static void + arrange_var_order (block) + tree block; + { + tree types; + int offset; + + while (block) + { + types = BLOCK_VARS (block); + + while (types) + { + /* skip the declaration that refers an external variable */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types) + && TREE_CODE (types) == VAR_DECL + && GET_CODE (DECL_RTL (types)) == MEM) + { + if (search_string_def (TREE_TYPE (types))) + { + /* found a string variable */ + int var_size = + ((TREE_INT_CST_LOW (DECL_SIZE (types)) + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + + if (GET_MODE (DECL_RTL (types)) == BLKmode) + { + int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; + var_size = CEIL_ROUND (var_size, alignment); + } + + /* skip the variable if it is top of the region + specified by sweep_frame_offset */ + offset = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (types), 0)); + if (offset >= sweep_frame_offset - var_size) + sweep_frame_offset -= var_size; + + else + sweep_string_variable (DECL_RTL (types), var_size); + } + } + + types = TREE_CHAIN(types); + } + + arrange_var_order (BLOCK_SUBBLOCKS (block)); + + block = BLOCK_CHAIN (block); + } + } + + + static void + copy_args_for_protection (void) + { + tree parms = DECL_ARGUMENTS (current_function_decl); + rtx temp_rtx; + int idx; + + escaped_arg_list_size = 0; + + /* count the number of argument passed in memory */ + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms)) + escaped_arg_list_size ++; + } + + if (escaped_arg_list) free (escaped_arg_list); + escaped_arg_list = xmalloc (sizeof (arg_status) * escaped_arg_list_size); + + parms = DECL_ARGUMENTS (current_function_decl); + for (idx = 0; parms; parms = TREE_CHAIN (parms), idx++) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) + { + int string_p; + + /* + skip arguemnt protection if the last argument is used + for the variable argument + */ + /* + tree fntype; + if (TREE_CHAIN (parms) == 0) + { + fntype = TREE_TYPE (current_function_decl); + + if ((TYPE_ARG_TYPES (fntype) != 0 && + TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node) + || current_function_varargs) + continue; + } + */ + + escaped_arg_list[idx].original = 0; + escaped_arg_list[idx].escaped = 0; + + string_p = search_string_def (TREE_TYPE(parms)); + + /* check if it is a candidate to move */ + if (string_p || search_pointer_def (TREE_TYPE (parms))) + { + int arg_size + = ((TREE_INT_CST_LOW (DECL_SIZE (parms)) + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + + start_sequence (); + + if (GET_CODE (DECL_RTL (parms)) == REG) + { + rtx movinsn; + rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms))); + + /* generate codes for copying the content */ + movinsn = emit_move_insn (safe, DECL_RTL (parms)); + PATTERN (movinsn)->volatil = 1; /* avoid register elimination in gcse.c (COPY-PROP)*/ + + change_arg_use_of_insns (prologue_insert_point, DECL_RTL (parms), safe, 0); + + /* save debugger info */ + escaped_arg_list[idx].original = DECL_RTL (parms); + escaped_arg_list[idx].escaped = safe; + } + + else if (GET_CODE (DECL_RTL (parms)) == MEM + && GET_CODE (XEXP (DECL_RTL (parms), 0)) == ADDRESSOF) + { + rtx movinsn; + rtx safe = gen_reg_rtx (GET_MODE (DECL_RTL (parms))); + + /* generate codes for copying the content */ + movinsn = emit_move_insn (safe, DECL_INCOMING_RTL (parms)); + PATTERN (movinsn)->volatil = 1; /* avoid register elimination in gcse.c (COPY-PROP)*/ + + /* change the addressof information to the newly allocated pseudo register */ + emit_move_insn (DECL_RTL (parms), safe); + + /* save debugger info */ + escaped_arg_list[idx].original = DECL_RTL (parms); + escaped_arg_list[idx].escaped = safe; + } + + else + { + /* declare temporary local variable DECL_NAME (parms) for it */ + temp_rtx + = assign_stack_local (DECL_MODE (parms), arg_size, + DECL_MODE (parms) == BLKmode ? -1 : 0); + + MEM_IN_STRUCT_P (temp_rtx) = AGGREGATE_TYPE_P (TREE_TYPE (parms)); + MEM_ALIAS_SET (temp_rtx) = get_alias_set (parms); + + /* generate codes for copying the content */ + store_expr (parms, temp_rtx, 0); + + /* change the reference for each instructions */ + move_arg_location (prologue_insert_point, DECL_RTL (parms), + temp_rtx, arg_size); + + /* change the location of parms variable */ + DECL_RTL (parms) = temp_rtx; + + /* change debugger info */ + DECL_INCOMING_RTL (parms) = temp_rtx; + } + + emit_insn_before (gen_sequence (), prologue_insert_point); + end_sequence (); + + #ifndef FRAME_GROWS_DOWNWARD + /* process the string argument */ + if (string_p) + { + if (DECL_MODE (parms) == BLKmode) + { + int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; + arg_size = CEIL_ROUND (arg_size, alignment); + } + + /* change the reference for each instructions */ + sweep_string_variable (DECL_RTL (parms), arg_size); + } + #endif + } + } + } + } + + + /* + sweep a string variable to the local variable addressed by sweep_frame_offset, that is + a last position of string variables. + */ + static void + sweep_string_variable (sweep_var, var_size) + int var_size; + rtx sweep_var; + { + int sweep_offset = DEBUGGER_AUTO_OFFSET(XEXP (sweep_var, 0)); + + /* scan all declarations of variables and fix the offset address of + the variable based on the frame pointer */ + sweep_string_in_decls (DECL_INITIAL (current_function_decl), sweep_offset, var_size); + + /* scan all argument variable and fix the offset address based on the frame pointer */ + sweep_string_in_args (DECL_ARGUMENTS (current_function_decl), sweep_offset, var_size); + + /* For making room for sweep variable, scan all insns and fix the offset address + of the variable that is based on frame pointer*/ + sweep_string_use_of_insns (function_first_insn, sweep_offset, var_size); + + + /* Clear all the USED bits in operands of all insns and declarations of local vars */ + reset_used_flags_for_decls (DECL_INITIAL (current_function_decl)); + reset_used_flags_for_insns (function_first_insn); + + sweep_frame_offset -= var_size; + } + + + + /* + move an argument to the local variable addressed by frame_offset + */ + static void + move_arg_location (insn, orig, new, var_size) + rtx insn, orig, new; + int var_size; + { + /* For making room for sweep variable, scan all insns and fix the offset address + of the variable that is based on frame pointer*/ + change_arg_use_of_insns (insn, orig, new, var_size); + + + /* Clear all the USED bits in operands of all insns and declarations of local vars */ + reset_used_flags_for_insns (insn); + } + + + static void + sweep_string_in_decls (block, sweep_offset, sweep_size) + tree block; + int sweep_offset, sweep_size; + { + tree types; + HOST_WIDE_INT offset; + rtx home; + + while (block) + { + types = BLOCK_VARS(block); + + while (types) + { + /* skip the declaration that refers an external variable and + also skip an global variable */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) { + + home = DECL_RTL (types); + if (home == 0) goto next; + + /* process for static local variable */ + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + goto next; + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == REG) + { + goto next; + } + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == MEM) + { + /* process for dynamically allocated aray */ + home = XEXP (home, 0); + } + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == PLUS + && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) + { + if (! XEXP (home, 0)->used) + { + offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0)); + + /* the operand related to the sweep variable */ + if (sweep_offset <= offset + && offset < sweep_offset + sweep_size) + { + + offset += sweep_frame_offset - sweep_size - sweep_offset; + XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); + + /* mark */ + XEXP (home, 0)->used = 1; + } + else if (sweep_offset <= offset + && offset < sweep_frame_offset) + { /* the rest of variables under sweep_frame_offset, + so shift the location */ + + XEXP (XEXP (home, 0), 1) + = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); + + /* mark */ + XEXP (home, 0)->used = 1; + } + } + } + + } + next: + types = TREE_CHAIN(types); + } + + sweep_string_in_decls (BLOCK_SUBBLOCKS (block), sweep_offset, sweep_size); + block = BLOCK_CHAIN (block); + } + } + + + static void + sweep_string_in_args (parms, sweep_offset, sweep_size) + tree parms; + int sweep_offset, sweep_size; + { + rtx home; + HOST_WIDE_INT offset; + + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) + { + home = DECL_INCOMING_RTL (parms); + + if (XEXP (home, 0)->used) continue; + + offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0)); + + /* the operand related to the sweep variable */ + if (DEBUGGER_AUTO_BASEPTR (XEXP (home, 0)) == virtual_stack_vars_rtx) + { + if (sweep_offset <= offset + && offset < sweep_offset + sweep_size) + { + offset += sweep_frame_offset - sweep_size - sweep_offset; + XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); + + /* mark */ + XEXP (home, 0)->used = 1; + } + else if (sweep_offset <= offset + && offset < sweep_frame_offset) + { /* the rest of variables under sweep_frame_offset, so shift the location */ + XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); + + /* mark */ + XEXP (home, 0)->used = 1; + } + } + } + } + } + + + static void + sweep_string_use_of_insns (insn, sweep_offset, sweep_size) + rtx insn; + int sweep_offset, sweep_size; + { + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + sweep_string_in_operand (PATTERN (insn), sweep_offset, sweep_size); + } + } + + + static void + sweep_string_in_operand (orig, sweep_offset, sweep_size) + rtx orig; + int sweep_offset, sweep_size; + { + register rtx x = orig; + register enum rtx_code code; + int offset, i, j; + const char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case ASM_INPUT: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case RETURN: + case REG: + case ADDRESSOF: + return; + + case SET: + break; + + case PLUS: + /* Handle special case of frame register plus constant. */ + if (CONSTANT_P (XEXP (x, 1)) + && XEXP (x, 0) == virtual_stack_vars_rtx + && ! x->used) + { + offset = DEBUGGER_AUTO_OFFSET(x); + + /* the operand related to the sweep variable */ + if (sweep_offset <= offset + && offset < sweep_offset + sweep_size) + { + offset += sweep_frame_offset - sweep_size - sweep_offset; + + XEXP (x, 0) = virtual_stack_vars_rtx; + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); + x->used = 1; + + return; + } + else if (sweep_offset <= offset + && offset < sweep_frame_offset) + { /* the rest of variables under sweep_frame_offset, so shift the location */ + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset - sweep_size); + x->used = 1; + + return; + } + + /* + process further subtree: + Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) + (const_int 5)) + */ + } + break; + + case CALL_PLACEHOLDER: + sweep_string_use_of_insns (XEXP (x, 0), sweep_offset, sweep_size); + sweep_string_use_of_insns (XEXP (x, 1), sweep_offset, sweep_size); + sweep_string_use_of_insns (XEXP (x, 2), sweep_offset, sweep_size); + break; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + sweep_string_in_operand (XEXP (x, i), sweep_offset, sweep_size); + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + sweep_string_in_operand (XVECEXP (x, i, j), sweep_offset, sweep_size); + } + + + /* + change a argument variable to the local variable addressed by the "new" variable. + */ + static void + change_arg_use_of_insns (insn, orig, new, size) + rtx insn, orig, new; + int size; + { + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + change_arg_use_in_operand (PATTERN (insn), orig, new, size); + } + } + + + static void + change_arg_use_in_operand (x, orig, new, size) + rtx x, orig, new; + int size; + { + register enum rtx_code code; + int offset, i, j; + const char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case ASM_INPUT: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case RETURN: + case REG: + case ADDRESSOF: + return; + + case PLUS: + /* Handle special case of frame register plus constant. */ + if (GET_CODE (orig) == MEM /* skip if orig is register variable in the optimization */ + && XEXP (x, 0) == virtual_incoming_args_rtx && CONSTANT_P (XEXP (x, 1)) + && ! x->used) + { + offset = DEBUGGER_AUTO_OFFSET(x); + + /* the operand related to the sweep variable */ + if (DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)) <= offset && + offset < DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)) + size) { + + offset += frame_offset - DEBUGGER_AUTO_OFFSET(XEXP (orig, 0)); + + XEXP (x, 0) = virtual_stack_vars_rtx; + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); + x->used = 1; + + return; + } + + /* + process further subtree: + Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) + (const_int 5)) + */ + } + break; + + case CALL_PLACEHOLDER: + change_arg_use_of_insns (XEXP (x, 0), orig, new, size); + change_arg_use_of_insns (XEXP (x, 1), orig, new, size); + change_arg_use_of_insns (XEXP (x, 2), orig, new, size); + break; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + if (XEXP (x, i) == orig) + { + XEXP (x, i) = new; + continue; + } + change_arg_use_in_operand (XEXP (x, i), orig, new, size); + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + { + + if (XVECEXP (x, i, j) == orig) + { + XVECEXP (x, i, j) = new; + continue; + } + change_arg_use_in_operand (XVECEXP (x, i, j), orig, new, size); + } + } + + static int + replace_return_reg (first, return_save) + rtx first, return_save; + { + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); + rtx insn; + + /* comfirm that insn patterns are the expected order */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + + rtx prev; + + if (PREV_INSN (insn)) prev = PREV_INSN (insn); + + if (GET_CODE (PATTERN (insn)) == USE && XEXP (PATTERN (insn), 0) == return_reg) + if (!(prev && GET_CODE (PATTERN (prev)) == SET && XEXP (PATTERN (prev), 0) == return_reg)) + return FALSE; + } + } + + /* replace return register */ + for (insn = first; insn; insn = NEXT_INSN (insn)) + { + if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + { + rtx prev; + + if (PREV_INSN (insn)) prev = PREV_INSN (insn); + if (GET_CODE (PATTERN (insn)) == USE + && XEXP (PATTERN (insn), 0) == return_reg + && prev + && GET_CODE (PATTERN (prev)) == SET + && XEXP (PATTERN (prev), 0) == return_reg) + { + XEXP (PATTERN (prev), 0) = return_save; + + /* change use insn to NOTE_INSN_DELETED */ + PUT_CODE (insn, NOTE); + NOTE_SOURCE_FILE (insn) = 0; + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + } + } + } + + return TRUE; + } + + + /* + Generate RTL to return from the current function, with value VAL. + It is copied and modified based on expand_value_return function of stmt.c + */ + + static void + expand_value_return (val) + rtx val; + { + rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl)); + + /* Copy the value to the return location + unless it's already there. */ + + if (return_reg != val) + { + #ifdef PROMOTE_FUNCTION_RETURN + tree type = TREE_TYPE (DECL_RESULT (current_function_decl)); + int unsignedp = TREE_UNSIGNED (type); + enum machine_mode mode + = promote_mode (type, DECL_MODE (DECL_RESULT (current_function_decl)), + &unsignedp, 1); + + if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) + convert_move (return_reg, val, unsignedp); + else + #endif + emit_move_insn (return_reg, val); + } + if (GET_CODE (return_reg) == REG + && REGNO (return_reg) < FIRST_PSEUDO_REGISTER) + emit_insn (gen_rtx_USE (VOIDmode, return_reg)); + /* Handle calls that return values in multiple non-contiguous locations. + The Irix 6 ABI has examples of this. */ + else if (GET_CODE (return_reg) == PARALLEL) + { + int i; + + for (i = 0; i < XVECLEN (return_reg, 0); i++) + { + rtx x = XEXP (XVECEXP (return_reg, 0, i), 0); + + if (GET_CODE (x) == REG + && REGNO (x) < FIRST_PSEUDO_REGISTER) + emit_insn (gen_rtx_USE (VOIDmode, x)); + } + } + } + + + + + /* + The following codes are invoked after the instantiation of pseuso registers. + + Reorder local variables to place a peudo register after buffers to avoid + the corruption of local variables that could be used to further corrupt + arbitrary memory locations. + */ + #ifndef FRAME_GROWS_DOWNWARD + static void push_frame PARAMS ((int var_size)); + static void push_frame_in_decls PARAMS ((tree block, int push_size)); + static void push_frame_in_args PARAMS ((tree parms, int push_size)); + static void push_frame_of_insns PARAMS ((rtx insn, int push_size)); + static void push_frame_in_operand PARAMS ((rtx orig, int push_size)); + static void push_frame_of_reg_equiv_memory_loc PARAMS ((int push_size)); + static void push_frame_of_reg_equiv_constant PARAMS ((int push_size)); + static void reset_used_flags_for_push_frame PARAMS ((void)); + #endif + + rtx + assign_stack_local_for_pseudo_reg (mode, size, align) + enum machine_mode mode; + HOST_WIDE_INT size; + int align; + { + #ifdef FRAME_GROWS_DOWNWARD + return assign_stack_local (mode, size, align); + #else + tree blocks = DECL_INITIAL (current_function_decl); + rtx new; + HOST_WIDE_INT previous_frame_offset, offset; + + previous_frame_offset = frame_offset; + new = assign_stack_local (mode, size, align); + if (! flag_propolice_protection + || size == 0 + || ! blocks || TREE_CODE (blocks) != BLOCK + || DECL_INLINE (current_function_decl) + || ! search_string_from_argsandvars () + || query_trampoline_list()) + return new; + + push_frame (frame_offset - previous_frame_offset); + + /* If we have already instantiated virtual registers, return the actual + address relative to the frame pointer. */ + /*if (virtuals_instantiated) {*/ + offset = DEBUGGER_AUTO_OFFSET(XEXP (new, 0)); + + offset -= previous_frame_offset; + XEXP (XEXP (new, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); + /*}*/ + + return new; + #endif + } + + + #ifndef FRAME_GROWS_DOWNWARD + /* + push frame infomation for instantiating pseudo register at the top of stack. + This is only for the "frame grows upward", it means FRAME_GROWS_DOWNWARD is + not defined. + + It is called by purge_addressof function and global_alloc (or reload) + function. + */ + static void + push_frame (var_size) + int var_size; + { + reset_used_flags_for_push_frame(); + + /* scan all declarations of variables and fix the offset address of the variable based on the frame pointer */ + push_frame_in_decls (DECL_INITIAL (current_function_decl), var_size); + + /* scan all argument variable and fix the offset address based on the frame pointer */ + push_frame_in_args (DECL_ARGUMENTS (current_function_decl), var_size); + + /* scan all operands of all insns and fix the offset address based on the frame pointer */ + push_frame_of_insns (get_insns (), var_size); + + /* scan all reg_equiv_memory_loc and reg_equiv_constant*/ + push_frame_of_reg_equiv_memory_loc (var_size); + push_frame_of_reg_equiv_constant (var_size); + + reset_used_flags_for_push_frame(); + } + + static void + reset_used_flags_for_push_frame() + { + int i; + extern rtx *reg_equiv_memory_loc; + extern rtx *reg_equiv_constant; + + /* Clear all the USED bits in operands of all insns and declarations of local vars */ + reset_used_flags_for_decls (DECL_INITIAL (current_function_decl)); + reset_used_flags_for_insns (get_insns ()); + + + /* The following codes are processed if the push_frame is called from + global_alloc (or reload) function */ + if (reg_equiv_memory_loc == 0) return; + + for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) + if (reg_equiv_memory_loc[i]) + { + rtx x = reg_equiv_memory_loc[i]; + + if (GET_CODE (x) == MEM + && GET_CODE (XEXP (x, 0)) == PLUS + && DEBUGGER_AUTO_BASEPTR (XEXP (x, 0)) == frame_pointer_rtx) + { + /* reset */ + XEXP (x, 0)->used = 0; + } + } + + + if (reg_equiv_constant == 0) return; + + for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) + if (reg_equiv_constant[i]) + { + rtx x = reg_equiv_constant[i]; + + if (GET_CODE (x) == PLUS + && DEBUGGER_AUTO_BASEPTR (x) == frame_pointer_rtx) + { + /* reset */ + x->used = 0; + } + } + } + + static void + push_frame_in_decls (block, push_size) + tree block; + int push_size; + { + tree types; + HOST_WIDE_INT offset; + rtx home; + + while (block) + { + types = BLOCK_VARS(block); + + while (types) + { + /* skip the declaration that refers an external variable and + also skip an global variable */ + if (! DECL_EXTERNAL (types) && ! TREE_STATIC (types)) + { + + home = DECL_RTL (types); + if (home == 0) goto next; + + /* process for static local variable */ + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + goto next; + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == REG) + { + goto next; + } + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == MEM) + { + + /* process for dynamically allocated aray */ + home = XEXP (home, 0); + } + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == PLUS + && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) + { + if (! XEXP (home, 0)->used) + { + offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0)); + + offset += push_size; + XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); + + /* mark */ + XEXP (home, 0)->used = 1; + } + } + + } + next: + types = TREE_CHAIN(types); + } + + push_frame_in_decls (BLOCK_SUBBLOCKS (block), push_size); + block = BLOCK_CHAIN (block); + } + } + + + static void + push_frame_in_args (parms, push_size) + tree parms; + int push_size; + { + rtx home; + HOST_WIDE_INT offset; + + for (; parms; parms = TREE_CHAIN (parms)) + if (DECL_NAME (parms) && TREE_TYPE (parms) != error_mark_node) + { + if (PARM_PASSED_IN_MEMORY (parms) && DECL_NAME (parms)) + { + home = DECL_INCOMING_RTL (parms); + + if (XEXP (home, 0)->used) continue; + + offset = DEBUGGER_AUTO_OFFSET(XEXP (home, 0)); + + /* the operand related to the sweep variable */ + if (DEBUGGER_AUTO_BASEPTR (XEXP (home, 0)) == frame_pointer_rtx) + { + offset += push_size; + XEXP (XEXP (home, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); + + /* mark */ + XEXP (home, 0)->used = 1; + } + } + } + } + + + static void + push_frame_of_insns (insn, push_size) + rtx insn; + int push_size; + { + for (; insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN + || GET_CODE (insn) == CALL_INSN) + { + push_frame_in_operand (PATTERN (insn), push_size); + + /* push frame in NOTE */ + push_frame_in_operand (REG_NOTES (insn), push_size); + + /* push frame in CALL EXPR_LIST */ + if (GET_CODE (insn) == CALL_INSN) + push_frame_in_operand (CALL_INSN_FUNCTION_USAGE (insn), push_size); + } + } + + + static void + push_frame_in_operand (orig, push_size) + rtx orig; + int push_size; + { + register rtx x = orig; + register enum rtx_code code; + int offset, i, j; + const char *fmt; + + if (x == 0) + return; + + code = GET_CODE (x); + + switch (code) + { + case CONST_INT: + case CONST_DOUBLE: + case CONST: + case SYMBOL_REF: + case CODE_LABEL: + case PC: + case CC0: + case ASM_INPUT: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case RETURN: + case REG: + case ADDRESSOF: + return; + + case SET: + break; + + case PLUS: + /* Handle special case of frame register plus constant. */ + if (CONSTANT_P (XEXP (x, 1)) + && XEXP (x, 0) == frame_pointer_rtx + && ! x->used) + { + offset = DEBUGGER_AUTO_OFFSET(x); + + offset += push_size; + + /* XEXP (x, 0) is frame_pointer_rtx */ + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); + x->used = 1; + + return; + } + /* + process further subtree: + Example: (plus:SI (mem/s:SI (plus:SI (reg:SI 17) (const_int 8))) + (const_int 5)) + */ + break; + + case CALL_PLACEHOLDER: + push_frame_of_insns (XEXP (x, 0), push_size); + push_frame_of_insns (XEXP (x, 1), push_size); + push_frame_of_insns (XEXP (x, 2), push_size); + break; + + default: + break; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + if (*fmt == 'e') + { + push_frame_in_operand (XEXP (x, i), push_size); + } + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + push_frame_in_operand (XVECEXP (x, i, j), push_size); + } + + static void + push_frame_of_reg_equiv_memory_loc (push_size) + int push_size; + { + int i; + extern rtx *reg_equiv_memory_loc; + + /* This function is processed if the push_frame is called from + global_alloc (or reload) function */ + if (reg_equiv_memory_loc == 0) return; + + for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) + if (reg_equiv_memory_loc[i]) + { + rtx x = reg_equiv_memory_loc[i]; + int offset; + + if (GET_CODE (x) == MEM + && GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == frame_pointer_rtx) + { + if (! XEXP (x, 0)->used) + { + offset = DEBUGGER_AUTO_OFFSET(XEXP (x, 0)); + + offset += push_size; + XEXP (XEXP (x, 0), 1) = gen_rtx_CONST_INT (VOIDmode, offset); + + /* mark */ + XEXP (x, 0)->used = 1; + } + } + } + } + + static void + push_frame_of_reg_equiv_constant (push_size) + int push_size; + { + int i; + extern rtx *reg_equiv_constant; + + /* This function is processed if the push_frame is called from + global_alloc (or reload) function */ + if (reg_equiv_constant == 0) return; + + for (i=LAST_VIRTUAL_REGISTER+1; i < max_regno; i++) + if (reg_equiv_constant[i]) + { + rtx x = reg_equiv_constant[i]; + int offset; + + if (GET_CODE (x) == PLUS + && XEXP (x, 0) == frame_pointer_rtx) + { + if (! x->used) + { + offset = DEBUGGER_AUTO_OFFSET(x); + + offset += push_size; + XEXP (x, 1) = gen_rtx_CONST_INT (VOIDmode, offset); + + /* mark */ + x->used = 1; + } + } + } + } + #endif + + + void + set_debuginfo_of_escaped_arg (rtx new, rtx old) + { + int idx; + + if (flag_propolice_protection) + for (idx = 0; idx < escaped_arg_list_size; idx++) + if (escaped_arg_list[idx].original == old) + { + /* change debugger info */ + escaped_arg_list[idx].escaped = new; + } + } + + + void + update_debuginfo_using_escaped_arg_list (tree parms) + { + rtx orig = DECL_RTL (parms); + int idx; + + if (flag_propolice_protection && PARM_PASSED_IN_MEMORY (parms)) + for (idx = 0; idx < escaped_arg_list_size; idx++) + if (escaped_arg_list[idx].original == orig) + { + rtx escaped = escaped_arg_list[idx].escaped; + + /* skip in the case where the escaped register was deleted */ + if (GET_CODE (escaped) == REG + && REGNO (escaped) >= FIRST_PSEUDO_REGISTER) + break; + + DECL_INCOMING_RTL (parms) = escaped; + break; + } + } *** /dev/null Sat May 19 03:36:36 2001 --- sys/libkern/stack_smash_handler.c Fri May 18 15:22:09 2001 *************** *** 0 **** --- 1,7 ---- + int __guard = '\0\0\n\777'; + + void __stack_smash_handler (int damaged, char func[]) + { + static char *message = "propolice detects %x at function %s.\n" ; + panic (message, damaged, func); + } ----Next_Part(Sat_May_19_09:32:24_2001_518)---- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message