From patchwork Mon Aug 10 12:31:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Dowad X-Patchwork-Id: 505607 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A10BF14018C for ; Mon, 10 Aug 2015 22:31:24 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b=v4kCCW4G; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; q=dns; s= default; b=iEwC2s1S4a9tUimd22ssqqZU81+gyWw3/7WoPyW+Jldw2bD5/4sPn 7xWHzBJAIlrE+ocsmIODcOY8E9nrXAo6Apx8mGBAfQ5sLm8G2keV8kGsmsMifWkj hAA7WPk8DCgCpcs1P35B6erIdTqqCpOMB4iQo1j9p3PgzwJebtwkbs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; s=default; bh=2r8oAnaBG//tDdwgBzSsZ+ZUtDA=; b=v4kCCW4GF29olYlYkY2exaxoQRh4 QELY7s3Ws3syrF0g2krVa9sCC8ZUif5kyZcKAhRKCPvAchqQfxw/qRONijozi0b0 St5cBlvaP5tLFSV6P73rOAj+Wuz+hWDdjjtgtZ9RD5LA7FoExJOM4wK3DtRr0D6A vWQHUdZ54PZohQo= Received: (qmail 38196 invoked by alias); 10 Aug 2015 12:31:18 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 38185 invoked by uid 89); 10 Aug 2015 12:31:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.6 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-wi0-f170.google.com X-Received: by 10.194.142.237 with SMTP id rz13mr31011778wjb.48.1439209873157; Mon, 10 Aug 2015 05:31:13 -0700 (PDT) From: Alex Dowad To: libc-alpha@sourceware.org Subject: [PATCH v2] Don't allow attackers to inject arbitrary data into stack through LD_DEBUG Date: Mon, 10 Aug 2015 14:31:05 +0200 Message-Id: <1439209865-17030-1-git-send-email-alexinbeijing@gmail.com> C programs which use uninitialized stack variables can be exploited if an attacker can control the contents of memory where the buggy function's stack frame lands. If the buggy function is called very early in the program's execution, that memory might still hold values written by ld.so, so manipulation of ld.so is one way to carry out such an exploit. But how can an unprivileged user, running a set-UID program, cause ld.so to write arbitrary data onto the stack? One way is to assign it to LD_DEBUG. When printing the resulting warning message, ld.so uses alloca to create a buffer on the stack, and copies the entire contents of LD_DEBUG into it (even if it is dozens of kilobytes long). Of course, people shouldn't write programs which use uninitialized variables, but it is easy enough to plug this hole if they do. Simply avoid copying the string onto the stack. Because the string may not be null-terminated, we need to provide a string length to _dl_error_printf. --- Thanks to Paul Eggert, Andreas Schwab, and Rich Felker for feedback on the v1. elf/dl-misc.c | 7 ++++--- elf/rtld.c | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/elf/dl-misc.c b/elf/dl-misc.c index 8fd6710..81b332c 100644 --- a/elf/dl-misc.c +++ b/elf/dl-misc.c @@ -143,7 +143,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) ++fmt; } - /* See whether with comes from a parameter. Note that no other + /* See whether width comes from a parameter. Note that no other way to specify the width is implemented. */ if (*fmt == '*') { @@ -205,9 +205,10 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) case 's': /* Get the string argument. */ iov[niov].iov_base = va_arg (arg, char *); - iov[niov].iov_len = strlen (iov[niov].iov_base); if (prec != -1) - iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len); + iov[niov].iov_len = strnlen (iov[niov].iov_base, (size_t) prec); + else + iov[niov].iov_len = strlen (iov[niov].iov_base); ++niov; break; diff --git a/elf/rtld.c b/elf/rtld.c index 6dcbabc..e10293a 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2405,9 +2405,8 @@ process_dl_debug (const char *dl_debug) { /* Display a warning and skip everything until next separator. */ - char *copy = strndupa (dl_debug, len); _dl_error_printf ("\ -warning: debug option `%s' unknown; try LD_DEBUG=help\n", copy); +warning: debug option `%.*s' unknown; try LD_DEBUG=help\n", len, dl_debug); } dl_debug += len;