|
|
Message-ID: <87bjjv3s9l.fsf@lin.moe>
Date: Fri, 19 Dec 2025 14:22:30 +0800
From: Linsen Zhou <i@....moe>
To: musl@...ts.openwall.com
Subject: Bug Report: getopt_long incorrectly permutes argv[argc] (NULL) into
argv
While debugging a `smartctl -l` segfault on Alpine[1], I identified a
scenario where the NULL terminator at argv[argc] is incorrectly permuted
into the middle of the argv array.
The issue occurs when the following two conditions are met:
+ A long option is defined with the `required_argument` flag.
+ `getopt_long` is called with that flag, but the required argument is missing.
In this case, argv[argc] (the NULL terminator) is swapped into the
middle of the argv array.
Reproduction Example:
=====================
#include <getopt.h>
#include <stdio.h>
int argc = 3;
char *argv[] = {"cmd_name", "argument1", "-l", 0, "env1=val1"};
void show_argv() {
for (int i = 0; i < 5; i++) {
printf("%s(%p) ", argv[i] == NULL ? "NULL":argv[i], argv[i] );
}
printf("\n");
}
int main() {
static struct option long_opts[] = {
{"log", required_argument, 0, 'l'},
{0, 0, 0, 0},
};
int optidx = 0;
show_argv(); getopt_long(argc, argv, "l:", long_opts, &optidx); show_argv();
}
=====================
$ ./main
cmd_name(0x55617b5c8000) argument1(0x55617b5c8009) -l(0x55617b5c8013) NULL(0) env1=val1(0x55617b5c8016)
cmd_name: option requires an argument: l
optind: 3
cmd_name(0x55617b5c8000) -l(0x55617b5c8013) NULL(0) argument1(0x55617b5c8009) env1=val1(0x55617b5c8016)
=====================
The issue appears to stem from getopt_long.c. After calling
__getopt_long_core, optind can become greater than argc (e.g., reaching
4 when argc is 3).
=====================
static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly){
...
ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
if (resumed > skipped) {
int i, cnt = optind-resumed;
for (i=0; i<cnt; i++)
permute(argv, skipped, optind-1);
optind = skipped + cnt;
}
...
}
=====================
When optind exceeds argc, the permute function includes the NULL
terminator at argv[argc] in its rotation logic, pushing it into the
active indices of argv.
[1] https://gitlab.alpinelinux.org/alpine/aports/-/issues/15948
--
Regards, Linsen Zhou
https://lin.moe
Download attachment "signature.asc" of type "application/pgp-signature" (244 bytes)
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.