selinux: Avoid dynamic memory allocation for temporary scontext buffers

Common sizes for the scontext buffers are small enough to fit on the stack,
saving two dynamic memory allocations from this hot path.

Change-Id: I9bace557c9ed55cee5c27a29cde4d2c897242c96
Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Signed-off-by: Richard Raya <rdxzv.dev@gmail.com>
This commit is contained in:
Sultan Alsawaf 2023-05-27 14:57:21 -07:00 committed by Richard Raya
parent 5da0bd5621
commit 5500733b43

View File

@ -1494,6 +1494,8 @@ static int security_context_to_sid_core(struct selinux_state *state,
{
struct policydb *policydb;
struct sidtab *sidtab;
char scontext2_onstack[SZ_128] __aligned(sizeof(long));
char str_onstack[SZ_128] __aligned(sizeof(long));
char *scontext2, *str = NULL;
struct context context;
int rc = 0;
@ -1503,9 +1505,15 @@ static int security_context_to_sid_core(struct selinux_state *state,
return -EINVAL;
/* Copy the string to allow changes and ensure a NUL terminator */
scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
if (!scontext2)
return -ENOMEM;
if (scontext_len < sizeof(scontext2_onstack)) {
scontext2 = scontext2_onstack;
memcpy(scontext2, scontext, scontext_len);
scontext2[scontext_len] = '\0';
} else {
scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
if (!scontext2)
return -ENOMEM;
}
if (!state->initialized) {
int i;
@ -1523,10 +1531,16 @@ static int security_context_to_sid_core(struct selinux_state *state,
if (force) {
/* Save another copy for storing in uninterpreted form */
rc = -ENOMEM;
str = kstrdup(scontext2, gfp_flags);
if (!str)
goto out;
if (scontext2 == scontext2_onstack) {
str = str_onstack;
memcpy(str, scontext2, scontext_len + 1);
} else {
str = kstrdup(scontext2, gfp_flags);
if (!str) {
rc = -ENOMEM;
goto out;
}
}
}
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
@ -1535,17 +1549,23 @@ static int security_context_to_sid_core(struct selinux_state *state,
&context, def_sid);
if (rc == -EINVAL && force) {
context.str = str;
context.len = strlen(str) + 1;
context.len = scontext_len + 1;
str = NULL;
} else if (rc)
goto out_unlock;
rc = context_struct_to_sid(state, &context, sid);
if (context.str == str_onstack)
context.str = NULL;
context_destroy(&context);
out_unlock:
read_unlock(&state->ss->policy_rwlock);
out:
kfree(scontext2);
kfree(str);
if (scontext2 != scontext2_onstack) {
kfree(scontext2);
kfree(str);
}
return rc;
}