top of page
Search
pyotrkulakov416

Use compiler flags for stack protection in GCC and Clang | Red Hat Developer[^1^]



Instrumenting all functions is known to result in a significant performance hit [source].-fstack-protector and -fstack-protector-strong attempt to mitigate this byinstrumenting only a subset of functions. Traditional stack overflows are theresult of string-based manipulations, and -fstack-protector is intended tocover many of these cases. However, there are rare cases where stack overflowsare caused by other types of stack variables. -fstack-protector-strong is intendedto cover more of these cases [source].


As -fstack-protector-strong strikes a balance between security and performance,this version of SSP is analyzed. Two metrics relevant to an embedded system willbe used for the analysis:




Use Fstack Protector All (stack Canaries For Mac




-fstack-protector-all -Wstack-protector --param ssp-buffer-size=4 Your choice of "-fstack-protector" does not protect all functions (see comments). You need -fstack-protector-all to guarantee guards are applied to all functions, although this will likely incur a performance penalty. Consider -fstack-protector-strong as a middle ground. The -Wstack-protector flag here gives warnings for any functions that aren't going to get protected.


Luckily, on its own, this bug is not enough to successfully execute code onnative binaries. By default, libolm is compiled for all supported targets withstack canaries (also called stack protectors or stack cookies), which are magicvalues unknown to the attacker, placed just before the current function's frameon the stack. This value is checked upon returning from the function -- if itsvalue is changed, the process aborts itself to prevent further damage. This isevident from the Abort message: 'stack corruption detected(-fstack-protector)' message above. Besides canaries, other system-levelprotections exist to make exploiting bugs such as this harder, such as ASLR.


All of the software in the Fedora Package Collection is compiled using a security feature called fstack-protector. fstack-protector puts a canary value on the stack of key functions. Just before the return address and just before returning from that value, that canary value is verified. If there was a buffer overflow, the canary no longer matches and the program aborts. The canary value is random for each time the application is started and makes it impossible to guess remotely. This is a security feature that has been backported from GCC 4.1 to the version of the GCC compiler used in Fedora Core 5 test1. This feature has been written by Red Hat developers and provides similar functionality to the IBM propolice/ssp patches.]


CopperheadOS also builds Chromium with -fstack-protector-strong rather than -fstack-protector and removes mremap from the system call whitelist since CopperheadOS is currently not using it as an optimization in the system allocator and it's not used elsewhere. It also temporarily makes use of -fwrapv to prevent optimizations from introducing security issues due to reliance on undefined signed overflow. However, this will be replaced by automatic integer overflow checking via usage of -fsanitize=shift,signed-integer-overflow -fsanitize-trap=shift,signed-integer-overflow once Chromium makes further progress towards eliminating bugs caught by UBSan.


The SSP feature is enabled using GCC command-line arguments. The -fstack-protector and -fno-stack-protector options enable and disable stack-smashing protection for functions with vulnerable objects (such as arrays). The -fstack-protector-all and -fno-stack-protector-all options enable and disable the protection of every function, not just the functions with character arrays. Finally, the -Wstack-protector option emits warnings about functions that receive no stack protection when -fstack-protector is used.


  • What's a Process?Several times already this term I've used the term "process". So whatis a process, anyway? A process is an instance of a running programon a multitasking or multiprogrammed OS. If we ignore performance,the concept of a process is what allows an application program tothink that it has the entire computer to itself. (In systemswith virtual memory, the process abstraction also allows programs tothink they have lots of memory, whether or not they really do.) Instance of a running program Virtualization of processor and memory Briefly: kernel v. user space Text, data, stack segments Process control structures Segments$B%;%0%a%s%H$O%a%b%j$N%(%j%"$G$9!#$$$/$D$+$N=qN`$,$"$k!'(Bthe text segment is the program itself

  • the data segment is for most variables

  • the stack segment holds the stack

  • A "segment" of a Unix process is one of its primary data areas: thetext segment is the program itself (including sharedlibraries), the data segment is for most variables (of severaltypes; those created using the malloc() memory acquisitionroutine, primarily), and the stack segment holds, well, thestack. The portion of the data segment that is dynamically allocatedand deallocated is often called the memory heap.Some operating systems explicitly support requests for memory alreadyfilled with zeroes or not; the choice of which to use is forefficiency. The choice the OS makes on whether or not tosupply memory that is not zero-filled is both an efficiency anda security issue. In Unix systems, application programs cannot assumethat freshly-allocated memory contains zeroes, but if it does not, itis usually because the memory allocator has reassigned memory that thesame process has recently freed. Handing out memory that otherprocesses have recently freed would allow one process to read someof another's memory, without permission!Process control structuresFrom include/linux/sched.h:struct task_struct volatile long state;/* -1 unrunnable, 0 runnable, >0 stopped */struct thread_info *thread_info;atomic_t usage;unsigned long flags;/* per process flags, defined below */unsigned long ptrace;int lock_depth;/* BKL lock depth */#ifdef CONFIG_SMP#ifdef __ARCH_WANT_UNLOCKED_CTXSWint oncpu;#endif#endifint load_weight;/* for niceness load balancing purposes */int prio, static_prio, normal_prio;struct list_head run_list;struct prio_array *array;unsigned short ioprio;#ifdef CONFIG_BLK_DEV_IO_TRACEunsigned int btrace_seq;#endifunsigned long sleep_avg;unsigned long long timestamp, last_ran;unsigned long long sched_time; /* sched_clock time spent running */enum sleep_type sleep_type;unsigned long policy;cpumask_t cpus_allowed;unsigned int time_slice, first_time_slice;#if defined(CONFIG_SCHEDSTATS) ;Unix fork() In Unix, fork() is the only way in Unix to make a new process.

  • The existing process is copied, and the copy is called a childprocess.

  • fork() is used very, very frequently.

fork() is the only way in Unix to make a new process. Thesystem call copies the existing process and creates a childprocess. The child process inherits everything, including open filedescriptors. In early versions of Unix, fork had to literallycopy every page of data memory, but the program (or textsegment) could be shared, because it is generally protected frombeing written to using processor page protection bits. However,copying all of the data memory can be expensive. Therefore, thevfork() system call was later introduced; we won't go intodetails, but vfork() stops the parent from executing until thechild is done with the memory. (The child should not actually touchthe memory, however.) Modern systems generally implementfork() by copying only the page table of the callingprocess, and setting the data pages to copy on write. We willdiscuss copy on write when we cover memory management.fork() is used very frequently. Every time the userrequests execution of a program (via the shell), fork() iscalled. The child process then generally calls exec(), whichreplaces the currently running program (generally the shell) inthis (the child) process, loading another program from disk, ifnecessary, and starting it. The parent can later choose to wait forthe child process to finish, or the parent can continue executing itsown work.Most of the work in Linux is actually done in thecopy_process function. do_fork() is fairly short.copy_process makes new copies of certain structures, andcreates new pointers to reference-counted objects for things that needto be shared.From kernel/fork.c:/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */long do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr){struct task_struct *p;int trace = 0;struct pid *pid = alloc_pid();long nr;if (!pid)return -EAGAIN;nr = pid->nr;if (unlikely(current->ptrace)) trace = fork_traceflag (clone_flags);if (trace)clone_flags p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);/* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. */if (!IS_ERR(p)) {struct completion vfork;if (clone_flags & CLONE_VFORK) p->vfork_done = &vfork;init_completion(&vfork);if ((p->ptrace & PT_PTRACED) (clone_flags & CLONE_STOPPED)) /* * We'll start up with an immediate SIGSTOP. */sigaddset(&p->pending.signal, SIGSTOP);set_tsk_thread_flag(p, TIF_SIGPENDING);if (!(clone_flags & CLONE_STOPPED))wake_up_new_task(p, clone_flags);elsep->state = TASK_STOPPED;if (unlikely (trace)) {current->ptrace_message = nr;ptrace_notify ((trace ptrace & PT_TRACE_VFORK_DONE)) {current->ptrace_message = nr;ptrace_notify ((PTRACE_EVENT_VFORK_DONE 2ff7e9595c


0 views0 comments

Recent Posts

See All

Comments


bottom of page