xref: /openbsd/libexec/ld.so/loader.c (revision db3296cf)
1 /*	$OpenBSD: loader.c,v 1.66 2003/07/09 21:01:10 drahn Exp $ */
2 
3 /*
4  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 
29 #define	_DYN_LOADER
30 
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <sys/exec.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #include <nlist.h>
37 #include <string.h>
38 #include <link.h>
39 
40 #include "syscall.h"
41 #include "archdep.h"
42 #include "resolve.h"
43 #include "sod.h"
44 
45 /*
46  * Local decls.
47  */
48 static char *_dl_getenv(const char *, char **);
49 static void _dl_unsetenv(const char *, char **);
50 unsigned long _dl_boot(const char **, char **, const long, long *);
51 void _dl_debug_state(void);
52 void _dl_setup_env(char **);
53 void _dl_dtors(void);
54 void _dl_boot_bind(const long, long *, Elf_Dyn *);
55 
56 const char *_dl_progname;
57 int  _dl_pagesz;
58 
59 char *_dl_libpath;
60 char *_dl_preload;
61 char *_dl_bindnow;
62 char *_dl_traceld;
63 char *_dl_debug;
64 char *_dl_showmap;
65 char *_dl_norandom;
66 
67 struct r_debug *_dl_debug_map;
68 
69 void _dl_dopreload(char *paths);
70 
71 void
72 _dl_debug_state(void)
73 {
74 	/* Debugger stub */
75 }
76 
77 /*
78  * Routine to walk through all of the objects except the first
79  * (main executable).
80  */
81 void
82 _dl_run_dtors(elf_object_t *object)
83 {
84 	DL_DEB(("doing dtors: [%s]\n", object->load_name));
85 	if (object->dyn.fini)
86 		(*object->dyn.fini)();
87 	if (object->next)
88 		_dl_run_dtors(object->next);
89 }
90 
91 void
92 _dl_dtors(void)
93 {
94 	DL_DEB(("doing dtors\n"));
95 	if (_dl_objects->next)
96 		_dl_run_dtors(_dl_objects->next);
97 }
98 
99 void
100 _dl_dopreload(char *paths)
101 {
102 	char		*cp, *dp;
103 	elf_object_t	*shlib;
104 
105 	dp = paths = _dl_strdup(paths);
106 	if (dp == NULL) {
107 		_dl_printf("preload: out of memory");
108 		_dl_exit(1);
109 	}
110 
111 	while ((cp = _dl_strsep(&dp, ":")) != NULL) {
112 		shlib = _dl_load_shlib(cp, _dl_objects, OBJTYPE_LIB);
113 		if (shlib == NULL) {
114 			_dl_printf("%s: can't load library '%s'\n",
115 			    _dl_progname, cp);
116 			_dl_exit(4);
117 		}
118 		_dl_add_object(shlib);
119 		_dl_link_sub(shlib, _dl_objects);
120 	}
121 	_dl_free(paths);
122 	return;
123 }
124 
125 /*
126  * grab interesting environment variables, zap bad env vars if
127  * issetugid
128  */
129 void
130 _dl_setup_env(char **envp)
131 {
132 	/*
133 	 * Get paths to various things we are going to use.
134 	 */
135 	_dl_libpath = _dl_getenv("LD_LIBRARY_PATH", envp);
136 	_dl_preload = _dl_getenv("LD_PRELOAD", envp);
137 	_dl_bindnow = _dl_getenv("LD_BIND_NOW", envp);
138 	_dl_traceld = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
139 	_dl_debug = _dl_getenv("LD_DEBUG", envp);
140 	_dl_norandom = _dl_getenv("LD_NORANDOM", envp);
141 
142 	/*
143 	 * Don't allow someone to change the search paths if he runs
144 	 * a suid program without credentials high enough.
145 	 */
146 	if (_dl_issetugid()) {	/* Zap paths if s[ug]id... */
147 		if (_dl_libpath) {
148 			_dl_libpath = NULL;
149 			_dl_unsetenv("LD_LIBRARY_PATH", envp);
150 		}
151 		if (_dl_preload) {
152 			_dl_preload = NULL;
153 			_dl_unsetenv("LD_PRELOAD", envp);
154 		}
155 		if (_dl_bindnow) {
156 			_dl_bindnow = NULL;
157 			_dl_unsetenv("LD_BIND_NOW", envp);
158 		}
159 		if (_dl_debug) {
160 			_dl_debug = NULL;
161 			_dl_unsetenv("LD_DEBUG", envp);
162 		}
163 		if (_dl_norandom) {
164 			_dl_norandom = NULL;
165 			_dl_unsetenv("LD_NORANDOM", envp);
166 		}
167 	}
168 }
169 
170 /*
171  * This is the dynamic loader entrypoint. When entering here, depending
172  * on architecture type, the stack and registers are set up according
173  * to the architectures ABI specification. The first thing required
174  * to do is to dig out all information we need to accomplish our task.
175  */
176 unsigned long
177 _dl_boot(const char **argv, char **envp, const long loff, long *dl_data)
178 {
179 	struct elf_object *exe_obj;	/* Pointer to executable object */
180 	struct elf_object *dyn_obj;	/* Pointer to executable object */
181 	struct r_debug **map_link;	/* Where to put pointer for gdb */
182 	struct r_debug *debug_map;
183 	Elf_Dyn *dynp;
184 	elf_object_t *dynobj;
185 	Elf_Phdr *phdp;
186 	char *us = "";
187 	unsigned int i;
188 	int libcnt = 0;
189 
190 	_dl_setup_env(envp);
191 
192 	_dl_progname = argv[0];
193 	if (dl_data[AUX_pagesz] != 0)
194 		_dl_pagesz = dl_data[AUX_pagesz];
195 	else
196 		_dl_pagesz = 4096;
197 
198 	/*
199 	 * now that GOT and PLT has been relocated, and we know
200 	 * page size, protect it from modification
201 	 */
202 	{
203 		extern char *__got_start;
204 		extern char *__got_end;
205 #ifndef __i386__
206 		extern char *__plt_start;
207 		extern char *__plt_end;
208 #endif
209 
210 		_dl_mprotect((void *)ELF_TRUNC((long)&__got_start, _dl_pagesz),
211 		    ELF_ROUND((long)&__got_end,_dl_pagesz) -
212 		    ELF_TRUNC((long)&__got_start, _dl_pagesz),
213 		    GOT_PERMS);
214 
215 #ifndef __i386__
216 		/* only for DATA_PLT or BSS_PLT */
217 		_dl_mprotect((void *)ELF_TRUNC((long)&__plt_start, _dl_pagesz),
218 		    ELF_ROUND((long)&__plt_end,_dl_pagesz) -
219 		    ELF_TRUNC((long)&__plt_start, _dl_pagesz),
220 		    PROT_READ|PROT_EXEC);
221 #endif
222 	}
223 
224 	DL_DEB(("rtld loading: '%s'\n", _dl_progname));
225 
226 	exe_obj = NULL;
227 	/*
228 	 * Examine the user application and set up object information.
229 	 */
230 	phdp = (Elf_Phdr *)dl_data[AUX_phdr];
231 	for (i = 0; i < dl_data[AUX_phnum]; i++) {
232 		if (phdp->p_type == PT_DYNAMIC) {
233 			exe_obj = _dl_finalize_object(argv[0],
234 			    (Elf_Dyn *)phdp->p_vaddr, dl_data, OBJTYPE_EXE,
235 			    0, 0);
236 			_dl_add_object(exe_obj);
237 		} else if (phdp->p_type == PT_INTERP) {
238 			us = _dl_strdup((char *)phdp->p_vaddr);
239 		}
240 		phdp++;
241 	}
242 
243 	if (_dl_preload != NULL)
244 		_dl_dopreload(_dl_preload);
245 
246 	/*
247 	 * Now, pick up and 'load' all libraries required. Start
248 	 * with the first on the list and then do whatever gets
249 	 * added along the tour.
250 	 */
251 	dynobj = _dl_objects;
252 	for (dynobj = _dl_objects; dynobj != NULL; dynobj = dynobj->next) {
253 		DL_DEB(("examining: '%s'\n", dynobj->load_name));
254 		libcnt = 0;
255 		for (dynp = dynobj->load_dyn; dynp->d_tag; dynp++) {
256 			if (dynp->d_tag == DT_NEEDED) {
257 				libcnt++;
258 			}
259 		}
260 		if ( libcnt != 0) {
261 			struct listent {
262 				Elf_Dyn *dynp;
263 				elf_object_t *dynobj;
264 			} *liblist;
265 			int *randomlist;
266 
267 			liblist = _dl_malloc(libcnt * sizeof(struct listent));
268 			randomlist =  _dl_malloc(libcnt * sizeof(int));
269 			if (liblist == NULL)
270 				_dl_exit(5);
271 
272 			for (dynp = dynobj->load_dyn, i = 0;
273 			    dynp->d_tag;
274 			    dynp++) {
275 				if (dynp->d_tag == DT_NEEDED) {
276 					liblist[i++].dynp = dynp;
277 				}
278 
279 			}
280 			/* Randomize these */
281 			for (i = 0; i < libcnt; i++)
282 				randomlist[i] = i;
283 
284 			if (!_dl_norandom)
285 				for (i = 1; i < libcnt; i++) {
286 					unsigned int rnd;
287 					int cur;
288 
289 					rnd = _dl_random();
290 
291 					rnd = rnd % (i+1);
292 
293 					cur = randomlist[rnd];
294 					randomlist[rnd] = randomlist[i];
295 					randomlist[i] = cur;
296 				}
297 
298 			for (i = 0; i < libcnt; i++) {
299 				elf_object_t *depobj;
300 				const char *libname;
301 
302 				libname = dynobj->dyn.strtab;
303 				libname +=
304 				    liblist[randomlist[i]].dynp->d_un.d_val;
305 				DL_DEB(("needs: '%s'\n", libname));
306 				depobj = _dl_load_shlib(libname, dynobj,
307 				    OBJTYPE_LIB);
308 				if (depobj == 0) {
309 					_dl_printf(
310 					    "%s: can't load library '%s'\n",
311 					    _dl_progname, libname);
312 					_dl_exit(4);
313 				}
314 				liblist[randomlist[i]].dynobj = depobj;
315 			}
316 			for (i = 0; i < libcnt; i++) {
317 				_dl_add_object(liblist[i].dynobj);
318 				_dl_link_sub(liblist[i].dynobj, dynobj);
319 			}
320 			_dl_free(liblist);
321 		}
322 	}
323 
324 	/*
325 	 * Now add the dynamic loader itself last in the object list
326 	 * so we can use the _dl_ code when serving dl.... calls.
327 	 */
328 	dynp = (Elf_Dyn *)((void *)_DYNAMIC);
329 	dyn_obj = _dl_finalize_object(us, dynp, 0, OBJTYPE_LDR,
330 	    dl_data[AUX_base], loff);
331 	_dl_add_object(dyn_obj);
332 	dyn_obj->status |= STAT_RELOC_DONE;
333 
334 	/*
335 	 * Everything should be in place now for doing the relocation
336 	 * and binding. Call _dl_rtld to do the job. Fingers crossed.
337 	 */
338 	if (_dl_traceld == NULL)
339 		_dl_rtld(_dl_objects);
340 
341 	/*
342 	 * The first object is the executable itself,
343 	 * it is responsible for running it's own ctors/dtors
344 	 * thus do NOT run the ctors for the executable, all of
345 	 * the shared libraries which follow.
346 	 * Do not run init code if run from ldd.
347 	 */
348 	if ((_dl_traceld == NULL) && (_dl_objects->next != NULL)) {
349 		_dl_objects->status |= STAT_INIT_DONE;
350 		_dl_call_init(_dl_objects);
351 	}
352 
353 	/*
354 	 * Schedule a routine to be run at shutdown, by using atexit.
355 	 * Cannot call atexit directly from ld.so?
356 	 * Do not schedule destructors if run from ldd.
357 	 */
358 	if (_dl_traceld == NULL) {
359 		const Elf_Sym *sym;
360 		Elf_Addr ooff;
361 
362 		sym = NULL;
363 		ooff = _dl_find_symbol("atexit", _dl_objects, &sym,
364 		    SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT, 0, "");
365 		if (sym == NULL)
366 			_dl_printf("cannot find atexit, destructors will not be run!\n");
367 		else
368 			(*(void (*)(Elf_Addr))(sym->st_value + ooff))
369 			    ((Elf_Addr)_dl_dtors);
370 	}
371 
372 	/*
373 	 * Finally make something to help gdb when poking around in the code.
374 	 */
375 #ifdef __mips__
376 	map_link = (struct r_debug **)(exe_obj->Dyn.info[DT_MIPS_RLD_MAP -
377 	    DT_LOPROC + DT_NUM]);
378 #else
379 	map_link = NULL;
380 	for (dynp = exe_obj->load_dyn; dynp->d_tag; dynp++) {
381 		if (dynp->d_tag == DT_DEBUG) {
382 			map_link = (struct r_debug **)&dynp->d_un.d_ptr;
383 			break;
384 		}
385 	}
386 	if (dynp->d_tag != DT_DEBUG)
387 		DL_DEB(("failed to mark DTDEBUG\n"));
388 #endif
389 	if (map_link) {
390 		debug_map = (struct r_debug *)_dl_malloc(sizeof(*debug_map));
391 		debug_map->r_version = 1;
392 		debug_map->r_map = (struct link_map *)_dl_objects;
393 		debug_map->r_brk = (Elf_Addr)_dl_debug_state;
394 		debug_map->r_state = RT_CONSISTENT;
395 		debug_map->r_ldbase = loff;
396 		_dl_debug_map = debug_map;
397 		*map_link = _dl_debug_map;
398 	}
399 
400 	_dl_debug_state();
401 
402 	if (_dl_debug || _dl_traceld) {
403 		_dl_show_objects();
404 		DL_DEB(("dynamic loading done.\n"));
405 	}
406 	if (_dl_traceld)
407 		_dl_exit(0);
408 
409 	DL_DEB(("entry point: 0x%lx\n", dl_data[AUX_entry]));
410 	/*
411 	 * Return the entry point.
412 	 */
413 	return(dl_data[AUX_entry]);
414 }
415 
416 void
417 _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp)
418 {
419 	struct elf_object  dynld;	/* Resolver data for the loader */
420 	AuxInfo		*auxstack;
421 	long		*stack;
422 	Elf_Dyn		*dynp;
423 	int		n, argc;
424 	char **argv, **envp;
425 	long loff;
426 
427 	/*
428 	 * Scan argument and environment vectors. Find dynamic
429 	 * data vector put after them.
430 	 */
431 	stack = (long *)sp;
432 	argc = *stack++;
433 	argv = (char **)stack;
434 	envp = &argv[argc + 1];
435 	stack = (long *)envp;
436 	while (*stack++ != NULL)
437 		;
438 
439 	/*
440 	 * Zero out dl_data.
441 	 */
442 	for (n = 0; n < AUX_entry; n++)
443 		dl_data[n] = 0;
444 
445 	/*
446 	 * Dig out auxiliary data set up by exec call. Move all known
447 	 * tags to an indexed local table for easy access.
448 	 */
449 	for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null;
450 	    auxstack++) {
451 		if (auxstack->au_id > AUX_entry)
452 			continue;
453 		dl_data[auxstack->au_id] = auxstack->au_v;
454 	}
455 	loff = dl_data[AUX_base];	/* XXX assumes linked at 0x0 */
456 
457 	/*
458 	 * We need to do 'selfreloc' in case the code weren't
459 	 * loaded at the address it was linked to.
460 	 *
461 	 * Scan the DYNAMIC section for the loader.
462 	 * Cache the data for easier access.
463 	 */
464 
465 #if defined(__alpha__)
466 	dynp = (Elf_Dyn *)((long)_DYNAMIC);
467 #elif defined(__sparc__) || defined(__sparc64__) || defined(__powerpc__)
468 	dynp = dynamicp;
469 #else
470 	dynp = (Elf_Dyn *)((long)_DYNAMIC + loff);
471 #endif
472 	while (dynp != NULL && dynp->d_tag != DT_NULL) {
473 		if (dynp->d_tag < DT_NUM)
474 			dynld.Dyn.info[dynp->d_tag] = dynp->d_un.d_val;
475 		else if (dynp->d_tag >= DT_LOPROC &&
476 		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
477 			dynld.Dyn.info[dynp->d_tag - DT_LOPROC + DT_NUM] =
478 			    dynp->d_un.d_val;
479 		if (dynp->d_tag == DT_TEXTREL)
480 			dynld.dyn.textrel = 1;
481 		dynp++;
482 	}
483 
484 	/*
485 	 * Do the 'bootstrap relocation'. This is really only needed if
486 	 * the code was loaded at another location than it was linked to.
487 	 * We don't do undefined symbols resolving (to difficult..)
488 	 */
489 
490 	/* "relocate" dyn.X values if they represent addresses */
491 	{
492 		int i, val;
493 		/* must be code, not pic data */
494 		int table[20];
495 
496 		i = 0;
497 		table[i++] = DT_PLTGOT;
498 		table[i++] = DT_HASH;
499 		table[i++] = DT_STRTAB;
500 		table[i++] = DT_SYMTAB;
501 		table[i++] = DT_RELA;
502 		table[i++] = DT_INIT;
503 		table[i++] = DT_FINI;
504 		table[i++] = DT_REL;
505 		table[i++] = DT_JMPREL;
506 		/* other processors insert their extras here */
507 		table[i++] = DT_NULL;
508 		for (i = 0; table[i] != DT_NULL; i++) {
509 			val = table[i];
510 			if (val > DT_HIPROC) /* ??? */
511 				continue;
512 			if (val > DT_LOPROC)
513 				val -= DT_LOPROC + DT_NUM;
514 			if (dynld.Dyn.info[val] != 0)
515 				dynld.Dyn.info[val] += loff;
516 		}
517 	}
518 
519 	{
520 		u_int32_t rs;
521 		Elf_Rel *rp;
522 		int	i;
523 
524 		rp = (Elf_Rel *)(dynld.Dyn.info[DT_REL]);
525 		rs = dynld.dyn.relsz;
526 
527 		for (i = 0; i < rs; i += sizeof (Elf_Rel)) {
528 			Elf_Addr *ra;
529 			const Elf_Sym *sp;
530 
531 			sp = dynld.dyn.symtab;
532 			sp += ELF_R_SYM(rp->r_info);
533 
534 			if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) {
535 #if 0
536 /* cannot printf in this function */
537 				_dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n");
538 				_dl_wrstderr("Undefined symbol: ");
539 				_dl_wrstderr((char *)dynld.dyn.strtab +
540 				    sp->st_name);
541 #endif
542 				_dl_exit(5);
543 			}
544 
545 			ra = (Elf_Addr *)(rp->r_offset + loff);
546 			RELOC_REL(rp, sp, ra, loff);
547 			rp++;
548 		}
549 	}
550 
551 	for (n = 0; n < 2; n++) {
552 		unsigned long rs;
553 		Elf_RelA *rp;
554 		int	i;
555 
556 		switch (n) {
557 		case 0:
558 			rp = (Elf_RelA *)(dynld.Dyn.info[DT_JMPREL]);
559 			rs = dynld.dyn.pltrelsz;
560 			break;
561 		case 1:
562 			rp = (Elf_RelA *)(dynld.Dyn.info[DT_RELA]);
563 			rs = dynld.dyn.relasz;
564 			break;
565 		default:
566 			rp = NULL;
567 			rs = 0;
568 		}
569 		for (i = 0; i < rs; i += sizeof (Elf_RelA)) {
570 			Elf_Addr *ra;
571 			const Elf_Sym *sp;
572 
573 			sp = dynld.dyn.symtab;
574 			sp += ELF_R_SYM(rp->r_info);
575 			if (ELF_R_SYM(rp->r_info) && sp->st_value == 0) {
576 #if 0
577 				_dl_wrstderr("Dynamic loader failure: self bootstrapping impossible.\n");
578 				_dl_wrstderr("Undefined symbol: ");
579 				_dl_wrstderr((char *)dynld.dyn.strtab +
580 				    sp->st_name);
581 #endif
582 				_dl_exit(6);
583 			}
584 
585 			ra = (Elf_Addr *)(rp->r_offset + loff);
586 			RELOC_RELA(rp, sp, ra, loff);
587 			rp++;
588 		}
589 	}
590 
591 	RELOC_GOT(&dynld, loff);
592 
593 	/*
594 	 * we have been fully relocated here, so most things no longer
595 	 * need the loff adjustment
596 	 */
597 }
598 
599 void
600 _dl_rtld(elf_object_t *object)
601 {
602 	if (object->next)
603 		_dl_rtld(object->next);
604 
605 	if (object->status & STAT_RELOC_DONE)
606 		return;
607 
608 	/*
609 	 * Do relocation information first, then GOT.
610 	 */
611 	_dl_md_reloc(object, DT_REL, DT_RELSZ);
612 	_dl_md_reloc(object, DT_RELA, DT_RELASZ);
613 	_dl_md_reloc_got(object, !(_dl_bindnow || object->dyn.bind_now));
614 	object->status |= STAT_RELOC_DONE;
615 }
616 
617 void
618 _dl_call_init(elf_object_t *object)
619 {
620 	struct dep_node *n;
621 
622 	for (n = object->first_child; n; n = n->next_sibling) {
623 		if (n->data->status & STAT_INIT_DONE)
624 			continue;
625 		_dl_call_init(n->data);
626 	}
627 
628 	if (object->status & STAT_INIT_DONE)
629 		return;
630 
631 	DL_DEB(("doing ctors: [%s]\n", object->load_name));
632 	if (object->dyn.init)
633 		(*object->dyn.init)();
634 
635 	/* What about loops? */
636 	object->status |= STAT_INIT_DONE;
637 }
638 
639 static char *
640 _dl_getenv(const char *var, char **env)
641 {
642 	const char *ep;
643 
644 	while ((ep = *env++)) {
645 		const char *vp = var;
646 
647 		while (*vp && *vp == *ep) {
648 			vp++;
649 			ep++;
650 		}
651 		if (*vp == '\0' && *ep++ == '=')
652 			return((char *)ep);
653 	}
654 	return(NULL);
655 }
656 
657 static void
658 _dl_unsetenv(const char *var, char **env)
659 {
660 	char *ep;
661 
662 	while ((ep = *env)) {
663 		const char *vp = var;
664 
665 		while (*vp && *vp == *ep) {
666 			vp++;
667 			ep++;
668 		}
669 		if (*vp == '\0' && *ep++ == '=') {
670 			char **P;
671 
672 			for (P = env;; ++P)
673 				if (!(*P = *(P + 1)))
674 					break;
675 		}
676 		env++;
677 	}
678 }
679