Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp2459083ybi; Sun, 9 Jun 2019 12:17:35 -0700 (PDT) X-Google-Smtp-Source: APXvYqwOJ7P8I4s8qYhOu6DAdkaech1I0H9hVQzSKdTi/YBTlLbvs2ImIOa+O3/18H6bhEd+hJl5 X-Received: by 2002:a63:1f11:: with SMTP id f17mr12688160pgf.311.1560107855285; Sun, 09 Jun 2019 12:17:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1560107855; cv=none; d=google.com; s=arc-20160816; b=gyZLnG1ctoBNlK0ltjb79hHGue3OTjUULbCtXPe/5Ese1qrrhQTP7VMKWo9j/lILfu oiKas905IaaFDlO2a7UhroEaISrMZVvHAG+bmxG9FjV0bTa/6mwbOTuBf0ige9uJ0LZm sCbXpu1e5cvV9JV+95B5Kj9u/4TA1XP5ZLTlOD8Ncx0xD1vI4DiPd3KWj1y+rhkDzK+R bXcR6K/s5X+L7kmnTKqi3TFBsZ0kKN6W6OiFHmVMDts4e/hXiZYjqgg9rWSFRjCqrURg JWVH673vTA9XcSAufY+17r/A0q3mn3x2u8bi3OfNqCpIs5FgBGgVSQwp7JS9o/m7IsCv p2Kw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=u9VtxTvEAzmOZ4RiMdxu8NNuNC2oEcgbqpbKmb5AgTc=; b=DZ+82NKiVFk/CUyKhMuvxF6pCkIRxb62xUtzPRyz1/qZstt3feM9g+/oQfpx8Fh7eI PoMDEexLjQu/EwnhW9an11e1nc4Hj8in4lgXDUHYVTVjUJ+IICRzWDAiKWcrXxKSZ2FD qYiti9sHVJIUeIpHCoKx0doRnGb5hfLwfS6iWDNh/v+PxjDhJ24obRStHTkaIvue1i39 57BGvZAi5zQ0OsJtR4KekZ5+t3U8AAs6q/Pay7weZmNlWxap/fn13va2Gtr5zJWqjK/S 0AIsPATCG7xQtWwRxKn4hx70uW8ky+qX86VSNDI4hZyFO//Y9zGKlr6ECAcYlHsWn2cZ VSQA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=uYdoVknN; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o184si7695982pgo.94.2019.06.09.12.17.18; Sun, 09 Jun 2019 12:17:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=uYdoVknN; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730736AbfFIQrE (ORCPT + 99 others); Sun, 9 Jun 2019 12:47:04 -0400 Received: from mail.kernel.org ([198.145.29.99]:45540 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730686AbfFIQrC (ORCPT ); Sun, 9 Jun 2019 12:47:02 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id EF1C92081C; Sun, 9 Jun 2019 16:47:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1560098821; bh=dXAI8+J7R8bpRX9mH8IiBBnSgPD7BhNOjOyyBKlp42c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uYdoVknNyxlXgAmlxJc6b7ybWzmc2EgFtIC8Tb10gYYy4cUl80W4k4HJlh9CaPRyl nRuIpukCSA0cQ1CsUBaQQYqpINaAleschz9TL45bvW3qzl/8iMW+Ja90zUSDsiBL75 MwoldrJ5Wdb2ALlm+vTiliAHKvOpb6Ga4dNk5Sso= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jann Horn , Linus Torvalds Subject: [PATCH 5.1 40/70] x86/insn-eval: Fix use-after-free access to LDT entry Date: Sun, 9 Jun 2019 18:41:51 +0200 Message-Id: <20190609164130.597045549@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190609164127.541128197@linuxfoundation.org> References: <20190609164127.541128197@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jann Horn commit de9f869616dd95e95c00bdd6b0fcd3421e8a4323 upstream. get_desc() computes a pointer into the LDT while holding a lock that protects the LDT from being freed, but then drops the lock and returns the (now potentially dangling) pointer to its caller. Fix it by giving the caller a copy of the LDT entry instead. Fixes: 670f928ba09b ("x86/insn-eval: Add utility function to get segment descriptor") Cc: stable@vger.kernel.org Signed-off-by: Jann Horn Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/lib/insn-eval.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) --- a/arch/x86/lib/insn-eval.c +++ b/arch/x86/lib/insn-eval.c @@ -557,7 +557,8 @@ static int get_reg_offset_16(struct insn } /** - * get_desc() - Obtain pointer to a segment descriptor + * get_desc() - Obtain contents of a segment descriptor + * @out: Segment descriptor contents on success * @sel: Segment selector * * Given a segment selector, obtain a pointer to the segment descriptor. @@ -565,18 +566,18 @@ static int get_reg_offset_16(struct insn * * Returns: * - * Pointer to segment descriptor on success. + * True on success, false on failure. * * NULL on error. */ -static struct desc_struct *get_desc(unsigned short sel) +static bool get_desc(struct desc_struct *out, unsigned short sel) { struct desc_ptr gdt_desc = {0, 0}; unsigned long desc_base; #ifdef CONFIG_MODIFY_LDT_SYSCALL if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) { - struct desc_struct *desc = NULL; + bool success = false; struct ldt_struct *ldt; /* Bits [15:3] contain the index of the desired entry. */ @@ -584,12 +585,14 @@ static struct desc_struct *get_desc(unsi mutex_lock(¤t->active_mm->context.lock); ldt = current->active_mm->context.ldt; - if (ldt && sel < ldt->nr_entries) - desc = &ldt->entries[sel]; + if (ldt && sel < ldt->nr_entries) { + *out = ldt->entries[sel]; + success = true; + } mutex_unlock(¤t->active_mm->context.lock); - return desc; + return success; } #endif native_store_gdt(&gdt_desc); @@ -604,9 +607,10 @@ static struct desc_struct *get_desc(unsi desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK); if (desc_base > gdt_desc.size) - return NULL; + return false; - return (struct desc_struct *)(gdt_desc.address + desc_base); + *out = *(struct desc_struct *)(gdt_desc.address + desc_base); + return true; } /** @@ -628,7 +632,7 @@ static struct desc_struct *get_desc(unsi */ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) { - struct desc_struct *desc; + struct desc_struct desc; short sel; sel = get_segment_selector(regs, seg_reg_idx); @@ -666,11 +670,10 @@ unsigned long insn_get_seg_base(struct p if (!sel) return -1L; - desc = get_desc(sel); - if (!desc) + if (!get_desc(&desc, sel)) return -1L; - return get_desc_base(desc); + return get_desc_base(&desc); } /** @@ -692,7 +695,7 @@ unsigned long insn_get_seg_base(struct p */ static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx) { - struct desc_struct *desc; + struct desc_struct desc; unsigned long limit; short sel; @@ -706,8 +709,7 @@ static unsigned long get_seg_limit(struc if (!sel) return 0; - desc = get_desc(sel); - if (!desc) + if (!get_desc(&desc, sel)) return 0; /* @@ -716,8 +718,8 @@ static unsigned long get_seg_limit(struc * not tested when checking the segment limits. In practice, * this means that the segment ends in (limit << 12) + 0xfff. */ - limit = get_desc_limit(desc); - if (desc->g) + limit = get_desc_limit(&desc); + if (desc.g) limit = (limit << 12) + 0xfff; return limit; @@ -741,7 +743,7 @@ static unsigned long get_seg_limit(struc */ int insn_get_code_seg_params(struct pt_regs *regs) { - struct desc_struct *desc; + struct desc_struct desc; short sel; if (v8086_mode(regs)) @@ -752,8 +754,7 @@ int insn_get_code_seg_params(struct pt_r if (sel < 0) return sel; - desc = get_desc(sel); - if (!desc) + if (!get_desc(&desc, sel)) return -EINVAL; /* @@ -761,10 +762,10 @@ int insn_get_code_seg_params(struct pt_r * determines whether a segment contains data or code. If this is a data * segment, return error. */ - if (!(desc->type & BIT(3))) + if (!(desc.type & BIT(3))) return -EINVAL; - switch ((desc->l << 1) | desc->d) { + switch ((desc.l << 1) | desc.d) { case 0: /* * Legacy mode. CS.L=0, CS.D=0. Address and operand size are * both 16-bit.