From patchwork Mon Jun 22 15:13:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1314522 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=libc-alpha-bounces@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=sourceware.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=oysBVMBb; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49rCcl4BwSz9s6w for ; Tue, 23 Jun 2020 01:14:31 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D35EF389853E; Mon, 22 Jun 2020 15:14:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D35EF389853E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1592838860; bh=AKjhWqzl0kPyp+T0z2lA9sGysPtiiHuxwCl8T2ZIZmQ=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=oysBVMBb80ObmvcbPxs0jzjZB2YVLT1B4r94Q67dI9GxqJUUk5JDsli3MSOgv6k3y FkWoXPFurK+oQzMiRRIHsuO+72b9rIYKu6+B2yDmOySeNKQ79MqKDexP49pRVrhrEm enmMBD4FgOukulq9v0pDbFPi7VYGWmTK59Ch3X7I= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by sourceware.org (Postfix) with ESMTP id 831903893678 for ; Mon, 22 Jun 2020 15:14:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 831903893678 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-172-06cCEauIN-OAQQXuaBy6ag-1; Mon, 22 Jun 2020 11:14:15 -0400 X-MC-Unique: 06cCEauIN-OAQQXuaBy6ag-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4AABC809880 for ; Mon, 22 Jun 2020 15:13:52 +0000 (UTC) Received: from oldenburg2.str.redhat.com (ovpn-112-185.ams2.redhat.com [10.36.112.185]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 947CE5D9E2 for ; Mon, 22 Jun 2020 15:13:51 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH 09/30] elf: Implement ld.so --help In-Reply-To: References: Message-Id: <59cdd2c02d8ee7b07b78aed5547006e12c726410.1592836143.git.fweimer@redhat.com> Date: Mon, 22 Jun 2020 17:13:50 +0200 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" --help processing is deferred to the point where the executable has been loaded, so that it is possible to eventually include information from the main executable in the help output. As suggested in the GNU command-line interface guidelines, the help message is printed to standard output, and the exit status is successful. Handle usage errors closer to the GNU command-line interface guidelines. --- elf/dl-main.h | 9 +++++++-- elf/dl-usage.c | 24 ++++++++++++++++++---- elf/rtld.c | 55 ++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/elf/dl-main.h b/elf/dl-main.h index 68dd27d0d7..71ca5114de 100644 --- a/elf/dl-main.h +++ b/elf/dl-main.h @@ -60,7 +60,7 @@ struct audit_list }; /* This is a list of all the modes the dynamic loader can be in. */ -enum mode { normal, list, verify, trace }; +enum mode { normal, list, verify, trace, rtld_help }; /* Aggregated state information extracted from environment variables and the ld.so command line. */ @@ -98,6 +98,11 @@ call_init_paths (const struct dl_main_state *state) } /* Print ld.so usage information and exit. */ -void _dl_usage (void) attribute_hidden __attribute__ ((__noreturn__)); +void _dl_usage (const char *argv0, const char *wrong_option) + attribute_hidden __attribute__ ((__noreturn__)); + +/* Print ld.so --help output and exit. */ +void _dl_help (const char *argv0, struct dl_main_state *state) + attribute_hidden __attribute__ ((__noreturn__)); #endif /* _DL_MAIN */ diff --git a/elf/dl-usage.c b/elf/dl-usage.c index e03f183622..e1dc5d33b2 100644 --- a/elf/dl-usage.c +++ b/elf/dl-usage.c @@ -19,12 +19,24 @@ #include #include #include +#include void -_dl_usage (void) +_dl_usage (const char *argv0, const char *wrong_option) { - _dl_fatal_printf ("\ -Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ + if (wrong_option != NULL) + _dl_error_printf ("%s: unrecognized option '%s'\n", argv0, wrong_option); + else + _dl_error_printf ("%s: missing program name\n", argv0); + _dl_error_printf ("Try '%s --help' for more information.\n", argv0); + _exit (1); +} + +void +_dl_help (const char *argv0, struct dl_main_state *state) +{ + _dl_printf ("\ +Usage: %s [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\ You have invoked `ld.so', the helper program for shared library executables.\n\ This program usually lives in the file `/lib/ld.so', and special directives\n\ in executable files using ELF shared libraries tell the system's program\n\ @@ -46,5 +58,9 @@ of this helper program; chances are you did not intend to run this program.\n\ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\ in LIST\n\ --audit LIST use objects named in LIST as auditors\n\ - --preload LIST preload objects named in LIST\n"); + --preload LIST preload objects named in LIST\n\ + --help display this help and exit\n\ +", + argv0); + _exit (0); } diff --git a/elf/rtld.c b/elf/rtld.c index eac9a1e743..610203d5d2 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1131,6 +1131,7 @@ dl_main (const ElfW(Phdr) *phdr, _dl_starting_up = 1; #endif + const char *argv0 = _dl_argv[0]; if (*user_entry == (ElfW(Addr)) ENTRY_POINT) { /* Ho ho. We are not the program interpreter! We are the program @@ -1156,8 +1157,12 @@ dl_main (const ElfW(Phdr) *phdr, while (_dl_argc > 1) if (! strcmp (_dl_argv[1], "--list")) { - state.mode = list; - GLRO(dl_lazy) = -1; /* This means do no dependency analysis. */ + if (state.mode != rtld_help) + { + state.mode = list; + /* This means do no dependency analysis. */ + GLRO(dl_lazy) = -1; + } ++_dl_skip_args; --_dl_argc; @@ -1165,7 +1170,8 @@ dl_main (const ElfW(Phdr) *phdr, } else if (! strcmp (_dl_argv[1], "--verify")) { - state.mode = verify; + if (state.mode != rtld_help) + state.mode = verify; ++_dl_skip_args; --_dl_argc; @@ -1212,13 +1218,34 @@ dl_main (const ElfW(Phdr) *phdr, _dl_argc -= 2; _dl_argv += 2; } + else if (strcmp (_dl_argv[1], "--help") == 0) + { + state.mode = rtld_help; + --_dl_argc; + ++_dl_argv; + } + else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-') + { + if (_dl_argv[1][1] == '\0') + /* End of option list. */ + break; + else + /* Unrecognized option. */ + _dl_usage (argv0, _dl_argv[1]); + } else break; /* If we have no further argument the program was called incorrectly. Grant the user some education. */ if (_dl_argc < 2) - _dl_usage (); + { + if (state.mode == rtld_help) + /* --help without an executable is not an error. */ + _dl_help (argv0, &state); + else + _dl_usage (argv0, NULL); + } ++_dl_skip_args; --_dl_argc; @@ -1243,7 +1270,7 @@ dl_main (const ElfW(Phdr) *phdr, break; } - if (__builtin_expect (state.mode, normal) == verify) + if (state.mode == verify || state.mode == rtld_help) { const char *objname; const char *err_str = NULL; @@ -1256,9 +1283,16 @@ dl_main (const ElfW(Phdr) *phdr, (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit, &args); if (__glibc_unlikely (err_str != NULL)) - /* We don't free the returned string, the programs stops - anyway. */ - _exit (EXIT_FAILURE); + { + /* We don't free the returned string, the programs stops + anyway. */ + if (state.mode == rtld_help) + /* Mask the failure to load the main object. The help + message contains less information in this case. */ + _dl_help (argv0, &state); + else + _exit (EXIT_FAILURE); + } } else { @@ -1607,6 +1641,11 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT); audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT); + /* At this point, all data has been obtained that is included in the + --help output. */ + if (__builtin_expect (state.mode, normal) == rtld_help) + _dl_help (argv0, &state); + /* If we have auditing DSOs to load, do it now. */ bool need_security_init = true; if (state.audit_list.length > 0)