1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Joyent, Inc.
  24  */
  25 /*
  26  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  31 /*        All Rights Reserved   */
  32 
  33 #include <sys/param.h>
  34 #include <sys/types.h>
  35 #include <sys/vmparam.h>
  36 #include <sys/systm.h>
  37 #include <sys/signal.h>
  38 #include <sys/stack.h>
  39 #include <sys/regset.h>
  40 #include <sys/privregs.h>
  41 #include <sys/frame.h>
  42 #include <sys/proc.h>
  43 #include <sys/brand.h>
  44 #include <sys/psw.h>
  45 #include <sys/ucontext.h>
  46 #include <sys/asm_linkage.h>
  47 #include <sys/errno.h>
  48 #include <sys/archsystm.h>
  49 #include <sys/schedctl.h>
  50 #include <sys/debug.h>
  51 #include <sys/sysmacros.h>
  52 #include <sys/sdt.h>
  53 
  54 /*
  55  * Save user context.
  56  */
  57 void
  58 savecontext(ucontext_t *ucp, const k_sigset_t *mask)
  59 {
  60         proc_t *p = ttoproc(curthread);
  61         klwp_t *lwp = ttolwp(curthread);
  62         struct regs *rp = lwptoregs(lwp);
  63 
  64         /*
  65          * We unconditionally assign to every field through the end
  66          * of the gregs, but we need to bzero() everything -after- that
  67          * to avoid having any kernel stack garbage escape to userland.
  68          */
  69         bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext_t) -
  70             offsetof(ucontext_t, uc_mcontext.fpregs));
  71 
  72         ucp->uc_flags = UC_ALL;
  73         ucp->uc_link = (struct ucontext *)lwp->lwp_oldcontext;
  74 
  75         /*
  76          * Try to copyin() the ustack if one is registered. If the stack
  77          * has zero size, this indicates that stack bounds checking has
  78          * been disabled for this LWP. If stack bounds checking is disabled
  79          * or the copyin() fails, we fall back to the legacy behavior.
  80          */
  81         if (lwp->lwp_ustack == (uintptr_t)NULL ||
  82             copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
  83             sizeof (ucp->uc_stack)) != 0 ||
  84             ucp->uc_stack.ss_size == 0) {
  85 
  86                 if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
  87                         ucp->uc_stack = lwp->lwp_sigaltstack;
  88                 } else {
  89                         ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize;
  90                         ucp->uc_stack.ss_size = p->p_stksize;
  91                         ucp->uc_stack.ss_flags = 0;
  92                 }
  93         }
  94 
  95         /*
  96          * If either the trace flag or REQUEST_STEP is set,
  97          * arrange for single-stepping and turn off the trace flag.
  98          */
  99         if ((rp->r_ps & PS_T) || (lwp->lwp_pcb.pcb_flags & REQUEST_STEP)) {
 100                 /*
 101                  * Clear PS_T so that saved user context won't have trace
 102                  * flag set.
 103                  */
 104                 rp->r_ps &= ~PS_T;
 105 
 106                 if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
 107                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 108                         /*
 109                          * trap() always checks DEBUG_PENDING before
 110                          * checking for any pending signal. This at times
 111                          * can potentially lead to DEBUG_PENDING not being
 112                          * honoured. (for eg: the lwp is stopped by
 113                          * stop_on_fault() called from trap(), after being
 114                          * awakened it might see a pending signal and call
 115                          * savecontext(), however on the way back to userland
 116                          * there is no place it can be detected). Hence in
 117                          * anticipation of such occassions, set AST flag for
 118                          * the thread which will make the thread take an
 119                          * excursion through trap() where it will be handled
 120                          * appropriately.
 121                          */
 122                         aston(curthread);
 123                 }
 124         }
 125 
 126         getgregs(lwp, ucp->uc_mcontext.gregs);
 127         if (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN)
 128                 getfpregs(lwp, &ucp->uc_mcontext.fpregs);
 129         else
 130                 ucp->uc_flags &= ~UC_FPU;
 131 
 132         if (mask != NULL) {
 133                 /*
 134                  * Save signal mask.
 135                  */
 136                 sigktou(mask, &ucp->uc_sigmask);
 137         } else {
 138                 ucp->uc_flags &= ~UC_SIGMASK;
 139                 bzero(&ucp->uc_sigmask, sizeof (ucp->uc_sigmask));
 140         }
 141 
 142         if (PROC_IS_BRANDED(p) && BROP(p)->b_savecontext != NULL) {
 143                 /*
 144                  * Allow the brand the chance to modify the context we
 145                  * saved:
 146                  */
 147                 BROP(p)->b_savecontext(ucp);
 148         }
 149 }
 150 
 151 /*
 152  * Restore user context.
 153  */
 154 void
 155 restorecontext(ucontext_t *ucp)
 156 {
 157         kthread_t *t = curthread;
 158         klwp_t *lwp = ttolwp(t);
 159         proc_t *p = lwptoproc(lwp);
 160 
 161         if (PROC_IS_BRANDED(p) && BROP(p)->b_restorecontext != NULL) {
 162                 /*
 163                  * Allow the brand the chance to modify the context before
 164                  * we restore it:
 165                  */
 166                 BROP(p)->b_restorecontext(ucp);
 167         }
 168 
 169         DTRACE_PROBE3(oldcontext__set, klwp_t *, lwp,
 170             uintptr_t, lwp->lwp_oldcontext,
 171             uintptr_t, (uintptr_t)ucp->uc_link);
 172         lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link;
 173 
 174         if (ucp->uc_flags & UC_STACK) {
 175                 if (ucp->uc_stack.ss_flags == SS_ONSTACK)
 176                         lwp->lwp_sigaltstack = ucp->uc_stack;
 177                 else
 178                         lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK;
 179         }
 180 
 181         if (ucp->uc_flags & UC_CPU) {
 182                 /*
 183                  * If the trace flag is set, mark the lwp to take a
 184                  * single-step trap on return to user level (below).
 185                  * The x86 lcall interface and sysenter has already done this,
 186                  * and turned off the flag, but amd64 syscall interface has not.
 187                  */
 188                 if (lwptoregs(lwp)->r_ps & PS_T)
 189                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 190                 setgregs(lwp, ucp->uc_mcontext.gregs);
 191                 lwp->lwp_eosys = JUSTRETURN;
 192                 t->t_post_sys = 1;
 193                 aston(curthread);
 194         }
 195 
 196         if (ucp->uc_flags & UC_FPU)
 197                 setfpregs(lwp, &ucp->uc_mcontext.fpregs);
 198 
 199         if (ucp->uc_flags & UC_SIGMASK) {
 200                 /*
 201                  * We don't need to acquire p->p_lock here;
 202                  * we are manipulating thread-private data.
 203                  */
 204                 schedctl_finish_sigblock(t);
 205                 sigutok(&ucp->uc_sigmask, &t->t_hold);
 206                 if (sigcheck(ttoproc(t), t))
 207                         t->t_sig_check = 1;
 208         }
 209 }
 210 
 211 
 212 int
 213 getsetcontext(int flag, void *arg)
 214 {
 215         ucontext_t uc;
 216         ucontext_t *ucp;
 217         klwp_t *lwp = ttolwp(curthread);
 218         stack_t dummy_stk;
 219         proc_t *p = lwptoproc(lwp);
 220 
 221         /*
 222          * In future releases, when the ucontext structure grows,
 223          * getcontext should be modified to only return the fields
 224          * specified in the uc_flags.  That way, the structure can grow
 225          * and still be binary compatible will all .o's which will only
 226          * have old fields defined in uc_flags
 227          */
 228 
 229         switch (flag) {
 230         default:
 231                 return (set_errno(EINVAL));
 232 
 233         case GETCONTEXT:
 234                 schedctl_finish_sigblock(curthread);
 235                 savecontext(&uc, &curthread->t_hold);
 236                 if (uc.uc_flags & UC_SIGMASK)
 237                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 238                 if (copyout(&uc, arg, sizeof (uc)))
 239                         return (set_errno(EFAULT));
 240                 return (0);
 241 
 242         case SETCONTEXT:
 243                 ucp = arg;
 244                 if (ucp == NULL)
 245                         exit(CLD_EXITED, 0);
 246                 /*
 247                  * Don't copyin filler or floating state unless we need it.
 248                  * The ucontext_t struct and fields are specified in the ABI.
 249                  */
 250                 if (copyin(ucp, &uc, sizeof (ucontext_t) -
 251                     sizeof (uc.uc_filler) -
 252                     sizeof (uc.uc_mcontext.fpregs))) {
 253                         return (set_errno(EFAULT));
 254                 }
 255                 if (uc.uc_flags & UC_SIGMASK)
 256                         SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
 257 
 258                 if ((uc.uc_flags & UC_FPU) &&
 259                     copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
 260                     sizeof (uc.uc_mcontext.fpregs))) {
 261                         return (set_errno(EFAULT));
 262                 }
 263 
 264                 /*
 265                  * If this is a branded process, copy in the brand-private
 266                  * data:
 267                  */
 268                 if (PROC_IS_BRANDED(p) && copyin(&ucp->uc_brand_data,
 269                     &uc.uc_brand_data, sizeof (uc.uc_brand_data)) != 0) {
 270                         return (set_errno(EFAULT));
 271                 }
 272 
 273                 restorecontext(&uc);
 274 
 275                 if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
 276                         (void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack,
 277                             sizeof (uc.uc_stack));
 278                 return (0);
 279 
 280         case GETUSTACK:
 281                 if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t)))
 282                         return (set_errno(EFAULT));
 283                 return (0);
 284 
 285         case SETUSTACK:
 286                 if (copyin(arg, &dummy_stk, sizeof (dummy_stk)))
 287                         return (set_errno(EFAULT));
 288                 lwp->lwp_ustack = (uintptr_t)arg;
 289                 return (0);
 290         }
 291 }
 292 
 293 #ifdef _SYSCALL32_IMPL
 294 
 295 /*
 296  * Save user context for 32-bit processes.
 297  */
 298 void
 299 savecontext32(ucontext32_t *ucp, const k_sigset_t *mask)
 300 {
 301         proc_t *p = ttoproc(curthread);
 302         klwp_t *lwp = ttolwp(curthread);
 303         struct regs *rp = lwptoregs(lwp);
 304 
 305         bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext32_t) -
 306             offsetof(ucontext32_t, uc_mcontext.fpregs));
 307 
 308         ucp->uc_flags = UC_ALL;
 309         ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext;
 310 
 311         if (lwp->lwp_ustack == (uintptr_t)NULL ||
 312             copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
 313             sizeof (ucp->uc_stack)) != 0 ||
 314             ucp->uc_stack.ss_size == 0) {
 315 
 316                 if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
 317                         ucp->uc_stack.ss_sp =
 318                             (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
 319                         ucp->uc_stack.ss_size =
 320                             (size32_t)lwp->lwp_sigaltstack.ss_size;
 321                         ucp->uc_stack.ss_flags = SS_ONSTACK;
 322                 } else {
 323                         ucp->uc_stack.ss_sp = (caddr32_t)(uintptr_t)
 324                             (p->p_usrstack - p->p_stksize);
 325                         ucp->uc_stack.ss_size = (size32_t)p->p_stksize;
 326                         ucp->uc_stack.ss_flags = 0;
 327                 }
 328         }
 329 
 330         /*
 331          * If either the trace flag or REQUEST_STEP is set, arrange
 332          * for single-stepping and turn off the trace flag.
 333          */
 334         if ((rp->r_ps & PS_T) || (lwp->lwp_pcb.pcb_flags & REQUEST_STEP)) {
 335                 /*
 336                  * Clear PS_T so that saved user context won't have trace
 337                  * flag set.
 338                  */
 339                 rp->r_ps &= ~PS_T;
 340 
 341                 if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
 342                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 343                         /*
 344                          * See comments in savecontext().
 345                          */
 346                         aston(curthread);
 347                 }
 348         }
 349 
 350         getgregs32(lwp, ucp->uc_mcontext.gregs);
 351         if (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN)
 352                 getfpregs32(lwp, &ucp->uc_mcontext.fpregs);
 353         else
 354                 ucp->uc_flags &= ~UC_FPU;
 355 
 356         if (mask != NULL) {
 357                 /*
 358                  * Save signal mask.
 359                  */
 360                 sigktou(mask, &ucp->uc_sigmask);
 361         } else {
 362                 ucp->uc_flags &= ~UC_SIGMASK;
 363                 bzero(&ucp->uc_sigmask, sizeof (ucp->uc_sigmask));
 364         }
 365 
 366         if (PROC_IS_BRANDED(p) && BROP(p)->b_savecontext32 != NULL) {
 367                 /*
 368                  * Allow the brand the chance to modify the context we
 369                  * saved:
 370                  */
 371                 BROP(p)->b_savecontext32(ucp);
 372         }
 373 }
 374 
 375 int
 376 getsetcontext32(int flag, void *arg)
 377 {
 378         ucontext32_t uc;
 379         ucontext_t ucnat;
 380         ucontext32_t *ucp;
 381         klwp_t *lwp = ttolwp(curthread);
 382         caddr32_t ustack32;
 383         stack32_t dummy_stk32;
 384         proc_t *p = lwptoproc(lwp);
 385 
 386         switch (flag) {
 387         default:
 388                 return (set_errno(EINVAL));
 389 
 390         case GETCONTEXT:
 391                 schedctl_finish_sigblock(curthread);
 392                 savecontext32(&uc, &curthread->t_hold);
 393                 if (uc.uc_flags & UC_SIGMASK)
 394                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 395                 if (copyout(&uc, arg, sizeof (uc)))
 396                         return (set_errno(EFAULT));
 397                 return (0);
 398 
 399         case SETCONTEXT:
 400                 ucp = arg;
 401                 if (ucp == NULL)
 402                         exit(CLD_EXITED, 0);
 403                 if (copyin(ucp, &uc, sizeof (uc) -
 404                     sizeof (uc.uc_filler) -
 405                     sizeof (uc.uc_mcontext.fpregs))) {
 406                         return (set_errno(EFAULT));
 407                 }
 408                 if (uc.uc_flags & UC_SIGMASK)
 409                         SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
 410                 if ((uc.uc_flags & UC_FPU) &&
 411                     copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
 412                     sizeof (uc.uc_mcontext.fpregs))) {
 413                         return (set_errno(EFAULT));
 414                 }
 415 
 416                 /*
 417                  * If this is a branded process, copy in the brand-private
 418                  * data:
 419                  */
 420                 if (PROC_IS_BRANDED(p) && copyin(&ucp->uc_brand_data,
 421                     &uc.uc_brand_data, sizeof (uc.uc_brand_data)) != 0) {
 422                         return (set_errno(EFAULT));
 423                 }
 424 
 425                 ucontext_32ton(&uc, &ucnat);
 426                 restorecontext(&ucnat);
 427 
 428                 if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
 429                         (void) copyout(&uc.uc_stack,
 430                             (stack32_t *)lwp->lwp_ustack, sizeof (uc.uc_stack));
 431                 return (0);
 432 
 433         case GETUSTACK:
 434                 ustack32 = (caddr32_t)lwp->lwp_ustack;
 435                 if (copyout(&ustack32, arg, sizeof (ustack32)))
 436                         return (set_errno(EFAULT));
 437                 return (0);
 438 
 439         case SETUSTACK:
 440                 if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32)))
 441                         return (set_errno(EFAULT));
 442                 lwp->lwp_ustack = (uintptr_t)arg;
 443                 return (0);
 444         }
 445 }
 446 
 447 #endif  /* _SYSCALL32_IMPL */