imgact_binmisc: move some calculations out of the exec path
The offset we need to account for in the interpreter string comes in two variants: 1. Fixed - macros other than #a that will not vary from invocation to invocation 2. Variable - #a, which is substitued with the argv0 that we're replacing Note that we don't have a mechanism to modify an existing entry. By recording both of these offset requirements when the interpreter is added, we can avoid some unnecessary calculations in the exec path. Most importantly, we can know up-front whether we need to grab calculate/grab the the filename for this interpreter. We also get to avoid walking the string a first time looking for macros. For most invocations, it's a swift exit as they won't have any, but there's no point entering a loop and searching for the macro indicator if we already know there will not be one. While we're here, go ahead and only calculate the argv0 name length once per invocation. While it's unlikely that we'll have more than one #a, there's no reason to recalculate it every time we encounter an #a when it will not change. I have not bothered trying to benchmark this at all, because it's arguably a minor and straightforward/obvious improvement. MFC after: 1 week
This commit is contained in:
parent
9470af395f
commit
1024ef27fe
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user