Use Fstack Protector All (stack Canaries For Mac
LINK >>> https://blltly.com/2t8ctv
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:
-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 itselfthe data segment is for most variablesthe stack segment holds the stackA "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) || defined(CONFIG_TASK_DELAY_ACCT)struct sched_info sched_info;#endifstruct list_head tasks;/* * ptrace_list/ptrace_children forms the list of my children * that were stolen by a ptracer. */struct list_head ptrace_children;struct list_head ptrace_list;struct mm_struct *mm, *active_mm;/* task state */struct linux_binfmt *binfmt;long exit_state;int exit_code, exit_signal;int pdeath_signal; /* The signal sent when the parent dies *//* ??? */unsigned long personality;unsigned did_exec:1;pid_t pid;pid_t tgid;#ifdef CONFIG_CC_STACKPROTECTOR/* Canary value for the -fstack-protector gcc feature */unsigned long stack_canary;#endif/* * pointers to (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->parent->pid) */struct task_struct *real_parent; /* real parent process (when being debugged) */struct task_struct *parent;/* parent process *//* * children/sibling forms the list of my children plus the * tasks I'm ptracing. */struct list_head children;/* list of my children */struct list_head sibling;/* linkage in my parent's children list */struct task_struct *group_leader;/* threadgroup leader *//* PID/PID hash table linkage. */struct pid_link pids[PIDTYPE_MAX];struct list_head thread_group;struct completion *vfork_done;/* for vfork() */int __user *set_child_tid;/* CLONE_CHILD_SETTID */int __user *clear_child_tid;/* CLONE_CHILD_CLEARTID */unsigned long rt_priority;cputime_t utime, stime;unsigned long nvcsw, nivcsw; /* context switch counts */struct timespec start_time;/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */unsigned long min_flt, maj_flt; cputime_t it_prof_expires, it_virt_expires;unsigned long long it_sched_expires;struct list_head cpu_timers[3];/* process credentials */uid_t uid,euid,suid,fsuid;gid_t gid,egid,sgid,fsgid;struct group_info *group_info;kernel_cap_t cap_effective, cap_inheritable, cap_permitted;unsigned keep_capabilities:1;struct user_struct *user;#ifdef CONFIG_KEYSstruct key *request_key_auth;/* assumed request_key authority */struct key *thread_keyring;/* keyring private to this thread */unsigned char jit_keyring;/* default keyring to attach requested keys to */#endif/* * fpu_counter contains the number of consecutive context switches * that the FPU is used. If this is over a threshold, the lazy fpu * saving becomes unlazy to save the trap. This is an unsigned char * so that after 256 times the counter wraps and the behavior turns * lazy again; this to deal with bursty apps that only use FPU for * a short time */unsigned char fpu_counter;int oomkilladj; /* OOM kill score adjustment (bit shift). */char comm[TASK_COMM_LEN]; /* executable name excluding path - access with [gs]et_task_comm (which lock it with task_lock()) - initialized normally by flush_old_exec *//* file system info */int link_count, total_link_count;#ifdef CONFIG_SYSVIPC/* ipc stuff */struct sysv_sem sysvsem;#endif/* CPU-specific state of this task */struct thread_struct thread;/* filesystem information */struct fs_struct *fs;/* open file information */struct files_struct *files;/* namespaces */struct nsproxy *nsproxy;/* signal handlers */struct signal_struct *signal;struct sighand_struct *sighand;sigset_t blocked, real_blocked;sigset_t saved_sigmask;/* To be restored with TIF_RESTORE_SIGMASK */struct sigpending pending;unsigned long sas_ss_sp;size_t sas_ss_size;int (*notifier)(void *priv);void *notifier_data;sigset_t *notifier_mask;void *security;struct audit_context *audit_context;seccomp_t seccomp;/* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id;/* Protection of (de-)allocation: mm, files, fs, tty, keyrings */spinlock_t alloc_lock;/* Protection of the PI data structures: */spinlock_t pi_lock;#ifdef CONFIG_RT_MUTEXES/* PI waiters blocked on a rt_mutex held by this task */struct plist_head pi_waiters;/* Deadlock detection and priority inheritance handling */struct rt_mutex_waiter *pi_blocked_on;#endif#ifdef CONFIG_DEBUG_MUTEXES/* mutex deadlock detection */struct mutex_waiter *blocked_on;#endif#ifdef CONFIG_TRACE_IRQFLAGSunsigned int irq_events;int hardirqs_enabled;unsigned long hardirq_enable_ip;unsigned int hardirq_enable_event;unsigned long hardirq_disable_ip;unsigned int hardirq_disable_event;int softirqs_enabled;unsigned long softirq_disable_ip;unsigned int softirq_disable_event;unsigned long softirq_enable_ip;unsigned int softirq_enable_event;int hardirq_context;int softirq_context;#endif#ifdef CONFIG_LOCKDEP# define MAX_LOCK_DEPTH 30ULu64 curr_chain_key;int lockdep_depth;struct held_lock held_locks[MAX_LOCK_DEPTH];unsigned int lockdep_recursion;#endif/* journalling filesystem info */void *journal_info;/* VM state */struct reclaim_state *reclaim_state;struct backing_dev_info *backing_dev_info;struct io_context *io_context;unsigned long ptrace_message;siginfo_t *last_siginfo; /* For ptrace use. *//* * current io wait handle: wait queue entry to use for io waits * If this thread is processing aio, this points at the waitqueue * inside the currently handled kiocb. It may be NULL (i.e. default * to a stack based synchronous wait) if its doing sync IO. */wait_queue_t *io_wait;/* i/o counters(bytes read/written, #syscalls */u64 rchar, wchar, syscr, syscw;#if defined(CONFIG_TASK_XACCT)u64 acct_rss_mem1;/* accumulated rss usage */u64 acct_vm_mem1;/* accumulated virtual memory usage */cputime_t acct_stimexpd;/* stime since last update */#endif#ifdef CONFIG_NUMA struct mempolicy *mempolicy;short il_next;#endif#ifdef CONFIG_CPUSETSstruct cpuset *cpuset;nodemask_t mems_allowed;int cpuset_mems_generation;int cpuset_mem_spread_rotor;#endifstruct robust_list_head __user *robust_list;#ifdef CONFIG_COMPATstruct compat_robust_list_head __user *compat_robust_list;#endifstruct list_head pi_state_list;struct futex_pi_state *pi_state_cache;atomic_t fs_excl;/* holding fs exclusive resources */struct rcu_head rcu;/* * cache last used pipe for splice */struct pipe_inode_info *splice_pipe;#ifdefCONFIG_TASK_DELAY_ACCTstruct task_delay_info *delays;#endif};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 |= CLONE_PTRACE;}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 2b1af7f3a8