Print this page
10907 hot_patch_kernel_text() has no respect for boundaries
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/os/subr.c
          +++ new/usr/src/uts/common/os/subr.c
↓ open down ↓ 15 lines elided ↑ open up ↑
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
       26 +/*
       27 + * Copyright 2019 Joyent, Inc.
       28 + */
       29 +
  26   30  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27      -/*        All Rights Reserved   */
       31 +/*        All Rights Reserved   */
  28   32  
  29   33  #include <sys/types.h>
  30   34  #include <sys/sysmacros.h>
  31   35  #include <sys/param.h>
  32   36  #include <sys/vmparam.h>
  33   37  #include <sys/systm.h>
  34   38  #include <sys/cred.h>
  35   39  #include <sys/user.h>
  36   40  #include <sys/proc.h>
  37   41  #include <sys/conf.h>
↓ open down ↓ 263 lines elided ↑ open up ↑
 301  305          40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  0,  0,  0,  0,  0,  0,
 302  306          50, 51, 52, 53, 54, 55, 56, 57, 58, 59,  0,  0,  0,  0,  0,  0,
 303  307          60, 61, 62, 63, 64, 65, 66, 67, 68, 69,  0,  0,  0,  0,  0,  0,
 304  308          70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  0,  0,  0,  0,  0,  0,
 305  309          80, 81, 82, 83, 84, 85, 86, 87, 88, 89,  0,  0,  0,  0,  0,  0,
 306  310          90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
 307  311  };
 308  312  
 309  313  /*
 310  314   * Hot-patch a single instruction in the kernel's text.
 311      - * If you want to patch multiple instructions you must
 312      - * arrange to do it so that all intermediate stages are
 313      - * sane -- we don't stop other cpus while doing this.
      315 + *
      316 + * If you want to patch multiple instructions you must arrange to do it so that
      317 + * all intermediate stages are sane -- we don't stop other cpus while doing
      318 + * this.
      319 + *
 314  320   * Size must be 1, 2, or 4 bytes with iaddr aligned accordingly.
      321 + *
      322 + * The instruction itself might straddle a page boundary, so we have to account
      323 + * for that.
 315  324   */
 316  325  void
 317  326  hot_patch_kernel_text(caddr_t iaddr, uint32_t new_instr, uint_t size)
 318  327  {
      328 +        const uintptr_t pageoff = (uintptr_t)iaddr & PAGEOFFSET;
      329 +        const boolean_t straddles = (pageoff + size > PAGESIZE);
      330 +        const size_t mapsize = straddles ? PAGESIZE * 2 : PAGESIZE;
      331 +        caddr_t ipageaddr = iaddr - pageoff;
 319  332          caddr_t vaddr;
 320  333          page_t **ppp;
 321      -        uintptr_t off = (uintptr_t)iaddr & PAGEOFFSET;
 322  334  
 323      -        vaddr = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
      335 +        vaddr = vmem_alloc(heap_arena, mapsize, VM_SLEEP);
 324  336  
 325      -        (void) as_pagelock(&kas, &ppp, iaddr - off, PAGESIZE, S_WRITE);
      337 +        (void) as_pagelock(&kas, &ppp, ipageaddr, mapsize, S_WRITE);
 326  338  
 327  339          hat_devload(kas.a_hat, vaddr, PAGESIZE,
 328      -            hat_getpfnum(kas.a_hat, iaddr - off),
 329      -            PROT_READ | PROT_WRITE, HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
      340 +            hat_getpfnum(kas.a_hat, ipageaddr), PROT_READ | PROT_WRITE,
      341 +            HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
 330  342  
      343 +        if (straddles) {
      344 +                hat_devload(kas.a_hat, vaddr + PAGESIZE, PAGESIZE,
      345 +                    hat_getpfnum(kas.a_hat, ipageaddr + PAGESIZE),
      346 +                    PROT_READ | PROT_WRITE, HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
      347 +        }
      348 +
 331  349          switch (size) {
 332  350          case 1:
 333      -                *(uint8_t *)(vaddr + off) = new_instr;
      351 +                *(uint8_t *)(vaddr + pageoff) = new_instr;
 334  352                  break;
 335  353          case 2:
 336      -                *(uint16_t *)(vaddr + off) = new_instr;
      354 +                *(uint16_t *)(vaddr + pageoff) = new_instr;
 337  355                  break;
 338  356          case 4:
 339      -                *(uint32_t *)(vaddr + off) = new_instr;
      357 +                *(uint32_t *)(vaddr + pageoff) = new_instr;
 340  358                  break;
 341  359          default:
 342  360                  panic("illegal hot-patch");
 343  361          }
 344  362  
 345  363          membar_enter();
 346      -        sync_icache(vaddr + off, size);
      364 +        sync_icache(vaddr + pageoff, size);
 347  365          sync_icache(iaddr, size);
 348      -        as_pageunlock(&kas, ppp, iaddr - off, PAGESIZE, S_WRITE);
 349      -        hat_unload(kas.a_hat, vaddr, PAGESIZE, HAT_UNLOAD_UNLOCK);
 350      -        vmem_free(heap_arena, vaddr, PAGESIZE);
      366 +        as_pageunlock(&kas, ppp, ipageaddr, mapsize, S_WRITE);
      367 +        hat_unload(kas.a_hat, vaddr, mapsize, HAT_UNLOAD_UNLOCK);
      368 +        vmem_free(heap_arena, vaddr, mapsize);
 351  369  }
 352  370  
 353  371  /*
 354  372   * Routine to report an attempt to execute non-executable data.  If the
 355  373   * address executed lies in the stack, explicitly say so.
 356  374   */
 357  375  void
 358  376  report_stack_exec(proc_t *p, caddr_t addr)
 359  377  {
 360  378          if (!noexec_user_stack_log)
↓ open down ↓ 56 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX