From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_MSPIKE_H2,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 26447 invoked from network); 25 May 2023 07:53:27 -0000 Received: from second.openwall.net (193.110.157.125) by inbox.vuxu.org with ESMTPUTF8; 25 May 2023 07:53:27 -0000 Received: (qmail 18093 invoked by uid 550); 25 May 2023 07:53:23 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 18055 invoked from network); 25 May 2023 07:53:23 -0000 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.ispras.ru D1C3344C100D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ispras.ru; s=default; t=1685001189; bh=/flKDx1bqrjiWXzW2h6LsAZIwCrH4lhB52Cc/z9A51I=; h=Date:From:To:Subject:Reply-To:From; b=nW/iWGzL1PHQhK6eZ7pLKKJvF6UFwQlQsKD7Sdn0c02MvKgH2OfWrgDUYxZh2TMaI mBDfnWULHCIcQvemQGdN7v1GopFdtc9nf05XN/YK7dQefepuKmQqIE/mrJ0B3YHyPM 2nGK69LnaY7lYIILWrmMDI2wMJZC0hkY67tNzGLs= MIME-Version: 1.0 Date: Thu, 25 May 2023 10:53:09 +0300 From: Alexey Izbyshev To: musl@lists.openwall.com Mail-Followup-To: musl@lists.openwall.com User-Agent: Roundcube Webmail/1.4.4 Message-ID: <4c82138762e69f64a1f95639090edbd8@ispras.ru> X-Sender: izbyshev@ispras.ru Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit Subject: [musl] getopt_long() can corrupt argv when an argument for a short option is missing POSIX requires getopt() to set optind to argc + 1 in case of a missing argument[1], and musl follows it. This bites getopt_long() (which reuses getopt()) in two ways: * getopt_long() moves argv[optind - 1] (NULL) when permuting argv to make all options precede other arguments, essentially corrupting argv. * even when permuting is not required, getopt_long() is both incompatible with glibc (which doesn't increment optind past NULL) and inconsistent with itself (for a long option with a missing argument, musl doesn't increment optind past NULL too). Example of the wrong NULL shifting: #include #include int main(int argc, char *argv[]) { for (int i = 0; i < 2; i++) { int r = getopt_long(argc, argv, "o:", NULL, NULL); printf("r: %d\n", r); printf("optind: %d\n", optind); for (int i = 0; i <= argc; i++) printf("%d: '%s'\n", i, argv[i]); } } With glibc: $ ./a.out arg -o ./a.out: option requires an argument -- 'o' r: 63 optind: 3 0: './a.out' 1: 'arg' 2: '-o' 3: '(null)' r: -1 optind: 2 0: './a.out' 1: '-o' 2: 'arg' 3: '(null)' (Note that glibc permutes argv *before* parsing then next option, and even before comparing optind and argc, so argv is still permuted on the second invocation.) With musl: $ ./a.out arg -o ./a.out: option requires an argument: o r: 63 optind: 3 0: './a.out' 1: '-o' 2: '(null)' 3: 'arg' r: -1 optind: 3 0: './a.out' 1: '-o' 2: '(null)' 3: 'arg' Maybe we could just skip permuting and adjust optind if we detected a missing argument? resumed = optind; ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly); + if (optind > argc) + return optind--, ret; if (resumed > skipped) { On a subsequent invocation we won't permute, unlike glibc, but maybe this is a good thing, given that such permutation makes it look like there is no missing argument, essentially changing the command semantics. Alexey [1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html