From patchwork Wed Apr 30 15:08:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Carpenter X-Patchwork-Id: 4094551 Return-Path: X-Original-To: patchwork-linux-acpi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 15E1C9F271 for ; Wed, 30 Apr 2014 15:09:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E0E72202DD for ; Wed, 30 Apr 2014 15:09:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8EB6D201D5 for ; Wed, 30 Apr 2014 15:09:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758933AbaD3PJS (ORCPT ); Wed, 30 Apr 2014 11:09:18 -0400 Received: from aserp1040.oracle.com ([141.146.126.69]:19953 "EHLO aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758872AbaD3PJS (ORCPT ); Wed, 30 Apr 2014 11:09:18 -0400 Received: from acsinet22.oracle.com (acsinet22.oracle.com [141.146.126.238]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id s3UF8wed000755 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 30 Apr 2014 15:08:59 GMT Received: from aserz7021.oracle.com (aserz7021.oracle.com [141.146.126.230]) by acsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s3UF8vmG018182 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 30 Apr 2014 15:08:58 GMT Received: from abhmp0016.oracle.com (abhmp0016.oracle.com [141.146.116.22]) by aserz7021.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s3UF8vaY000525; Wed, 30 Apr 2014 15:08:57 GMT Received: from mwanda (/41.202.240.8) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 30 Apr 2014 08:08:55 -0700 Date: Wed, 30 Apr 2014 18:08:44 +0300 From: Dan Carpenter To: Dan Carpenter Cc: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, devel@acpica.org, kernel-hardening@lists.openwall.com, Kees Cook , Dave Jones , Andrew Morton Subject: [patch] lib: check for strcpy() overflows to fixed length buffers Message-ID: <20140430150844.GA10621@mwanda> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-Source-IP: acsinet22.oracle.com [141.146.126.238] Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There are sometimes where we know that we are doing an strcpy() into a fixed length buffer. In those cases, we could verify that the strcpy() doesn't overflow. This patch introduces DEBUG_STRICT_SLOW_STRCPY_CHECKS if you want to check for that. The downside is that it makes strcpy slower. I introduced __compiletime_size() to make this work. It returns the size of the destination buffer or zero if the size isn't known. The __compiletime_object_size() is similar but if you pass it a struct member then it returns the size of everything from there to the end of the struct. Another difference is __compiletime_object_size() returns -1 for unknown sizes. If you pass a char pointer to __compiletime_size() then it returns zero. The strcpy() check ignores buffers with just one byte because people often use those for variable length strings at the end of a struct. I have tested this patch lightly and created some bugs for it to detect but I have not detected any real life overflows. Signed-off-by: Dan Carpenter --- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index e863dd5..5e0fc2b 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -320,7 +320,7 @@ #define ACPI_STRSTR(s1,s2) strstr((s1), (s2)) #define ACPI_STRCHR(s1,c) strchr((s1), (c)) #define ACPI_STRLEN(s) (acpi_size) strlen((s)) -#define ACPI_STRCPY(d,s) (void) strcpy((d), (s)) +#define ACPI_STRCPY(d,s) strcpy((d), (s)) #define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (acpi_size)(n)) #define ACPI_STRNCMP(d,s,n) strncmp((d), (s), (acpi_size)(n)) #define ACPI_STRCMP(d,s) strcmp((d), (s)) diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h index 2507fd2..1fb7fd0 100644 --- a/include/linux/compiler-gcc4.h +++ b/include/linux/compiler-gcc4.h @@ -16,6 +16,9 @@ #if GCC_VERSION >= 40100 && GCC_VERSION < 40600 # define __compiletime_object_size(obj) __builtin_object_size(obj, 0) #endif +#if GCC_VERSION > 40600 +# define __compiletime_size(obj) __builtin_object_size(obj, 3) +#endif #if GCC_VERSION >= 40300 /* Mark functions as cold. gcc will assume any path leading to a call diff --git a/include/linux/compiler.h b/include/linux/compiler.h index ee7239e..b615964 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -318,6 +318,9 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); #ifndef __compiletime_object_size # define __compiletime_object_size(obj) -1 #endif +#ifndef __compiletime_size +# define __compiletime_size(obj) 0 +#endif #ifndef __compiletime_warning # define __compiletime_warning(message) #endif diff --git a/include/linux/string.h b/include/linux/string.h index ac889c5..fc126a1 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -154,4 +154,13 @@ static inline const char *kbasename(const char *path) return tail ? tail + 1 : path; } +#if CONFIG_DEBUG_STRICT_SLOW_STRCPY_CHECKS +#define strcpy(dest, src) do { \ + int len = __compiletime_size(dest); \ + if (len > 1 && strlen(src) >= len) \ + WARN_ONCE(1, "strcpy() overflow copying \"%s\"\n", src); \ + strcpy(dest, src); \ +} while (0) +#endif + #endif /* _LINUX_STRING_H_ */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 819ac51..94db086 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1431,6 +1431,15 @@ config DEBUG_STRICT_USER_COPY_CHECKS If unsure, say N. +config DEBUG_STRICT_SLOW_STRCPY_CHECKS + bool "Strict checks for strcpy() overflows" + depends on DEBUG_KERNEL + help + Enabling this option adds some extra sanity checks when strcpy() is + called(). This will slow down the kernel a bit. + + If unsure, say N. + source kernel/trace/Kconfig menu "Runtime Testing"