From patchwork Tue Dec 22 11:46:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Huw Davies X-Patchwork-Id: 7904181 Return-Path: X-Original-To: patchwork-selinux@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1B7C29F349 for ; Tue, 22 Dec 2015 12:00:03 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 20351203C2 for ; Tue, 22 Dec 2015 12:00:02 +0000 (UTC) Received: from emvm-gh1-uea09.nsa.gov (emvm-gh1-uea09.nsa.gov [63.239.67.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E491B20304 for ; Tue, 22 Dec 2015 12:00:00 +0000 (UTC) X-TM-IMSS-Message-ID: <0d1c223400006747@nsa.gov> Received: from tarius.tycho.ncsc.mil ([144.51.242.1]) by nsa.gov ([10.208.42.194]) with ESMTP (TREND IMSS SMTP Service 7.1) id 0d1c223400006747 ; Tue, 22 Dec 2015 07:01:01 -0500 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id tBMBwL2S008083; Tue, 22 Dec 2015 06:58:22 -0500 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id tBMBlai1214457 for ; Tue, 22 Dec 2015 06:47:36 -0500 Received: from goalie.tycho.ncsc.mil (goalie [144.51.242.250]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id tBMBlNwS006814 for ; Tue, 22 Dec 2015 06:47:36 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1ChBADIM3lW/4O9+9heGQEBAg8BAQEBhEmMUa8JhAMHEgWFdoF5AQEBAQEBhW0ZAQE3AYEcIhKILgGsBIVUAQWNSicGkxEMQYE3lwWcR0SNc2SCBA0dFoFAcoUCAQEB X-IPAS-Result: A1ChBADIM3lW/4O9+9heGQEBAg8BAQEBhEmMUa8JhAMHEgWFdoF5AQEBAQEBhW0ZAQE3AYEcIhKILgGsBIVUAQWNSicGkxEMQYE3lwWcR0SNc2SCBA0dFoFAcoUCAQEB X-IronPort-AV: E=Sophos;i="5.20,464,1444708800"; d="scan'208";a="5052970" Received: from emvm-gh1-uea08.nsa.gov ([10.208.42.193]) by goalie.tycho.ncsc.mil with ESMTP; 22 Dec 2015 06:47:35 -0500 X-TM-IMSS-Message-ID: <316b354600093bd2@nsa.gov> Received: from mail.codeweavers.com (mail.codeweavers.com [216.251.189.131]) by nsa.gov ([10.208.42.193]) with ESMTP (TREND IMSS SMTP Service 7.1; TLSv1/SSLv3 DHE-RSA-AES128-SHA (128/128)) id 316b354600093bd2 ; Tue, 22 Dec 2015 06:47:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=codeweavers.com; s=6377696661; h=Message-Id:Date:Subject:Cc:To:From; bh=Vw1pPw+HMo3tbt/fqNXCmbzknWdb6wqkoP8U7MvoTKk=; b=ex7yanGL9dj1vBhk8mHqWEeSe/MlPbwnglp9b77oCE7XaMaiz3TQLnsgnAin7XVLRqsECbc/hQ+tPer9CJAgvtbomc1Hw75Ew91A3oPLfbUYRILLH0Uq801qp66eZ8HEfAW34M5hdBNK7jZvfTR7qhosrQIPELntEwfHu8oY7T4=; Received: from merlot.physics.ox.ac.uk ([163.1.241.98]) by mail.codeweavers.com with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1aBLPg-0000YE-Fr; Tue, 22 Dec 2015 05:47:34 -0600 Received: from daviesh by merlot.physics.ox.ac.uk with local (Exim 4.71) (envelope-from ) id 1aBLPS-0005Jp-K3; Tue, 22 Dec 2015 11:47:18 +0000 From: Huw Davies To: netdev@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@tycho.nsa.gov Subject: [RFC PATCH 08/17] ipv6: Add ipv6_renew_options_kern() that accepts a kernel mem pointer. Date: Tue, 22 Dec 2015 11:46:44 +0000 Message-Id: <1450784813-18304-9-git-send-email-huw@codeweavers.com> X-Mailer: git-send-email 1.8.0 X-Spam-Score: -2.9 X-TM-AS-MML: disable X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=ham 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 The functionality is equivalent to ipv6_renew_options() except that the newopt pointer is in kernel, not user, memory The kernel memory implementation will be used by the CALIPSO network labelling engine, which needs to be able to set IPv6 hop-by-hop options. Signed-off-by: Huw Davies --- include/net/ipv6.h | 6 +++ net/ipv6/exthdrs.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9a5c9f0..5a72ffd 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -304,6 +304,12 @@ struct ipv6_txoptions *ipv6_renew_options(struct sock *sk, int newtype, struct ipv6_opt_hdr __user *newopt, int newoptlen); +struct ipv6_txoptions * +ipv6_renew_options_kern(struct sock *sk, + struct ipv6_txoptions *opt, + int newtype, + struct ipv6_opt_hdr *newopt, + int newoptlen); struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, struct ipv6_txoptions *opt); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index ea7c4d6..9426b26 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -734,11 +734,16 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt) EXPORT_SYMBOL_GPL(ipv6_dup_options); static int ipv6_renew_option(void *ohdr, - struct ipv6_opt_hdr __user *newopt, int newoptlen, + struct ipv6_opt_hdr __user *newopt_user, + struct ipv6_opt_hdr *newopt, + int newoptlen, int inherit, struct ipv6_opt_hdr **hdr, char **p) { + if (WARN_ON_ONCE(newopt_user && newopt)) + return -EINVAL; + if (inherit) { if (ohdr) { memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr)); @@ -746,28 +751,65 @@ static int ipv6_renew_option(void *ohdr, *p += CMSG_ALIGN(ipv6_optlen(*hdr)); } } else { - if (newopt) { - if (copy_from_user(*p, newopt, newoptlen)) + if (newopt_user) { + if (copy_from_user(*p, newopt_user, newoptlen)) return -EFAULT; *hdr = (struct ipv6_opt_hdr *)*p; if (ipv6_optlen(*hdr) > newoptlen) return -EINVAL; *p += CMSG_ALIGN(newoptlen); + } else if (newopt) { + memcpy(*p, newopt, newoptlen); + *hdr = (struct ipv6_opt_hdr *)*p; + if (ipv6_optlen(*hdr) > newoptlen) + return -EINVAL; + *p += CMSG_ALIGN(newoptlen); } } return 0; } -struct ipv6_txoptions * -ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, - int newtype, - struct ipv6_opt_hdr __user *newopt, int newoptlen) +/** + * __ipv6_renew_options - replace a specific ext hdr with a new one. + * + * @sk: sock from which to allocate memory + * @opt: original options + * @newtype: option type to replace in @opt + * @newopt_user: new option of type @newtype to replace (user-mem) + * @newopt: new option of type @newtype to replace (kernel-mem) + * @newoptlen: length of @newopt_user or @newopt + * + * The implementation of ipv6_renew_options() and + * ipv6_renew_options_from_user(). + * + * Returns a new set of options which is a copy of @opt with the + * option type @newtype replaced with either @newopt_user or @newopt. + * Only one of @newopt_user or @newopt may be non-NULL. + * + * @opt may be NULL, in which case a new set of options is returned + * containing just @newopt_user or @newopt. + * + * Both @newopt_user and @newopt may be NULL, in which case the + * specified option type is not copied into the new set of options. + * + * The new set of options is allocated from the socket option memory + * buffer of @sk. + */ +static struct ipv6_txoptions * +__ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, + int newtype, + struct ipv6_opt_hdr __user *newopt_user, + struct ipv6_opt_hdr *newopt, + int newoptlen) { int tot_len = 0; char *p; struct ipv6_txoptions *opt2; int err; + if (WARN_ON_ONCE(newopt_user && newopt)) + return NULL; + if (opt) { if (newtype != IPV6_HOPOPTS && opt->hopopt) tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); @@ -779,7 +821,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); } - if (newopt && newoptlen) + if ((newopt_user || newopt) && newoptlen) tot_len += CMSG_ALIGN(newoptlen); if (!tot_len) @@ -795,25 +837,29 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, opt2->tot_len = tot_len; p = (char *)(opt2 + 1); - err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen, + err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt_user, + newopt, newoptlen, newtype != IPV6_HOPOPTS, &opt2->hopopt, &p); if (err) goto out; - err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen, + err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt_user, + newopt, newoptlen, newtype != IPV6_RTHDRDSTOPTS, &opt2->dst0opt, &p); if (err) goto out; - err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen, + err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt_user, + newopt, newoptlen, newtype != IPV6_RTHDR, (struct ipv6_opt_hdr **)&opt2->srcrt, &p); if (err) goto out; - err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen, + err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt_user, + newopt, newoptlen, newtype != IPV6_DSTOPTS, &opt2->dst1opt, &p); if (err) @@ -830,6 +876,67 @@ out: return ERR_PTR(err); } +/** + * ipv6_renew_options_kern - replace a specific ext hdr with a new one. + * + * @sk: sock from which to allocate memory + * @opt: original options + * @newtype: option type to replace in @opt + * @newopt: new option of type @newtype to replace (kernel-mem) + * @newoptlen: length of or @newopt + * + * Returns a new set of options which is a copy of @opt with the + * option type @newtype replaced with @newopt. + * + * @opt may be NULL, in which case a new set of options is returned + * containing just @newopt. + * + * @newopt may be NULL, in which case the specified option type is not + * copied into the new set of options. + * + * The new set of options is allocated from the socket option memory + * buffer of @sk. + */ +struct ipv6_txoptions * +ipv6_renew_options_kern(struct sock *sk, struct ipv6_txoptions *opt, + int newtype, struct ipv6_opt_hdr *newopt, + int newoptlen) +{ + return __ipv6_renew_options(sk, opt, newtype, + NULL, newopt, newoptlen); +} + +/** + * ipv6_renew_options - replace a specific ext hdr with a new one. + * + * @sk: sock from which to allocate memory + * @opt: original options + * @newtype: option type to replace in @opt + * @newopt_user: new option of type @newtype to replace (user-mem) + * @newoptlen: length of or @newopt + * + * Returns a new set of options which is a copy of @opt with the + * option type @newtype replaced with @newopt_user. + * + * @opt may be NULL, in which case a new set of options is returned + * containing just @newopt_user. + * + * @newopt_user may be NULL, in which case the specified option type is not + * copied into the new set of options. + * + * The new set of options is allocated from the socket option memory + * buffer of @sk. + */ +struct ipv6_txoptions * +ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, + int newtype, + struct ipv6_opt_hdr __user *newopt_user, + int newoptlen) +{ + return __ipv6_renew_options(sk, opt, newtype, + newopt_user, NULL, newoptlen); +} + struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, struct ipv6_txoptions *opt) {