From: Mark Rutland <mark.rutland@arm.com>
To: "Williams, Dan J" <dan.j.williams@intel.com>
Cc: "torvalds@linux-foundation.org" <torvalds@linux-foundation.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"peterz@infradead.org" <peterz@infradead.org>,
"tglx@linutronix.de" <tglx@linutronix.de>,
"alan@linux.intel.com" <alan@linux.intel.com>,
"Reshetova, Elena" <elena.reshetova@intel.com>,
"gnomes@lxorguk.ukuu.org.uk" <gnomes@lxorguk.ukuu.org.uk>,
"gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>,
"jikos@kernel.org" <jikos@kernel.org>,
"linux-arch@vger.kernel.org" <linux-arch@vger.kernel.org>
Subject: Re: [RFC PATCH] asm/generic: introduce if_nospec and nospec_barrier
Date: Thu, 4 Jan 2018 11:47:32 +0000 [thread overview]
Message-ID: <20180104114732.utkixumxt7rfuf3g@salmiak> (raw)
In-Reply-To: <1515035438.20588.4.camel@intel.com>
Hi Dan,
Thanks for these examples.
On Thu, Jan 04, 2018 at 03:10:51AM +0000, Williams, Dan J wrote:
> Note, the following is Elena's work, I'm just helping poke the upstream
> discussion along while she's offline.
>
> Elena audited the static analysis reports down to the following
> locations where userspace provides a value for a conditional branch and
> then later creates a dependent load on that same userspace controlled
> value.
>
> 'osb()', observable memory barrier, resolves to an lfence on x86. My
> concern with these changes is that it is not clear what content within
> the branch block is of concern. Peter's 'if_nospec' proposal combined
> with Mark's 'nospec_load' would seem to clear that up, from a self
> documenting code perspective, and let archs optionally protect entire
> conditional blocks or individual loads within those blocks.
I'm a little concerned by having to use two helpers that need to be paired. It
means that we have to duplicate the bounds information, and I suspect in
practice that they'll often be paired improperly.
I think that we can avoid those problems if we use nospec_ptr() on its own. It
returns NULL if the pointer would be out-of-bounds, so we can use it in the
if-statement.
On x86, that can contain the bounds checks followed be an OSB / lfence, like
if_nospec(). On arm we can use our architected sequence. In either case,
nospec_ptr() returns NULL if the pointer would be out-of-bounds.
Then, rather than sequences like:
if_nospec(idx < max) {
val = nospec_array_load(array, idx, max);
...
}
... we could have:
if ((elem_ptr = nospec_array_ptr(array, idx, max)) {
val = *elem_ptr;
...
}
... which also means we don't have to annotate every single load in the branch
if the element is a structure with multiple fields.
Does that sound workable to you?
From a quick scan, it looks like it would fit all of the example cases below.
Thanks,
Mark.
> Note that these are "a human looked at static analysis reports and
> could not rationalize that these are false positives". Specific domain
> knowledge about these paths may find that some of them are indeed false
> positives.
>
> The change to m_start in kernel/user_namespace.c is interesting because
> that's an example where the nospec_load() approach by itself would need
> to barrier speculation twice whereas if_nospec can do it once for the
> whole block.
>
> [ forgive any whitespace damage ]
>
> 8<---
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 3e7e283a44a8..65175bbe805f 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -821,6 +821,7 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh,
> }
> pin = iterm->id;
> } else if (index < selector->bNrInPins) {
> + osb();
> pin = selector->baSourceID[index];
> list_for_each_entry(iterm, &chain->entities, chain) {
> if (!UVC_ENTITY_IS_ITERM(iterm))
> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
> index 988c8857d78c..cf267b709af6 100644
> --- a/drivers/net/wireless/ath/carl9170/main.c
> +++ b/drivers/net/wireless/ath/carl9170/main.c
> @@ -1388,6 +1388,7 @@ static int carl9170_op_conf_tx(struct ieee80211_hw *hw,
>
> mutex_lock(&ar->mutex);
> if (queue < ar->hw->queues) {
> + osb();
> memcpy(&ar->edcf[ar9170_qmap[queue]], param, sizeof(*param));
> ret = carl9170_set_qos(ar);
> } else {
> diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
> index ab6d39e12069..f024f1ad81ff 100644
> --- a/drivers/net/wireless/intersil/p54/main.c
> +++ b/drivers/net/wireless/intersil/p54/main.c
> @@ -415,6 +415,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev,
>
> mutex_lock(&priv->conf_mutex);
> if (queue < dev->queues) {
> + osb();
> P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
> params->cw_min, params->cw_max, params->txop);
> ret = p54_set_edcf(priv);
> diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
> index 38678e9a0562..b4a2a7ba04e8 100644
> --- a/drivers/net/wireless/st/cw1200/sta.c
> +++ b/drivers/net/wireless/st/cw1200/sta.c
> @@ -619,6 +619,7 @@ int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
> mutex_lock(&priv->conf_mutex);
>
> if (queue < dev->queues) {
> + osb();
> old_uapsd_flags = le16_to_cpu(priv->uapsd_info.uapsd_flags);
>
> WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0);
> diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
> index d5da3981cefe..dec8b6e087e3 100644
> --- a/drivers/scsi/qla2xxx/qla_mr.c
> +++ b/drivers/scsi/qla2xxx/qla_mr.c
> @@ -2304,10 +2304,12 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
> req = ha->req_q_map[que];
>
> /* Validate handle. */
> - if (handle < req->num_outstanding_cmds)
> + if (handle < req->num_outstanding_cmds) {
> + osb();
> sp = req->outstanding_cmds[handle];
> - else
> + } else {
> sp = NULL;
> + }
>
> if (sp == NULL) {
> ql_dbg(ql_dbg_io, vha, 0x3034,
> @@ -2655,10 +2657,12 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha,
> req = ha->req_q_map[que];
>
> /* Validate handle. */
> - if (handle < req->num_outstanding_cmds)
> + if (handle < req->num_outstanding_cmds) {
> + osb();
> sp = req->outstanding_cmds[handle];
> - else
> + } else {
> sp = NULL;
> + }
>
> if (sp == NULL) {
> ql_dbg(ql_dbg_io, vha, 0x3044,
> diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
> index 145a5c53ff5c..d732b34e120d 100644
> --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
> +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
> @@ -57,15 +57,16 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
> if (d->override_ops && d->override_ops->get_trip_temp)
> return d->override_ops->get_trip_temp(zone, trip, temp);
>
> - if (trip < d->aux_trip_nr)
> + if (trip < d->aux_trip_nr) {
> + osb();
> *temp = d->aux_trips[trip];
> - else if (trip == d->crt_trip_id)
> + } else if (trip == d->crt_trip_id) {
> *temp = d->crt_temp;
> - else if (trip == d->psv_trip_id)
> + } else if (trip == d->psv_trip_id) {
> *temp = d->psv_temp;
> - else if (trip == d->hot_trip_id)
> + } else if (trip == d->hot_trip_id) {
> *temp = d->hot_temp;
> - else {
> + } else {
> for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
> if (d->act_trips[i].valid &&
> d->act_trips[i].id == trip) {
> diff --git a/fs/udf/misc.c b/fs/udf/misc.c
> index 401e64cde1be..c5394760d26b 100644
> --- a/fs/udf/misc.c
> +++ b/fs/udf/misc.c
> @@ -104,6 +104,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
> iinfo->i_lenEAttr) {
> uint32_t aal =
> le32_to_cpu(eahd->appAttrLocation);
> +
> + osb();
> memmove(&ea[offset - aal + size],
> &ea[aal], offset - aal);
> offset -= aal;
> @@ -114,6 +116,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
> iinfo->i_lenEAttr) {
> uint32_t ial =
> le32_to_cpu(eahd->impAttrLocation);
> +
> + osb();
> memmove(&ea[offset - ial + size],
> &ea[ial], offset - ial);
> offset -= ial;
> @@ -125,6 +129,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
> iinfo->i_lenEAttr) {
> uint32_t aal =
> le32_to_cpu(eahd->appAttrLocation);
> +
> + osb();
> memmove(&ea[offset - aal + size],
> &ea[aal], offset - aal);
> offset -= aal;
> diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
> index 1c65817673db..dbc12007da51 100644
> --- a/include/linux/fdtable.h
> +++ b/include/linux/fdtable.h
> @@ -82,8 +82,10 @@ static inline struct file *__fcheck_files(struct files_struct *files, unsigned i
> {
> struct fdtable *fdt = rcu_dereference_raw(files->fdt);
>
> - if (fd < fdt->max_fds)
> + if (fd < fdt->max_fds) {
> + osb();
> return rcu_dereference_raw(fdt->fd[fd]);
> + }
> return NULL;
> }
>
> diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
> index 246d4d4ce5c7..aa0be8cef2d4 100644
> --- a/kernel/user_namespace.c
> +++ b/kernel/user_namespace.c
> @@ -648,15 +648,18 @@ static void *m_start(struct seq_file *seq, loff_t *ppos,
> {
> loff_t pos = *ppos;
> unsigned extents = map->nr_extents;
> - smp_rmb();
>
> - if (pos >= extents)
> - return NULL;
> + /* paired with smp_wmb in map_write */
> + smp_rmb();
>
> - if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
> - return &map->extent[pos];
> + if (pos < extents) {
> + osb();
> + if (extents <= UID_GID_MAP_MAX_BASE_EXTENTS)
> + return &map->extent[pos];
> + return &map->forward[pos];
> + }
>
> - return &map->forward[pos];
> + return NULL;
> }
>
> static void *uid_m_start(struct seq_file *seq, loff_t *ppos)
> diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
> index 125c1eab3eaa..56909c8fa025 100644
> --- a/net/ipv4/raw.c
> +++ b/net/ipv4/raw.c
> @@ -476,6 +476,7 @@ static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
> if (offset < rfv->hlen) {
> int copy = min(rfv->hlen - offset, len);
>
> + osb();
> if (skb->ip_summed == CHECKSUM_PARTIAL)
> memcpy(to, rfv->hdr.c + offset, copy);
> else
> diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
> index 761a473a07c5..0942784f3f8d 100644
> --- a/net/ipv6/raw.c
> +++ b/net/ipv6/raw.c
> @@ -729,6 +729,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
> if (offset < rfv->hlen) {
> int copy = min(rfv->hlen - offset, len);
>
> + osb();
> if (skb->ip_summed == CHECKSUM_PARTIAL)
> memcpy(to, rfv->c + offset, copy);
> else
> diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
> index 8ca9915befc8..7f83abdea255 100644
> --- a/net/mpls/af_mpls.c
> +++ b/net/mpls/af_mpls.c
> @@ -81,6 +81,8 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
> if (index < net->mpls.platform_labels) {
> struct mpls_route __rcu **platform_label =
> rcu_dereference(net->mpls.platform_label);
> +
> + osb();
> rt = rcu_dereference(platform_label[index]);
> }
> return rt;
WARNING: multiple messages have this Message-ID (diff)
From: Mark Rutland <mark.rutland@arm.com>
To: "Williams, Dan J" <dan.j.williams@intel.com>
Cc: "torvalds@linux-foundation.org" <torvalds@linux-foundation.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"peterz@infradead.org" <peterz@infradead.org>,
"tglx@linutronix.de" <tglx@linutronix.de>,
"alan@linux.intel.com" <alan@linux.intel.com>,
"Reshetova, Elena" <elena.reshetova@intel.com>,
"gnomes@lxorguk.ukuu.org.uk" <gnomes@lxorguk.ukuu.org.uk>,
"gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>,
"jikos@kernel.org" <jikos@kernel.org>,
"linux-arch@vger.kernel.org" <linux-arch@vger.kernel.org>
Subject: Re: [RFC PATCH] asm/generic: introduce if_nospec and nospec_barrier
Date: Thu, 4 Jan 2018 11:47:32 +0000 [thread overview]
Message-ID: <20180104114732.utkixumxt7rfuf3g@salmiak> (raw)
Message-ID: <20180104114732.4cUHfB-h53Ba1adcUTPO8wG5-zxSjAnlWxiRLcYY6Nk@z> (raw)
In-Reply-To: <1515035438.20588.4.camel@intel.com>
Hi Dan,
Thanks for these examples.
On Thu, Jan 04, 2018 at 03:10:51AM +0000, Williams, Dan J wrote:
> Note, the following is Elena's work, I'm just helping poke the upstream
> discussion along while she's offline.
>
> Elena audited the static analysis reports down to the following
> locations where userspace provides a value for a conditional branch and
> then later creates a dependent load on that same userspace controlled
> value.
>
> 'osb()', observable memory barrier, resolves to an lfence on x86. My
> concern with these changes is that it is not clear what content within
> the branch block is of concern. Peter's 'if_nospec' proposal combined
> with Mark's 'nospec_load' would seem to clear that up, from a self
> documenting code perspective, and let archs optionally protect entire
> conditional blocks or individual loads within those blocks.
I'm a little concerned by having to use two helpers that need to be paired. It
means that we have to duplicate the bounds information, and I suspect in
practice that they'll often be paired improperly.
I think that we can avoid those problems if we use nospec_ptr() on its own. It
returns NULL if the pointer would be out-of-bounds, so we can use it in the
if-statement.
On x86, that can contain the bounds checks followed be an OSB / lfence, like
if_nospec(). On arm we can use our architected sequence. In either case,
nospec_ptr() returns NULL if the pointer would be out-of-bounds.
Then, rather than sequences like:
if_nospec(idx < max) {
val = nospec_array_load(array, idx, max);
...
}
... we could have:
if ((elem_ptr = nospec_array_ptr(array, idx, max)) {
val = *elem_ptr;
...
}
... which also means we don't have to annotate every single load in the branch
if the element is a structure with multiple fields.
Does that sound workable to you?
next prev parent reply other threads:[~2018-01-04 11:47 UTC|newest]
Thread overview: 82+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-03 22:38 [RFC PATCH 0/4] API for inhibiting speculative arbitrary read primitives Mark Rutland
2018-01-03 22:38 ` [RFC PATCH 1/4] asm-generic/barrier: add generic nospec helpers Mark Rutland
2018-01-03 22:38 ` Mark Rutland
2018-01-04 12:00 ` Mark Rutland
2018-01-05 4:21 ` Dan Williams
2018-01-05 9:15 ` Mark Rutland
2018-01-03 22:38 ` [RFC PATCH 2/4] Documentation: document " Mark Rutland
2018-01-03 22:38 ` Mark Rutland
2018-01-03 22:38 ` [RFC PATCH 3/4] arm64: implement nospec_{load,ptr}() Mark Rutland
2018-01-03 22:38 ` Mark Rutland
2018-01-03 22:38 ` [RFC PATCH 4/4] bpf: inhibit speculated out-of-bounds pointers Mark Rutland
2018-01-03 22:38 ` Mark Rutland
2018-01-03 23:45 ` Peter Zijlstra
2018-01-03 23:45 ` Peter Zijlstra
2018-01-04 10:59 ` Mark Rutland
2018-01-04 0:15 ` [RFC PATCH] asm/generic: introduce if_nospec and nospec_barrier Dan Williams
2018-01-04 0:15 ` Dan Williams
2018-01-04 0:39 ` Linus Torvalds
2018-01-04 1:07 ` Alan Cox
2018-01-04 1:13 ` Dan Williams
2018-01-04 1:13 ` Dan Williams
2018-01-04 6:28 ` Julia Lawall
2018-01-04 17:58 ` Dan Williams
2018-01-04 19:26 ` Pavel Machek
2018-01-04 19:26 ` Pavel Machek
2018-01-04 21:43 ` Dan Williams
2018-01-04 22:20 ` Linus Torvalds
2018-01-04 22:23 ` Linus Torvalds
2018-01-04 22:55 ` Alan Cox
2018-01-04 23:06 ` Linus Torvalds
2018-01-04 23:11 ` Alan Cox
2018-01-04 23:11 ` Alan Cox
2018-01-05 0:24 ` Dan Williams
2018-01-04 22:44 ` Pavel Machek
2018-01-04 23:12 ` Dan Williams
2018-01-04 23:12 ` Dan Williams
2018-01-04 23:21 ` Alan Cox
2018-01-04 23:33 ` Pavel Machek
2018-01-05 8:11 ` Julia Lawall
2018-01-04 1:27 ` Jiri Kosina
2018-01-04 1:27 ` Jiri Kosina
2018-01-04 1:41 ` Alan Cox
2018-01-04 1:47 ` Jiri Kosina
2018-01-04 1:47 ` Jiri Kosina
2018-01-04 19:39 ` Pavel Machek
2018-01-04 20:32 ` Alan Cox
2018-01-04 20:32 ` Alan Cox
2018-01-04 20:39 ` Jiri Kosina
2018-01-04 21:23 ` Alan Cox
2018-01-04 21:23 ` Alan Cox
2018-01-04 21:48 ` Pavel Machek
2018-01-04 1:51 ` Dan Williams
2018-01-04 1:51 ` Dan Williams
2018-01-04 1:54 ` Linus Torvalds
2018-01-04 1:54 ` Linus Torvalds
2018-01-04 3:10 ` Williams, Dan J
2018-01-04 4:44 ` Al Viro
2018-01-04 5:44 ` Dan Williams
2018-01-04 5:49 ` Dave Hansen
2018-01-04 5:49 ` Dave Hansen
2018-01-04 5:50 ` Al Viro
2018-01-04 5:55 ` Al Viro
2018-01-04 6:42 ` Dan Williams
2018-01-04 5:01 ` Eric W. Biederman
2018-01-04 6:32 ` Dan Williams
2018-01-04 14:54 ` Eric W. Biederman
2018-01-04 16:39 ` Mark Rutland
2018-01-04 20:56 ` Pavel Machek
2018-01-04 20:56 ` Pavel Machek
2018-01-04 11:47 ` Mark Rutland [this message]
2018-01-04 11:47 ` Mark Rutland
2018-01-04 22:09 ` Dan Williams
2018-01-05 14:40 ` Mark Rutland
2018-01-05 16:44 ` Dan Williams
2018-01-05 18:05 ` Dan Williams
2018-01-04 1:59 ` Jiri Kosina
2018-01-04 1:59 ` Jiri Kosina
2018-01-04 2:15 ` Alan Cox
2018-01-04 3:12 ` Alexei Starovoitov
2018-01-04 9:16 ` Reshetova, Elena
2018-01-04 9:16 ` Reshetova, Elena
2018-01-04 20:40 ` Pavel Machek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180104114732.utkixumxt7rfuf3g@salmiak \
--to=mark.rutland@arm.com \
--cc=alan@linux.intel.com \
--cc=dan.j.williams@intel.com \
--cc=elena.reshetova@intel.com \
--cc=gnomes@lxorguk.ukuu.org.uk \
--cc=gregkh@linuxfoundation.org \
--cc=jikos@kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox