From owner-freebsd-arch@freebsd.org Thu Feb 11 21:21:44 2016 Return-Path: Delivered-To: freebsd-arch@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 9EDF1AA5278 for ; Thu, 11 Feb 2016 21:21:44 +0000 (UTC) (envelope-from cturt@hardenedbsd.org) Received: from mailman.ysv.freebsd.org (mailman.ysv.freebsd.org [IPv6:2001:1900:2254:206a::50:5]) by mx1.freebsd.org (Postfix) with ESMTP id 812AF798 for ; Thu, 11 Feb 2016 21:21:44 +0000 (UTC) (envelope-from cturt@hardenedbsd.org) Received: by mailman.ysv.freebsd.org (Postfix) id 7F137AA5277; Thu, 11 Feb 2016 21:21:44 +0000 (UTC) Delivered-To: arch@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7E98DAA5276 for ; Thu, 11 Feb 2016 21:21:44 +0000 (UTC) (envelope-from cturt@hardenedbsd.org) Received: from mail-wm0-x22c.google.com (mail-wm0-x22c.google.com [IPv6:2a00:1450:400c:c09::22c]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G2" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 0CE98796 for ; Thu, 11 Feb 2016 21:21:44 +0000 (UTC) (envelope-from cturt@hardenedbsd.org) Received: by mail-wm0-x22c.google.com with SMTP id p63so92034782wmp.1 for ; Thu, 11 Feb 2016 13:21:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hardenedbsd-org.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=ErBCO5h2rhk+NQp6e3orRZHHComipOs5achMki+w09k=; b=gVlwwyqwYb8fMzjDlS9fHHXtsUbzV4v25MQFfZ7GVQpzg02pZ33+nxgvjR0Vf1bc7D iiwfgtI7BGfP6pKvM48vXpoulrOqsOx5WU1cPm8fAII/DCKU8YwYwFPv90qBkxonlHyF MScEoJ4VsZ5rbNtKM2JRMEJmo+D66gBUFNRf+65HidwqEqcBE6YWvAn06f9DrsazrqqX 083XTxvYM7LQuftUSJrwhCH6B4+/7bGt21tAVWUWqb7sRwvpT3A1AgFhr9c8mejFxC+w IenvpVKEDrMd1du7sE55RIFpY1Prh6dnmxwyBzKOG6LUrqNCSmPT3NiXG9shkc8SCr2M 6tcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type; bh=ErBCO5h2rhk+NQp6e3orRZHHComipOs5achMki+w09k=; b=bcuUpNnzxGIKx8rA7q7kw5S8T5zUPtV3u2mqDb6/WBRRK5UOUmIOsg8z1vT3GDVAFa FxEttjqR3sDur2rGIwlz8vaUOq5JULXvfZF0F0vFxhYUS5ZOjOhLg915k2N9F2T3pdp7 HpQ2WUrn/unnMfEDEiTN/7Y1Ij7Q+Et21zcluKs3HOOtPWBaz6fIxAjpzPzyIb/BdrDd 7LduWO88UIwEz7ObNVgpReMKkuaNPf62JQqjeaHweVzlU9ovJKr22WPl+tMsqoiGod53 4oU0QuA6TRBw5nhx62VBrO6V7UXvz34O8RL3hPziV/Dnpc9tkiQHWJkfX/aiWlORt9Nn WRmQ== X-Gm-Message-State: AG10YOSxM4+Fm0Rollq383BAxTZ1FLBXV5rZ5Oj4NkzdZek7t/T4qK+sj1G554b/GXJ8TrJJfUQLkJVceIOG8OH6 MIME-Version: 1.0 X-Received: by 10.194.103.131 with SMTP id fw3mr55681585wjb.55.1455225702506; Thu, 11 Feb 2016 13:21:42 -0800 (PST) Received: by 10.27.157.18 with HTTP; Thu, 11 Feb 2016 13:21:42 -0800 (PST) In-Reply-To: References: Date: Thu, 11 Feb 2016 21:21:42 +0000 Message-ID: Subject: Re: OpenBSD mallocarray From: C Turt To: arch@freebsd.org Content-Type: text/plain; charset=UTF-8 X-Content-Filtered-By: Mailman/MimeDel 2.1.20 X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Feb 2016 21:21:44 -0000 I just wanted to post some real world examples of bugs which could be mitigated with `mallocarray` to attract more interest. My most meritable example of a real world attack from this behaviour would be the sys_dynlib_prepare_dlclose kernel exploit for PS4 (PS4 OS is based on FreeBSD 9.0). You may read my write-up of this exploit here: http://cturt.github.io/dlclose-overflow.html The significance of this example is that if a `mallocarray` wrapper was available, and used here, the bug would not have been exploitable, because it would have intentionally panicked instead of continuing with an under allocated buffer. You may think that this is clearly Sony's fault for not checking the count at all, and that FreeBSD kernel code would never have a bug like this, which is why I would like to mention that similar overflows can be possible even if there initially appear to be sufficient bound checks performed. There are several pieces of vulnerable code present in FreeBSD kernel (albeit most of them are triggerable only as root so are not critical), however I will use the file `/sys/kern/kern_alq.c` to demonstrate. There are some checks on counts and sizes, but they are insufficient: [CODE]int alq_open(struct alq **alqp, const char *file, struct ucred *cred, int cmode, int size, int count) { int ret; KASSERT((count >= 0), ("%s: count < 0", __func__)); if (count > 0) { if ((ret = alq_open_flags(alqp, file, cred, cmode, size*count, 0)) == 0) { (*alqp)->aq_flags |= AQ_LEGACY; (*alqp)->aq_entmax = count; (*alqp)->aq_entlen = size; } ... int alq_open_flags(struct alq **alqp, const char *file, struct ucred *cred, int cmode, int size, int flags) { ... KASSERT((size > 0), ("%s: size <= 0", __func__)); ... alq->aq_buflen = size; ... alq->aq_entbuf = malloc(alq->aq_buflen, M_ALD, M_WAITOK|M_ZERO);[/CODE] The check on `count` being greater than or equal to 0 in `alq_open`, and the check for `size` being greater than 0 in `alq_open_flags` are cute, but they don't check for an overflow of `size*count`. This code path is reachable in several places, such as `sysctl_debug_ktr_alq_enable`: [CODE]static int sysctl_debug_ktr_alq_enable(SYSCTL_HANDLER_ARGS) { ... error = alq_open(&ktr_alq, (const char *)ktr_alq_file, req->td->td_ucred, ALQ_DEFAULT_CMODE, sizeof(struct ktr_entry), ktr_alq_depth); [/CODE] With `ktr_alq_depth` being controllable from userland (but only as root): [CODE]SYSCTL_INT(_debug_ktr, OID_AUTO, alq_depth, CTLFLAG_RW, &ktr_alq_depth, 0, "Number of items in the write buffer");[/CODE] `sizeof(struct ktr_entry)` is 88 bytes. So theoretically if `ktr_alq_depth` is set to `48806447`, we'll get an allocation of `0x100000028`, which truncates to 0x28 = 40 bytes. A heap overflow would then possible when this buffer is iterated over with `aq_entmax` and `aq_entlen`. On Mon, Feb 1, 2016 at 7:57 PM, C Turt wrote: > I've recently started browsing the OpenBSD kernel source code, and have > found the mallocarray function positively wonderful. I would like to > discuss the possibility of getting this into FreeBSD kernel. > > For example, many parts of kernel code in FreeBSD use something like > malloc(xxx * sizeof(struct xxx)). If xxx is 64bit and controllable by user, > this allocation can easily overflow, resulting in a heap overflow later on. > > The mallocarray is a wrapper for malloc which can be used in this > situations to detect an integer overflow before allocating: > > /* > * Copyright (c) 2008 Otto Moerbeek > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above > * copyright notice and this permission notice appear in all copies. > * > * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > */ > > /* > * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX > * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW > */ > #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) > > void * > mallocarray(size_t nmemb, size_t size, int type, int flags) > { > if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && > nmemb > 0 && SIZE_MAX / nmemb < size) { > if (flags & M_CANFAIL) > return (NULL); > panic("mallocarray: overflow %zu * %zu", nmemb, size); > } > return (malloc(size * nmemb, type, flags)); > } > >