From 287c718f32efc7ecfe375f22897c971bc6831074 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Thu, 5 Oct 2017 12:29:34 +0000 Subject: [PATCH] Improve amd64_get_ldt(). Provide consistent snapshot of the requested descriptors by preventing other threads from modifying LDT while we fetch the data, lock dt_lock around the read. Copy the data into intermediate buffer, which is copied out after the lock is dropped. Use guaranteed atomic (aligned volatile) reads of the descriptors to use same-size atomic as CPU update to set A bit in the descriptor type field. Improve overflow checking for the descriptors range calculations and remove unneeded casts. Reviewed by: bde Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/amd64/amd64/sys_machdep.c | 36 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index 5babbf45e22..9a7de13bdcf 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -550,34 +550,36 @@ user_ldt_deref(struct proc_ldt *pldt) int amd64_get_ldt(struct thread *td, struct i386_ldt_args *uap) { - int error = 0; struct proc_ldt *pldt; - int num; struct user_segment_descriptor *lp; + uint64_t *data; + u_int i, num; + int error; #ifdef DEBUG printf("amd64_get_ldt: start=%u num=%u descs=%p\n", uap->start, uap->num, (void *)uap->descs); #endif - if ((pldt = td->td_proc->p_md.md_ldt) != NULL) { - lp = &((struct user_segment_descriptor *)(pldt->ldt_base)) - [uap->start]; - num = min(uap->num, max_ldt_segment); - } else + if (uap->start >= max_ldt_segment) return (EINVAL); - - if ((uap->start > (unsigned int)max_ldt_segment) || - ((unsigned int)num > (unsigned int)max_ldt_segment) || - ((unsigned int)(uap->start + num) > (unsigned int)max_ldt_segment)) - return(EINVAL); - - error = copyout(lp, uap->descs, num * + num = min(uap->num, max_ldt_segment - uap->start); + pldt = td->td_proc->p_md.md_ldt; + if (pldt == NULL) + return (EINVAL); + lp = &((struct user_segment_descriptor *)(pldt->ldt_base))[uap->start]; + data = malloc(num * sizeof(struct user_segment_descriptor), M_TEMP, + M_WAITOK); + mtx_lock(&dt_lock); + for (i = 0; i < num; i++) + data[i] = ((volatile uint64_t *)lp)[i]; + mtx_unlock(&dt_lock); + error = copyout(data, uap->descs, num * sizeof(struct user_segment_descriptor)); - if (!error) + free(data, M_TEMP); + if (error == 0) td->td_retval[0] = num; - - return(error); + return (error); } int