2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-22 09:58:09 +00:00

net/sysctl: fix broken ipv4_sysctls_op

We have ability to skip sysctl if there is no value, but we still give
n requests to sysctl_op, that is not correct and probably can segfault
on nullptr access. Fix it by adding ri to count non skipped requests.

To be on the safe side, let's add a check that ri == n on read, as we
should not do any skips there.

While on it lets fix bad error message prefix: s/unix/ipv4/.

Remove excess has_iarg set, and add sarg reset to NULL for the case
sysctl_op skipped it.

Signed-off-by: Andrei Vagin <avagin@google.com>
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
This commit is contained in:
Pavel Tikhomirov 2025-06-10 11:33:59 +08:00 committed by Andrei Vagin
parent d83f5b458a
commit 0f94256bf9

View File

@ -2144,51 +2144,53 @@ static int ipv4_sysctls_op(SysctlEntry ***rsysctl, size_t *pn, int op)
char path[ARRAY_SIZE(ipv4_sysctl_entries)][MAX_IPV4_SYSCTL_PATH] = {}; char path[ARRAY_SIZE(ipv4_sysctl_entries)][MAX_IPV4_SYSCTL_PATH] = {};
struct sysctl_req req[ARRAY_SIZE(ipv4_sysctl_entries)] = {}; struct sysctl_req req[ARRAY_SIZE(ipv4_sysctl_entries)] = {};
SysctlEntry **sysctl = *rsysctl; SysctlEntry **sysctl = *rsysctl;
size_t n = *pn; size_t n = *pn, ri;
if (n != ARRAY_SIZE(ipv4_sysctl_entries)) { if (n != ARRAY_SIZE(ipv4_sysctl_entries)) {
pr_err("unix: Unexpected entries in sysctl (%zu %zu)\n", n, ARRAY_SIZE(ipv4_sysctl_entries)); pr_err("ipv4: Unexpected entries in sysctl (%zu %zu)\n", n, ARRAY_SIZE(ipv4_sysctl_entries));
return -EINVAL; return -EINVAL;
} }
if (opts.weak_sysctls || op == CTL_READ) if (opts.weak_sysctls || op == CTL_READ)
flags = CTL_FLAGS_OPTIONAL; flags = CTL_FLAGS_OPTIONAL;
for (i = 0; i < n; i++) { for (i = 0, ri = 0; i < n; i++) {
snprintf(path[i], MAX_IPV4_SYSCTL_PATH, IPV4_SYSCTL_FMT, ipv4_sysctl_entries[i]); snprintf(path[ri], MAX_IPV4_SYSCTL_PATH, IPV4_SYSCTL_FMT, ipv4_sysctl_entries[i]);
req[i].name = path[i]; req[ri].name = path[ri];
req[i].flags = flags; req[ri].flags = flags;
switch (sysctl[i]->type) { switch (sysctl[i]->type) {
case SYSCTL_TYPE__CTL_STR: case SYSCTL_TYPE__CTL_STR:
req[i].type = CTL_STR(MAX_STR_IPV4_SYSCTL_LEN); req[ri].type = CTL_STR(MAX_STR_IPV4_SYSCTL_LEN);
/* skip write if have no value */ /* skip write if have no value */
if (op == CTL_WRITE && !sysctl[i]->sarg) if (op == CTL_WRITE && !sysctl[i]->sarg)
continue; continue;
req[i].arg = sysctl[i]->sarg; req[ri].arg = sysctl[i]->sarg;
break; break;
default: default:
pr_err("ipv4: Unknown sysctl type %d\n", sysctl[i]->type); pr_err("ipv4: Unknown sysctl type %d\n", sysctl[i]->type);
return -1; return -1;
} }
ri++;
} }
ret = sysctl_op(req, n, op, CLONE_NEWNET); ret = sysctl_op(req, ri, op, CLONE_NEWNET);
if (ret < 0) { if (ret < 0) {
pr_err("unix: Failed to %s %s/<sysctls>\n", (op == CTL_READ) ? "read" : "write", IPV4_SYSCTL_BASE); pr_err("ipv4: Failed to %s %s/<sysctls>\n", (op == CTL_READ) ? "read" : "write", IPV4_SYSCTL_BASE);
return -1; return -1;
} }
if (op == CTL_READ) { if (op == CTL_READ) {
bool has_entries = false; bool has_entries = false;
BUG_ON(ri != n);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (req[i].flags & CTL_FLAGS_HAS) { if (req[i].flags & CTL_FLAGS_HAS) {
sysctl[i]->has_iarg = true;
if (!has_entries)
has_entries = true; has_entries = true;
} else {
sysctl[i]->sarg = NULL;
} }
} }