From patchwork Tue Dec 5 03:48:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 81330 X-Patchwork-Delegate: fweimer@redhat.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8DF093881D2B for ; Tue, 5 Dec 2023 03:48:41 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 52D653858421 for ; Tue, 5 Dec 2023 03:48:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 52D653858421 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 52D653858421 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701748107; cv=none; b=hrD4Iqb0v/3ZloU2mL3zDifWHpkndQ4vqPmhYSgznFb8fZTViv8HgAXYCeLMaQs30/fzpbBwo5/NNSB8zmQYOYgqbNfX7txQSEdTv7m5yUb0mrJIM7jv/qj7jk69e47UHG2qmWVaJCHnnEKMjE0k3mNN23YfZ0CfllCxN4+8TSU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701748107; c=relaxed/simple; bh=juClqpZLwQYyPo21uQwsF8B5g/vNLEPp9/48IowUavw=; h=DKIM-Signature:Date:Message-Id:From:To:Subject; b=EJCuYVu6xx9kAKuDW1bU0zC0Eyqhcdo33ZAUPgdfknTQKF4f5SeRlHWhq4NXgQElimId/oqur6MNhdix+dm6cnHyD/xsiyqS3GcjL/pZPIzUiPHEK5A/E6eNoRRMV8nwmm29Oyg1MC4GbqcKjRG44XR+E/7j5yFc/pABmD1eSH0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1701748096; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:content-type:content-type; bh=hn5Np4vmTRvQTeJWT+01pddACwQ+eqqmp9e47iAnSLM=; b=hWiinsf0kVBLx2zVihVXBkOIxWQTYfFiumKAEGyYJWx97ZRqvfsIdmKTI5tT90FMpbqqju gL6s+IXKokq9j9QF7K0n/22cW9PTCg7Zmj2FGWnieJ7udlQq6yzss5QfjmF11QBRlcqLLC SUKx11MkBTojU0G6sl3mVZI5ej3QQgk= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-222--cet5sIcOPSLOJG4OMpaZw-1; Mon, 04 Dec 2023 22:48:15 -0500 X-MC-Unique: -cet5sIcOPSLOJG4OMpaZw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DEE291C068DC for ; Tue, 5 Dec 2023 03:47:57 +0000 (UTC) Received: from greed.delorie.com (unknown [10.22.9.35]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8A275C1596F for ; Tue, 5 Dec 2023 03:48:07 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.15.2/8.15.2) with ESMTP id 3B53mEMN946642 for ; Mon, 4 Dec 2023 22:48:14 -0500 Date: Mon, 04 Dec 2023 22:48:14 -0500 Message-Id: From: DJ Delorie To: libc-alpha@sourceware.org Subject: RFD/patch:system-wide tunables: parser preview X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org I've gotten to the point where the ldconfig half of the problem has a working solution, which is probably the best time to show and tell so people can argue whether I'm doing it the right way or not ;-) Here's the chunk of the cache file that's worth discussion: /* One of these is at the beginning of the tunable data block. */ struct tunable_header_cached { uint32_t signature; uint32_t version; uint32_t num_tunables; uint32_t unused_1; /* for alignment */ struct tunable_entry_cached tunables[0 /* num_tunables */]; }; /* An array of [num_tunables] of these follows the header. */ struct tunable_entry_cached { uint32_t flags; uint32_t tunable_id; uint32_t name_offset; uint32_t value_offset; uint32_t flag_offset; uint32_t unused_1; /* for alignment */ uint64_t parsed_value; }; The cache data allows for a filter (specified in the flags, with a corresponding string at flag_offset), as it's been requested to have per-program overrides in /etc/tunables.conf for programs that need it. I have not yet written the code to *read* this cached data, so no filters have yet been defined. I was originally going to have a separate program and cache, but it was argued that training sysadmins to do something new was much harder than just extending something they already knew how and when to do. As for testing, I'm running a new-built cache on my RHEL 8 work machine (glibc 2.28) without problems. In theory, this patch could be applied today (sans debug printfs ;) without affecting systems. From 1c8f70636d761b5559df34d3e78697a38cced53e Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Mon, 4 Dec 2023 20:48:18 -0500 Subject: Add system-wide tunables: ldconfig part Adds support for reading /etc/tunables.conf The file contains one line per tunable, like this: glibc.foo.bar=14 glibc.malloc.more=0 Additionally, each line can be prefixed with a single character that controls overridability by the GLIBC_TUNABLES env var: !glibc.foo=0 ^ May be made more secure +glibc.foo=0 ^ May be overridden -glibc.foo=0 ^ May not be overridden Internally, each tunable will later have a default "overridability" and logic for what "more secure" means. The tunable cache format allows for a filter to be assigned to each tunable, to be used at program start to decide if a tunable applies to that program. No such filters have yet been specified. The cache format also can store a pre-parsed value for the tunable, and the ID of the tunable, to improve load-time performance. Note that the parser still contains my debug code in case it helps understand the code. diff --git a/elf/Makefile b/elf/Makefile index c1e9038a44..4a7885f93f 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -221,6 +221,7 @@ ldconfig-modules := \ readlib \ static-stubs \ stringtable \ + tunconf \ xmalloc \ xstrdup \ # ldconfig-modules diff --git a/elf/cache.c b/elf/cache.c index 8149f889ba..4d58d24c0b 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -36,6 +36,7 @@ #include #include #include +#include /* Used to store library names, paths, and other strings. */ static struct stringtable strings; @@ -278,7 +279,8 @@ check_new_cache (struct cache_file_new *cache) /* Print the extension information in *EXT. */ static void -print_extensions (struct cache_extension_all_loaded *ext) +print_extensions (struct cache_extension_all_loaded *ext, + const char *cache_data) { if (ext->sections[cache_extension_tag_generator].base != NULL) { @@ -287,6 +289,30 @@ print_extensions (struct cache_extension_all_loaded *ext) ext->sections[cache_extension_tag_generator].size, stdout); putchar ('\n'); } + if (ext->sections[cache_extension_tag_tunables].base != NULL) + { + struct tunable_header_cached *thc; + struct tunable_entry_cached *tec; + int i, count; + + thc = (struct tunable_header_cached *) + ext->sections[cache_extension_tag_tunables].base; + tec = thc->tunables; + count = thc->num_tunables; + printf("tunables sig 0x%08x ver 0x%08x count %u\n", + thc->signature, thc->version, thc->num_tunables); + for (i = 0; i < count; ++ i) + { + printf(" [%d] %s : %s [flags 0x%08x", + i, + cache_data + tec[i].name_offset, + cache_data + tec[i].value_offset, + tec[i].flags); + if (tec[i].flag_offset != 0) + printf(" : %s", cache_data + tec[i].flag_offset); + printf("]\n"); + } + } } /* Print the whole cache file, if a file contains the new cache format @@ -397,7 +423,7 @@ print_cache (const char *cache_name) cache_new->libs[i].hwcap, hwcaps_string, cache_data + cache_new->libs[i].value); } - print_extensions (&ext); + print_extensions (&ext, cache_data); } /* Cleanup. */ munmap (cache, cache_size); @@ -501,6 +527,28 @@ write_extensions (int fd, uint32_t str_offset, ext->sections[xid].size = hwcaps_size; } + struct tunable_header_cached *tunable_data; + size_t tunable_size; + size_t tunable_aligner = 0; + + tunable_data = get_tunconf_ext (str_offset); + if (tunable_data != NULL) + { + uint32_t tunable_offset_ua; + uint32_t tunable_offset; + + tunable_size = TUNCONF_SIZE (tunable_data); + tunable_offset_ua = generator_offset + strlen (generator); + tunable_offset = ALIGN_UP (tunable_offset_ua, 8); + tunable_aligner = tunable_offset - tunable_offset_ua; + + ++xid; + ext->sections[xid].tag = cache_extension_tag_tunables; + ext->sections[xid].flags = 0; + ext->sections[xid].offset = tunable_offset; + ext->sections[xid].size = tunable_size; + } + ++xid; ext->count = xid; assert (xid <= cache_extension_count); @@ -512,6 +560,13 @@ write_extensions (int fd, uint32_t str_offset, || write (fd, generator, strlen (generator)) != strlen (generator)) error (EXIT_FAILURE, errno, _("Writing of cache extension data failed")); + if (tunable_data) + { + if (write (fd, " ", tunable_aligner) != tunable_aligner + || write (fd, tunable_data, tunable_size) != tunable_size) + error (EXIT_FAILURE, errno, _("Writing of cache tunable data failed")); + } + free (hwcaps_array); free (ext); } @@ -1109,3 +1164,9 @@ out_fail: free (temp_name); free (file_entries); } + +struct stringtable_entry * +cache_store_string (const char *string) +{ + return stringtable_add (&strings, string); +} diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 02387a169c..b2e2fc844d 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -43,6 +43,7 @@ #include #include #include +#include "tunconf.h" #include @@ -50,6 +51,10 @@ # define LD_SO_CONF SYSCONFDIR "/ld.so.conf" #endif +#ifndef TUNABLES_CONF +# define TUNABLES_CONF SYSCONFDIR "/tunables.conf" +#endif + /* Get libc version number. */ #include @@ -107,9 +112,12 @@ static int opt_ignore_aux_cache; /* Cache file to use. */ static char *cache_file; -/* Configuration file. */ +/* Configuration file for libraries. */ static const char *config_file; +/* Configuration file for tunables. */ +static const char *tunconfig_file; + /* Name and version of program. */ static void print_version (FILE *stream, struct argp_state *state); void (*argp_program_version_hook) (FILE *, struct argp_state *) @@ -127,7 +135,8 @@ static const struct argp_option options[] = { NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0}, { NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0}, { NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0}, - { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0}, + { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file for libraries"), 0}, + { NULL, 't', N_("TUNCONF"), 0, N_("Use TUNCONF as configuration file for tunables"), 0}, { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0}, { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0}, { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0}, @@ -164,6 +173,9 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'f': config_file = arg; break; + case 't': + tunconfig_file = arg; + break; case 'i': opt_ignore_aux_cache = 1; break; @@ -1229,6 +1241,9 @@ main (int argc, char **argv) if (config_file == NULL) config_file = LD_SO_CONF; + if (tunconfig_file == NULL) + tunconfig_file = TUNABLES_CONF; + if (opt_print_cache) { if (opt_chroot != NULL) @@ -1304,6 +1319,8 @@ main (int argc, char **argv) search_dirs (); + parse_tunconf (tunconfig_file, true, opt_chroot); + if (opt_build_cache) { save_cache (cache_file); diff --git a/elf/tunconf.c b/elf/tunconf.c new file mode 100644 index 0000000000..a59a2d64c0 --- /dev/null +++ b/elf/tunconf.c @@ -0,0 +1,408 @@ +/* Manage /etc/tunables.* + Copyright (C) 1999-2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TUNABLES_INTERNAL +#include +#include + +#include +#include +#include +#include + +#include "tunconf.h" + +/* Declared in chroot_canon.c. */ +extern char *chroot_canon (const char *chroot, const char *name); + +/*----------------------------------------------------------------------*/ + +#ifndef TUNABLES_CONF +# define TUNABLES_CONF SYSCONFDIR "/tunables.conf" +#endif + +#ifndef TUNABLES_CACHE +# define TUNABLES_CACHE SYSCONFDIR "/tunables.cache" +#endif + +// Tunable Override Policies +typedef enum { + TOP_DEFAULT = 0, // let the internal code decide + TOP_ALLOW, // let the environment variable override + TOP_STRICT, // internal code will only allow "stricter" setting + TOP_DENY // no override allowed +} TOP; + +struct tunable_entry_int { + struct stringtable_entry *name; + struct stringtable_entry *value; + TOP top; + int tunable_id; + int value_is_negative:1; + int value_was_parsed:1; + unsigned long long value_ull; + signed long long value_sll; + + struct tunable_entry_int *next; +}; + +struct tunable_entry_int *entry_list; +struct tunable_entry_int **entry_list_next = &entry_list; + +/*----------------------------------------------------------------------*/ + +static void parse_tunconf_include (const char *tunconfig_file, unsigned int lineno, + bool do_chroot, const char *pattern, const char *opt_chroot); + +static void +add_tunable (char *line, const char *filename, int lineno) +{ + TOP top = TOP_DEFAULT; + char *name; + char *value; + char *eq; + char *orig_line; + struct tunable_entry_int *entry; + int i, id; + + orig_line = line; + printf("%s:%d: `%s'\n", filename, lineno, line); + + // Leading whitespace has already been stripped. + + if (*line == '!' || *line == '+' || *line == '-') + { + switch (*line) + { + case '!': + top = TOP_STRICT; + break; + case '+': + top = TOP_ALLOW; + break; + case '-': + top = TOP_DENY; + break; + } + printf("TOP: %d\n", top); + line ++; + while (*line && isspace(*line)) + line ++; + } + + // NAME now points to the start of the tunable name. + name = line; + + // Look for the '=' separator. + eq = strchr (line, '='); + if (eq == NULL) + { + printf("%s:%d: syntax error, line ignored: `%s' (missing '=')\n", + filename, lineno, orig_line); + return; + } + + if (eq == name) + { + printf("%s:%d: syntax error, line ignored: `%s' (missing tunable name)\n", + filename, lineno, orig_line); + return; + } + + // At this point, EQ actually points to '=' + value = eq + 1; + + while (*value && isspace(*value)) + value ++; + + if (*value == 0) + { + printf("%s:%d: syntax error, line ignored: `%s' (missing value)\n", + filename, lineno, orig_line); + return; + } + + // VALUE now points to the start of the value + + // Split the string into name and value c-strings. + *eq = 0; + // Trim trailing whitespace off NAME + while (*name && isspace (name[strlen(name)-1])) + name[strlen(name)-1] = 0; + // Trim trailing whitespace off VALUE + while (*value && isspace (name[strlen(value)-1])) + value[strlen(value)-1] = 0; + + id = -1; + for (i=0; iname = cache_store_string (name); + entry->value = cache_store_string (value); + entry->tunable_id = id; + entry->top = top; + + *entry_list_next = entry; + entry_list_next = & (entry->next); +} + +void +parse_tunconf (const char *filename, int do_chroot, char *opt_chroot) +{ + FILE *file = NULL; + char *line = NULL; + const char *canon; + size_t len = 0; + unsigned int lineno; + + if (do_chroot && opt_chroot) + { + canon = chroot_canon (opt_chroot, filename); + if (canon) + file = fopen (canon, "r"); + else + canon = filename; + } + else + { + canon = filename; + file = fopen (filename, "r"); + } + + if (file == NULL) + { + if (errno != ENOENT) + error (0, errno, _("\ +Warning: ignoring configuration file that cannot be opened: %s"), + canon); + if (canon != filename) + free ((char *) canon); + return; + } + + /* No threads use this stream. */ + __fsetlocking (file, FSETLOCKING_BYCALLER); + + if (canon != filename) + free ((char *) canon); + lineno = 0; + do + { + ssize_t n = getline (&line, &len, file); + if (n < 0) + break; + + ++lineno; + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + /* Because the file format does not know any form of quoting we + can search forward for the next '#' character and if found + make it terminating the line. */ + *strchrnul (line, '#') = '\0'; + + /* Remove leading whitespace. NUL is no whitespace character. */ + char *cp = line; + while (isspace (*cp)) + ++cp; + + /* If the line is blank it is ignored. */ + if (cp[0] == '\0') + continue; + + if (!strncmp (cp, "include", 7) && isblank (cp[7])) + { + char *dir; + cp += 8; + while ((dir = strsep (&cp, " \t")) != NULL) + if (dir[0] != '\0') + parse_tunconf_include (filename, lineno, do_chroot, dir, opt_chroot); + } + else + add_tunable (cp, filename, lineno); + } + while (!feof_unlocked (file)); + + /* Free buffer and close file. */ + free (line); + fclose (file); +} + +/* Handle one word in an `include' line, a glob pattern of additional + config files to read. */ +static void +parse_tunconf_include (const char *tunconfig_file, unsigned int lineno, + bool do_chroot, const char *pattern, const char *opt_chroot) +{ + if (opt_chroot != NULL && pattern[0] != '/') + error (EXIT_FAILURE, 0, + _("need absolute file name for configuration file when using -r")); + + char *copy = NULL; + if (pattern[0] != '/' && strchr (tunconfig_file, '/') != NULL) + { + if (asprintf (©, "%s/%s", dirname (strdupa (tunconfig_file)), + pattern) < 0) + error (EXIT_FAILURE, 0, _("memory exhausted")); + pattern = copy; + } + + glob64_t gl; + int result; + if (do_chroot && opt_chroot) + { + char *canon = chroot_canon (opt_chroot, pattern); + if (canon == NULL) + return; + result = glob64 (canon, 0, NULL, &gl); + free (canon); + } + else + result = glob64 (pattern, 0, NULL, &gl); + + switch (result) + { + case 0: + for (size_t i = 0; i < gl.gl_pathc; ++i) + parse_tunconf (gl.gl_pathv[i], false, NULL); + globfree64 (&gl); + break; + + case GLOB_NOMATCH: + break; + + case GLOB_NOSPACE: + errno = ENOMEM; + /* Fall through. */ + case GLOB_ABORTED: + if (opt_verbose) + error (0, errno, _("%s:%u: cannot read directory %s"), + tunconfig_file, lineno, pattern); + break; + + default: + abort (); + break; + } + + free (copy); +} + +struct tunable_header_cached * +get_tunconf_ext (uint32_t string_table_offset) +{ + struct tunable_entry_int *tei; + struct tunable_header_cached *thc; + size_t count; + size_t size; + + /* First, count the number of entries we have. */ + tei = entry_list; + count = 0; + while (tei != NULL) + { + ++ count; + tei = tei->next; + } + printf("get_tunconf_ext: found %lu entries\n", count); + + /* Allocate enough space for the whole cached block. */ + size = sizeof (struct tunable_header_cached) + + sizeof (struct tunable_entry_cached) * count; + thc = (struct tunable_header_cached *) malloc (size); + + if (thc == NULL) + { + error (0, 0, _("Unable to allocate %lu bytes in get_tunable_ext"), size); + return NULL; + } + + /* Now, fill in the structures. */ + + thc->signature = TUNCONF_SIGNATURE; + thc->version = TUNCONF_VERSION; + thc->num_tunables = count; + thc->unused_1 = 0; + + tei = entry_list; + count = 0; + while (tei != NULL) + { + struct tunable_entry_cached *tec; + + tec = & ( thc->tunables[count] ); + + tec->flags = 0; + if (tei->value_was_parsed) + tec->flags |= TUNCONF_FLAG_PARSED; + if (tei->value_is_negative) + tec->flags |= TUNCONF_FLAG_NEGATIVE; + printf("tei->top is %d\n", tei->top); + switch (tei->top) + { + case TOP_DEFAULT: + tec->flags |= TUNCONF_OVERRIDE_DEFAULT; + break; + case TOP_ALLOW: + tec->flags |= TUNCONF_OVERRIDE_ALLOW; + break; + case TOP_STRICT: + tec->flags |= TUNCONF_OVERRIDE_STRICTER; + break; + case TOP_DENY: + tec->flags |= TUNCONF_OVERRIDE_DENY; + break; + } + + tec->tunable_id = tei->tunable_id; + tec->name_offset = tei->name->offset + string_table_offset; + tec->value_offset = tei->value->offset + string_table_offset; + tec->flag_offset = 0; + tec->unused_1 = 0; + if (tei->value_is_negative) + tec->parsed_value = (uint64_t) tei->value_sll; + else + tec->parsed_value = (uint64_t) tei->value_ull; + printf("tec->flags is %08x\n", tec->flags); + + ++ count; + tei = tei->next; + } + + return thc; +} diff --git a/elf/tunconf.h b/elf/tunconf.h new file mode 100644 index 0000000000..a6c5f0dd9a --- /dev/null +++ b/elf/tunconf.h @@ -0,0 +1,40 @@ +#define TUNCONF_SIGNATURE 0x7c3ba94f +#define TUNCONF_VERSION 0x01000000 + +#define TUNCONF_FLAG_PARSED 0x00000001 +#define TUNCONF_FLAG_NEGATIVE 0x00000002 + +#define TUNCONF_FLAG_OVERRIDABLE 0x0000000C +#define TUNCONF_OVERRIDE_DEFAULT 0x00000000 +#define TUNCONF_OVERRIDE_ALLOW 0x00000004 +#define TUNCONF_OVERRIDE_STRICTER 0x00000008 +#define TUNCONF_OVERRIDE_DENY 0x0000000C + +#define TUNCONF_FLAG_FILTER 0x0000ff00 +#define TUNCONF_FILTER_PERPROC 0x00000100 + +/* An array of [num_tunables] of these follows the below. */ +struct tunable_entry_cached { + uint32_t flags; + uint32_t tunable_id; + uint32_t name_offset; + uint32_t value_offset; + uint32_t flag_offset; + uint32_t unused_1; /* for alignment */ + uint64_t parsed_value; +}; + +/* One of these is at the beginning of the tunable data block. */ +struct tunable_header_cached { + uint32_t signature; + uint32_t version; + uint32_t num_tunables; + uint32_t unused_1; /* for alignment */ + struct tunable_entry_cached tunables[0 /* num_tunables */]; +}; + +void parse_tunconf (const char *filename, int do_chroot, char *opt_chroot); + +struct tunable_header_cached * get_tunconf_ext (uint32_t str_offset); +#define TUNCONF_SIZE(thc_p) (sizeof(struct tunable_header_cached) \ + + thc_p->num_tunables * sizeof (struct tunable_entry_cached)) diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h index bd39ff7fb7..53dea39ce5 100644 --- a/sysdeps/generic/dl-cache.h +++ b/sysdeps/generic/dl-cache.h @@ -220,6 +220,12 @@ enum cache_extension_tag size must be a multiple of 4. */ cache_extension_tag_glibc_hwcaps, + /* Array of system-wide tunable information. + + For this section, 8-byte alignment is required, and the section + size must be a multiple of 8. */ + cache_extension_tag_tunables, + /* Total number of known cache extension tags. */ cache_extension_count }; diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h index 59da12ad89..aa531b781f 100644 --- a/sysdeps/generic/ldconfig.h +++ b/sysdeps/generic/ldconfig.h @@ -75,6 +75,8 @@ extern void add_to_cache (const char *path, const char *filename, unsigned int isa_level, struct glibc_hwcaps_subdirectory *); +extern struct stringtable_entry *cache_store_string (const char *string); + extern void init_aux_cache (void); extern void load_aux_cache (const char *aux_cache_name);