diff --git a/sys/kern/imgact_binmisc.c b/sys/kern/imgact_binmisc.c index 9a78d24fe8b..266cf15f6e3 100644 --- a/sys/kern/imgact_binmisc.c +++ b/sys/kern/imgact_binmisc.c @@ -63,8 +63,10 @@ typedef struct imgact_binmisc_entry { uint8_t *ibe_magic; uint8_t *ibe_mask; uint8_t *ibe_interpreter; + ssize_t ibe_interp_offset; uint32_t ibe_interp_argcnt; uint32_t ibe_interp_length; + uint32_t ibe_argv0_cnt; uint32_t ibe_flags; uint32_t ibe_moffset; uint32_t ibe_msize; @@ -154,7 +156,8 @@ imgact_binmisc_populate_interp(char *str, imgact_binmisc_entry_t *ibe) * Allocate memory and populate a new entry for the interpreter table. */ static imgact_binmisc_entry_t * -imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe) +imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe, ssize_t interp_offset, + int argv0_cnt) { imgact_binmisc_entry_t *ibe = NULL; size_t namesz = min(strlen(xbe->xbe_name) + 1, IBE_NAME_MAX); @@ -175,7 +178,8 @@ imgact_binmisc_new_entry(ximgact_binmisc_entry_t *xbe) ibe->ibe_moffset = xbe->xbe_moffset; ibe->ibe_msize = xbe->xbe_msize; ibe->ibe_flags = xbe->xbe_flags; - + ibe->ibe_interp_offset = interp_offset; + ibe->ibe_argv0_cnt = argv0_cnt; return (ibe); } @@ -227,7 +231,8 @@ imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe) { imgact_binmisc_entry_t *ibe; char *p; - int cnt; + ssize_t interp_offset; + int argv0_cnt, cnt; if (xbe->xbe_msize > IBE_MAGIC_MAX) return (EINVAL); @@ -242,23 +247,21 @@ imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe) /* Make sure we don't have any invalid #'s. */ p = xbe->xbe_interpreter; - while (1) { - p = strchr(p, '#'); - if (!p) - break; - + interp_offset = 0; + argv0_cnt = 0; + while ((p = strchr(p, '#')) != NULL) { p++; switch(*p) { case ISM_POUND: /* "##" */ p++; + interp_offset--; break; - case ISM_OLD_ARGV0: /* "#a" */ p++; + argv0_cnt++; break; - case 0: default: /* Anything besides the above is invalid. */ @@ -273,7 +276,7 @@ imgact_binmisc_add_entry(ximgact_binmisc_entry_t *xbe) } /* Preallocate a new entry. */ - ibe = imgact_binmisc_new_entry(xbe); + ibe = imgact_binmisc_new_entry(xbe, interp_offset, argv0_cnt); SLIST_INSERT_HEAD(&interpreter_list, ibe, link); interp_list_entry_count++; @@ -586,12 +589,16 @@ imgact_binmisc_exec(struct image_params *imgp) const char *image_header = imgp->image_header; const char *fname = NULL; int error = 0; - size_t offset, l; +#ifdef INVARIANTS + int argv0_cnt = 0; +#endif + size_t namelen, offset; imgact_binmisc_entry_t *ibe; struct sbuf *sname; char *s, *d; sname = NULL; + namelen = 0; /* Do we have an interpreter for the given image header? */ INTERP_LIST_RLOCK(); if ((ibe = imgact_binmisc_find_interpreter(image_header)) == NULL) { @@ -607,14 +614,22 @@ imgact_binmisc_exec(struct image_params *imgp) imgp->interpreted |= IMGACT_BINMISC; - if (imgp->args->fname != NULL) { - fname = imgp->args->fname; - } else { - /* Use the fdescfs(5) path for fexecve(2). */ - sname = sbuf_new_auto(); - sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd); - sbuf_finish(sname); - fname = sbuf_data(sname); + /* + * Don't bother with the overhead of putting fname together if we're not + * using #a. + */ + if (ibe->ibe_argv0_cnt != 0) { + if (imgp->args->fname != NULL) { + fname = imgp->args->fname; + } else { + /* Use the fdescfs(5) path for fexecve(2). */ + sname = sbuf_new_auto(); + sbuf_printf(sname, "/dev/fd/%d", imgp->args->fd); + sbuf_finish(sname); + fname = sbuf_data(sname); + } + + namelen = strlen(fname); } /* @@ -622,38 +637,14 @@ imgact_binmisc_exec(struct image_params *imgp) * we first shift all the other values in the `begin_argv' area to * provide the exact amount of room for the values added. Set up * `offset' as the number of bytes to be added to the `begin_argv' - * area. + * area. ibe_interp_offset is the fixed offset from macros present in + * the interpreter string. */ - offset = ibe->ibe_interp_length; + offset = ibe->ibe_interp_length + ibe->ibe_interp_offset; - /* Adjust the offset for #'s. */ - s = ibe->ibe_interpreter; - while (1) { - s = strchr(s, '#'); - if (!s) - break; - - s++; - switch(*s) { - case ISM_POUND: - /* "##" -> "#": reduce offset by one. */ - offset--; - break; - - case ISM_OLD_ARGV0: - /* "#a" -> (old argv0): increase offset to fit fname */ - offset += strlen(fname) - 2; - break; - - default: - /* Hmm... This shouldn't happen. */ - printf("%s: Unknown macro #%c sequence in " - "interpreter string\n", KMOD_NAME, *(s + 1)); - error = EINVAL; - goto done; - } - s++; - } + /* Variable offset to be added from macros to the interpreter string. */ + MPASS(ibe->ibe_argv0_cnt == 0 || namelen > 0); + offset += ibe->ibe_argv0_cnt * (namelen - 2); /* Make room for the interpreter */ error = exec_args_adjust_args(imgp->args, 0, offset); @@ -680,26 +671,20 @@ imgact_binmisc_exec(struct image_params *imgp) /* "##": Replace with a single '#' */ *d++ = '#'; break; - case ISM_OLD_ARGV0: /* "#a": Replace with old arg0 (fname). */ - if ((l = strlen(fname)) != 0) { - memcpy(d, fname, l); - d += l; - } + MPASS(ibe->ibe_argv0_cnt >= ++argv0_cnt); + memcpy(d, fname, namelen); + d += namelen; break; - default: - /* Shouldn't happen but skip it if it does. */ - break; + __assert_unreachable(); } break; - case ' ': /* Replace space with NUL to separate arguments. */ *d++ = '\0'; break; - default: *d++ = *s; break; @@ -708,6 +693,8 @@ imgact_binmisc_exec(struct image_params *imgp) } *d = '\0'; + /* Catch ibe->ibe_argv0_cnt counting more #a than we did. */ + MPASS(ibe->ibe_argv0_cnt == argv0_cnt); imgp->interpreter_name = imgp->args->begin_argv; done: