diff -u linux-2.6.29.4/arch/x86/include/asm/uaccess_32.h linux-2.6.29.4-devel/arch/x86/include/asm/uaccess_32.h --- linux-2.6.29.4/arch/x86/include/asm/uaccess_32.h 2009-05-27 04:31:25.000000000 -0400 +++ linux-2.6.29.4-devel/arch/x86/include/asm/uaccess_32.h 2009-05-27 03:37:55.000000000 -0400 @@ -22,6 +22,10 @@ unsigned long __must_check __copy_from_user_ll_nocache_nozero (void *to, const void __user *from, unsigned long n); +#ifdef CONFIG_PAX_FORTIFY_SOURCE +extern void __chk_fail(void); +#endif + /** * __copy_to_user_inatomic: - Copy a block of data into user space, with less checking. * @to: Destination address, in user space. @@ -62,6 +66,10 @@ return ret; } } +#ifdef CONFIG_PAX_FORTIFY_SOURCE + if (__bos0 (from) != (size_t) -1 && n > __bos0 (from)) + __chk_fail(); +#endif if (!__builtin_constant_p(n)) check_object_size(from, n, true); return __copy_to_user_ll(to, from, n); @@ -229,6 +237,10 @@ static __always_inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { +#ifdef CONFIG_PAX_FORTIFY_SOURCE + if (__bos0 (to) != (size_t) -1 && n > __bos0 (to)) + __chk_fail(); +#endif if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); else if ((long)n > 0) diff -u linux-2.6.29.4/include/linux/gralloc.h linux-2.6.29.4-devel/include/linux/gralloc.h --- linux-2.6.29.4/include/linux/gralloc.h 2009-05-27 04:31:29.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/gralloc.h 2009-06-01 20:20:26.000000000 -0400 @@ -2,7 +2,9 @@ #define __GRALLOC_H +#include + void acl_free_all(void); int acl_alloc_stack_init(unsigned long size); -void *acl_alloc(unsigned long len); +void *acl_alloc(unsigned long len) __malloc__attributes; #endif diff -u linux-2.6.29.4/include/linux/percpu.h linux-2.6.29.4-devel/include/linux/percpu.h --- linux-2.6.29.4/include/linux/percpu.h 2009-05-27 04:31:29.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/percpu.h 2009-06-01 19:57:57.000000000 -0400 @@ -81,7 +81,7 @@ (__typeof__(ptr))__p->ptrs[(cpu)]; \ }) -extern void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask); +extern void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask) __malloc__attributes; extern void percpu_free(void *__pdata); #else /* CONFIG_SMP */ diff -u linux-2.6.29.4/include/linux/slab.h linux-2.6.29.4-devel/include/linux/slab.h --- linux-2.6.29.4/include/linux/slab.h 2009-05-27 04:31:30.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/slab.h 2009-06-01 19:57:21.000000000 -0400 @@ -11,6 +11,7 @@ #include #include +#include /* * Flags to pass to kmem_cache_create(). @@ -208,7 +209,14 @@ * for general use, and so are not documented here. For a full list of * potential flags, always refer to linux/gfp.h. */ + +#ifdef CONFIG_PAX_FORTIFY_SOURCE +extern void *kcalloc(size_t n, size_t size, gfp_t flags) + __calloc__attributes; +static inline void *__fortify_kcalloc(size_t n, size_t size, gfp_t flags) +#else static inline void *kcalloc(size_t n, size_t size, gfp_t flags) +#endif { if (size != 0 && n > ULONG_MAX / size) return NULL; diff -u linux-2.6.29.4/include/linux/slub_def.h linux-2.6.29.4-devel/include/linux/slub_def.h --- linux-2.6.29.4/include/linux/slub_def.h 2009-05-27 04:31:30.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/slub_def.h 2009-06-01 20:26:28.000000000 -0400 @@ -202,14 +203,19 @@ #endif void *kmem_cache_alloc(struct kmem_cache *, gfp_t); -void *__kmalloc(size_t size, gfp_t flags); +void *__kmalloc(size_t size, gfp_t flags) __malloc__attributes; static __always_inline void *kmalloc_large(size_t size, gfp_t flags) { return (void *)__get_free_pages(flags | __GFP_COMP, get_order(size)); } +#ifdef CONFIG_PAX_FORTIFY_SOURCE +extern void *kmalloc(size_t size, gfp_t flags) __attribute__((malloc)) __attribute__((alloc_size(1))); +static __always_inline void *__fortify_kmalloc(size_t size, gfp_t flags) +#else static __always_inline void *kmalloc(size_t size, gfp_t flags) +#endif { if (__builtin_constant_p(size)) { if (size > PAGE_SIZE) @@ -231,7 +237,12 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node); void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); +#ifdef CONFIG_PAX_FORTIFY_SOURCE +extern void *kmalloc_node(size_t size, gfp_t flags, int node) __malloc__attributes; +static __always_inline void *__fortify_kmalloc_node(size_t size, gfp_t flags, int node) +#else static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) +#endif { if (__builtin_constant_p(size) && size <= PAGE_SIZE && !(flags & SLUB_DMA)) { diff -u linux-2.6.29.4/include/linux/vmalloc.h linux-2.6.29.4-devel/include/linux/vmalloc.h --- linux-2.6.29.4/include/linux/vmalloc.h 2009-05-27 04:31:30.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/vmalloc.h 2009-06-01 00:15:03.000000000 -0400 @@ -55,13 +55,13 @@ } #endif -extern void *vmalloc(unsigned long size); -extern void *vmalloc_user(unsigned long size); -extern void *vmalloc_node(unsigned long size, int node); -extern void *vmalloc_exec(unsigned long size); -extern void *vmalloc_32(unsigned long size); -extern void *vmalloc_32_user(unsigned long size); -extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); +extern void *vmalloc(unsigned long size) __malloc__attributes; +extern void *vmalloc_user(unsigned long size) __malloc__attributes; +extern void *vmalloc_node(unsigned long size, int node) __malloc__attributes; +extern void *vmalloc_exec(unsigned long size) __malloc__attributes; +extern void *vmalloc_32(unsigned long size) __malloc__attributes; +extern void *vmalloc_32_user(unsigned long size) __malloc__attributes; +extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) __malloc__attributes; extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot); extern void vfree(const void *addr); diff -u linux-2.6.29.4/mm/page_alloc.c linux-2.6.29.4-devel/mm/page_alloc.c --- linux-2.6.29.4/mm/page_alloc.c 2009-05-27 04:31:31.000000000 -0400 +++ linux-2.6.29.4-devel/mm/page_alloc.c 2009-06-01 20:16:51.000000000 -0400 @@ -1703,6 +1703,7 @@ EXPORT_SYMBOL(__get_free_pages); +#undef get_zeroed_page unsigned long get_zeroed_page(gfp_t gfp_mask) { struct page * page; diff -u linux-2.6.29.4/security/Kconfig linux-2.6.29.4-devel/security/Kconfig --- linux-2.6.29.4/security/Kconfig 2009-05-27 04:31:31.000000000 -0400 +++ linux-2.6.29.4-devel/security/Kconfig 2009-05-27 03:08:50.000000000 -0400 @@ -442,6 +442,14 @@ Since this has a negligible performance impact, you should enable this feature. +config PAX_FORTIFY_SOURCE + bool "Enable limited buffer overflow checking" + depends on GRKERNSEC && X86_32 + help + By saying Y here the kernel will use a recent gcc feature that + allows several key kernel string/memory copying routines to + check for buffer overflows when dealing with static buffers. + config PAX_USERCOPY bool "Bounds check heap object copies between kernel and userland" depends on X86 only in patch2: unchanged: --- linux-2.6.29.4/arch/x86/lib/memcpy_32.c 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/arch/x86/lib/memcpy_32.c 2009-05-31 14:51:32.000000000 -0400 @@ -3,6 +3,7 @@ #undef memcpy #undef memset +#undef memmove void *memcpy(void *to, const void *from, size_t n) { only in patch2: unchanged: --- linux-2.6.29.4/drivers/isdn/hardware/eicon/platform.h 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/drivers/isdn/hardware/eicon/platform.h 2009-05-31 14:08:30.000000000 -0400 @@ -127,8 +127,6 @@ #define DIVAS_CONTAINING_RECORD(address, type, field) \ ((type *)((char*)(address) - (char*)(&((type *)0)->field))) -extern int sprintf(char *, const char*, ...); - typedef void* LIST_ENTRY; typedef char DEVICE_NAME[64]; only in patch2: unchanged: --- linux-2.6.29.4/include/linux/compiler-gcc4.h 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/compiler-gcc4.h 2009-06-01 00:09:34.000000000 -0400 @@ -12,6 +12,13 @@ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) #define __always_inline inline __attribute__((always_inline)) +#if __GNUC_MINOR__ >= 3 +#define __bos1(ptr) __builtin_object_size (ptr, 1) +#define __bos0(ptr) __builtin_object_size (ptr, 0) +#define __malloc__attributes __attribute__((malloc)) __attribute__((alloc_size(1))) +#define __calloc__attributes __attribute__((malloc)) __attribute__((alloc_size(1, 2))) +#endif + /* * A trick to suppress uninitialized variable warning without generating any * code only in patch2: unchanged: --- linux-2.6.29.4/include/linux/compiler.h 2009-05-27 00:30:00.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/compiler.h 2009-06-01 00:10:19.000000000 -0400 @@ -275,4 +275,20 @@ void ftrace_likely_update(struct ftrace_ */ #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) +#ifndef __bos1 +#define __bos1(x) -1 +#endif + +#ifndef __bos0 +#define __bos0(x) -1 +#endif + +#ifndef __malloc__attributes +#define __malloc__attributes +#endif + +#ifndef __calloc__attributes +#define __calloc__attributes +#endif + #endif /* __LINUX_COMPILER_H */ only in patch2: unchanged: --- linux-2.6.29.4/include/linux/gfp.h 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/gfp.h 2009-06-01 20:15:42.000000000 -0400 @@ -220,9 +220,15 @@ extern struct page *alloc_page_vma(gfp_t #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); + extern unsigned long get_zeroed_page(gfp_t gfp_mask); -void *alloc_pages_exact(size_t size, gfp_t gfp_mask); +#ifdef CONFIG_PAX_FORTIFY_SOURCE +extern void *get_zeroed_page_chk(size_t size, gfp_t gfp_mask) __malloc__attributes; +#define get_zeroed_page(x) (unsigned long)get_zeroed_page_chk(PAGE_SIZE, (x)) +#endif + +void *alloc_pages_exact(size_t size, gfp_t gfp_mask) __malloc__attributes; void free_pages_exact(void *virt, size_t size); #define __get_free_page(gfp_mask) \ only in patch2: unchanged: --- linux-2.6.29.4/include/linux/kernel.h 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/kernel.h 2009-05-31 12:27:15.000000000 -0400 @@ -196,6 +196,25 @@ extern int sscanf(const char *, const ch extern int vsscanf(const char *, const char *, va_list) __attribute__ ((format (scanf, 2, 0))); +#ifdef CONFIG_PAX_FORTIFY_SOURCE +#undef sprintf +#define sprintf(buf, fmt, ...) \ + __builtin___sprintf_chk (buf, 0, __bos0 (buf), fmt, ## __VA_ARGS__) + +#undef vsprintf +#define vsprintf(buf, fmt, va_list) \ + __builtin___vsprintf_chk (buf, 0, __bos0 (buf), fmt, va_list) + +#undef snprintf +#define snprintf(buf, maxlen, fmt, ...) \ + __builtin___snprintf_chk (buf, maxlen, 0, __bos0 (buf), fmt, ## __VA_ARGS__) + +#undef vsnprintf +#define vsnprintf(buf, maxlen, fmt, va_list) \ + __builtin___vsnprintf_chk (buf, maxlen, 0, __bos0 (buf), fmt, va_list) + +#endif + extern int get_option(char **str, int *pint); extern char *get_options(const char *str, int nints, int *ints); extern unsigned long long memparse(const char *ptr, char **retptr); only in patch2: unchanged: --- linux-2.6.29.4/include/linux/string.h 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/include/linux/string.h 2009-06-01 19:31:44.000000000 -0400 @@ -102,6 +102,143 @@ extern int memcmp(const void *,const voi extern void * memchr(const void *,int,__kernel_size_t); #endif +#ifdef CONFIG_PAX_FORTIFY_SOURCE + +/* + * "fortified" variants of some of these functions that for certain cases make + * gcc emit code that checks for buffer overflows. + */ + +#undef strcpy +#undef __HAVE_ARCH_STRCPY +#define strcpy(dest, src) \ + ((__bos1 (dest) != (size_t) -1) \ + ? __builtin___strcpy_chk (dest, src, __bos1 (dest)) \ + : __strcpy_ichk (dest, src)) +#if 1 +extern char * +__strcpy_ichk (char * __dest, const char * __src); +#else +static __always_inline char * +__strcpy_ichk (char * __dest, const char * __src) +{ + return __builtin___strcpy_chk (__dest, __src, __bos1 (__dest)); +} +#endif + +#undef strncpy +#undef __HAVE_ARCH_STRNCPY +#define strncpy(dest, src, len) \ + ((__bos1 (dest) != (size_t) -1) \ + ? __builtin___strncpy_chk (dest, src, len, __bos1 (dest)) \ + : __strncpy_ichk (dest, src, len)) +#if 1 +extern char * +__strncpy_ichk (char * __dest, const char * __src, size_t __len); +#else +static __always_inline char * +__strncpy_ichk (char * __dest, const char * __src, size_t __len) +{ + return __builtin___strncpy_chk (__dest, __src, __len, __bos1 (__dest)); +} +#endif + +#undef strcat +#undef __HAVE_ARCH_STRCAT +#define strcat(dest, src) \ + ((__bos1 (dest) != (size_t) -1) \ + ? __builtin___strcat_chk (dest, src, __bos1 (dest)) \ + : __strcat_ichk (dest, src)) + +#if 1 +extern char * +__strcat_ichk (char * __dest, const char * __src); +#else +static __always_inline char * +__strcat_ichk (char * __dest, const char * __src) +{ + return __builtin___strcat_chk (__dest, __src, __bos1 (__dest)); +} +#endif + +#undef strncat +#undef __HAVE_ARCH_STRNCAT +#define strncat(dest, src, len) \ + ((__bos1 (dest) != (size_t) -1) \ + ? __builtin___strncat_chk (dest, src, len, __bos1 (dest)) \ + : __strncat_ichk (dest, src, len)) + +#if 1 +extern char * +__strncat_ichk (char * __dest, const char * __src, size_t __len); +#else +static __always_inline char * +__strncat_ichk (char * __dest, const char * __src, size_t __len) +{ + return __builtin___strncat_chk (__dest, __src, __len, __bos1 (__dest)); +} +#endif + +#undef memcpy +#define memcpy(dest, src, len) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memcpy_chk (dest, src, len, __bos0 (dest)) \ + : __memcpy_ichk (dest, src, len)) + +#if 1 +extern void * +__memcpy_ichk (void * __dest, const void *__src, size_t __len); +#else +static __always_inline void * +__memcpy_ichk (void * __dest, const void *__src, size_t __len) +{ + return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); +} +#endif + +#undef memmove +#define memmove(dest, src, len) \ + ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memmove_chk (dest, src, len, __bos0 (dest)) \ + : __memmove_ichk (dest, src, len)) + +#if 1 +extern void * +__memmove_ichk (void * __dest, const void *__src, size_t __len); +#else +static __always_inline void * +__memmove_ichk (void * __dest, const void *__src, size_t __len) +{ + return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); +} +#endif + +/* memset(x,y,0) is a common typo; this dummy non-existent function is + * there to create a linker error in that case + */ +extern void __warn_memset_zero_len(void); + +#undef memset +#define memset(dest, ch, len) \ + (__builtin_constant_p (len) && (len) == 0 && (!__builtin_constant_p(ch) || ((ch)!=0)) \ + ? (__warn_memset_zero_len (), (void) (ch), (void) (len), (void *) (dest)) \ + : ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memset_chk (dest, ch, len, __bos0 (dest)) \ + : __memset_ichk (dest, ch, len))) + +#if 1 +extern void * +__memset_ichk (void *__dest, int __ch, size_t __len); +#else +static __always_inline void * +__memset_ichk (void *__dest, int __ch, size_t __len) +{ + return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); +} +#endif + +#endif + extern char *kstrdup(const char *s, gfp_t gfp); extern char *kstrndup(const char *s, size_t len, gfp_t gfp); extern void *kmemdup(const void *src, size_t len, gfp_t gfp); @@ -116,3 +253,4 @@ extern ssize_t memory_read_from_buffer(v #endif #endif /* _LINUX_STRING_H_ */ + only in patch2: unchanged: --- linux-2.6.29.4/lib/fortify.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.29.4-devel/lib/fortify.c 2009-06-01 20:55:17.000000000 -0400 @@ -0,0 +1,434 @@ +/* + * Copyright (C) 1991, 1997, 2003, 2004 Free Software Foundation, Inc. + * *alloc/memmove/*printf support by Brad Spengler + * Portions Copyright (C) 2005 Arjan van de Ven + * Portions Copyright (C) 1991, 1992 Linus Torvalds + * + * (Several of these functions were copied from various FSF projects) + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +char *__strcpy_ichk(char *d, const char *s) +{ + return NULL; +} + +char *__strncpy_ichk(char *d, const char *s, size_t len) +{ + return NULL; +} + +char *__strcat_ichk(char *d, const char *s) +{ + return NULL; +} + +char *__strncat_ichk(char *d, const char *s, size_t len) +{ + return NULL; +} + +void *__memcpy_ichk(void *d, const void *s, size_t len) +{ + return NULL; +} + +void *__memmove_ichk(void *d, const void *s, size_t len) +{ + return NULL; +} + +void *__memset_ichk(void *d, int i, size_t len) +{ + return NULL; +} + +void __chk_fail(void) +{ + if (current->signal->curr_ip) + printk(KERN_ALERT "PAX: From %u.%u.%u.%u: %s:%d, uid/euid: %u/%u, attempted to overflow a kernel buffer\n", + NIPQUAD(current->signal->curr_ip), current->comm, task_pid_nr(current), current_uid(), current_euid()); + else + printk(KERN_ALERT "PAX: %s:%d, uid/euid: %u/%u, attempted to overflow a kernel buffer\n", + current->comm, task_pid_nr(current), current_uid(), current_euid()); + BUG(); +} +EXPORT_SYMBOL(__chk_fail); + +void * __memcpy_chk (void *dstpp, const void* srcpp, size_t len, size_t dstlen) +{ + char *d = (char *) dstpp; + const char *s = (const char *) srcpp; + + if (unlikely(dstlen < len)) + __chk_fail (); + + while (len--) + *d++ = *s++; + + return d; +} + +EXPORT_SYMBOL(__memcpy_chk); + +void * __memmove_chk (void *dstpp, const void* srcpp, size_t len, size_t dstlen) +{ + char *d; + const char *s; + + if (unlikely(dstlen < len)) + __chk_fail (); + + if (dstpp <= srcpp) { + d = (char *)dstpp; + s = (const char *)(srcpp); + while (len--) + *d++ = *s++; + } else { + d = (char *)dstpp; + d += len; + s = (const char *)srcpp; + s += len; + while (len--) + *--d = *--s; + } + + return d; +} + +EXPORT_SYMBOL(__memmove_chk); + +void * __memset_chk (void *dst, const int c, size_t len, size_t dstlen) +{ + char *d = (char *) dst; + + if (unlikely(dstlen < len)) + __chk_fail (); + + while (len--) + *d++ = c; + + return d; +} + +EXPORT_SYMBOL(__memset_chk); + +/* Copy SRC to DEST with checking of destination buffer overflow. */ +char * __strcpy_chk (char *dest, const char *src, size_t destlen) +{ + char c; + char *s = (char *) src; + const ptrdiff_t off = dest - s; + + while (__builtin_expect (destlen >= 4, 0)) + { + c = s[0]; + s[off] = c; + if (c == '\0') + return dest; + c = s[1]; + s[off + 1] = c; + if (c == '\0') + return dest; + c = s[2]; + s[off + 2] = c; + if (c == '\0') + return dest; + c = s[3]; + s[off + 3] = c; + if (c == '\0') + return dest; + destlen -= 4; + s += 4; + } + + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + c = *s; + *(s++ + off) = c; + } + while (c != '\0'); + + return dest; +} + +EXPORT_SYMBOL(__strcpy_chk); + + +char * __strcat_chk (char *dest, const char *src, size_t destlen) +{ + char *s1 = dest; + const char *s2 = src; + char c; + + /* Find the end of the string. */ + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + c = *s1++; + } + while (c != '\0'); + + /* Make S1 point before the next character, so we can increment + it while memory is read (wins on pipelined cpus). */ + ++destlen; + s1 -= 2; + + do + { + if (__builtin_expect (destlen-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + } + while (c != '\0'); + + return dest; +} + +EXPORT_SYMBOL(__strcat_chk); + +char * __strncat_chk (char *s1, const char *s2, size_t n, size_t s1len) +{ + char c; + char *s = s1; + + /* Find the end of S1. */ + do + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s1++; + } + while (c != '\0'); + + /* Make S1 point before next character, so we can increment + it while memory is read (wins on pipelined cpus). */ + ++s1len; + s1 -= 2; + + if (n >= 4) + { + size_t n4 = n >> 2; + do + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + } while (--n4 > 0); + n &= 3; + } + + while (n > 0) + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + n--; + } + + if (c != '\0') + { + if (__builtin_expect (s1len-- == 0, 0)) + __chk_fail (); + *++s1 = '\0'; + } + + return s; +} + +EXPORT_SYMBOL(__strncat_chk); + + +char * __strncpy_chk (char *s1, const char *s2, size_t n, size_t s1len) +{ + char c; + char *s = s1; + + if (__builtin_expect (s1len < n, 0)) + __chk_fail (); + + --s1; + + if (n >= 4) + { + size_t n4 = n >> 2; + + for (;;) + { + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + if (--n4 == 0) + goto last_chars; + } + n = n - (s1 - s) - 1; + if (n == 0) + return s; + goto zero_fill; + } + + last_chars: + n &= 3; + if (n == 0) + return s; + + do + { + c = *s2++; + *++s1 = c; + if (--n == 0) + return s; + } + while (c != '\0'); + + zero_fill: + do + *++s1 = '\0'; + while (--n > 0); + + return s; +} + +EXPORT_SYMBOL(__strncpy_chk); + +int +__vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen, const char *format, va_list args) +{ + if (__builtin_expect (slen < maxlen, 0)) + __chk_fail (); + + return __builtin___vsnprintf_chk (s, maxlen, 0, -1, format, args); +} + +EXPORT_SYMBOL(__vsnprintf_chk); + +int +__vsprintf_chk (char *s, int flags, size_t slen, const char *format, va_list args) +{ + if (slen == 0) + __chk_fail (); + return __vsnprintf_chk(s, INT_MAX, flags, slen, format, args); +} + +EXPORT_SYMBOL(__vsprintf_chk); + +int +__sprintf_chk (char *s, int flags, size_t slen, const char *format, ...) +{ + va_list arg; + int done; + + va_start (arg, format); + done = __vsprintf_chk (s, flags, slen, format, arg); + va_end (arg); + + return done; +} + +EXPORT_SYMBOL(__sprintf_chk); + +int +__snprintf_chk (char *s, size_t maxlen, int flags, size_t slen, const char *format, ...) +{ + va_list arg; + int done; + + va_start (arg, format); + done = __vsnprintf_chk (s, maxlen, flags, slen, format, arg); + va_end (arg); + + return done; +} + +EXPORT_SYMBOL(__snprintf_chk); + +void *kmalloc(size_t size, gfp_t flags) +{ + return __fortify_kmalloc(size, flags); +} + +EXPORT_SYMBOL(kmalloc); + +void *kcalloc(size_t n, size_t size, gfp_t flags) +{ + return __fortify_kcalloc(n, size, flags); +} + +EXPORT_SYMBOL(kcalloc); + +#ifdef CONFIG_NUMA +void *kmalloc_node(size_t size, gfp_t flags, int node) +{ + return __fortify_kmalloc_node(size, flags, node); +} + +EXPORT_SYMBOL(kmalloc_node); + +#endif + +void *get_zeroed_page_chk(size_t size, gfp_t flags) +{ + return (void *)get_zeroed_page(flags); +} + +EXPORT_SYMBOL(get_zeroed_page_chk); only in patch2: unchanged: --- linux-2.6.29.4/lib/Makefile 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/lib/Makefile 2009-05-27 03:09:46.000000000 -0400 @@ -44,6 +44,7 @@ obj-$(CONFIG_PLIST) += plist.o obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o obj-$(CONFIG_DEBUG_LIST) += list_debug.o obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o +lib-$(CONFIG_PAX_FORTIFY_SOURCE) += fortify.o ifneq ($(CONFIG_HAVE_DEC_LOCK),y) lib-y += dec_and_lock.o only in patch2: unchanged: --- linux-2.6.29.4/lib/string.c 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/lib/string.c 2009-05-31 11:48:48.000000000 -0400 @@ -95,7 +95,7 @@ EXPORT_SYMBOL(strncasecmp); * @src: Where to copy the string from */ #undef strcpy -char *strcpy(char *dest, const char *src) +char * __attribute__((weak)) strcpy(char *dest, const char *src) { char *tmp = dest; @@ -120,7 +120,8 @@ EXPORT_SYMBOL(strcpy); * count, the remainder of @dest will be padded with %NUL. * */ -char *strncpy(char *dest, const char *src, size_t count) +#undef strncpy +char * __attribute__((weak)) strncpy(char *dest, const char *src, size_t count) { char *tmp = dest; @@ -168,7 +169,7 @@ EXPORT_SYMBOL(strlcpy); * @src: The string to append to it */ #undef strcat -char *strcat(char *dest, const char *src) +char * __attribute__((weak)) strcat(char *dest, const char *src) { char *tmp = dest; @@ -191,7 +192,8 @@ EXPORT_SYMBOL(strcat); * Note that in contrast to strncpy(), strncat() ensures the result is * terminated. */ -char *strncat(char *dest, const char *src, size_t count) +#undef strncat +char * __attribute__((weak)) strncat(char *dest, const char *src, size_t count) { char *tmp = dest; @@ -529,6 +531,7 @@ EXPORT_SYMBOL(sysfs_streq); * * Do not use memset() to access IO space, use memset_io() instead. */ +#undef memset void *memset(void *s, int c, size_t count) { char *xs = s; @@ -550,6 +553,7 @@ EXPORT_SYMBOL(memset); * You should not use this function to access IO space, use memcpy_toio() * or memcpy_fromio() instead. */ +#undef memcpy void *memcpy(void *dest, const void *src, size_t count) { char *tmp = dest; @@ -571,6 +575,7 @@ EXPORT_SYMBOL(memcpy); * * Unlike memcpy(), memmove() copes with overlapping areas. */ +#undef memmove void *memmove(void *dest, const void *src, size_t count) { char *tmp; only in patch2: unchanged: --- linux-2.6.29.4/lib/vsprintf.c 2009-05-08 18:47:21.000000000 -0400 +++ linux-2.6.29.4-devel/lib/vsprintf.c 2009-05-31 15:26:02.000000000 -0400 @@ -723,7 +723,9 @@ static char *pointer(const char *fmt, ch * Call this function if you are already dealing with a va_list. * You probably want snprintf() instead. */ -int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) + +#undef vsnprintf +int __attribute__((weak)) vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { unsigned long long num; int base; @@ -978,7 +980,8 @@ EXPORT_SYMBOL(vscnprintf); * * See the vsnprintf() documentation for format string extensions over C99. */ -int snprintf(char * buf, size_t size, const char *fmt, ...) +#undef snprintf +int __attribute__((weak)) snprintf(char * buf, size_t size, const char *fmt, ...) { va_list args; int i; @@ -1028,7 +1031,8 @@ EXPORT_SYMBOL(scnprintf); * * See the vsnprintf() documentation for format string extensions over C99. */ -int vsprintf(char *buf, const char *fmt, va_list args) +#undef vsprintf +int __attribute__((weak)) vsprintf(char *buf, const char *fmt, va_list args) { return vsnprintf(buf, INT_MAX, fmt, args); } @@ -1046,7 +1050,8 @@ EXPORT_SYMBOL(vsprintf); * * See the vsnprintf() documentation for format string extensions over C99. */ -int sprintf(char * buf, const char *fmt, ...) +#undef sprintf +int __attribute__((weak)) sprintf(char * buf, const char *fmt, ...) { va_list args; int i;