From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 17-DEC-1990 12:24:37.99
To:	MRGATE::"ARISIA::EVERHART"
CC:	
Subj:	System Service tracing - bug fixes (LONG)

Received:  by crdgw1.ge.com (5.57/GE 1.80)
	 id AA13986; Sun, 16 Dec 90 10:41:05 EST
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Sun, 16 DEC 90 05:55:43 PST
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA20657; Sun, 16 Dec 90 05:31:19 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 14 Dec 90 09:05:32 GMT
From: mcsun!cernvax!chx400!cgch!fizciba-geigy.ch!bnebga@uunet.uu.net  (Gary Nebbett)
Organization: Ciba-Geigy AG, Basel, Switzerland
Subject: System Service tracing - bug fixes (LONG)
Message-Id: <1990Dec14.100415@fizciba-geigy.ch>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

Attached to this message are copies of new or modified routines for
sstrace (a system service tracing program). The changes address the
following problems:

1) In the return path from a system service call register R1 was
   not preserved; this is not important from the majority of
   system services, but routines run via sys$cm%%%% can return
   a value in R1. Tracing sys$system:decw$startlogin would cause
   the system to crash for this reason, for example.

2) The address translation buffer was not flushed after the page
   table entries for the system service vector table were modified.
   The system was only vulnerable when sstrace was deinstalled.

Gary Nebbett


Many comments have been deleted to save space.
---------------------------ssloadg.mar------------------------------
INTERCEPT::
        MOVPSL  R1                  
        EXTZV   #16, #5, R1, R0     
        BNEQ    HIGHIPL             
        EXTZV   #22, #4, R1, R0     
        BNEQ    STACKOK             
        PROBEW  #0, #512, -516(SP)  
        BNEQ    STACKOK             
HIGHIPL:                            
        POPL    R0                  
        ADDL2   #^X121FA, R0        
        JMP     (R0)                
STACKOK:                            
        PUSHL   AP                  
        CALLS   #2, ENTER           
        CALLG   (AP), (R0)          
RETURN:                             
        PUSHL   R1                  
        PUSHL   R0                  
        CALLS   #0, LEAVE           
        POPL    R0                  
        POPL    R1                  
        RET                         
---------------------------sstracem.mar-----------------------------
        .LIBRARY    /SYS$SHARE:LIB.MLB/

LKWSET_START:
        .ENTRY  INVALIDATE_TB, ^M<R2>
        INVALIDATE_TB                   
        RET                             
LKWSET_END:

LKWSET_RANGE::
        .LONG   LKWSET_START, LKWSET_END
---------------------------sstrace.c--------------------------------
static void tidy()
{
    unsigned long status;
    struct ssinfo *ssinfo;

    ssinfo = CTL$GL_SITESPEC; 

    cmkrnl(restore_ptes, &status);
    if (status != SS$_WASSET)
        lib$stop(status);

    if (ssinfo->ss_vectors) {
        cmkrnl(unlock_vec, ssinfo, &status);
        if (status != SS$_WASSET && status != SS$_NORMAL)
            printf("Tidy unlock error %x\n", status);

        p1free(ssinfo->ss_vectors_size, ssinfo->ss_vectors);
    }

    if (ssinfo->ss_file) {
        cmkrnl(close_file, ssinfo->ss_file, &status);
        if (status != SS$_NORMAL)
            printf("Tidy file error %x\n", status);
    }

    if (ssinfo->ss_base) 
        p1free(ssinfo->ss_base_size, ssinfo->ss_base);

    if (ssinfo->ss_info) 
        p1free(ssinfo->ss_info_size, ssinfo->ss_info, &status);

    cmkrnl(clear_sitespec);
}

/* ----------------------------------------------------------------------- */

/*
 * These routines modify page tables; this may cause trouble with cached
 * virtual to physical address translations held in the hardware
 * "Translation Lookaside Buffer" (TLB), so we must flush this
 * buffer. See the INVALIDATE_TB macro in the VMS Device Support 
 * Reference Manual for a description of this process.
 *
 * Failure to flush does not cause any problem when installing the
 * sstrace tables, as address references using the old mapping will
 * just address the intact system supplied vector table. However when
 * deinstalling sstrace, the memory occupied by the sstrace vector
 * tables is freed and is therefore liable to modification - this
 * could cause problems.
 */

/*
 * First make sure that the memory that will hold our modified vector
 * routines is paged aligned. Then set the PFN fields of the PTEs for 
 * the P1 vector pages to have the same value as the PFN fields of the
 * pages holding our modified vector routines.
 *
 * We remember the original PTEs so that we can subsequently restore
 * them.
 *
 * The code to invalidate the TB is locked in the working set in accordance
 * with the advice given in the manual entry for the macro. As we are 
 * changing part of the process private part of the virtual address space
 * which this process should never reference, I do not think that it is
 * necessary to protect the small window between the modification of the
 * PTEs and the flushing of the translation buffer.
 *
 * If an error occurs whilst locking the invalidate_tb code into the
 * working set, we eventually report this back to the user mode code, but
 * we do not let it stop us from completing the installation of sstrace.
 * This is because, as mentioned above, the only consequence of failing
 * to flush the TB is that sstrace will not take immediate effect, but
 * will remain dormant until the relevant address translations are
 * flushed, possibly as a result of a reschedule of the process.
 */

globalref unsigned long lkwset_range[2];

static unsigned long modify_ptes(struct ssinfo *ssinfo, unsigned long *status)
{
    unsigned long *p1br, newpage, result[2];
    struct valid_pte *oldpte, *newpte;
    int pages;

    *status = sys$lkwset(lkwset_range, result, PSL$C_KERNEL);

    newpage = (ssinfo->ss_vectors + 511) & 0xfffffe00;

    p1br = CTL$GL_PHD + PHD$L_P1BR;

    oldpte = (((P1SYSVECTORS - 0x40000000) / 0x200) * 4) + *p1br;
    newpte = (((newpage - 0x40000000) / 0x200) * 4) + *p1br;

    for (pages = 0; pages < (NUMVEC / 64); pages++) {
        ssinfo->ss_saved_pte[pages] = *oldpte;
        (oldpte++)->pfn = (newpte++)->pfn;
    }

    if (*status != SS$_WASCLR) return(SS$_NORMAL);
    invalidate_tb();
    *status = sys$ulwset(lkwset_range, result, PSL$C_KERNEL);

    return(SS$_NORMAL);
}

/*
 * Because the user mode information block has already been copied
 * to the P1 buffer, we must pass the address of the P1 buffer to
 * modify_ptes; we do things in this order so that the switch of
 * vector tables remains the last major operaion performed by the
 * program. 
 */

static void switch_ptes(struct ssinfo *ssinfo)
{
    unsigned long status;

    cmkrnl(modify_ptes, ssinfo->ss_info, &status);
    if (status != SS$_WASSET)
        lib$stop(status);
}

/*
 * Restore the vectors by setting the P1 vector table PTEs to contain
 * the PFNs we saved when we started tracing.
 *
 * Most of the comments about the address translation buffer made above 
 * modify_ptes() also apply here.
 *
 * One difference is that failure to lock the invalidate_tb() code into
 * memory means that we abort the run-down of sstrace. This is because
 * after changing the VA mappings we free the physical memory which
 * previously implemented part of the VA space.
 */

static unsigned long restore_ptes(unsigned long *status)
{
    unsigned long *p1br, result[2];
    struct valid_pte *oldpte;
    int pages;

    *status = sys$lkwset(lkwset_range, result, PSL$C_KERNEL);
    if (*status != SS$_WASCLR) return(SS$_NORMAL);

    p1br = CTL$GL_PHD + PHD$L_P1BR;

    oldpte = (((P1SYSVECTORS - 0x40000000) / 0x200) * 4) + *p1br;

    for (pages = 0; pages < NUMVECPAGES; pages++)
        (oldpte++)->pfn = CTL$GL_SITESPEC->ss_saved_pte[pages].pfn;

    invalidate_tb();

    *status = sys$ulwset(lkwset_range, result, PSL$C_KERNEL);

    return(SS$_NORMAL);
}

