From patchwork Thu Nov 5 00:50:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amanieu d'Antras X-Patchwork-Id: 7556201 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C9292BEEA4 for ; Thu, 5 Nov 2015 00:52:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C561220711 for ; Thu, 5 Nov 2015 00:52:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BF440207F3 for ; Thu, 5 Nov 2015 00:52:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1031605AbbKEAwS (ORCPT ); Wed, 4 Nov 2015 19:52:18 -0500 Received: from mail-wm0-f52.google.com ([74.125.82.52]:38850 "EHLO mail-wm0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1031435AbbKEAv7 (ORCPT ); Wed, 4 Nov 2015 19:51:59 -0500 Received: by wmeg8 with SMTP id g8so275296wme.1; Wed, 04 Nov 2015 16:51:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Fx7h8Si+pR8ORfAegz/WIa01QiMX6IAb7+D/m9pfTYU=; b=QeNyiLA9fKMyn6H8UNUOx1Oh74TknU9QHTkAPoCsUa3l0f4s5+NIE7e7Gn4W8suK1r zx78wz+hK61eYJMuitY41bNGhHbryi3JKLG0+BqGJj57lYV6xzzCTesxZoU/26XeZAiu TxmRd3tb8CpFm7XGYgU65ty94Aq/h8yqEkuldknt7b5tTlfAmioZQDeJWI33QWWE+xBA BTIu1UwzAS6CgQMk8/XeNUmbKoCF1Eb7jZks8kEemWq6zE1/5VlorJeF/ztBlc5/zQgz loJWNLRI4jRDtl736WSIeX6wDaNKFhaGa62r0FDsSxfpsZ1jqCk1wOf2MXdiUd9fvENR 5wAA== X-Received: by 10.28.51.78 with SMTP id z75mr46527wmz.51.1446684718082; Wed, 04 Nov 2015 16:51:58 -0800 (PST) Received: from amanieu-laptop.wireless.ropemaker.crm.lan ([31.205.92.76]) by smtp.gmail.com with ESMTPSA id 194sm5558927wmh.19.2015.11.04.16.51.57 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 04 Nov 2015 16:51:57 -0800 (PST) From: Amanieu d'Antras To: linux-kernel@vger.kernel.org Cc: Oleg Nesterov , Amanieu d'Antras , Alexander Viro , linux-fsdevel@vger.kernel.org Subject: [PATCH v2 19/20] signalfd: Fix some issues in signalfd_copyinfo Date: Thu, 5 Nov 2015 00:50:38 +0000 Message-Id: <1446684640-4112-20-git-send-email-amanieu@gmail.com> X-Mailer: git-send-email 2.6.2 In-Reply-To: <1446684640-4112-1-git-send-email-amanieu@gmail.com> References: <1446684640-4112-1-git-send-email-amanieu@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_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 several issues here: 1) The value of ssi_ptr was incorrect for compat tasks. It was previously copied directly from si_ptr, which contains garbage for 32-bit processes, especially on big-endian architectures. 2) A SIGSYS would cause various fields to be filled with incorrect values. SIGSYS fields are not in signalfd_siginfo, and it should avoid filling in unrelated fields. 3) ssi_ptr and ssi_int should not be filled in for any unrecognized si_code, but only for those generated by sigqueue. The si_ptr and si_int fields in siginfo_t may not be initialized otherwise. 4) ssi_ptr and ssi_addr values for compat tasks did not match those generated by 32-bit kernels. The values need to be sign-extended to 64 bits rather than zero-extended. Signed-off-by: Amanieu d'Antras --- fs/signalfd.c | 58 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/fs/signalfd.c b/fs/signalfd.c index 270221f..1c0bde7 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -80,39 +80,66 @@ static unsigned int signalfd_poll(struct file *file, poll_table *wait) static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, siginfo_t const *kinfo) { - long err; + long err, ssi_ptr, ssi_addr; BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); /* + * ssi_ptr for a compat task should be sourced from si_int instead + * of si_ptr since that is what copy_siginfo_from_user32 and + * get_compat_sigevent use. 32-bit pointer values are sign-extended + * to 64 bits when written to ssi_ptr, which matches the behavior of + * 32-bit kernels. + */ + ssi_ptr = is_compat_task() ? kinfo->si_int : (long) kinfo->si_ptr; + + /* * Unused members should be zero ... */ err = __clear_user(uinfo, sizeof(*uinfo)); /* - * If you change siginfo_t structure, please be sure - * this code is fixed accordingly. + * If you change siginfo_t structure, please be sure that + * all these functions are fixed accordingly: + * copy_siginfo_to_user + * copy_siginfo_to_user32 + * copy_siginfo_from_user32 + * signalfd_copyinfo + * They should never copy any pad contained in the structure + * to avoid security leaks, but must copy the generic + * 3 ints plus the relevant union member. */ err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo); err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno); err |= __put_user((short) kinfo->si_code, &uinfo->ssi_code); + if (kinfo->si_code < 0) { + /* Grab some standard fields for sigqueue()-generated signals */ + err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); + err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); + err |= __put_user(ssi_ptr, &uinfo->ssi_ptr); + err |= __put_user(kinfo->si_int, &uinfo->ssi_int); + return err ? -EFAULT : sizeof(*uinfo); + } switch (kinfo->si_code & __SI_MASK) { case __SI_KILL: err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); break; case __SI_TIMER: - err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); - err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); - err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); - err |= __put_user(kinfo->si_int, &uinfo->ssi_int); + err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); + err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); + err |= __put_user(ssi_ptr, &uinfo->ssi_ptr); + err |= __put_user(kinfo->si_int, &uinfo->ssi_int); break; case __SI_POLL: err |= __put_user(kinfo->si_band, &uinfo->ssi_band); err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd); break; case __SI_FAULT: - err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr); + /* Ensure that ssi_addr is sign-extended to 64 bits */ + ssi_addr = is_compat_task() ? (int)(long) kinfo->si_addr : + (long) kinfo->si_addr; + err |= __put_user(ssi_addr, &uinfo->ssi_addr); #ifdef __ARCH_SI_TRAPNO err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); #endif @@ -139,21 +166,20 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, case __SI_MESGQ: /* But this is */ err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); - err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); + err |= __put_user(ssi_ptr, &uinfo->ssi_ptr); err |= __put_user(kinfo->si_int, &uinfo->ssi_int); break; - default: - /* - * This case catches also the signals queued by sigqueue(). - */ +#ifdef __ARCH_SIGSYS + case __SI_SYS: /* SIGSYS fields are not in signalfd_siginfo */ + break; +#endif + default: /* this is just in case for now ... */ err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); - err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); - err |= __put_user(kinfo->si_int, &uinfo->ssi_int); break; } - return err ? -EFAULT: sizeof(*uinfo); + return err ? -EFAULT : sizeof(*uinfo); } static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,