crash of 32-bit powerpc -r347549 kernel built via system-clang-8, _init_tls is where the initial DIAGNOSTICS-reported SIGSEGV happens

Mark Millard marklmi at yahoo.com
Sun Jun 9 20:21:13 UTC 2019


[Never mind: I found exec_setregs /usr/src/sys/powerpc/powerpc/exec_machdep.c
and were it is used.]

On 2019-Jun-9, at 01:49, Mark Millard <marklmi at yahoo.com> wrote:


> So far I've not been able to find the code that is supposed
> to establish the value of environ in /sbin/init as matching
> the value of arginfo->ps_envstr from the exec_copyout_strings
> use by do_execve in the kernel.
> 
> Anyone know where to point me to for what I seem to have
> missed?
> 
> The issue driving the question is having the *sp++ in
> _init_tls code below get SIGSEGV on 32-bit FreeBSD when
> built via system-clang-8 and devel/powerpc64-binutils:
> 
>       sp = (Elf_Addr *) environ;
>       while (*sp++ != 0)
>               ;
> 
> 
> The below is relevant detail that I've found.
> 
> _start in /sbin/init 's instance of lib/csu/powerpc/crt1.c
> calls _init_tls that is from lib/libc/gen/tls.c but first
> might assign to environ :
> 
> . . .
> #include "ignore_init.c"
> . . .
> void
> _start(int argc, char **argv, char **env,
>    const struct Struct_Obj_Entry *obj __unused, void (*cleanup)(void),
>    struct ps_strings *ps_strings)
> {
> 
> 
>        handle_argv(argc, argv, env);
> 
>        if (ps_strings != (struct ps_strings *)0)
>                __ps_strings = ps_strings;
> 
>        if (&_DYNAMIC != NULL)
>                atexit(cleanup);
>        else
>                _init_tls();
> 
> #ifdef GCRT
>        atexit(_mcleanup);
>        monstartup(&eprol, &etext);
> #endif
> 
>        handle_static_init(argc, argv, env);
>        exit(main(argc, argv, env));
> }
> 
> lib/csu/common/ignore_init.c has:
> 
> char **environ;
> . . .
> static inline void
> handle_argv(int argc, char *argv[], char **env)
> {
>        const char *s;
> 
>        if (environ == NULL)
>                environ = env;
>        if (argc > 0 && argv[0] != NULL) {
>                __progname = argv[0];
>                for (s = __progname; *s != '\0'; s++) {
>                        if (*s == '/')
>                                __progname = s + 1;
>                }
>        }
> }
> 
> So _start's char**env argument might be used to assign
> environ. But either way I've not managed to find the
> binding to the kernel exec_copyout_strings operation.
> 
> _init_tls has the *sp++ loop that I referenced earlier:
> 
> extern char **environ;
> 
> void
> _init_tls(void)
> {
> #ifndef PIC
>       Elf_Addr *sp;
>       Elf_Auxinfo *aux, *auxp;
>       Elf_Phdr *phdr;
>       size_t phent, phnum;
>       int i;
>       void *tls;
> 
>       sp = (Elf_Addr *) environ;
>       while (*sp++ != 0)
>               ;
> . . .
> 
> 
> On the kernel side for invoking /sbin/init is . . .
> 
> From /usr/src/sys/sys/imgact.h :
> 
> struct image_args {
>        char *buf;              /* pointer to string buffer */
>        void *bufkva;           /* cookie for string buffer KVA */
>        char *begin_argv;       /* beginning of argv in buf */
>        char *begin_envv;       /* (interal use only) beginning of envv in buf,
>                                 * access with exec_args_get_begin_envv(). */
>        char *endp;             /* current `end' pointer of arg & env strings */
>        char *fname;            /* pointer to filename of executable (system space) */
>        char *fname_buf;        /* pointer to optional malloc(M_TEMP) buffer */
>        int stringspace;        /* space left in arg & env buffer */
>        int argc;               /* count of argument strings */
>        int envc;               /* count of environment strings */
>        int fd;                 /* file descriptor of the executable */
>        struct filedesc *fdp;   /* new file descriptor table */
> };
> 
> do_execve from sys/kern/kern_exec.c has use, including envc
> but avoiding begin_envv (via starting from begin_argv):
> 
> static int
> do_execve(struct thread *td, struct image_args *args, struct mac *mac_p)
> {
> . . .
>        /*
>         * Copy out strings (args and env) and initialize stack base.
>         */
>        stack_base = (*p->p_sysent->sv_copyout_strings)(imgp);
> 
> 
> The exec_copyout_strings code (accessed via ->sv_copyout_strings)
> does
> 
>        stack_base = (register_t *)vectp;
> 
>        stringp = imgp->args->begin_argv;
>        argc = imgp->args->argc;
>        envc = imgp->args->envc;
> . . .
> 
>        /* a null vector table pointer separates the argp's from the envp's */
>        suword(vectp++, 0);
> 
>        suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
>        suword32(&arginfo->ps_nenvstr, envc);
> 
>        /*
>         * Fill in environment portion of vector table.
>         */
>        for (; envc > 0; --envc) {
>                suword(vectp++, (long)(intptr_t)destp);
>                while (*stringp++ != 0)
>                        destp++;
>                destp++;
>        }
> 
>        /* end of vector table is a null pointer */
>        suword(vectp, 0);
> . . .
> 
> (From what I've seen for /sbin/init being invoked, envc==0 .)
> 
> The use involves struct ps_strings from /usr/src/sys/sys/exec.h :
> 
> struct ps_strings {
>        char    **ps_argvstr;   /* first of 0 or more argument strings */
>        unsigned int ps_nargvstr; /* the number of argument strings */
>        char    **ps_envstr;    /* first of 0 or more environment strings */
>        unsigned int ps_nenvstr; /* the number of environment strings */
> };
> 
> 
> The initialization of the begin_envv and envc for much of
> the code seems to trace back to:
> 
> static void
> start_init(void *dummy)
> {
>        struct image_args args;
> . . .
>        while ((path = strsep(&tmp_init_path, ":")) != NULL) {
>                if (bootverbose)
>                        printf("start_init: trying %s\n", path);
> 
>                memset(&args, 0, sizeof(args));
> . . .


I found it:

/usr/src/sys/powerpc/powerpc/exec_machdep.c has
exec_setregs that is accessed (via sv_setregs).
This sets up arguments for _start .



===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)



More information about the freebsd-hackers mailing list