svn commit: r323772 - in head/sys: amd64/amd64 i386/i386
Konstantin Belousov
kib at FreeBSD.org
Tue Sep 19 17:57:05 UTC 2017
Author: kib
Date: Tue Sep 19 17:57:04 2017
New Revision: 323772
URL: https://svnweb.freebsd.org/changeset/base/323772
Log:
Do not do torn writes to active LDTs.
Care must be taken when updating the active LDT, since parallel
threads might try to load a segment descriptor which is currently
updated. Since the results are undefined, this cannot be ignored by
claiming to be an application race.
Reviewed by: jhb
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Differential revision: https://reviews.freebsd.org/D12413
Modified:
head/sys/amd64/amd64/sys_machdep.c
head/sys/i386/i386/sys_machdep.c
Modified: head/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- head/sys/amd64/amd64/sys_machdep.c Tue Sep 19 17:12:18 2017 (r323771)
+++ head/sys/amd64/amd64/sys_machdep.c Tue Sep 19 17:57:04 2017 (r323772)
@@ -583,22 +583,22 @@ amd64_get_ldt(td, uap)
}
int
-amd64_set_ldt(td, uap, descs)
- struct thread *td;
- struct i386_ldt_args *uap;
- struct user_segment_descriptor *descs;
+amd64_set_ldt(struct thread *td, struct i386_ldt_args *uap,
+ struct user_segment_descriptor *descs)
{
- int error = 0;
- unsigned int largest_ld, i;
- struct mdproc *mdp = &td->td_proc->p_md;
+ struct mdproc *mdp;
struct proc_ldt *pldt;
struct user_segment_descriptor *dp;
struct proc *p;
+ int error;
+ unsigned int largest_ld, i;
#ifdef DEBUG
printf("amd64_set_ldt: start=%d num=%d descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
+ mdp = &td->td_proc->p_md;
+ error = 0;
set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
p = td->td_proc;
@@ -616,10 +616,9 @@ amd64_set_ldt(td, uap, descs)
largest_ld = max_ldt_segment;
if (largest_ld < uap->start)
return (EINVAL);
- i = largest_ld - uap->start;
mtx_lock(&dt_lock);
- bzero(&((struct user_segment_descriptor *)(pldt->ldt_base))
- [uap->start], sizeof(struct user_segment_descriptor) * i);
+ for (i = uap->start; i < largest_ld; i++)
+ ((uint64_t *)(pldt->ldt_base))[i] = 0;
mtx_unlock(&dt_lock);
return (0);
}
@@ -741,14 +740,18 @@ int
amd64_set_ldt_data(struct thread *td, int start, int num,
struct user_segment_descriptor *descs)
{
- struct mdproc *mdp = &td->td_proc->p_md;
- struct proc_ldt *pldt = mdp->md_ldt;
+ struct mdproc *mdp;
+ struct proc_ldt *pldt;
+ uint64_t *dst, *src;
+ int i;
mtx_assert(&dt_lock, MA_OWNED);
- /* Fill in range */
- bcopy(descs,
- &((struct user_segment_descriptor *)(pldt->ldt_base))[start],
- num * sizeof(struct user_segment_descriptor));
+ mdp = &td->td_proc->p_md;
+ pldt = mdp->md_ldt;
+ dst = (uint64_t *)(pldt->ldt_base);
+ src = (uint64_t *)descs;
+ for (i = 0; i < num; i++)
+ dst[start + i] = src[i];
return (0);
}
Modified: head/sys/i386/i386/sys_machdep.c
==============================================================================
--- head/sys/i386/i386/sys_machdep.c Tue Sep 19 17:12:18 2017 (r323771)
+++ head/sys/i386/i386/sys_machdep.c Tue Sep 19 17:57:04 2017 (r323772)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
+#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/pcb.h>
#include <machine/pcb_ext.h>
@@ -546,7 +547,7 @@ i386_set_ldt(td, uap, descs)
struct i386_ldt_args *uap;
union descriptor *descs;
{
- int error = 0, i;
+ int error, i;
int largest_ld;
struct mdproc *mdp = &td->td_proc->p_md;
struct proc_ldt *pldt;
@@ -556,6 +557,7 @@ i386_set_ldt(td, uap, descs)
printf("i386_set_ldt: start=%d num=%d descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
+ error = 0;
if (descs == NULL) {
/* Free descriptors */
@@ -578,9 +580,9 @@ i386_set_ldt(td, uap, descs)
largest_ld = uap->start + uap->num;
if (largest_ld > pldt->ldt_len)
largest_ld = pldt->ldt_len;
- i = largest_ld - uap->start;
- bzero(&((union descriptor *)(pldt->ldt_base))[uap->start],
- sizeof(union descriptor) * i);
+ for (i = uap->start; i < largest_ld; i++)
+ atomic_store_rel_64(&((uint64_t *)(pldt->ldt_base))[i],
+ 0);
mtx_unlock_spin(&dt_lock);
return (0);
}
@@ -702,17 +704,27 @@ again:
static int
i386_set_ldt_data(struct thread *td, int start, int num,
- union descriptor *descs)
+ union descriptor *descs)
{
- struct mdproc *mdp = &td->td_proc->p_md;
- struct proc_ldt *pldt = mdp->md_ldt;
+ struct mdproc *mdp;
+ struct proc_ldt *pldt;
+ uint64_t *dst, *src;
+ int i;
mtx_assert(&dt_lock, MA_OWNED);
- /* Fill in range */
- bcopy(descs,
- &((union descriptor *)(pldt->ldt_base))[start],
- num * sizeof(union descriptor));
+ mdp = &td->td_proc->p_md;
+ pldt = mdp->md_ldt;
+ dst = (uint64_t *)(pldt->ldt_base);
+ src = (uint64_t *)descs;
+
+ /*
+ * Atomic(9) is used only to get 64bit atomic store with
+ * cmpxchg8b when available. There is no op without release
+ * semantic.
+ */
+ for (i = 0; i < num; i++)
+ atomic_store_rel_64(&dst[start + i], src[i]);
return (0);
}
More information about the svn-src-head
mailing list