On 04/12/17(Mon) 12:24, Martin Pieuchot wrote:
> Since SMAP is enabled ddb(4)'s 'trace /u' and 'trace /p' for a userland
> processes result, as expected, in page faults.
> 
> Diff below disable SMAP for the duration of the command.  This allows us
> to see any possible frame corruption.

Updated version that:

 - Removes the goto by shuffling parameter tests
 - Initializes cr4save to limit the effect of this gadget. 
 - Skip lcr4() completely if the CPU doesn't support SMAP.

ok?

Index: arch/amd64/amd64/db_trace.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/db_trace.c,v
retrieving revision 1.36
diff -u -p -r1.36 db_trace.c
--- arch/amd64/amd64/db_trace.c 3 Nov 2017 11:29:46 -0000       1.36
+++ arch/amd64/amd64/db_trace.c 5 Dec 2017 10:21:03 -0000
@@ -169,9 +169,11 @@ db_stack_trace_print(db_expr_t addr, boo
        struct callframe *frame, *lastframe;
        unsigned long   *argp, *arg0;
        db_addr_t       callpc;
+       unsigned int    cr4save = CR4_SMEP|CR4_SMAP;
        int             is_trap = 0;
        boolean_t       kernel_only = TRUE;
        boolean_t       trace_proc = FALSE;
+       struct proc     *p;
 
        {
                char *cp = modif;
@@ -185,22 +187,30 @@ db_stack_trace_print(db_expr_t addr, boo
                }
        }
 
+       if (trace_proc) {
+               p = tfind((pid_t)addr);
+               if (p == NULL) {
+                       (*pr) ("not found\n");
+                       return;
+               }
+       }
+
+       cr4save = rcr4();
+       if (cr4save & CR4_SMAP)
+               lcr4(cr4save & ~CR4_SMAP);
+
        if (!have_addr) {
                frame = (struct callframe *)ddb_regs.tf_rbp;
                callpc = (db_addr_t)ddb_regs.tf_rip;
+       } else if (trace_proc) {
+               frame = (struct callframe *)p->p_addr->u_pcb.pcb_rbp;
+               callpc = (db_addr_t)
+                   db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE);
+               frame = (struct callframe *)frame->f_frame;
        } else {
-               if (trace_proc) {
-                       struct proc *p = tfind((pid_t)addr);
-                       if (p == NULL) {
-                               (*pr) ("not found\n");
-                               return;
-                       }
-                       frame = (struct callframe *)p->p_addr->u_pcb.pcb_rbp;
-               } else {
-                       frame = (struct callframe *)addr;
-               }
+               frame = (struct callframe *)addr;
                callpc = (db_addr_t)
-                        db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE);
+                   db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE);
                frame = (struct callframe *)frame->f_frame;
        }
 
@@ -212,8 +222,13 @@ db_stack_trace_print(db_expr_t addr, boo
                db_expr_t       offset;
                Elf_Sym *       sym;
 
-               sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
-               db_symbol_values(sym, &name, NULL);
+               if (INKERNEL(frame)) {
+                       sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+                       db_symbol_values(sym, &name, NULL);
+               } else {
+                       sym = NULL;
+                       name = NULL;
+               }
 
                if (lastframe == 0 && sym == NULL) {
                        /* Symbol not found, peek at code */
@@ -332,6 +347,9 @@ db_stack_trace_print(db_expr_t addr, boo
                db_printsym(callpc, DB_STGY_XTRN, pr);
                (*pr)(":\n");
        }
+
+       if (cr4save & CR4_SMAP)
+               lcr4(cr4save);
 }
 
 void
Index: arch/i386/i386/db_trace.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/db_trace.c,v
retrieving revision 1.31
diff -u -p -r1.31 db_trace.c
--- arch/i386/i386/db_trace.c   3 Nov 2017 11:29:46 -0000       1.31
+++ arch/i386/i386/db_trace.c   5 Dec 2017 10:21:12 -0000
@@ -184,18 +184,17 @@ db_stack_trace_print(db_expr_t addr, boo
        struct callframe *frame, *lastframe;
        int             *argp, *arg0;
        db_addr_t       callpc;
+       unsigned int    cr4save = CR4_SMEP|CR4_SMAP;
        int             is_trap = 0;
        boolean_t       kernel_only = TRUE;
-       boolean_t       trace_thread = FALSE;
        boolean_t       trace_proc = FALSE;
+       struct proc     *p;
 
        {
                char *cp = modif;
                char c;
 
                while ((c = *cp++) != 0) {
-                       if (c == 't')
-                               trace_thread = TRUE;
                        if (c == 'p')
                                trace_proc = TRUE;
                        if (c == 'u')
@@ -206,24 +205,29 @@ db_stack_trace_print(db_expr_t addr, boo
        if (count == -1)
                count = 65535;
 
-       if (!have_addr) {
-               frame = (struct callframe *)ddb_regs.tf_ebp;
-               callpc = (db_addr_t)ddb_regs.tf_eip;
-       } else if (trace_thread) {
-               (*pr) ("%s: can't trace thread\n", __func__);
-       } else if (trace_proc) {
-               struct proc *p = tfind((pid_t)addr);
+       if (trace_proc) {
+               p = tfind((pid_t)addr);
                if (p == NULL) {
                        (*pr) ("not found\n");
                        return;
                }
+       }
+
+       cr4save = rcr4();
+       if (cr4save & CR4_SMAP)
+               lcr4(cr4save & ~CR4_SMAP);
+
+       if (!have_addr) {
+               frame = (struct callframe *)ddb_regs.tf_ebp;
+               callpc = (db_addr_t)ddb_regs.tf_eip;
+       } else if (trace_proc) {
                frame = (struct callframe *)p->p_addr->u_pcb.pcb_ebp;
                callpc = (db_addr_t)
                    db_get_value((int)&frame->f_retaddr, 4, FALSE);
        } else {
                frame = (struct callframe *)addr;
                callpc = (db_addr_t)
-                        db_get_value((int)&frame->f_retaddr, 4, FALSE);
+                   db_get_value((int)&frame->f_retaddr, 4, FALSE);
        }
 
        lastframe = 0;
@@ -233,8 +237,13 @@ db_stack_trace_print(db_expr_t addr, boo
                db_expr_t       offset;
                Elf_Sym         *sym;
 
-               sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
-               db_symbol_values(sym, &name, NULL);
+               if (INKERNEL(frame)) {
+                       sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+                       db_symbol_values(sym, &name, NULL);
+               } else {
+                       sym = NULL;
+                       name = NULL;
+               }
 
                if (lastframe == 0 && sym == NULL) {
                        /* Symbol not found, peek at code */
@@ -306,8 +315,10 @@ db_stack_trace_print(db_expr_t addr, boo
                        }
                } else if (INKERNEL(lastframe)) {
                        /* switch from user to kernel */
-                       if (kernel_only)
+                       if (kernel_only) {
+                               (*pr)("end of kernel\n");
                                break;  /* kernel stack only */
+                       }
                } else {
                        /* in user */
                        if (frame <= lastframe) {
@@ -323,6 +334,9 @@ db_stack_trace_print(db_expr_t addr, boo
                db_printsym(callpc, DB_STGY_XTRN, pr);
                (*pr)(":\n");
        }
+
+       if (cr4save & CR4_SMAP)
+               lcr4(cr4save);
 }
 
 void

Reply via email to