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>


   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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 




  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 #include <sys/types.h>
  30 #include <sys/sysmacros.h>
  31 #include <sys/param.h>
  32 #include <sys/vmparam.h>
  33 #include <sys/systm.h>
  34 #include <sys/cred.h>
  35 #include <sys/user.h>
  36 #include <sys/proc.h>
  37 #include <sys/conf.h>
  38 #include <sys/tuneable.h>
  39 #include <sys/cpuvar.h>
  40 #include <sys/archsystm.h>
  41 #include <sys/vmem.h>
  42 #include <vm/seg_kmem.h>
  43 #include <sys/errno.h>
  44 #include <sys/cmn_err.h>
  45 #include <sys/debug.h>


 291         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
 292         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
 293         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
 294 };
 295 
 296 uchar_t bcd_to_byte[256] = {            /* CSTYLED */
 297          0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0,
 298         10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0,  0,  0,  0,  0,
 299         20, 21, 22, 23, 24, 25, 26, 27, 28, 29,  0,  0,  0,  0,  0,  0,
 300         30, 31, 32, 33, 34, 35, 36, 37, 38, 39,  0,  0,  0,  0,  0,  0,
 301         40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  0,  0,  0,  0,  0,  0,
 302         50, 51, 52, 53, 54, 55, 56, 57, 58, 59,  0,  0,  0,  0,  0,  0,
 303         60, 61, 62, 63, 64, 65, 66, 67, 68, 69,  0,  0,  0,  0,  0,  0,
 304         70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  0,  0,  0,  0,  0,  0,
 305         80, 81, 82, 83, 84, 85, 86, 87, 88, 89,  0,  0,  0,  0,  0,  0,
 306         90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
 307 };
 308 
 309 /*
 310  * 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.


 314  * Size must be 1, 2, or 4 bytes with iaddr aligned accordingly.



 315  */
 316 void
 317 hot_patch_kernel_text(caddr_t iaddr, uint32_t new_instr, uint_t size)
 318 {




 319         caddr_t vaddr;
 320         page_t **ppp;
 321         uintptr_t off = (uintptr_t)iaddr & PAGEOFFSET;
 322 
 323         vaddr = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
 324 
 325         (void) as_pagelock(&kas, &ppp, iaddr - off, PAGESIZE, S_WRITE);
 326 
 327         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);

 330 
 331         switch (size) {
 332         case 1:
 333                 *(uint8_t *)(vaddr + off) = new_instr;
 334                 break;
 335         case 2:
 336                 *(uint16_t *)(vaddr + off) = new_instr;
 337                 break;
 338         case 4:
 339                 *(uint32_t *)(vaddr + off) = new_instr;
 340                 break;
 341         default:
 342                 panic("illegal hot-patch");
 343         }
 344 
 345         membar_enter();
 346         sync_icache(vaddr + off, size);
 347         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);
 351 }
 352 
 353 /*
 354  * Routine to report an attempt to execute non-executable data.  If the
 355  * address executed lies in the stack, explicitly say so.
 356  */
 357 void
 358 report_stack_exec(proc_t *p, caddr_t addr)
 359 {
 360         if (!noexec_user_stack_log)
 361                 return;
 362 
 363         if (addr < p->p_usrstack && addr >= (p->p_usrstack - p->p_stksize)) {
 364                 cmn_err(CE_NOTE, "%s[%d] attempt to execute code "
 365                     "on stack by uid %d", p->p_user.u_comm,
 366                     p->p_pid, crgetruid(p->p_cred));
 367         } else {
 368                 cmn_err(CE_NOTE, "%s[%d] attempt to execute non-executable "
 369                     "data at 0x%p by uid %d", p->p_user.u_comm,
 370                     p->p_pid, (void *) addr, crgetruid(p->p_cred));




   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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2019 Joyent, Inc.
  28  */
  29 
  30 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  31 /*        All Rights Reserved   */
  32 
  33 #include <sys/types.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/param.h>
  36 #include <sys/vmparam.h>
  37 #include <sys/systm.h>
  38 #include <sys/cred.h>
  39 #include <sys/user.h>
  40 #include <sys/proc.h>
  41 #include <sys/conf.h>
  42 #include <sys/tuneable.h>
  43 #include <sys/cpuvar.h>
  44 #include <sys/archsystm.h>
  45 #include <sys/vmem.h>
  46 #include <vm/seg_kmem.h>
  47 #include <sys/errno.h>
  48 #include <sys/cmn_err.h>
  49 #include <sys/debug.h>


 295         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
 296         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
 297         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
 298 };
 299 
 300 uchar_t bcd_to_byte[256] = {            /* CSTYLED */
 301          0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0,
 302         10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,  0,  0,  0,  0,  0,
 303         20, 21, 22, 23, 24, 25, 26, 27, 28, 29,  0,  0,  0,  0,  0,  0,
 304         30, 31, 32, 33, 34, 35, 36, 37, 38, 39,  0,  0,  0,  0,  0,  0,
 305         40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  0,  0,  0,  0,  0,  0,
 306         50, 51, 52, 53, 54, 55, 56, 57, 58, 59,  0,  0,  0,  0,  0,  0,
 307         60, 61, 62, 63, 64, 65, 66, 67, 68, 69,  0,  0,  0,  0,  0,  0,
 308         70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  0,  0,  0,  0,  0,  0,
 309         80, 81, 82, 83, 84, 85, 86, 87, 88, 89,  0,  0,  0,  0,  0,  0,
 310         90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
 311 };
 312 
 313 /*
 314  * Hot-patch a single instruction in the kernel's text.
 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  *
 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.
 324  */
 325 void
 326 hot_patch_kernel_text(caddr_t iaddr, uint32_t new_instr, uint_t size)
 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;
 332         caddr_t vaddr;
 333         page_t **ppp;

 334 
 335         vaddr = vmem_alloc(heap_arena, mapsize, VM_SLEEP);
 336 
 337         (void) as_pagelock(&kas, &ppp, ipageaddr, mapsize, S_WRITE);
 338 
 339         hat_devload(kas.a_hat, vaddr, PAGESIZE,
 340             hat_getpfnum(kas.a_hat, ipageaddr), PROT_READ | PROT_WRITE,
 341             HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
 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 
 349         switch (size) {
 350         case 1:
 351                 *(uint8_t *)(vaddr + pageoff) = new_instr;
 352                 break;
 353         case 2:
 354                 *(uint16_t *)(vaddr + pageoff) = new_instr;
 355                 break;
 356         case 4:
 357                 *(uint32_t *)(vaddr + pageoff) = new_instr;
 358                 break;
 359         default:
 360                 panic("illegal hot-patch");
 361         }
 362 
 363         membar_enter();
 364         sync_icache(vaddr + pageoff, size);
 365         sync_icache(iaddr, size);
 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);
 369 }
 370 
 371 /*
 372  * Routine to report an attempt to execute non-executable data.  If the
 373  * address executed lies in the stack, explicitly say so.
 374  */
 375 void
 376 report_stack_exec(proc_t *p, caddr_t addr)
 377 {
 378         if (!noexec_user_stack_log)
 379                 return;
 380 
 381         if (addr < p->p_usrstack && addr >= (p->p_usrstack - p->p_stksize)) {
 382                 cmn_err(CE_NOTE, "%s[%d] attempt to execute code "
 383                     "on stack by uid %d", p->p_user.u_comm,
 384                     p->p_pid, crgetruid(p->p_cred));
 385         } else {
 386                 cmn_err(CE_NOTE, "%s[%d] attempt to execute non-executable "
 387                     "data at 0x%p by uid %d", p->p_user.u_comm,
 388                     p->p_pid, (void *) addr, crgetruid(p->p_cred));