From patchwork Fri Mar 20 20:41:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132108 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id C0CD64C91751 for ; Fri, 20 Mar 2026 20:44:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C0CD64C91751 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=dIl2qNE3 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.129.124]) by sourceware.org (Postfix) with ESMTP id DF5234C900E1 for ; Fri, 20 Mar 2026 20:41:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DF5234C900E1 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 DF5234C900E1 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039274; cv=none; b=MKKYyExPW8r400+Sc8EVZkcNlYIv1cVo6o/ZvtB1Y2zwdM1WMMYDhjDzifUPg3w6y/9Sj0FkKMrq0EezithAC+YEDOUnpCEVeYrOV9NMQrPFefxrjoVVVmN2Qe+Rg+IE4JHhQ9m5WuS/wGoPq295Im6Xw2RqO2W9gnNcAVyx9SU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039274; c=relaxed/simple; bh=NcU1GhL1KWOT6QvbfjGddwECuhaDRe97x0cHNkA4h8g=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=tyskH4RUh81MazABvf2r8x747dHB1N0h5kZL5C4W2erF9gFkv9WfTujdA0He42zz3NmJ+NRfp14XeCeBYnz9+Q/oCLyX4WjRxudoemWDstM4jpb3KKrDzMY9te7mLlZ9fiB9V1EbkhRmYS5pr+EzzKsnt0kVsyYjFiT9j1RvePg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DF5234C900E1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039273; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=e919GZJdi4pi2g7iRbnfJTrJnB0Ton0azDrsymkiJFI=; b=dIl2qNE3qCydfG1wwkog9eipIAxmXgjjrgDR3w7Ie3ek+WgfW4xnVTThHLtd+pL8oZfocV /vEKeU+A4DHpp0SPsNA5GpkFt6QF1d5yDXFAE8X9rV+ndS1lGNXX6p7IH7g9FXZFXXQGgS yUbrmbmS3ZjKpdjST8m4KZ3Dag+2fhs= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-573-N6yiEC-wP7SZf03GniCanQ-1; Fri, 20 Mar 2026 16:41:12 -0400 X-MC-Unique: N6yiEC-wP7SZf03GniCanQ-1 X-Mimecast-MFC-AGG-ID: N6yiEC-wP7SZf03GniCanQ_1774039271 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 55A3D195608C for ; Fri, 20 Mar 2026 20:41:11 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 661641800351 for ; Fri, 20 Mar 2026 20:41:09 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 01/23] support: Update support_format_* NSS formatting routines for null pointers In-Reply-To: Message-ID: <6bf77cf6e09f069826341a381625578b4c2a2392.1774037705.git.fweimer@redhat.com> References: X-From-Line: 6bf77cf6e09f069826341a381625578b4c2a2392 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:07 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: AFbhqcG42SpHgyinu1Te5sYMEMYRLeABP_7KbY307AU_1774039271 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.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, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Some tests will need to check for the presence of null pointers. It makes sense to support this in the formatting functions. --- support/support_format_group.c | 7 +++++-- support/support_format_hostent.c | 31 ++++++++++++++++++++----------- support/support_format_netent.c | 9 +++++++-- support/support_format_protoent.c | 11 ++++++++--- support/support_format_rpcent.c | 8 ++++++-- support/support_format_servent.c | 9 +++++++-- support/support_format_sgrp.c | 16 ++++++++++++---- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/support/support_format_group.c b/support/support_format_group.c index fb714564cd..a9ad4973c0 100644 --- a/support/support_format_group.c +++ b/support/support_format_group.c @@ -35,8 +35,11 @@ support_format_group (const struct group *g) fprintf (mem.out, "name: %s\n", g->gr_name); fprintf (mem.out, "passwd: %s\n", g->gr_passwd); fprintf (mem.out, "gid: %u\n", (unsigned) g->gr_gid); - for (char **mp = g->gr_mem; *mp != NULL; ++mp) - fprintf (mem.out, "member: %s\n", *mp); + if (g->gr_mem != NULL) + for (char **mp = g->gr_mem; *mp != NULL; ++mp) + fprintf (mem.out, "member: %s\n", *mp); + else + fputs ("gr_mem: (null)\n", mem.out); xfclose_memstream (&mem); return mem.buffer; diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c index f76ec459cd..4b3ef8e1d8 100644 --- a/support/support_format_hostent.c +++ b/support/support_format_hostent.c @@ -59,17 +59,26 @@ support_format_hostent (const struct hostent *h) xopen_memstream (&mem); fprintf (mem.out, "name: %s\n", h->h_name); - for (char **alias = h->h_aliases; *alias != NULL; ++alias) - fprintf (mem.out, "alias: %s\n", *alias); - for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i) - { - char buf[128]; - if (inet_ntop (h->h_addrtype, h->h_addr_list[i], - buf, sizeof (buf)) == NULL) - fprintf (mem.out, "error: inet_ntop failed: %m\n"); - else - fprintf (mem.out, "address: %s\n", buf); - } + + if (h->h_aliases != NULL) + for (char **alias = h->h_aliases; *alias != NULL; ++alias) + fprintf (mem.out, "alias: %s\n", *alias); + else + fputs ("h_aliases: (null)\n", mem.out); + + if (h->h_addr_list != NULL) + for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i) + { + char buf[128]; + if (inet_ntop (h->h_addrtype, h->h_addr_list[i], + buf, sizeof (buf)) == NULL) + fprintf (mem.out, "error: inet_ntop failed: %m\n"); + else + fprintf (mem.out, "address: %s\n", buf); + } + else + fputs ("h_addr_list: (null)\n", mem.out); + if (h->h_length != address_length (h->h_addrtype)) { char *family = support_format_address_family (h->h_addrtype); diff --git a/support/support_format_netent.c b/support/support_format_netent.c index 7f08476dd3..1ff2f93c26 100644 --- a/support/support_format_netent.c +++ b/support/support_format_netent.c @@ -41,8 +41,13 @@ support_format_netent (const struct netent *e) if (e->n_name != NULL) fprintf (mem.out, "name: %s\n", e->n_name); - for (char **ap = e->n_aliases; *ap != NULL; ++ap) - fprintf (mem.out, "alias: %s\n", *ap); + + if (e->n_aliases != NULL) + for (char **ap = e->n_aliases; *ap != NULL; ++ap) + fprintf (mem.out, "alias: %s\n", *ap); + else + fputs ("n_aliases: (null)\n", mem.out); + if (e->n_addrtype != AF_INET) fprintf (mem.out, "addrtype: %d\n", e->n_addrtype); /* On alpha, e->n_net is an unsigned long. */ diff --git a/support/support_format_protoent.c b/support/support_format_protoent.c index 25c177f5da..187e7ff318 100644 --- a/support/support_format_protoent.c +++ b/support/support_format_protoent.c @@ -32,9 +32,14 @@ support_format_protoent (const struct protoent *e) struct xmemstream mem; xopen_memstream (&mem); - fprintf (mem.out, "name: %s\n", e->p_name); - for (char **ap = e->p_aliases; *ap != NULL; ++ap) - fprintf (mem.out, "alias: %s\n", *ap); + fprintf (mem.out, "name: %s\n", e->p_name ?: "(null)"); + + if (e->p_aliases != NULL) + for (char **ap = e->p_aliases; *ap != NULL; ++ap) + fprintf (mem.out, "alias: %s\n", *ap); + else + fputs ("p_aliases: (null)\n", mem.out); + fprintf (mem.out, "proto: %d\n", e->p_proto); xfclose_memstream (&mem); diff --git a/support/support_format_rpcent.c b/support/support_format_rpcent.c index 1b898f3e27..66ee00f319 100644 --- a/support/support_format_rpcent.c +++ b/support/support_format_rpcent.c @@ -34,8 +34,12 @@ support_format_rpcent (const struct rpcent *r) fprintf (mem.out, "name: %s\n", r->r_name); fprintf (mem.out, "number: %d\n", r->r_number); - for (char **ap = r->r_aliases; *ap != NULL; ++ap) - fprintf (mem.out, "alias: %s\n", *ap); + + if (r->r_aliases != NULL) + for (char **ap = r->r_aliases; *ap != NULL; ++ap) + fprintf (mem.out, "alias: %s\n", *ap); + else + fputs ("r_aliases: (null)\n", mem.out); xfclose_memstream (&mem); return mem.buffer; diff --git a/support/support_format_servent.c b/support/support_format_servent.c index fbe8138222..b8823ab485 100644 --- a/support/support_format_servent.c +++ b/support/support_format_servent.c @@ -34,8 +34,13 @@ support_format_servent (const struct servent *e) xopen_memstream (&mem); fprintf (mem.out, "name: %s\n", e->s_name); - for (char **ap = e->s_aliases; *ap != NULL; ++ap) - fprintf (mem.out, "alias: %s\n", *ap); + + if (e->s_aliases != NULL) + for (char **ap = e->s_aliases; *ap != NULL; ++ap) + fprintf (mem.out, "alias: %s\n", *ap); + else + fputs ("s_aliases: (null)\n", mem.out); + fprintf (mem.out, "port: %d\n", ntohs (e->s_port)); fprintf (mem.out, "proto: %s\n", e->s_proto); diff --git a/support/support_format_sgrp.c b/support/support_format_sgrp.c index d9b7d12478..0b4bdd7dfc 100644 --- a/support/support_format_sgrp.c +++ b/support/support_format_sgrp.c @@ -34,10 +34,18 @@ support_format_sgrp (const struct sgrp *s) fprintf (mem.out, "name: %s\n", s->sg_namp); fprintf (mem.out, "passwd: %s\n", s->sg_passwd); - for (char **ap = s->sg_adm; *ap != NULL; ++ap) - fprintf (mem.out, "admin: %s\n", *ap); - for (char **mp = s->sg_mem; *mp != NULL; ++mp) - fprintf (mem.out, "member: %s\n", *mp); + + if (s->sg_adm != NULL) + for (char **ap = s->sg_adm; *ap != NULL; ++ap) + fprintf (mem.out, "admin: %s\n", *ap); + else + fputs ("sg_adm: (null)\n", mem.out); + + if (s->sg_mem != NULL) + for (char **mp = s->sg_mem; *mp != NULL; ++mp) + fprintf (mem.out, "member: %s\n", *mp); + else + fputs ("sg_mem: (null)\n", mem.out); xfclose_memstream (&mem); return mem.buffer; From patchwork Fri Mar 20 20:41:17 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132104 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 3F1364C3185E for ; Fri, 20 Mar 2026 20:42:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3F1364C3185E Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=VENLPwjQ 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 ESMTP id ECD554C515F9 for ; Fri, 20 Mar 2026 20:41:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ECD554C515F9 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 ECD554C515F9 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=1774039283; cv=none; b=J1vQXh3wHzt5ckInjBI6l2jKgxdG5tRwPRCCLUqnMkgJhlbgPtAMNF1ZUhySs4EEJ18QHpPSjq/VR3f68gsZzCcIRrfvxcVU6YrIi5LaBAI+GyRfCJyRD8F05bwKanu78c/h5/1kL+pl6+45jRL1nRz+8omqMxmfh6bMDkBQgL8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039283; c=relaxed/simple; bh=bwFr4PqMqezvmMIxH8HrDcyYkYxf0PNTmhmEvNtHsRY=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=xTP9NSNUZMthWEOFQ5ob6qkNE6ccFzjNX6MIJwpvCVLLj9GnUW8gB/k0HxFv6iBkpNab4KOF9XqhcL/NEIsJBT/URBAKuy3DpqpUuxNd1i/XfuLfFrgwuYMWFlbN4bmtV9ZXV0jytzRcGSKwfBMb4C6KlaS7Xi8wYRvMMgdaK0E= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ECD554C515F9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039282; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=aRvWolzjRkB9bG5Gf32hifYKrrtR4jvoEQx3TzX4N9k=; b=VENLPwjQIJcxm+OZZ1zCwt0z0J1NStJtx+/LfNphR4saR8HuHeX5MTuJxEkX8BzFmifuGA X99wP+PF58S5c/tWo/4OoMi8qiocCpa4AgF3a+8SeST3QqWjbk/+RNav6ZeX9WnSNCLOf5 +l7R9mzUd7Cld2nhzc8niDeLoiGKjx4= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-582-wiXeR_WdNjqCPVQpg9g23w-1; Fri, 20 Mar 2026 16:41:21 -0400 X-MC-Unique: wiXeR_WdNjqCPVQpg9g23w-1 X-Mimecast-MFC-AGG-ID: wiXeR_WdNjqCPVQpg9g23w_1774039280 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A5AFA195609F for ; Fri, 20 Mar 2026 20:41:20 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F001C30001A1 for ; Fri, 20 Mar 2026 20:41:19 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 02/23] nscd: Extract dbtype and struct statdata types to separate headers In-Reply-To: Message-ID: <46558f4181ad5c04f7e7d2439a88a0a37018b0dc.1774037705.git.fweimer@redhat.com> References: X-From-Line: 46558f4181ad5c04f7e7d2439a88a0a37018b0dc Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:17 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: MDN6YydZVPu3x60UNOrZYa-YKMrrWMC_MmhnXOlP93M_1774039280 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 So that they can be used in test code which uses _ISOMAC (so not in internal tests). --- nscd/nscd-dbtype.h | 32 ++++++++++++++ nscd/nscd-statdata.h | 99 ++++++++++++++++++++++++++++++++++++++++++++ nscd/nscd.h | 14 +------ nscd/nscd_stat.c | 73 +------------------------------- 4 files changed, 133 insertions(+), 85 deletions(-) create mode 100644 nscd/nscd-dbtype.h create mode 100644 nscd/nscd-statdata.h diff --git a/nscd/nscd-dbtype.h b/nscd/nscd-dbtype.h new file mode 100644 index 0000000000..7d553d020a --- /dev/null +++ b/nscd/nscd-dbtype.h @@ -0,0 +1,32 @@ +/* Database types handled by nscd. + Copyright (c) 1998-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef NSCD_DBTYPE_H +#define NSCD_DBTYPE_H + +typedef enum +{ + pwddb, + grpdb, + hstdb, + servdb, + netgrdb, + lastdb +} dbtype; + +#endif /* NSCD_DBTYPE_H */ diff --git a/nscd/nscd-statdata.h b/nscd/nscd-statdata.h new file mode 100644 index 0000000000..255dcdfc54 --- /dev/null +++ b/nscd/nscd-statdata.h @@ -0,0 +1,99 @@ +/* Statistics data for nscd. + Copyright (c) 1998-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef NSCD_STATDATA_H +#define NSCD_STATDATA_H + +#include +#include + +#ifdef HAVE_SELINUX +# include +# include +#endif /* HAVE_SELINUX */ + +#include "nscd-dbtype.h" + +/* We use this to make sure the receiver is the same. The lower 16 + bits are reserved for flags indicating compilation variants. This + version needs to be updated if the definition of struct statdata + changes. */ +#define STATDATA_VERSION 0x01020000U + +#ifdef HAVE_SELINUX +# define STATDATA_VERSION_SELINUX_FLAG 0x0001U +#else +# define STATDATA_VERSION_SELINUX_FLAG 0x0000U +#endif + +/* All flags affecting the struct statdata layout. */ +#define STATDATA_VERSION_FLAGS STATDATA_VERSION_SELINUX_FLAG + +/* The full version number for struct statdata. */ +#define STATDATA_VERSION_FULL (STATDATA_VERSION | STATDATA_VERSION_FLAGS) + +/* Statistic data for one database. */ +struct dbstat +{ + int enabled; + int check_file; + int shared; + int persistent; + size_t module; + + unsigned long int postimeout; + unsigned long int negtimeout; + + size_t nentries; + size_t maxnentries; + size_t maxnsearched; + size_t datasize; + size_t dataused; + + uintmax_t poshit; + uintmax_t neghit; + uintmax_t posmiss; + uintmax_t negmiss; + + uintmax_t rdlockdelayed; + uintmax_t wrlockdelayed; + + uintmax_t addfailed; +}; + +/* Record for transmitting statistics. If this definition changes, + update STATDATA_VERSION above. */ +struct statdata +{ + unsigned int version; /* Must be STATDATA_VERSION_FULL. */ + int debug_level; + time_t runtime; + unsigned long int client_queued; + int nthreads; + int max_nthreads; + int paranoia; + time_t restart_interval; + unsigned int reload_count; + int ndbs; + struct dbstat dbs[lastdb]; +#ifdef HAVE_SELINUX + struct avc_cache_stats cstats; +#endif /* HAVE_SELINUX */ +}; + +#endif /* NSCD_STATDATA_H */ diff --git a/nscd/nscd.h b/nscd/nscd.h index 7d1bac2dc1..fffcb7a719 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -27,19 +27,7 @@ "nscd-client.h", which should contain everything needed by client functions. */ #include "nscd-client.h" - - -/* Handle databases. */ -typedef enum -{ - pwddb, - grpdb, - hstdb, - servdb, - netgrdb, - lastdb -} dbtype; - +#include "nscd-dbtype.h" /* Default limit on the number of times a value gets reloaded without being used in the meantime. NSCD does not throw a value out as diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c index 3a0ed54617..d67910cd9e 100644 --- a/nscd/nscd_stat.c +++ b/nscd/nscd_stat.c @@ -29,78 +29,7 @@ #include "nscd.h" #include "dbg_log.h" #include "selinux.h" -#ifdef HAVE_SELINUX -# include -# include -#endif /* HAVE_SELINUX */ - -/* We use this to make sure the receiver is the same. The lower 16 - bits are reserved for flags indicating compilation variants. This - version needs to be updated if the definition of struct statdata - changes. */ -#define STATDATA_VERSION 0x01020000U - -#ifdef HAVE_SELINUX -# define STATDATA_VERSION_SELINUX_FLAG 0x0001U -#else -# define STATDATA_VERSION_SELINUX_FLAG 0x0000U -#endif - -/* All flags affecting the struct statdata layout. */ -#define STATDATA_VERSION_FLAGS STATDATA_VERSION_SELINUX_FLAG - -/* The full version number for struct statdata. */ -#define STATDATA_VERSION_FULL (STATDATA_VERSION | STATDATA_VERSION_FLAGS) - -/* Statistic data for one database. */ -struct dbstat -{ - int enabled; - int check_file; - int shared; - int persistent; - size_t module; - - unsigned long int postimeout; - unsigned long int negtimeout; - - size_t nentries; - size_t maxnentries; - size_t maxnsearched; - size_t datasize; - size_t dataused; - - uintmax_t poshit; - uintmax_t neghit; - uintmax_t posmiss; - uintmax_t negmiss; - - uintmax_t rdlockdelayed; - uintmax_t wrlockdelayed; - - uintmax_t addfailed; -}; - -/* Record for transmitting statistics. If this definition changes, - update STATDATA_VERSION above. */ -struct statdata -{ - unsigned int version; /* Must be STATDATA_VERSION_FULL. */ - int debug_level; - time_t runtime; - unsigned long int client_queued; - int nthreads; - int max_nthreads; - int paranoia; - time_t restart_interval; - unsigned int reload_count; - int ndbs; - struct dbstat dbs[lastdb]; -#ifdef HAVE_SELINUX - struct avc_cache_stats cstats; -#endif /* HAVE_SELINUX */ -}; - +#include "nscd-statdata.h" void send_stats (int fd, struct database_dyn dbs[lastdb]) From patchwork Fri Mar 20 20:41:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132106 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 0EE354BBCD92 for ; Fri, 20 Mar 2026 20:43:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0EE354BBCD92 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=DqVXsu9k 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.129.124]) by sourceware.org (Postfix) with ESMTP id 9BDD64C31818 for ; Fri, 20 Mar 2026 20:41:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9BDD64C31818 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 9BDD64C31818 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039291; cv=none; b=eAleiEt6CWdongwhSmubnkvqXIA05ug8rJiMbXNa/obpWK4O+vCb5lfhnsgwYGxvoDTZCv+bZXl9nId0fQbbx1Bc++hvKSwBqz5PISMAYb4J3TNGozK4vbqVMgZJ3yDPnueHfgcjwSFM3FFxkcKImKybtKB+GpnIqeHIVCv+oxw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039291; c=relaxed/simple; bh=CxUjfzOMpx3al8G+0S2auzijEdoMV457SR3Whaf9OpI=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=AV2y/dpIajNziwtMzIYGZH5wXG2IlM9mZCUZ5xoaKlzNgF4uMv//d49OWgfj41Chn1oNDbNpA1/BGaFGDzyDY+p/sTuWMpJmVnEDu4SR1ynaJAe6Z9VArO/T7CI0DF9BBIFSDLCkgCluaJhOLhFjM9WIhkhBNr8i7CGf+jFMKYk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9BDD64C31818 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039291; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=OGil5NiEFoyurnpDtmwQJhbimHHsXajUhzYjNgc6BtI=; b=DqVXsu9k0dhjrdo+xiQzDBRDzazyr40FPO2zMmAK9Hjv2UmvYP09hCz/tb74spoofJGeBn Ai+jiXXNS1G8daR2VUJwLgR7FS8mudvTatsdp37djlDetPW8Ous92L0yO078T+Wy764BJj hyHdbQDRXX5kP6dwKqGf7js801sH898= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-41-CmDYux_4NYSZj9uZQg9EdQ-1; Fri, 20 Mar 2026 16:41:30 -0400 X-MC-Unique: CmDYux_4NYSZj9uZQg9EdQ-1 X-Mimecast-MFC-AGG-ID: CmDYux_4NYSZj9uZQg9EdQ_1774039288 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 52607195609D for ; Fri, 20 Mar 2026 20:41:28 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9CD8B180075B for ; Fri, 20 Mar 2026 20:41:27 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 03/23] nscd: Enhance tst-nscd-basic with query counters In-Reply-To: Message-ID: <10c9ef7c1c250ca75ce3193cd4de9cf7eb997d82.1774037705.git.fweimer@redhat.com> References: X-From-Line: 10c9ef7c1c250ca75ce3193cd4de9cf7eb997d82 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:25 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: xQOHfnvkAiySqFDTGq24Aa-d1PqFevOCwJBccS2IyX4_1774039288 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.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_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This helps to test that the cache is actually used. --- nscd/tst-nscd-basic.c | 58 ++++++++++++++++++++++++++++++++++++++++++ support/nscd_test.h | 4 +++ support/support_nscd.c | 33 ++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/nscd/tst-nscd-basic.c b/nscd/tst-nscd-basic.c index 2ce1fece60..3dfde92c36 100644 --- a/nscd/tst-nscd-basic.c +++ b/nscd/tst-nscd-basic.c @@ -31,6 +31,8 @@ #include #include +#include + /* Large GECOS string for the large-gecos user. */ static char *large_gecos; @@ -452,17 +454,73 @@ do_test (void) /* First run the tests without nscd running, to check that the test expectations are correct. Use a separate process to avoid caching nscd availability. */ + puts ("info: testing without nscd"); support_isolate_in_subprocess (all_tests, NULL); support_nscd_copy_configuration (); support_nscd_start (); + /* Initially the query counters are all zero. */ + { + struct statdata stat; + support_nscd_get_statistics (&stat); + for (int i = 0; i < lastdb; ++i) + { + TEST_COMPARE (stat.dbs[i].nentries, 0); + TEST_COMPARE (stat.dbs[i].poshit, 0); + TEST_COMPARE (stat.dbs[i].neghit, 0); + TEST_COMPARE (stat.dbs[i].posmiss, 0); + TEST_COMPARE (stat.dbs[i].negmiss, 0); + } + } + + puts ("info: first pass with nscd"); all_tests (NULL); + /* After running the tests, we have cache entries in all databases. + The counters have been empirically determined. They mostly check + that nscd is actually used. */ + struct statdata stat_first_pass; + support_nscd_get_statistics (&stat_first_pass); + TEST_COMPARE (stat_first_pass.dbs[pwddb].nentries, 10); + TEST_COMPARE (stat_first_pass.dbs[pwddb].posmiss, 4); + TEST_COMPARE (stat_first_pass.dbs[pwddb].negmiss, 2); + TEST_COMPARE (stat_first_pass.dbs[grpdb].nentries, 10); + TEST_COMPARE (stat_first_pass.dbs[grpdb].posmiss, 5); + TEST_COMPARE (stat_first_pass.dbs[grpdb].negmiss, 2); + TEST_COMPARE (stat_first_pass.dbs[hstdb].nentries, 5); + TEST_COMPARE (stat_first_pass.dbs[hstdb].posmiss, 5); + TEST_COMPARE (stat_first_pass.dbs[hstdb].negmiss, 0); + TEST_COMPARE (stat_first_pass.dbs[netgrdb].nentries, 25); + TEST_COMPARE (stat_first_pass.dbs[netgrdb].posmiss, 25); + TEST_COMPARE (stat_first_pass.dbs[netgrdb].negmiss, 0); + TEST_COMPARE (stat_first_pass.dbs[servdb].nentries, 5); + TEST_COMPARE (stat_first_pass.dbs[servdb].posmiss, 3); + TEST_COMPARE (stat_first_pass.dbs[servdb].negmiss, 2); + /* Retry from cache. */ + puts ("info: second pass with nscd, with caching"); all_tests (NULL); + /* Retries should have used the cache and not increment the query + counters. This means that the shared mapping is used, not the + socket query interface or the in-process nss_files service + module. */ + { + struct statdata stat; + support_nscd_get_statistics (&stat); + for (int i = 0; i < lastdb; ++i) + { + TEST_COMPARE (stat.dbs[i].nentries, stat_first_pass.dbs[i].nentries); + TEST_COMPARE (stat.dbs[i].poshit, stat_first_pass.dbs[i].poshit); + TEST_COMPARE (stat.dbs[i].neghit, stat_first_pass.dbs[i].neghit); + TEST_COMPARE (stat.dbs[i].posmiss, stat_first_pass.dbs[i].posmiss); + TEST_COMPARE (stat.dbs[i].negmiss, stat_first_pass.dbs[i].negmiss); + } + } + + puts ("info: pass with interleaved invalidation"); invalidate = support_nscd_invalidate; all_tests (NULL); diff --git a/support/nscd_test.h b/support/nscd_test.h index 60208098f4..95d9c1cd38 100644 --- a/support/nscd_test.h +++ b/support/nscd_test.h @@ -36,4 +36,8 @@ void support_nscd_stop (void); services). */ void support_nscd_invalidate (const char *database); +/* Fill in *STATS with data from the running nscd daemon. */ +struct statdata; +void support_nscd_get_statistics (struct statdata *stat); + #endif /* SUPPORT_NSCD_TEST_H */ diff --git a/support/support_nscd.c b/support/support_nscd.c index 2d7d503ad6..96d1e6b874 100644 --- a/support/support_nscd.c +++ b/support/support_nscd.c @@ -18,20 +18,25 @@ #include +#include #include #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include static pid_t nscd_pid; @@ -113,3 +118,31 @@ support_nscd_invalidate (const char *database) TEST_COMPARE (system (cmd), 0); free (cmd); } + +void +support_nscd_get_statistics (struct statdata *stat) +{ + struct sockaddr_un sun; + sun.sun_family = AF_UNIX; + strcpy (sun.sun_path, _PATH_NSCDSOCKET); + + int sock = socket (PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sock < 0 || connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0) + FAIL_EXIT1 ("failed to open nscd socket: %m"); + + request_header req; + req.version = NSCD_VERSION; + req.type = GETSTAT; + req.key_len = 0; + + if (TEMP_FAILURE_RETRY (send (sock, &req, sizeof (req), MSG_NOSIGNAL)) + != sizeof (req)) + FAIL_EXIT1 ("failed to send request to nscd: %m"); + + ssize_t ret = TEMP_FAILURE_RETRY (recv (sock, stat, sizeof (*stat), 0)); + + errno = EMSGSIZE; + if (ret != sizeof (*stat) || stat->version != STATDATA_VERSION_FULL) + FAIL_EXIT1 ("failed to receive statistics from nscd: %m"); + close (sock); +} From patchwork Fri Mar 20 20:41:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132110 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id BACC84C900E8 for ; Fri, 20 Mar 2026 20:45:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BACC84C900E8 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=N4qzchvr 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.129.124]) by sourceware.org (Postfix) with ESMTP id 1B22A4C900DA for ; Fri, 20 Mar 2026 20:41:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1B22A4C900DA Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 1B22A4C900DA Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039308; cv=none; b=lECS9uV5YCEC0QNDuwiox1rJT8Llb9xBOxtWtuOt58ELV2I11dn6UhvXz/Q+2wHki0w0fk1BqBNO3eDuIw7MHZctutGOLjt214vB+0KcAXxl3GpUkFyMgTbxA9zOWmF1G1MjUCRzSkvDNugt8ruXDcQRnub8pf2OqHDFk6BTtp0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039308; c=relaxed/simple; bh=jmvs47ZhXaea0lKeWQ+U5mdLjyMCSW08lzpBRaimZOs=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=KkhfLsjp+GEKVJ36QJM7BLL2F3Sfd2a2y5t8+u1Z7KYGbku0BtPWLimZONN+4SqhJTPXEWjBuC7uFR5yrIeDw0ROt5VcIKCHqXZ0FlbE3tdu98cPc83YBK+n5G2UK1x8vhxRRrXQb9fLM9SHFKNxxqJm5aArPQ9Cgec/3jHymKo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1B22A4C900DA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039302; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=ed2JHbdSh17E6kKEI+Kq6rEeIglkgth1n3BtcRKCECI=; b=N4qzchvrYjUxrCrKpmXiyWjUbkVtVpZRXcImvmItEeV6XjD0AnbLZoIFXBlSYcfy67TdHF UW16CR4qvFOBQeVt+7YIugdrwUa6+hrmWIergTeDrf5irpI9SanUcRQNvK1owQfa+IVh0p 4l4qjrHhV3v5lBhz+6thQwI+H/+SxAA= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-453-VdWUIDeqMf6delme95-9pw-1; Fri, 20 Mar 2026 16:41:41 -0400 X-MC-Unique: VdWUIDeqMf6delme95-9pw-1 X-Mimecast-MFC-AGG-ID: VdWUIDeqMf6delme95-9pw_1774039300 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6F90E1956048 for ; Fri, 20 Mar 2026 20:41:40 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B6BBD1953944 for ; Fri, 20 Mar 2026 20:41:39 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 04/23] nss: Add negative lookup test In-Reply-To: Message-ID: <6f3039be2fe4e959a64c69ad177b4a70d539eda1.1774037705.git.fweimer@redhat.com> References: X-From-Line: 6f3039be2fe4e959a64c69ad177b4a70d539eda1 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:37 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: W3XRofMmm7ek4lGKOP6edMzt8g5kpi3eHqLcG_T3iUk_1774039300 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, PROLO_LEO1, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 --- nss/Makefile | 3 + nss/tst-nss-does-not-exist.cc | 210 ++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 nss/tst-nss-does-not-exist.cc diff --git a/nss/Makefile b/nss/Makefile index 1c48bd0876..42d28cf40a 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -324,6 +324,7 @@ tests := \ tst-gethnm \ tst-getpw \ tst-gshadow \ + tst-nss-does-not-exist \ tst-nss-getpwent \ tst-nss-hash \ tst-nss-malloc-failure-getlogin_r \ @@ -537,3 +538,5 @@ LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags + +LDLIBS-tst-nss-does-not-exist = -lstdc++ diff --git a/nss/tst-nss-does-not-exist.cc b/nss/tst-nss-does-not-exist.cc new file mode 100644 index 0000000000..72f7c635d8 --- /dev/null +++ b/nss/tst-nss-does-not-exist.cc @@ -0,0 +1,210 @@ +/* Verify that lookup failures have the expected error behavior. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This test case triggers lookup failures for most NSS functions + (both allocated and *_r variants). It is written in C++ so that + the required types can be inferred from the lookup functions + themselves. */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char non_existing_name[] + = "this-name-does-not-exist-in-the-system"; + +/* True if *_r lookup functions for type T use an extra h_errno + argument. */ +template constexpr bool uses_h_errno = + std::is_same_v || std::is_same_v ; + +/* Call a *_r NSS function that produces an NSS lookup of result T + repeatedly until it does not return ERANGE. The final return value + is written to the ret member, and the pointer to the result + structure to the result member. The result can be nullptr for a + negative lookup result. */ +template +struct erange_wrapper +{ + int ret; + T *result; + + template + erange_wrapper (Impl impl, Args&&... args) + { + buffer.resize (32); + result = (T *) -1; + while (true) + { + h_errno = 0; + int herrno = 0; + if constexpr (uses_h_errno ) + ret = impl (std::forward(args)..., + &storage, buffer.data (), buffer.size (), &result, + &herrno); + else + { + /* No h_errno pointer argument. Pretend that failures + are always due to NETDB_INTERNAL. */ + ret = impl (std::forward(args)..., + &storage, buffer.data (), buffer.size (), &result); + herrno = NETDB_INTERNAL; + } + if (herrno == NETDB_INTERNAL && ret == ERANGE) + { + buffer.resize (buffer.size () * 2); + TEST_VERIFY (buffer.size () > 0); + } + else + break; + } + } + + /* Verify that ret and result denote a negative lookup result. */ + void expected_negative () + { + TEST_COMPARE (ret, 0); + TEST_VERIFY (result == nullptr); + } + +private: + T storage; + std::vector buffer; +}; + +/* Verify that looking up non_existing_name fails for the non-_r and _r + function variants. */ +template +static void +check_missing_name (Lookup lookup, LookupR lookup_r, Args&&... args) +{ + verbose_printf ("info: name lookup: %s\n", + strchr (__PRETTY_FUNCTION__, '[')); + errno = 0; + auto r = lookup (non_existing_name, std::forward(args)...); + TEST_VERIFY (r == nullptr); + TEST_COMPARE (errno, 0); + using nss_type = typename std::remove_reference ::type; + erange_wrapper (lookup_r, non_existing_name, + std::forward(args)...).expected_negative (); +} + +/* Find an ID that results in a lookup failure using the non-_r function, + and then verify that it also fails with the _r function. ID_MEMBER + is the pointer to the struct member that contains the looked-up ID. */ +template +static void +find_missing_id (const char *type_name, Lookup lookup, LookupR lookup_r, + Member id_member, Args&&... args) +{ + verbose_printf ("info: ID lookup for %s: %s\n", + type_name, strchr (__PRETTY_FUNCTION__, '[')); + using nss_type = typename std::remove_reference + (args)...))>::type; + using id_type = decltype(nss_type{}.*id_member); + for (id_type i = 0; i < 65536; ++i) + { + verbose_printf ("info: trying %lld\n", (long long int) i); + errno = 0; + nss_type *r = lookup (i, std::forward(args)...); + if (r == nullptr) + { + TEST_COMPARE (errno, 0); + printf ("info: first missing %s: %lld\n", type_name, + (long long int) i); + + erange_wrapper (lookup_r, i, std::forward(args)...) + .expected_negative (); + return; + } + TEST_COMPARE (r->*id_member, i); + } + printf ("warning: could not find an undefined ID for %s\n", type_name); +} + +static void +checks (void *closure) +{ + check_missing_name (getpwnam, getpwnam_r); + find_missing_id ("passwd", getpwuid, getpwuid_r, &passwd::pw_uid); + + check_missing_name (getgrnam, getgrnam_r); + find_missing_id ("group", getgrgid, getgrgid_r, &group::gr_gid); + + check_missing_name (getprotobyname, getprotobyname_r); + find_missing_id ("protoent", getprotobynumber, getprotobynumber_r, + &protoent::p_proto); + + check_missing_name (getservbyname, getservbyname_r, "tcp"); + find_missing_id ("servent", getservbyport, getservbyport_r, + &servent::s_port, "tcp"); + + check_missing_name (getaliasbyname, getaliasbyname_r); + + check_missing_name (getrpcbyname, getrpcbyname_r); + find_missing_id ("rpcent", getrpcbynumber, getrpcbynumber_r, + &rpcent::r_number); + + check_missing_name (gethostbyname, gethostbyname_r); + check_missing_name (gethostbyname2, gethostbyname2_r, AF_INET); + + check_missing_name (getnetbyname, getnetbyname_r); + + /* Exceptional case: no buffer argument, no ERANGE protocol. */ + { + errno = 0; + TEST_VERIFY (ether_aton (non_existing_name) == nullptr); + TEST_COMPARE (errno, 0); + struct ether_addr addr; + TEST_VERIFY (ether_aton_r (non_existing_name, &addr) == nullptr); + TEST_COMPARE (errno, 0); + } +} + +static int +do_test (void) +{ + /* First test the system default. */ + puts ("info: testing system default"); + support_isolate_in_subprocess (checks, nullptr); + + /* Then test the files module specifically. */ + puts ("info: testing files module"); +#define DEFINE_DATABASE(db) __nss_configure_lookup (#db, "files"); +#include "databases.def" +#undef DEFINE_DATABASE + support_isolate_in_subprocess (checks, nullptr); + + return 0; +} + +#include From patchwork Fri Mar 20 20:41:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132105 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id C594B4C91741 for ; Fri, 20 Mar 2026 20:43:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C594B4C91741 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=he06lZMO 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 ESMTP id 0A63D4C318BD for ; Fri, 20 Mar 2026 20:41:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0A63D4C318BD Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 0A63D4C318BD 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=1774039315; cv=none; b=nZWSTw+ESQeDSySXv62z7yZwuj8pM8nvCQTVZhorEE5u87CSuIEmOkMvke/18lSW2isFSvTf4/3mC3ucxv6sl6X+ewAhe4o8idhRh1xr18JkRBexFPRO8vQvzpJro7EbZSgnzYIUHAazJhotCDA+AlHeYeTulwqJMq7oVzk+kU4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039315; c=relaxed/simple; bh=s2LoEyKLqFbHU+vRAgJMHwNNrwmeKFnqRgzER5PR2T8=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=E85Y46TfXse99tYuPM/6M1EKXX9q1NKSzrF/43XOJZ5PTHAe+CakLnGQ9wyv1zH07nSW08hUNMlKttLF424SGxKknXUKvuL3P8UgKN5SwjYwIM6A0Y843KrKzeFqmiRzvggNvDYe5IphkXDXX7kJh52+kvaouQo315UzS/LZyxE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0A63D4C318BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039314; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Uv5MYpsmCP6hJyZeFDpCbtswZodhIiHYeyHJSLtCs+8=; b=he06lZMOMbwqgvI/Vl2aCB0uSAlCp7+9oBQN/iOVOiskwF1OTy8OZGkFEeGJe3tHUQWO/7 UWwB+mJnlD4N5DTarHSiM0r0sWgrXTxP+lWNvODU0SBymxcdG8PqtiEjGGdRHYRZ7BwElC fwsUyoAKMIPL5LxvVNhvNXaW1fc7qH0= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-304-9gPu7Je2NzSt12E1rx9miQ-1; Fri, 20 Mar 2026 16:41:52 -0400 X-MC-Unique: 9gPu7Je2NzSt12E1rx9miQ-1 X-Mimecast-MFC-AGG-ID: 9gPu7Je2NzSt12E1rx9miQ_1774039311 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 54D6219560A1 for ; Fri, 20 Mar 2026 20:41:51 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1A70B1955F21 for ; Fri, 20 Mar 2026 20:41:48 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 05/23] nscd: Use a real read-write lock for the client mapping In-Reply-To: Message-ID: <1e048d41dc8149f70536e8b0868af56b57642926.1774037705.git.fweimer@redhat.com> References: X-From-Line: 1e048d41dc8149f70536e8b0868af56b57642926 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:46 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 4DYnhP-4kHZiT16mA_xJo4z_55Mevr44PX7PBKJLdQA_1774039311 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 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_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 The old code had half of an implementation of a rwlock, but did not have code to wait in case the mapping was used by another thread, so it performed busy waiting in some cases. Switch to a proper rwlock instead. Simplify the memory management by pre-allocating the struct mapped_database structures. Consolidate all struct definitions in an array in nscd_helper.c. This will make it possible to add fork safety later, in a centralized fashion. Simplify the error reporting and consolidate the retry logic. There is still no proper software TM protocol, the code is just simplified while retaining the old (incorrect) GC checks. Assume that SCM_RIGHTS and MSG_CMSG_CLOEXEC are always available (Linux and Hurd have them). I converted nscd_getpw_r.c manually, and guided automation to update the other files. Adjusting __nscd_get_nl_timestamp required additional instructions (use __nscd_get_map_ref, despite the potential loss of efficiency). Auto-generation should be fine here because the changes are mechanical and they mostly delete code. The definition of MAPPED_DATABASE_INITIALIZER is a slight layering violation, but both htl and ntpl use pthread rwlocks directly. --- include/set-freeres.h | 5 -- malloc/set-freeres.c | 15 ---- nscd/nscd-client.h | 90 ++++++---------------- nscd/nscd_getai.c | 39 +++------- nscd/nscd_getgr_r.c | 52 +++---------- nscd/nscd_gethst_r.c | 85 +++++--------------- nscd/nscd_getpw_r.c | 46 ++--------- nscd/nscd_getserv_r.c | 55 +++---------- nscd/nscd_helper.c | 171 +++++++++++++++++++++++++---------------- nscd/nscd_initgroups.c | 32 ++------ nscd/nscd_netgroup.c | 72 ++++------------- 11 files changed, 208 insertions(+), 454 deletions(-) diff --git a/include/set-freeres.h b/include/set-freeres.h index 470ce00791..55093aa89d 100644 --- a/include/set-freeres.h +++ b/include/set-freeres.h @@ -46,11 +46,6 @@ extern void __gconv_dl_freemem (void) attribute_hidden; extern void __intl_freemem (void) attribute_hidden; extern void __libio_freemem (void) attribute_hidden; extern void __libc_fstab_freemem (void) attribute_hidden; -extern void __nscd_gr_map_freemem (void) attribute_hidden; -extern void __nscd_hst_map_freemem (void) attribute_hidden; -extern void __nscd_pw_map_freemem (void) attribute_hidden; -extern void __nscd_serv_map_freemem (void) attribute_hidden; -extern void __nscd_group_map_freemem (void) attribute_hidden; extern void __libc_regcomp_freemem (void) attribute_hidden; extern void __libc_atfork_freemem (void) attribute_hidden; extern void __libc_resolv_conf_freemem (void) attribute_hidden; diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c index ab2998db89..39fd7d4d27 100644 --- a/malloc/set-freeres.c +++ b/malloc/set-freeres.c @@ -36,13 +36,6 @@ # pragma weak __intl_freemem # pragma weak __libio_freemem # pragma weak __libc_fstab_freemem -#ifdef USE_NSCD -# pragma weak __nscd_gr_map_freemem -# pragma weak __nscd_hst_map_freemem -# pragma weak __nscd_pw_map_freemem -# pragma weak __nscd_serv_map_freemem -# pragma weak __nscd_group_map_freemem -#endif # pragma weak __libc_regcomp_freemem # pragma weak __libc_atfork_freemem # pragma weak __res_thread_freeres @@ -144,14 +137,6 @@ __libc_freeres (void) call_function_static_weak (__libio_freemem); call_function_static_weak (__libc_fstab_freemem); -#ifdef USE_NSCD - call_function_static_weak (__nscd_gr_map_freemem); - call_function_static_weak (__nscd_hst_map_freemem); - call_function_static_weak (__nscd_pw_map_freemem); - call_function_static_weak (__nscd_serv_map_freemem); - call_function_static_weak (__nscd_group_map_freemem); -#endif - call_function_static_weak (__libc_regcomp_freemem); call_function_static_weak (__libc_atfork_freemem); /* __res_thread_freeres deallocates the per-thread resolv_context); diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h index 0906de2929..aff303b757 100644 --- a/nscd/nscd-client.h +++ b/nscd/nscd-client.h @@ -29,7 +29,7 @@ #include #include #include - +#include /* Version number of the daemon interface */ #define NSCD_VERSION 2 @@ -351,83 +351,43 @@ struct mapped_database { const struct database_pers_head *head; const char *data; - size_t mapsize; - int counter; /* > 0 indicates it is usable. */ + size_t mapsize; /* Zero means not in use. */ size_t datasize; -}; -#define NO_MAPPING ((struct mapped_database *) -1l) -struct locked_map_ptr -{ - int lock; - struct mapped_database *mapped; + /* Use of the mapping must acquire a read lock. If the mapping is + changed, acquire a write lock. */ + __libc_rwlock_define (, lock); }; -#define libc_locked_map_ptr(class, name) class struct locked_map_ptr name - -/* Try acquiring lock for mapptr, returns true if it succeeds, false - if not. */ -static inline bool -__nscd_acquire_maplock (volatile struct locked_map_ptr *mapptr) -{ - int cnt = 0; - while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock, - 1, 0) != 0, 0)) - { - // XXX Best number of rounds? - if (__glibc_unlikely (++cnt > 5)) - return false; - - atomic_spin_nop (); - } - - return true; -} - /* Open socket connection to nscd server. */ extern int __nscd_open_socket (const char *key, size_t keylen, request_type type, void *response, size_t responselen) attribute_hidden; -/* Try to get a file descriptor for the shared memory segment - containing the database. */ -extern struct mapped_database *__nscd_get_mapping (request_type type, - const char *key, - struct mapped_database **mappedp) attribute_hidden; - -/* Get reference of mapping. */ -extern struct mapped_database *__nscd_get_map_ref (request_type type, - const char *name, - volatile struct locked_map_ptr *mapptr, - int *gc_cyclep) - attribute_hidden; +/* Acquire reference to the mapping for DB (see ). On + success, return a pointer to the mapping descriptor, and lock the + mapping. + + Errors are not fatal (socket fallback should be used, + rather than reporting an error immediately to the caller). -/* Unmap database. */ -extern void __nscd_unmap (struct mapped_database *mapped) + To release the map reference, call __nscd_map_ref_retry_or_drop below. */ +struct mapped_database *__nscd_get_map_ref (unsigned int db, int *gc_cyclep) attribute_hidden; -/* Drop reference of mapping. */ -static int -__attribute__ ((unused)) -__nscd_drop_map_ref (struct mapped_database *map, int *gc_cycle) -{ - if (map != NO_MAPPING) - { - int now_cycle = map->head->gc_cycle; - if (__glibc_unlikely (now_cycle != *gc_cycle)) - { - /* We might have read inconsistent data. */ - *gc_cycle = now_cycle; - return -1; - } - - if (atomic_fetch_add_relaxed (&map->counter, -1) == 1) - __nscd_unmap (map); - } - - return 0; -} +/* If *MAPPED is not null, check that *GC_CYCLE matches the current cycle in + **MAPPED. If not, the function may return true to indicate another + attempt, and increments *NRETRIES. If the retry counter is + exceeded, set *MAPPED to null, unlock the mapping, and return + true to retry once more without the mapping. + + If no retries are needed, unlock the mapping (for non-null *MAPPED), and + return false. This always happens if retval == -1. + Must be called after __nscd_get_map_ref. */ +bool __nscd_map_ref_retry_or_drop (struct mapped_database **mapped, + int *gc_cycle, int *nretries, int retval) + attribute_hidden; /* Search the mapped database. */ extern struct datahead *__nscd_cache_search (request_type type, diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c index 4aca0a18c4..a2e5da6b1c 100644 --- a/nscd/nscd_getai.c +++ b/nscd/nscd_getai.c @@ -24,16 +24,13 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" /* Define in nscd_gethst_r.c. */ extern int __nss_not_use_nscd_hosts; - -/* We use the mapping from nscd_gethst. */ -libc_locked_map_ptr (extern, __hst_map_handle) attribute_hidden; - /* Defined in nscd_gethst_r.c. */ extern int __nss_have_localdomain attribute_hidden; @@ -58,9 +55,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle, - &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (hstdb, &gc_cycle); retry:; struct nscd_ai_result *resultbuf = NULL; @@ -70,10 +65,10 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) int sock = -1; ai_response_header ai_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { struct datahead *found = __nscd_cache_search (GETAI, key, keylen, - mapped, sizeof ai_resp); + map, sizeof ai_resp); if (found != NULL) { respdata = (char *) (&found->data[0].aidata + 1); @@ -81,7 +76,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) recend = (const char *) found->data + found->recsize; /* Now check if we can trust ai_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -157,7 +152,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) && resultbuf->canon[ai_resp.canonlen - 1] != '\0') /* We cannot use the database. */ { - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) retval = -2; else free (resultbuf); @@ -190,25 +185,11 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - { - *result = NULL; - free (resultbuf); - goto retry; - } + *result = NULL; + free (resultbuf); + goto retry; } return retval; diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c index db3c0ab464..746b11d792 100644 --- a/nscd/nscd_getgr_r.c +++ b/nscd/nscd_getgr_r.c @@ -33,6 +33,7 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" int __nss_not_use_nscd_group; @@ -63,23 +64,6 @@ __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer, buffer, buflen, result); } - -libc_locked_map_ptr (,__gr_map_handle) attribute_hidden; -/* Note that we only free the structure if necessary. The memory - mapping is not removed since it is not visible to the malloc - handling. */ -void -__nscd_gr_map_freemem (void) -{ - if (__gr_map_handle.mapped != NO_MAPPING) - { - void *p = __gr_map_handle.mapped; - __gr_map_handle.mapped = NO_MAPPING; - free (p); - } -} - - static int nscd_getgr_r (const char *key, size_t keylen, request_type type, struct group *resultbuf, char *buffer, size_t buflen, @@ -93,9 +77,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped = __nscd_get_map_ref (GETFDGR, "group", - &__gr_map_handle, - &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (grpdb, &gc_cycle); retry:; const char *gr_name = NULL; size_t gr_name_len = 0; @@ -103,9 +85,9 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, const char *recend = (const char *) ~UINTMAX_C (0); gr_response_header gr_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped, + struct datahead *found = __nscd_cache_search (type, key, keylen, map, sizeof gr_resp); if (found != NULL) { @@ -117,7 +99,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, recend = (const char *) found->data + found->recsize; /* Now check if we can trust gr_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -239,7 +221,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, { /* len array might contain garbage during nscd GC cycle, retry rather than fail in that case. */ - if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle) + if (gr_name != NULL && map->head->gc_cycle != gc_cycle) retval = -2; goto out_close; } @@ -247,7 +229,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, { /* len array might contain garbage during nscd GC cycle, retry rather than fail in that case. */ - if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle) + if (gr_name != NULL && map->head->gc_cycle != gc_cycle) { retval = -2; goto out_close; @@ -286,7 +268,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, cnt < gr_resp.gr_mem_cnt; })) { /* We cannot use the database. */ - retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1; + retval = map != NULL && map->head->gc_cycle != gc_cycle ? -2 : -1; goto out_close; } @@ -305,22 +287,8 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) - { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - goto retry; - } + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) + goto retry; scratch_buffer_free (&lenbuf); diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c index 9291039008..15d747fc33 100644 --- a/nscd/nscd_gethst_r.c +++ b/nscd/nscd_gethst_r.c @@ -24,6 +24,7 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" int __nss_not_use_nscd_hosts; @@ -77,52 +78,22 @@ __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type, } -libc_locked_map_ptr (, __hst_map_handle) attribute_hidden; -/* Note that we only free the structure if necessary. The memory - mapping is not removed since it is not visible to the malloc - handling. */ -void -__nscd_hst_map_freemem (void) -{ - if (__hst_map_handle.mapped != NO_MAPPING) - { - void *p = __hst_map_handle.mapped; - __hst_map_handle.mapped = NO_MAPPING; - free (p); - } -} - - uint32_t __nscd_get_nl_timestamp (void) { - uint32_t retval; if (__nss_not_use_nscd_hosts != 0) return 0; - /* __nscd_get_mapping can change hst_map_handle.mapped to NO_MAPPING. - However, __nscd_get_mapping assumes the prior value was not NO_MAPPING. - Thus we have to acquire the lock to prevent this thread from changing - hst_map_handle.mapped to NO_MAPPING while another thread is inside - __nscd_get_mapping. */ - if (!__nscd_acquire_maplock (&__hst_map_handle)) - return 0; - - struct mapped_database *map = __hst_map_handle.mapped; - - if (map == NULL - || (map != NO_MAPPING - && map->head->nscd_certainly_running == 0 - && map->head->timestamp + MAPPING_TIMEOUT < time64_now ())) - map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped); - - if (map == NO_MAPPING) - retval = 0; + int gc_cycle; + uint32_t retval; + struct mapped_database *map = __nscd_get_map_ref (hstdb, &gc_cycle); + if (map != NULL) + { + retval = map->head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]; + __libc_rwlock_unlock (map->lock); + } else - retval = map->head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP]; - - /* Release the lock. */ - __hst_map_handle.lock = 0; + retval = 0; return retval; } @@ -151,9 +122,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle, - &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (hstdb, &gc_cycle); retry:; const char *h_name = NULL; @@ -164,11 +133,11 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, const char *recend = (const char *) ~UINTMAX_C (0); int sock = -1; hst_response_header hst_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { /* No const qualifier, as it can change during garbage collection. */ - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped, - sizeof hst_resp); + struct datahead *found = __nscd_cache_search (type, key, keylen, + map, sizeof hst_resp); if (found != NULL) { h_name = (char *) (&found->data[0].hstdata + 1); @@ -180,7 +149,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, recend = (const char *) found->data + found->recsize; /* Now check if we can trust hst_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -364,7 +333,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, { /* aliases_len array might contain garbage during nscd GC cycle, retry rather than fail in that case. */ - if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle) + if (addr_list != NULL && map->head->gc_cycle != gc_cycle) retval = -2; goto out_close; } @@ -373,7 +342,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, { /* aliases_len array might contain garbage during nscd GC cycle, retry rather than fail in that case. */ - if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle) + if (addr_list != NULL && map->head->gc_cycle != gc_cycle) { retval = -2; goto out_close; @@ -406,7 +375,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, cnt < hst_resp.h_aliases_cnt; })) { /* We cannot use the database. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) retval = -2; goto out_close; } @@ -430,22 +399,8 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) - { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - goto retry; - } + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) + goto retry; return retval; } diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c index f19b7a271c..938eac9c70 100644 --- a/nscd/nscd_getpw_r.c +++ b/nscd/nscd_getpw_r.c @@ -31,6 +31,7 @@ #include <_itoa.h> #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" int __nss_not_use_nscd_passwd; @@ -63,22 +64,6 @@ __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer, } -libc_locked_map_ptr (static, map_handle); -/* Note that we only free the structure if necessary. The memory - mapping is not removed since it is not visible to the malloc - handling. */ -void -__nscd_pw_map_freemem (void) -{ - if (map_handle.mapped != NO_MAPPING) - { - void *p = map_handle.mapped; - map_handle.mapped = NO_MAPPING; - free (p); - } -} - - static int nscd_getpw_r (const char *key, size_t keylen, request_type type, struct passwd *resultbuf, char *buffer, size_t buflen, @@ -89,8 +74,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (pwddb, &gc_cycle); retry:; const char *pw_name = NULL; @@ -98,9 +82,9 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, const char *recend = (const char *) ~UINTMAX_C (0); pw_response_header pw_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped, + struct datahead *found = __nscd_cache_search (type, key, keylen, map, sizeof pw_resp); if (found != NULL) { @@ -109,7 +93,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, recend = (const char *) found->data + found->recsize; /* Now check if we can trust pw_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -199,7 +183,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0') { /* We cannot use the database. */ - retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1; + retval = map->head->gc_cycle != gc_cycle ? -2 : -1; goto out_close; } @@ -218,22 +202,8 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) - { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - goto retry; - } + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) + goto retry; return retval; } diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c index 63cd6d5860..519078d8fe 100644 --- a/nscd/nscd_getserv_r.c +++ b/nscd/nscd_getserv_r.c @@ -23,6 +23,7 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" @@ -58,22 +59,6 @@ __nscd_getservbyport_r (int port, const char *proto, } -libc_locked_map_ptr (, __serv_map_handle) attribute_hidden; -/* Note that we only free the structure if necessary. The memory - mapping is not removed since it is not visible to the malloc - handling. */ -void -__nscd_serv_map_freemem (void) -{ - if (__serv_map_handle.mapped != NO_MAPPING) - { - void *p = __serv_map_handle.mapped; - __serv_map_handle.mapped = NO_MAPPING; - free (p); - } -} - - static int nscd_getserv_r (const char *crit, size_t critlen, const char *proto, request_type type, struct servent *resultbuf, @@ -85,9 +70,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDSERV, "services", &__serv_map_handle, - &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (servdb, &gc_cycle); size_t protolen = proto == NULL ? 0 : strlen (proto); size_t keylen = critlen + 1 + protolen + 1; int alloca_key = __libc_use_alloca (keylen); @@ -114,9 +97,9 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, int sock = -1; serv_response_header serv_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { - struct datahead *found = __nscd_cache_search (type, key, keylen, mapped, + struct datahead *found = __nscd_cache_search (type, key, keylen, map, sizeof serv_resp); if (found != NULL) @@ -131,7 +114,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, recend = (const char *) found->data + found->recsize; /* Now check if we can trust serv_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -291,7 +274,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, { /* aliases_len array might contain garbage during nscd GC cycle, retry rather than fail in that case. */ - if (aliases_list != NULL && mapped->head->gc_cycle != gc_cycle) + if (aliases_list != NULL && map->head->gc_cycle != gc_cycle) retval = -2; goto out_close; } @@ -301,7 +284,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, { /* aliases_len array might contain garbage during nscd GC cycle, retry rather than fail in that case. */ - if (aliases_list != NULL && mapped->head->gc_cycle != gc_cycle) + if (aliases_list != NULL && map->head->gc_cycle != gc_cycle) { retval = -2; goto out_close; @@ -334,7 +317,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, cnt < serv_resp.s_aliases_cnt; })) { /* We cannot use the database. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) retval = -2; goto out_close; } @@ -355,25 +338,11 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - { - if (!alloca_aliases_len) - free ((void *) aliases_len); - goto retry; - } + if (!alloca_aliases_len) + free ((void *) aliases_len); + goto retry; } if (!alloca_aliases_len) diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index 6319fde6f2..d3bfc208ad 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -39,6 +39,7 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" /* Extra time we wait if the socket is still receiving data. This value is in milliseconds. Note that the other side is nscd on the @@ -241,32 +242,64 @@ open_socket (request_type type, const char *key, size_t keylen) return -1; } +#define MAPPED_DATABASE_INITIALIZER \ + ((struct mapped_database) { .lock = PTHREAD_RWLOCK_INITIALIZER, }) -void -__nscd_unmap (struct mapped_database *mapped) -{ - assert (mapped->counter == 0); - __munmap ((void *) mapped->head, mapped->mapsize); - free (mapped); -} - +static struct mapped_database __nscd_mapped_databases[lastdb] = + { + [pwddb] = MAPPED_DATABASE_INITIALIZER, + [grpdb] = MAPPED_DATABASE_INITIALIZER, + [hstdb] = MAPPED_DATABASE_INITIALIZER, + [servdb] = MAPPED_DATABASE_INITIALIZER, + [netgrdb] = MAPPED_DATABASE_INITIALIZER, + }; /* Try to get a file descriptor for the shared memory segment - containing the database. */ -struct mapped_database * -__nscd_get_mapping (request_type type, const char *key, - struct mapped_database **mappedp) + containing the database. Lock the mapping, but mapsize might still + be 0 after return because there is no mapping. */ +static void +__nscd_get_mapping (unsigned int db) { - struct mapped_database *result = NO_MAPPING; -#ifdef SCM_RIGHTS + struct mapped_database *mapped = &__nscd_mapped_databases[db]; + + static const uint8_t requests[] = + { + [pwddb] = GETFDPW, + [grpdb] = GETFDGR, + [hstdb] = GETFDHST, + [servdb] = GETFDSERV, + [netgrdb] = GETFDNETGR, + }; + + static const char keys[][9] = + { + [pwddb] = "passwd", + [grpdb] = "group", + [hstdb] = "hosts", + [servdb] = "services", + [netgrdb] = "netgroup" + }; + const char *key = keys[db]; const size_t keylen = strlen (key) + 1; + + __libc_rwlock_wrlock (mapped->lock); + + /* Remove any previously existing mapping. */ + if (mapped->mapsize > 0) + { + __munmap ((void *) mapped->head, mapped->mapsize); + mapped->head = NULL; + mapped->data = NULL; + mapped->mapsize = 0; + } + int saved_errno = errno; int mapfd = -1; - char resdata[keylen]; + char resdata[sizeof (keys[0])]; /* Open a socket and send the request. */ - int sock = open_socket (type, key, keylen); + int sock = open_socket (requests[db], key, keylen); if (sock < 0) goto out; @@ -302,9 +335,6 @@ __nscd_get_mapping (request_type type, const char *key, if (wait_on_socket (sock, 5 * 1000) <= 0) goto out_close2; -# ifndef MSG_CMSG_CLOEXEC -# define MSG_CMSG_CLOEXEC 0 -# endif ssize_t n = TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, MSG_CMSG_CLOEXEC)); if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL @@ -362,21 +392,11 @@ __nscd_get_mapping (request_type type, const char *key, if (__glibc_unlikely (mapsize < size)) goto out_unmap; - /* Allocate a record for the mapping. */ - struct mapped_database *newp = malloc (sizeof (*newp)); - if (newp == NULL) - /* Ugh, after all we went through the memory allocation failed. */ - goto out_unmap; - - newp->head = mapping; - newp->data = ((char *) mapping + head->header_size + mapped->head = mapping; + mapped->data = ((char *) mapping + head->header_size + roundup (head->module * sizeof (ref_t), ALIGN)); - newp->mapsize = size; - newp->datasize = head->data_size; - /* Set counter to 1 to show it is usable. */ - newp->counter = 1; - - result = newp; + mapped->mapsize = size; + mapped->datasize = head->data_size; } out_close: @@ -385,56 +405,71 @@ __nscd_get_mapping (request_type type, const char *key, __close (sock); out: __set_errno (saved_errno); -#endif /* SCM_RIGHTS */ - - struct mapped_database *oldval = *mappedp; - *mappedp = result; - if (oldval != NULL && atomic_fetch_add_relaxed (&oldval->counter, -1) == 1) - __nscd_unmap (oldval); - - return result; + /* Downgrade lock to a read lock. The mapping may go away between + the two calls, but the caller has to handle the no-mapping case + anyway. */ + __libc_rwlock_unlock (mapped->lock); + __libc_rwlock_rdlock (mapped->lock); } struct mapped_database * -__nscd_get_map_ref (request_type type, const char *name, - volatile struct locked_map_ptr *mapptr, int *gc_cyclep) +__nscd_get_map_ref (unsigned int db, int *gc_cyclep) { - struct mapped_database *cur = mapptr->mapped; - if (cur == NO_MAPPING) - return cur; + assert (db < lastdb); + struct mapped_database *mapped = &__nscd_mapped_databases[db]; + + __libc_rwlock_rdlock (mapped->lock); + if (mapped->mapsize == 0 + || (mapped->head->nscd_certainly_running == 0 + && mapped->head->timestamp + MAPPING_TIMEOUT < time_now ()) + || mapped->head->data_size > mapped->datasize) + { + __libc_rwlock_unlock (mapped->lock); + __nscd_get_mapping (db); + } - if (!__nscd_acquire_maplock (mapptr)) - return NO_MAPPING; + if (mapped->mapsize > 0) + { + *gc_cyclep = mapped->head->gc_cycle; + if ((*gc_cyclep & 1) == 0) + return mapped; + } - cur = mapptr->mapped; + __libc_rwlock_unlock (mapped->lock); + return NULL; +} + +bool +__nscd_map_ref_retry_or_drop (struct mapped_database **mapped, + int *gc_cycle, int *nretries, int retval) +{ + if (*mapped == NULL) + return false; - if (__glibc_likely (cur != NO_MAPPING)) + int now_cycle = (*mapped)->head->gc_cycle; + if (__glibc_unlikely (now_cycle != *gc_cycle)) { - /* If not mapped or timestamp not updated, request new map. */ - if (cur == NULL - || (cur->head->nscd_certainly_running == 0 - && cur->head->timestamp + MAPPING_TIMEOUT < time_now ()) - || cur->head->data_size > cur->datasize) - cur = __nscd_get_mapping (type, name, - (struct mapped_database **) &mapptr->mapped); - - if (__glibc_likely (cur != NO_MAPPING)) + /* When we come here this means there has been a GC cycle while we + were looking for the data. This means the data might have been + inconsistent. Retry if possible. */ + + *gc_cycle = now_cycle; + if ((*gc_cycle & 1) != 0 || ++*nretries == 5) { - if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0, - 0)) - cur = NO_MAPPING; - else - atomic_fetch_add_relaxed (&cur->counter, 1); + __libc_rwlock_unlock ((*mapped)->lock); + *mapped = NULL; + return true; } - } - mapptr->lock = 0; + if (retval != -1) + return true; + } - return cur; + __libc_rwlock_unlock ((*mapped)->lock); + return false; } - /* Using sizeof (hashentry) is not always correct to determine the size of the data structure as found in the nscd cache. The program could be a 64-bit process and nscd could be a 32-bit process. In this case diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c index 71ad7c7f96..f1e821b8d0 100644 --- a/nscd/nscd_initgroups.c +++ b/nscd/nscd_initgroups.c @@ -24,13 +24,10 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" -/* We use the same mapping as in nscd_getgr. */ -libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden; - - int __nscd_getgrouplist (const char *user, gid_t group, long int *size, gid_t **groupsp, long int limit) @@ -41,8 +38,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size, /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (grpdb, &gc_cycle); retry:; char *respdata = NULL; @@ -50,10 +46,10 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size, int sock = -1; initgr_response_header initgr_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { struct datahead *found = __nscd_cache_search (INITGROUPS, user, - userlen, mapped, + userlen, map, sizeof initgr_resp); if (found != NULL) { @@ -63,7 +59,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size, /* Now check if we can trust initgr_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -158,22 +154,8 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size, if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) - { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - goto retry; - } + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) + goto retry; return retval; } diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c index 990d071cc0..53649adc82 100644 --- a/nscd/nscd_netgroup.c +++ b/nscd/nscd_netgroup.c @@ -22,27 +22,11 @@ #include #include "nscd-client.h" +#include "nscd-dbtype.h" #include "nscd_proto.h" int __nss_not_use_nscd_netgroup; - -libc_locked_map_ptr (static, map_handle); -/* Note that we only free the structure if necessary. The memory - mapping is not removed since it is not visible to the malloc - handling. */ -void -__nscd_group_map_freemem (void) -{ - if (map_handle.mapped != NO_MAPPING) - { - void *p = map_handle.mapped; - map_handle.mapped = NO_MAPPING; - free (p); - } -} - - int __nscd_setnetgrent (const char *group, struct __netgrent *datap) { @@ -52,18 +36,17 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) /* If the mapping is available, try to search there instead of communicating with the nscd. */ - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (netgrdb, &gc_cycle); retry:; char *respdata = NULL; int retval = -1; netgroup_response_header netgroup_resp; - if (mapped != NO_MAPPING) + if (map != NULL) { struct datahead *found = __nscd_cache_search (GETNETGRENT, group, - group_len, mapped, + group_len, map, sizeof netgroup_resp); if (found != NULL) { @@ -71,7 +54,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) netgroup_resp = found->data[0].netgroupdata; /* Now check if we can trust pw_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -141,22 +124,8 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) - { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - goto retry; - } + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) + goto retry; return retval; } @@ -206,25 +175,24 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user, communicating with the nscd. */ int gc_cycle; int nretries = 0; - struct mapped_database *mapped; - mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle); + struct mapped_database *map = __nscd_get_map_ref (netgrdb, &gc_cycle); retry:; int retval = -1; innetgroup_response_header innetgroup_resp; int sock = -1; - if (mapped != NO_MAPPING) + if (map != NULL) { struct datahead *found = __nscd_cache_search (INNETGR, key, - key_len, mapped, + key_len, map, sizeof innetgroup_resp); if (found != NULL) { innetgroup_resp = found->data[0].innetgroupdata; /* Now check if we can trust pw_resp fields. If GC is in progress, it can contain anything. */ - if (mapped->head->gc_cycle != gc_cycle) + if (map->head->gc_cycle != gc_cycle) { retval = -2; goto out; @@ -265,22 +233,8 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user, if (sock != -1) __close_nocancel_nostatus (sock); out: - if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) - { - /* When we come here this means there has been a GC cycle while we - were looking for the data. This means the data might have been - inconsistent. Retry if possible. */ - if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) - { - /* nscd is just running gc now. Disable using the mapping. */ - if (atomic_fetch_add_relaxed (&mapped->counter, -1) == 1) - __nscd_unmap (mapped); - mapped = NO_MAPPING; - } - - if (retval != -1) - goto retry; - } + if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) + goto retry; if (! use_alloca) free (key); From patchwork Fri Mar 20 20:41:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132113 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 484EB4C91755 for ; Fri, 20 Mar 2026 20:47:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 484EB4C91755 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=QlpmTTBg 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.129.124]) by sourceware.org (Postfix) with ESMTP id 76A554C3185E for ; Fri, 20 Mar 2026 20:41:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 76A554C3185E Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 76A554C3185E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039319; cv=none; b=q5N6swvWCa2RrKCsVuQWZBtPdqj+nDFJ0a21Usb7lUU4B/ccPMenKYnK5o2XRIxPTSr7tSFU5IxkDnkTQweS0k6/XEd9YyqDreMr54CWL361fp/hIU5hNLJk8Asr3SLEqMwigvOL6tx+YReszkoz6akeNEjvrgQISozXRx2MHLM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039319; c=relaxed/simple; bh=PBiZ6zdtDpVAbp+sG27dL2IHNdmEvNJBrghrNCXZNyk=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=DFOGJGZOKDgO/v63fOoEsL9/2B+F7smG8MoLqufCGW8h/Pygu3pVEZV4hg0RhHfVOv9zfMWB8OY0OiT9soahAY7FjxUudy63nCc7OImoNnb3HsYpAOYExy4t+F0sSM8KRagz5gFMiq3t43LEiWlQQdtKfYNKVsEBPdUT4k+7Gik= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 76A554C3185E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039319; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=z2UA0nWsPIi7Gf7sqvTdywN587FzeJImNbqNHIs5hys=; b=QlpmTTBg77NJoT6m2xU9D5343dR9KVF2Zek7AlzybTilDBBmmhgQHGaaiqmXbqe84ZoFrR KbNXZKhuppVEL+JRedpueZzPojzlWrCRmcisOaFOvSSnKDXOm9CEbQqTCg5TlHZUjP6+el FnROdSAsdcAKmPYiqIK20R5boyXTpEw= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-327-8s7ZVQVyMxOwsWf93nuB7g-1; Fri, 20 Mar 2026 16:41:57 -0400 X-MC-Unique: 8s7ZVQVyMxOwsWf93nuB7g-1 X-Mimecast-MFC-AGG-ID: 8s7ZVQVyMxOwsWf93nuB7g_1774039317 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 228DB180044D for ; Fri, 20 Mar 2026 20:41:57 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6E2741800764 for ; Fri, 20 Mar 2026 20:41:56 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 06/23] nscd: Re-flow and sort Makefile In-Reply-To: Message-ID: References: X-From-Line: ee789bd04f3cc6d4a768c99e1f48db8195a2e628 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:54 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: PV8FvQYWESaULhJApmZaDZntp3s3iyDOkEDy11AaSrI_1774039317 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.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, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 --- nscd/Makefile | 52 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/nscd/Makefile b/nscd/Makefile index 649112488f..2578b00e27 100644 --- a/nscd/Makefile +++ b/nscd/Makefile @@ -23,20 +23,52 @@ subdir := nscd include ../Makeconfig ifneq ($(use-nscd),no) -routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \ - nscd_initgroups nscd_getserv_r nscd_netgroup -aux := nscd_helper -endif +routines := \ + nscd_getai \ + nscd_getgr_r \ + nscd_gethst_r \ + nscd_getpw_r \ + nscd_getserv_r \ + nscd_initgroups \ + nscd_netgroup \ + # routines +aux := \ + nscd_helper \ + # aux +endif # $(use-nscd) # To find xmalloc.c vpath %.c ../locale/programs -nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \ - getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \ - getsrvbynm_r getsrvbypt_r servicescache \ - dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \ - xmalloc xstrdup aicache initgrcache res_hconf \ - netgroupcache cachedumper +nscd-modules := \ + aicache \ + cache \ + cachedumper \ + connections \ + dbg_log \ + getgrgid_r \ + getgrnam_r \ + gethstbyad_r \ + gethstbynm3_r \ + getpwnam_r \ + getpwuid_r \ + getsrvbynm_r \ + getsrvbypt_r \ + grpcache \ + hstcache \ + initgrcache \ + mem \ + netgroupcache \ + nscd \ + nscd_conf \ + nscd_setup_thread \ + nscd_stat \ + pwdcache \ + res_hconf \ + servicescache \ + xmalloc \ + xstrdup \ + # nscd-modules ifeq ($(build-nscd)$(have-thread-library),yesyes) From patchwork Fri Mar 20 20:41:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132107 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id A960E4C900C3 for ; Fri, 20 Mar 2026 20:43:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A960E4C900C3 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=ifL8ZUzb 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 ESMTP id 167854C318BD for ; Fri, 20 Mar 2026 20:42:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 167854C318BD Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 167854C318BD 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=1774039325; cv=none; b=CfARxsNhR2ZQtoV6B5tGcHy/3xayCTsXtoIn7MCFX9k3POxWBMQugbIE649pEwq9yhsDyQ/mvyEKAYTvlmuDqB6daiiF1AF346T064RklB45pP5IqSiC2DK/oOmnltFALDDCX2eXXtQlb24dAd6FAwln7lDxBU6rNsb7L1LhOJ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039325; c=relaxed/simple; bh=sZuSm6Dmazf4kYSRJanfy/rd/clA+eBVmZfoBKP2FiM=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=fy83VBbQd01guyWF4QlHgkKbaMxCP/LO4CF1RDjkpM2RWKsTqc7xApMYEVorN9zEjZAhyPwmqkNbf+D54zWLAHbjYPCIyvF5J7P1EiPOOwYQeSsa+yamBsaToXRBG/ldDfac+KFrNbUJ1nUEZiWfak3aP+g3+n6mBxabUjhpUak= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 167854C318BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039324; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=PHL6uwUADUx6e+YncrRihYn1q2OsJE13TafY2QGI3ow=; b=ifL8ZUzb5GAB9Zcq5PILXWJ0gf+FTjAaNTfkQ3+ryUi3EspttlBUVBWEpvtixzoNbi6g5/ XSi7GitaCuIXfYOEtR0/xcv+U+RW9G0g4OyhNtlLUoq9dX6odX5TzbRd0EnM8tb+WEtbWw h8V4WbAMlJVj3bh6xlX9LyRRcc37gDw= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-532-wA6jc-gBOhC1_reAOG0lrg-1; Fri, 20 Mar 2026 16:42:03 -0400 X-MC-Unique: wA6jc-gBOhC1_reAOG0lrg-1 X-Mimecast-MFC-AGG-ID: wA6jc-gBOhC1_reAOG0lrg_1774039322 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 76C92195609E for ; Fri, 20 Mar 2026 20:42:02 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 86677180075C for ; Fri, 20 Mar 2026 20:42:01 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 07/23] nss: Add __nss_generic_copy and __nss_generic_dup functions In-Reply-To: Message-ID: References: X-From-Line: f2b330b78e7d10e1df2a38c369e3db2c43cc29e6 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:58 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: qLBxVcjrK4u6fiJve-zlLZpi2660-yICmA5T755Z8pE_1774039322 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 So far for struct group and struct passwd only. These functions will be used internally in the type-generic NSS implementation, to preserve intermediate results and to produce the final *_r result. --- nss/Makefile | 11 +- nss/nss-lookups.def | 28 +++++ nss/nss_generic.h | 67 +++++++++++ nss/nss_generic_copy.c | 120 ++++++++++++++++++ nss/nss_generic_dup.c | 125 +++++++++++++++++++ nss/nss_generic_nscd.c | 29 +++++ nss/tst-nss_generic_copy.c | 241 +++++++++++++++++++++++++++++++++++++ nss/tst-nss_generic_dup.c | 231 +++++++++++++++++++++++++++++++++++ 8 files changed, 851 insertions(+), 1 deletion(-) create mode 100644 nss/nss-lookups.def create mode 100644 nss/nss_generic.h create mode 100644 nss/nss_generic_copy.c create mode 100644 nss/nss_generic_dup.c create mode 100644 nss/nss_generic_nscd.c create mode 100644 nss/tst-nss_generic_copy.c create mode 100644 nss/tst-nss_generic_dup.c diff --git a/nss/Makefile b/nss/Makefile index 42d28cf40a..ec68954f3b 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -45,6 +45,9 @@ routines = \ nss_files_data \ nss_files_fopen \ nss_files_functions \ + nss_generic_copy \ + nss_generic_dup \ + nss_generic_nscd \ nss_hash \ nss_module \ nss_parse_line_result \ @@ -302,10 +305,16 @@ makedb-modules = xmalloc hash-string others-extras = $(makedb-modules) extra-objs += $(makedb-modules:=.o) -tests-static = tst-field +tests-static = \ + tst-field \ + tst-nss_generic_copy \ + tst-nss_generic_dup \ + # tests-static tests-internal := \ tst-field \ + tst-nss_generic_copy \ + tst-nss_generic_dup \ tst-rfc3484 \ tst-rfc3484-2 \ tst-rfc3484-3 \ diff --git a/nss/nss-lookups.def b/nss/nss-lookups.def new file mode 100644 index 0000000000..80ec36d170 --- /dev/null +++ b/nss/nss-lookups.def @@ -0,0 +1,28 @@ +/* Lookup type definitions for NSS. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +DEFINE_LOOKUP (getgrgid, group, "getgrgid_r", grpdb) +DEFINE_LOOKUP (getgrnam, group, "getgrnam_r", grpdb) +DEFINE_LOOKUP (getpwnam, passwd, "getpwnam_r", pwddb) +DEFINE_LOOKUP (getpwuid, passwd, "getpwuid_r", pwddb) + +/* + Local Variables: + mode:C + End: + */ diff --git a/nss/nss_generic.h b/nss/nss_generic.h new file mode 100644 index 0000000000..fcddf8bf54 --- /dev/null +++ b/nss/nss_generic.h @@ -0,0 +1,67 @@ +/* Type- and query-agnostic NSS functionality. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* The functions declared in this file use void * instead of concrete + pointer types such as struct group and NSS service module function + pointers. They can be combined to implement different high-level, + type-safe functions. */ + + +#ifndef NSS_GENERIC_H +#define NSS_GENERIC_H + +#include +#include + +enum nss_lookup_type + { +#define DEFINE_LOOKUP(name, database, function_1, nscd) nss_lookup_##name, +#include "nss-lookups.def" +#undef DEFINE_LOOKUP + }; + +/* Define the nss_lookup_MAX constant. This is not part of enum + nss_lookup_type so that switch coverage warnings work. */ +enum + { +#define DEFINE_LOOKUP(name, database, function_1, nscd) \ + HIDDEN_nss_lookup_##name, +#include "nss-lookups.def" +#undef DEFINE_LOOKUP + nss_lookup_MAX + }; + +/* Copy an NSS struct corresponding to LT into RESULT, potentially + using additional storage of LENGTH bytes at BUFFER. If BUFFER is + not large enough, return ERANGE and set errno to ERANGE. Otherwise + return zero. */ +int __nss_generic_copy (enum nss_lookup_type lt, const void *source, + void *result, char *buffer, size_t length) + attribute_hidden; + +/* Create a malloc-allocated copy of the NSS struct of type LT at + SOURCE and return a pointer to it. Return NULL on allocation + failure. */ +void *__nss_generic_dup (enum nss_lookup_type lt, const void *source) + attribute_hidden; + +/* This array contains a dbtype value (see ) for + each lookup type, or -1 if the lookup has no corresponding database. */ +extern int8_t __nscd_database_for_lookup[nss_lookup_MAX] attribute_hidden; + +#endif /* NSS_GENERIC_H */ diff --git a/nss/nss_generic_copy.c b/nss/nss_generic_copy.c new file mode 100644 index 0000000000..62d6d40390 --- /dev/null +++ b/nss/nss_generic_copy.c @@ -0,0 +1,120 @@ +/* Copy data referenced in an NSS struct into a fixed-size destination buffer. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +static char * +safe_copy_string (struct alloc_buffer *buf, const char *source) +{ + if (source == NULL) + return NULL; + else + return alloc_buffer_copy_string (buf, source); +} + +/* Copy *SOURCE into *RESULT, interpreted according to LT. Use *BUF + to store referenced data for the deep copy. May mark *BUF as + failed. */ +static void +__nss_do_copy (enum nss_lookup_type lt, const void *source, void *result, + struct alloc_buffer *buf); + +/* Implementation of __nss_do_copy for struct group. Use the same + function signature to help with switch compilation in __nss_do_copy. */ +static void +__nss_copy_grp (enum nss_lookup_type lt, const struct group *source, + struct group *result, struct alloc_buffer *buf) +{ + result->gr_gid = source->gr_gid; + + if (source->gr_mem == NULL) + result->gr_mem = NULL; + else + { + size_t member_count = 0; + while (source->gr_mem[member_count] != NULL) + ++member_count; + + /* Copy the array first, to minimize the alignment requirements. */ + result->gr_mem = alloc_buffer_alloc_array (buf, char *, + member_count + 1); + if (result->gr_mem == NULL) + return; + + for (size_t i = 0; i < member_count; ++i) + result->gr_mem[i] + = alloc_buffer_copy_string (buf, source->gr_mem[i]); + + result->gr_mem[member_count] = NULL; + } + + result->gr_name = safe_copy_string (buf, source->gr_name); + result->gr_passwd = safe_copy_string (buf, source->gr_passwd); +} + +/* Implementation of __nss_do_copy for struct passwd. */ +static void +__nss_copy_pwd (enum nss_lookup_type lt, const struct passwd *source, + struct passwd *result, struct alloc_buffer *buf) +{ + result->pw_name = safe_copy_string (buf, source->pw_name); + result->pw_passwd = safe_copy_string (buf, source->pw_passwd); + result->pw_uid = source->pw_uid; + result->pw_gid = source->pw_gid; + result->pw_gecos = safe_copy_string (buf, source->pw_gecos); + result->pw_dir = safe_copy_string (buf, source->pw_dir); + result->pw_shell = safe_copy_string (buf, source->pw_shell); +} + +static void +__nss_do_copy (enum nss_lookup_type lt, const void *source, void *result, + struct alloc_buffer *buf) +{ + switch (lt) + { + case nss_lookup_getgrgid: + case nss_lookup_getgrnam: + return __nss_copy_grp (lt, source, result, buf); + case nss_lookup_getpwnam: + case nss_lookup_getpwuid: + return __nss_copy_pwd (lt, source, result, buf); + } + __builtin_unreachable (); +} + +int +__nss_generic_copy (enum nss_lookup_type lt, const void *source, + void *result, char *buffer, size_t length) +{ + struct alloc_buffer buf = alloc_buffer_create (buffer, length); + + __nss_do_copy (lt, source, result, &buf); + + if (alloc_buffer_has_failed (&buf)) + { + __set_errno (ERANGE); + return ERANGE; + } + + return 0; +} diff --git a/nss/nss_generic_dup.c b/nss/nss_generic_dup.c new file mode 100644 index 0000000000..42939f2db9 --- /dev/null +++ b/nss/nss_generic_dup.c @@ -0,0 +1,125 @@ +/* Duplicate NSS data with a single malloc allocation. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include +#include + +/* Return 0 if SOURCE is a null pointer, otherwise the length of the + string including the terminating null byte. */ +static size_t +safe_strlen_null (const char *source) +{ + if (source == NULL) + return 0; + else + return strlen (source) + 1; +} + +/* Interpret SOURCE as a pointer to an NSS struct type according to + LT. Return the size of the buffer space required by the data in + *SOURCE, and write the size of the struct type itself to + *STRUCT_SIZE. */ +static size_t +__nss_buffer_size (enum nss_lookup_type lt, const void *source, + size_t *struct_size); + +/* Variant of __nss_buffer_size for struct group. */ +static size_t +__nss_group_buffer_size (const struct group *source, size_t *struct_size) +{ + *struct_size = sizeof (*source); + size_t size = 0; + size += safe_strlen_null (source->gr_name); + size += safe_strlen_null (source->gr_passwd); + + /* Assume that the array is allocated first, so that no + alignment is needed. */ + if (source->gr_mem != NULL) + { + for (size_t i = 0; source->gr_mem[i] != NULL; ++i) + size += sizeof (char *) + strlen (source->gr_mem[i]) + 1; + size += sizeof (char *); + } + + return size; +} + +/* Variant of __nss_buffer_size for struct passwd. */ +static size_t +__nss_passwd_buffer_size (const struct passwd *source, size_t *struct_size) +{ + *struct_size = sizeof (*source); + size_t size = 0; + size += safe_strlen_null (source->pw_name); + size += safe_strlen_null (source->pw_passwd); + size += safe_strlen_null (source->pw_gecos); + size += safe_strlen_null (source->pw_dir); + size += safe_strlen_null (source->pw_shell); + return size; +} + +static size_t +__nss_buffer_size (enum nss_lookup_type lt, const void *source, + size_t *struct_size) +{ + switch (lt) + { + case nss_lookup_getgrgid: + case nss_lookup_getgrnam: + return __nss_group_buffer_size (source, struct_size); + case nss_lookup_getpwnam: + case nss_lookup_getpwuid: + return __nss_passwd_buffer_size (source, struct_size); + } + + __builtin_unreachable (); +} + +void * +__nss_generic_dup (enum nss_lookup_type lt, const void *source) +{ + void *result; + char *buf; + char *end; + { + size_t struct_size; + size_t size = __nss_buffer_size (lt, source, &struct_size); + size_t alloc_size = struct_size + size; + result = malloc (alloc_size); + if (result == NULL) + return NULL; + buf = (char *) result + struct_size; + end = (char *) result + alloc_size; + } + + int ret __attribute__ ((unused)) + = __nss_generic_copy (lt, source, result, buf, end - buf); + /* If this assert fails, *SOURCE was concurrently modified, pointers + in *source aliased and collectively covered more than the address + space (so that size computation overflowed), or malloc did not + return the expected alignment. */ + assert (ret == 0); + + return result; +} diff --git a/nss/nss_generic_nscd.c b/nss/nss_generic_nscd.c new file mode 100644 index 0000000000..28fc8446ae --- /dev/null +++ b/nss/nss_generic_nscd.c @@ -0,0 +1,29 @@ +/* Generic malloc-compatible version of nscd get functions. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +int8_t __nscd_database_for_lookup[nss_lookup_MAX] = + { +#define DEFINE_LOOKUP(name, dbname, function, nscddb) \ + [nss_lookup_##name] = nscddb, +#include +#undef DEFINE_LOOKUP + }; diff --git a/nss/tst-nss_generic_copy.c b/nss/tst-nss_generic_copy.c new file mode 100644 index 0000000000..fd01d03e6e --- /dev/null +++ b/nss/tst-nss_generic_copy.c @@ -0,0 +1,241 @@ +/* Test program for the __nss_generic_copy function. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This test needs to be statically linked because it accesses the + hidden function __nss_generic_copy. */ + +#include + +#include +#include +#include +#include +#include +#include + +static void +test_group (enum nss_lookup_type lt) +{ + char *members[4] = { (char *) "user1", (char *) "user2", (char *) "user3", }; + struct group source = + { + .gr_name = (char *) "group-name", + .gr_passwd = (char *) "password", + .gr_gid = 1000, + .gr_mem = members + }; + + /* Test with sufficient buffer size. */ + { + char buffer[1024]; + struct group result; + + errno = 23587; + TEST_COMPARE (__nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)), + 0); + TEST_VERIFY (errno != 0); + + check_group ("sufficient buffer", &result, + "name: group-name\n" + "passwd: password\n" + "gid: 1000\n" + "member: user1\n" + "member: user2\n" + "member: user3\n"); + } + + /* Test with insufficient buffer size. */ + { + char buffer[10]; + struct group result; + + errno = 23587; + int ret = __nss_generic_copy (lt, &source, + &result, buffer, sizeof (buffer)); + TEST_COMPARE (ret, ERANGE); + TEST_COMPARE (errno, ERANGE); + } + + /* Test with NULL members. */ + { + source.gr_name = NULL; + source.gr_passwd = NULL; + source.gr_mem = NULL; + + char buffer[1024]; + struct group result; + memset (&result, 0xcc, sizeof (result)); + + errno = 23587; + TEST_COMPARE (__nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)), + 0); + TEST_VERIFY (errno != 0); + + check_group ("NULL group members", &result, + "name: (null)\n" + "passwd: (null)\n" + "gid: 1000\n" + "gr_mem: (null)\n"); + } + + /* Test with empty strings. */ + { + char empty[] = ""; + char *list[] = { empty, NULL }; + source.gr_name = (char *) ""; + source.gr_passwd = (char *) ""; + source.gr_mem = list; + + char buffer[1024]; + struct group result; + + errno = 23587; + TEST_COMPARE (__nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)), + 0); + TEST_VERIFY (errno != 0); + + check_group ("empty group strings", &result, + "name: \n" + "passwd: \n" + "gid: 1000\n" + "member: \n"); + } +} + +static void +test_passwd (enum nss_lookup_type lt) +{ + struct passwd source_template = + { + .pw_name = (char *) "user-name", + .pw_passwd = (char *) "password", + .pw_uid = 2000, + .pw_gid = 3000, + .pw_gecos = (char *) "User Gecos", + .pw_dir = (char *) "/home/user", + .pw_shell = (char *) "/bin/sh", + }; + + /* Test with sufficient buffer size. */ + { + struct passwd source = source_template; + char buffer[1024]; + struct passwd result; + + errno = 23587; + TEST_COMPARE (__nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)), + 0); + TEST_VERIFY (errno != 0); + + check_passwd ("sufficient buffer", &result, + "name: user-name\n" + "passwd: password\n" + "uid: 2000\n" + "gid: 3000\n" + "gecos: User Gecos\n" + "dir: /home/user\n" + "shell: /bin/sh\n"); + } + + /* Test with insufficient buffer size. */ + { + struct passwd source = source_template; + char buffer[10]; + struct passwd result; + + errno = 23587; + int ret = __nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)); + TEST_COMPARE (ret, ERANGE); + TEST_COMPARE (errno, ERANGE); + } + + /* Test with NULL strings. */ + { + struct passwd source = source_template; + source.pw_name = NULL; + source.pw_passwd = NULL; + source.pw_gecos = NULL; + source.pw_dir = NULL; + source.pw_shell = NULL; + + char buffer[1024]; + struct passwd result; + memset (&result, 0xcc, sizeof (result)); + + errno = 23587; + TEST_COMPARE (__nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)), + 0); + TEST_VERIFY (errno != 0); + + check_passwd ("NULL passwd fields", &result, + "name: (null)\n" + "passwd: (null)\n" + "uid: 2000\n" + "gid: 3000\n" + "gecos: (null)\n" + "dir: (null)\n" + "shell: (null)\n"); + } + + /* Test with empty strings. */ + { + struct passwd source = source_template; + source.pw_name = (char *) ""; + source.pw_passwd = (char *) ""; + source.pw_gecos = (char *) ""; + source.pw_dir = (char *) ""; + source.pw_shell = (char *) ""; + + char buffer[1024]; + struct passwd result; + + errno = 23587; + TEST_COMPARE (__nss_generic_copy (lt, &source, &result, + buffer, sizeof (buffer)), + 0); + TEST_VERIFY (errno != 0); + + check_passwd ("empty passwd strings", &result, + "name: \n" + "passwd: \n" + "uid: 2000\n" + "gid: 3000\n" + "gecos: \n" + "dir: \n" + "shell: \n"); + } +} + +static int +do_test (void) +{ + test_group (nss_lookup_getgrgid); + test_group (nss_lookup_getgrnam); + test_passwd (nss_lookup_getpwnam); + test_passwd (nss_lookup_getpwuid); + + return 0; +} + +#include diff --git a/nss/tst-nss_generic_dup.c b/nss/tst-nss_generic_dup.c new file mode 100644 index 0000000000..4cf9557fc8 --- /dev/null +++ b/nss/tst-nss_generic_dup.c @@ -0,0 +1,231 @@ +/* Test program for the __nss_generic_dup function. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This test needs to be statically linked because it accesses the + hidden function __nss_generic_dup. */ + +#include + +#include +#include +#include +#include +#include +#include + +static void +check_pointer_in_allocation (void *allocation, void *ptr) +{ + TEST_VERIFY (ptr >= allocation); + TEST_VERIFY (ptr < (void *) ((char *) allocation + + malloc_usable_size (allocation))); +} + +static void +test_group (enum nss_lookup_type lt) +{ + char *members[4] = { (char *) "user1", (char *) "user2", + (char *) "long-user-3-name" }; + struct group source = + { + .gr_name = (char *) "group-name", + .gr_passwd = (char *) "password", + .gr_gid = 1000, + .gr_mem = members + }; + + /* Test with normal group data. */ + { + struct group *result = __nss_generic_dup (lt, &source); + TEST_VERIFY (result != NULL); + + check_group ("normal group data", result, + "name: group-name\n" + "passwd: password\n" + "gid: 1000\n" + "member: user1\n" + "member: user2\n" + "member: long-user-3-name\n"); + + check_pointer_in_allocation (result, result->gr_name); + check_pointer_in_allocation (result, result->gr_passwd); + check_pointer_in_allocation (result, result->gr_mem); + for (int i = 0; result->gr_mem[i] != NULL; i++) + check_pointer_in_allocation (result, result->gr_mem[i]); + + free (result); + } + + /* Test with NULL members. */ + { + struct group source_null = + { + .gr_gid = 2000, + }; + + struct group *result = __nss_generic_dup (lt, &source_null); + TEST_VERIFY (result != NULL); + + check_group ("NULL group members", result, + "name: (null)\n" + "passwd: (null)\n" + "gid: 2000\n" + "gr_mem: (null)\n"); + + free (result); + } + + /* Test with empty strings. */ + { + char empty[] = ""; + char *empty_list[] = { empty, NULL }; + struct group source_empty = + { + .gr_name = (char *) "", + .gr_passwd = (char *) "", + .gr_gid = 3000, + .gr_mem = empty_list + }; + + struct group *result = __nss_generic_dup (lt, &source_empty); + TEST_VERIFY (result != NULL); + + check_group ("empty group strings", result, + "name: \n" + "passwd: \n" + "gid: 3000\n" + "member: \n"); + + check_pointer_in_allocation (result, result->gr_name); + check_pointer_in_allocation (result, result->gr_passwd); + check_pointer_in_allocation (result, result->gr_mem); + for (int i = 0; result->gr_mem[i] != NULL; i++) + check_pointer_in_allocation (result, result->gr_mem[i]); + + free (result); + } +} + +static void +test_passwd (enum nss_lookup_type lt) +{ + struct passwd source = + { + .pw_name = (char *) "user-name", + .pw_passwd = (char *) "password", + .pw_uid = 1001, + .pw_gid = 1002, + .pw_gecos = (char *) "gecos-field", + .pw_dir = (char *) "/home/user", + .pw_shell = (char *) "/bin/sh" + }; + + /* Test with normal passwd data. */ + { + struct passwd *result = __nss_generic_dup (lt, &source); + TEST_VERIFY (result != NULL); + + check_passwd ("normal passwd data", result, + "name: user-name\n" + "passwd: password\n" + "uid: 1001\n" + "gid: 1002\n" + "gecos: gecos-field\n" + "dir: /home/user\n" + "shell: /bin/sh\n"); + + check_pointer_in_allocation (result, result->pw_name); + check_pointer_in_allocation (result, result->pw_passwd); + check_pointer_in_allocation (result, result->pw_gecos); + check_pointer_in_allocation (result, result->pw_dir); + check_pointer_in_allocation (result, result->pw_shell); + + free (result); + } + + /* Test with NULL fields. */ + { + struct passwd source_null = + { + .pw_uid = 2001, + .pw_gid = 2002, + }; + + struct passwd *result = __nss_generic_dup (lt, &source_null); + TEST_VERIFY (result != NULL); + + check_passwd ("NULL passwd fields", result, + "name: (null)\n" + "passwd: (null)\n" + "uid: 2001\n" + "gid: 2002\n" + "gecos: (null)\n" + "dir: (null)\n" + "shell: (null)\n"); + + free (result); + } + + /* Test with empty strings. */ + { + char empty[] = ""; + struct passwd source_empty = + { + .pw_name = empty, + .pw_passwd = empty, + .pw_uid = 3001, + .pw_gid = 3002, + .pw_gecos = empty, + .pw_dir = empty, + .pw_shell = empty + }; + + struct passwd *result = __nss_generic_dup (lt, &source_empty); + TEST_VERIFY (result != NULL); + + check_passwd ("empty passwd strings", result, + "name: \n" + "passwd: \n" + "uid: 3001\n" + "gid: 3002\n" + "gecos: \n" + "dir: \n" + "shell: \n"); + + check_pointer_in_allocation (result, result->pw_name); + check_pointer_in_allocation (result, result->pw_passwd); + check_pointer_in_allocation (result, result->pw_gecos); + check_pointer_in_allocation (result, result->pw_dir); + check_pointer_in_allocation (result, result->pw_shell); + + free (result); + } +} + +static int +do_test (void) +{ + test_group (nss_lookup_getgrgid); + test_group (nss_lookup_getgrnam); + test_passwd (nss_lookup_getpwnam); + test_passwd (nss_lookup_getpwuid); + + return 0; +} + +#include From patchwork Fri Mar 20 20:42:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132109 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 26CFB4C318BC for ; Fri, 20 Mar 2026 20:45:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 26CFB4C318BC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Os2WF/y7 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 ESMTP id 868AB4C9177A for ; Fri, 20 Mar 2026 20:42:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 868AB4C9177A Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 868AB4C9177A 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=1774039330; cv=none; b=tYV/0msZ/muHLkCbx+2gB1ZbTxmyru+9fSB8aby6daQmkuydKFbwEkaYVjAlsBCvzHYGVWVs8yD96P/eiv2I6heL83FJRdLgWcQ5nkXGy3JpgzDph2/uvuV1db36RakpJXvWntO59PBGSocIbpP2yjxKeuS0JVEOkUPk4CKoE8Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039330; c=relaxed/simple; bh=oVzyxNwb0xDcf7Erm7Yq6nyao16y+yEpnGqvyMnjyEk=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=fas8qMsOzkLUU2NDAvUka3K6qPESDT4uMMmBYDFpYazU7kLPW7KznWkPz1SMFI3Okv3azK3IRcpXBWRkJWpPc9PigmEco05kWBjlr/tFIutGxLJWuAfOwi9/H0f/KEzGHfVksbY4qrqrqcY2i17JB+t7+eZPMuP58SHs/LrqFRg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 868AB4C9177A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039330; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=OeVyl3q9Aeq9oDfRKba9XQ9A8uTY1enDimMqhu1hjRs=; b=Os2WF/y7LP3wNMULbguOjmundaRX9d4veZXoCD6o0CYQkfB4bzCMWn7cUh2yZ3E1Oi3tMA 4fPwGlnRO8VNqvtLS64oxJtm/a7LD/4fSOp7lkoPLH/bx5FE70xJT5HQUVl4CVs1Ab6N1Q vxs9iCf0M+ByjQryYSYRQ85vbg3Jj2Y= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-614-ZYR647gZPoe5t2RCd3GAIQ-1; Fri, 20 Mar 2026 16:42:08 -0400 X-MC-Unique: ZYR647gZPoe5t2RCd3GAIQ-1 X-Mimecast-MFC-AGG-ID: ZYR647gZPoe5t2RCd3GAIQ_1774039327 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CAE6B19560AA for ; Fri, 20 Mar 2026 20:42:07 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A95C91955F21 for ; Fri, 20 Mar 2026 20:42:06 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 08/23] nscd: Fix data races in client retry counters (bug 33654) In-Reply-To: Message-ID: <925c2367bd945a00033d4ddcd283e86d3b77c5b0.1774037705.git.fweimer@redhat.com> References: X-From-Line: 925c2367bd945a00033d4ddcd283e86d3b77c5b0 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:04 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: rydzoiXkwhbHCsDw-5JxedGi03fZp-zOXqJtAM2cAEE_1774039327 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Store the skip counters inside struct mapped_database. Introduce helper functions __nscd_use_database, __nscd_defer_database, __nscd_disable_database to access these counters. Teach the NSS code to translate to nscd database indices when calling these functions. Remove the special check from getaddrinfo (in get_nscd_addresses) that avoided fallback to an in-process operation for nscd protocol errors. Errors from service modules still produce a response from the nscd, so this check only avoided fallback if there were certain nscd communication errors. Checking the skip counters in this way for nscd usage was not reliable because another thread might have updated the skip counters. --- nscd/nscd-client.h | 7 +++++++ nscd/nscd-dbtype.h | 3 +++ nscd/nscd_getai.c | 9 +++------ nscd/nscd_getgr_r.c | 6 ++---- nscd/nscd_gethst_r.c | 10 ++++------ nscd/nscd_getpw_r.c | 6 ++---- nscd/nscd_getserv_r.c | 7 ++----- nscd/nscd_helper.c | 41 +++++++++++++++++++++++++++++++++++++++++ nscd/nscd_initgroups.c | 5 +++-- nscd/nscd_netgroup.c | 10 ++++------ nscd/nscd_proto.h | 15 +++++++++------ nss/getXXbyYY_r.c | 11 +++-------- nss/getaddrinfo.c | 19 +++++-------------- nss/getnetgrent_r.c | 15 +++------------ nss/initgroups.c | 10 ++-------- nss/nss_database.c | 23 ++++++++++++++++++++++- nss/nss_module.c | 8 +++----- nss/nsswitch.c | 5 ----- nss/nsswitch.h | 20 ++++++++------------ 19 files changed, 126 insertions(+), 104 deletions(-) diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h index aff303b757..dd7421c5d1 100644 --- a/nscd/nscd-client.h +++ b/nscd/nscd-client.h @@ -354,6 +354,13 @@ struct mapped_database size_t mapsize; /* Zero means not in use. */ size_t datasize; + /* This is set to 1 by nscd client functions to request not using nscd + for a bit. The main NSS code increments them until NSS_NSCD_RETRY + is reached, at which point nscd is attempted again. If the counter + is 0 (the default), use of nscd is attempted. If it is -1, nscd is + never used for this database. */ + int skip_counter; + /* Use of the mapping must acquire a read lock. If the mapping is changed, acquire a write lock. */ __libc_rwlock_define (, lock); diff --git a/nscd/nscd-dbtype.h b/nscd/nscd-dbtype.h index 7d553d020a..262c96fd78 100644 --- a/nscd/nscd-dbtype.h +++ b/nscd/nscd-dbtype.h @@ -19,6 +19,9 @@ #ifndef NSCD_DBTYPE_H #define NSCD_DBTYPE_H +/* Note: If you add new database types here, you must add another call + to __nscd_disable_database in __nss_configure_lookup. */ + typedef enum { pwddb, diff --git a/nscd/nscd_getai.c b/nscd/nscd_getai.c index a2e5da6b1c..65970b59ee 100644 --- a/nscd/nscd_getai.c +++ b/nscd/nscd_getai.c @@ -28,9 +28,6 @@ #include "nscd_proto.h" -/* Define in nscd_gethst_r.c. */ -extern int __nss_not_use_nscd_hosts; - /* Defined in nscd_gethst_r.c. */ extern int __nss_have_localdomain attribute_hidden; @@ -44,7 +41,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) __nss_have_localdomain = getenv ("LOCALDOMAIN") != NULL ? 1 : -1; if (__nss_have_localdomain > 0) { - __nss_not_use_nscd_hosts = 1; + __nscd_defer_database (hstdb); return -1; } } @@ -93,7 +90,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) if (sock == -1) { /* nscd not running or wrong version. */ - __nss_not_use_nscd_hosts = 1; + __nscd_defer_database (hstdb); goto out; } } @@ -168,7 +165,7 @@ __nscd_getai (const char *key, struct nscd_ai_result **result, int *h_errnop) if (__glibc_unlikely (ai_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_hosts = 1; + __nscd_defer_database (hstdb); goto out_close; } diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c index 746b11d792..f77650b25f 100644 --- a/nscd/nscd_getgr_r.c +++ b/nscd/nscd_getgr_r.c @@ -36,8 +36,6 @@ #include "nscd-dbtype.h" #include "nscd_proto.h" -int __nss_not_use_nscd_group; - static int nscd_getgr_r (const char *key, size_t keylen, request_type type, struct group *resultbuf, char *buffer, size_t buflen, struct group **result); @@ -117,7 +115,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, sizeof (gr_resp)); if (sock == -1) { - __nss_not_use_nscd_group = 1; + __nscd_defer_database (grpdb); goto out; } } @@ -128,7 +126,7 @@ nscd_getgr_r (const char *key, size_t keylen, request_type type, if (__glibc_unlikely (gr_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_group = 1; + __nscd_defer_database (grpdb); goto out_close; } diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c index 15d747fc33..9bb52614b7 100644 --- a/nscd/nscd_gethst_r.c +++ b/nscd/nscd_gethst_r.c @@ -27,8 +27,6 @@ #include "nscd-dbtype.h" #include "nscd_proto.h" -int __nss_not_use_nscd_hosts; - static int nscd_gethst_r (const char *key, size_t keylen, request_type type, struct hostent *resultbuf, char *buffer, size_t buflen, struct hostent **result, @@ -81,7 +79,7 @@ __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type, uint32_t __nscd_get_nl_timestamp (void) { - if (__nss_not_use_nscd_hosts != 0) + if (!__nscd_use_database (hstdb)) return 0; int gc_cycle; @@ -112,7 +110,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, __nss_have_localdomain = getenv ("LOCALDOMAIN") != NULL ? 1 : -1; if (__nss_have_localdomain > 0) { - __nss_not_use_nscd_hosts = 1; + __nscd_defer_database (hstdb); return -1; } } @@ -186,7 +184,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, sizeof (hst_resp)); if (sock == -1) { - __nss_not_use_nscd_hosts = 1; + __nscd_defer_database (hstdb); goto out; } } @@ -197,7 +195,7 @@ nscd_gethst_r (const char *key, size_t keylen, request_type type, if (__glibc_unlikely (hst_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_hosts = 1; + __nscd_defer_database (hstdb); goto out_close; } diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c index 938eac9c70..8ce1009fe0 100644 --- a/nscd/nscd_getpw_r.c +++ b/nscd/nscd_getpw_r.c @@ -34,8 +34,6 @@ #include "nscd-dbtype.h" #include "nscd_proto.h" -int __nss_not_use_nscd_passwd; - static int nscd_getpw_r (const char *key, size_t keylen, request_type type, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result); @@ -108,7 +106,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, sizeof (pw_resp)); if (sock == -1) { - __nss_not_use_nscd_passwd = 1; + __nscd_defer_database (pwddb); goto out; } } @@ -119,7 +117,7 @@ nscd_getpw_r (const char *key, size_t keylen, request_type type, if (__glibc_unlikely (pw_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_passwd = 1; + __nscd_defer_database (pwddb); goto out_close; } diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c index 519078d8fe..8f0c010118 100644 --- a/nscd/nscd_getserv_r.c +++ b/nscd/nscd_getserv_r.c @@ -27,9 +27,6 @@ #include "nscd_proto.h" -int __nss_not_use_nscd_services; - - static int nscd_getserv_r (const char *crit, size_t critlen, const char *proto, request_type type, struct servent *resultbuf, char *buf, size_t buflen, struct servent **result); @@ -162,7 +159,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, sizeof (serv_resp)); if (sock == -1) { - __nss_not_use_nscd_services = 1; + __nscd_defer_database (servdb); goto out; } } @@ -173,7 +170,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto, if (__glibc_unlikely (serv_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_services = 1; + __nscd_defer_database (servdb); goto out_close; } diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index d3bfc208ad..2a60c3572e 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -40,6 +40,7 @@ #include "nscd-client.h" #include "nscd-dbtype.h" +#include "nscd_proto.h" /* Extra time we wait if the socket is still receiving data. This value is in milliseconds. Note that the other side is nscd on the @@ -413,6 +414,46 @@ __nscd_get_mapping (unsigned int db) __libc_rwlock_rdlock (mapped->lock); } +bool +__nscd_use_database (unsigned int db) +{ + assert (db < lastdb); + + int *pcounter = &__nscd_mapped_databases[db].skip_counter; + int counter; + while (true) + { + counter = atomic_load_relaxed (pcounter); + if (counter <= 0) + break; + else if (counter > 0) + { + int old_counter = counter; + ++counter; + if (counter > NSS_NSCD_RETRY) + counter = 0; + if (atomic_compare_exchange_weak_relaxed + (pcounter, &old_counter, counter)) + break; + } + } + return counter == 0; +} + +void +__nscd_defer_database (unsigned int db) +{ + assert (db < lastdb); + atomic_store_relaxed (&__nscd_mapped_databases[db].skip_counter, 1); +} + +void +__nscd_disable_database (unsigned int db) +{ + assert (db < lastdb); + atomic_store_relaxed (&__nscd_mapped_databases[db].skip_counter, -1); +} + struct mapped_database * __nscd_get_map_ref (unsigned int db, int *gc_cyclep) { diff --git a/nscd/nscd_initgroups.c b/nscd/nscd_initgroups.c index f1e821b8d0..acc799cf55 100644 --- a/nscd/nscd_initgroups.c +++ b/nscd/nscd_initgroups.c @@ -16,6 +16,7 @@ . */ #include +#include #include #include #include @@ -79,7 +80,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size, if (sock == -1) { /* nscd not running or wrong version. */ - __nss_not_use_nscd_group = 1; + __nscd_disable_database (grpdb); goto out; } } @@ -128,7 +129,7 @@ __nscd_getgrouplist (const char *user, gid_t group, long int *size, if (__glibc_unlikely (initgr_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_group = 1; + __nscd_disable_database (grpdb); goto out_close; } diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c index 53649adc82..22c7cdcc9c 100644 --- a/nscd/nscd_netgroup.c +++ b/nscd/nscd_netgroup.c @@ -25,8 +25,6 @@ #include "nscd-dbtype.h" #include "nscd_proto.h" -int __nss_not_use_nscd_netgroup; - int __nscd_setnetgrent (const char *group, struct __netgrent *datap) { @@ -70,7 +68,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) if (sock == -1) { /* nscd not running or wrong version. */ - __nss_not_use_nscd_netgroup = 1; + __nscd_defer_database (netgrdb); goto out; } } @@ -110,7 +108,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) if (__glibc_unlikely (netgroup_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_netgroup = 1; + __nscd_defer_database (netgrdb); goto out_close; } @@ -207,7 +205,7 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user, if (sock == -1) { /* nscd not running or wrong version. */ - __nss_not_use_nscd_netgroup = 1; + __nscd_defer_database (netgrdb); goto out; } @@ -219,7 +217,7 @@ __nscd_innetgr (const char *netgroup, const char *host, const char *user, if (__glibc_unlikely (innetgroup_resp.found == -1)) { /* The daemon does not cache this database. */ - __nss_not_use_nscd_netgroup = 1; + __nscd_defer_database (netgrdb); goto out_close; } diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h index 917324aebd..6c4a318bc0 100644 --- a/nscd/nscd_proto.h +++ b/nscd/nscd_proto.h @@ -28,13 +28,16 @@ /* Type needed in the interfaces. */ struct nscd_ai_result; +/* Update the internal per-database counters if necessary and return + true if nscd should be used for DB for the next lookup. + DB is defined in . */ +_Bool __nscd_use_database (unsigned int db) attribute_hidden; -/* Variables for communication between NSCD handler functions and NSS. */ -extern int __nss_not_use_nscd_passwd attribute_hidden; -extern int __nss_not_use_nscd_group attribute_hidden; -extern int __nss_not_use_nscd_hosts attribute_hidden; -extern int __nss_not_use_nscd_services attribute_hidden; -extern int __nss_not_use_nscd_netgroup attribute_hidden; +/* Stop using DB until NSS_NSCD_RETRY lookups have been performed. */ +void __nscd_defer_database (unsigned int db) attribute_hidden; + +/* Completely stop using DB. */ +void __nscd_disable_database (unsigned int db) attribute_hidden; extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer, size_t buflen, diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index 21e82886b0..9527b6722d 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -23,6 +23,7 @@ #include "sysdep.h" #ifdef USE_NSCD # include +# include #endif #ifdef NEED__RES # include @@ -78,9 +79,7 @@ # define NSCD_NAME ADD_NSCD (REENTRANT_NAME) # define ADD_NSCD(name) ADD_NSCD1 (name) # define ADD_NSCD1(name) __nscd_##name -# define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME) -# define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name) -# define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name +# define NSS_DATABASE_INDEX CONCAT2 (NSS_DBSIDX_, DATABASE_NAME) # define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2) # define CONCAT2_2(arg1, arg2) arg1##arg2 #endif @@ -235,11 +234,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, #endif #ifdef USE_NSCD - if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY) - NOT_USENSCD_NAME = 0; - - if (!NOT_USENSCD_NAME - && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)]) + if (__nscd_use_database (NSS_DATABASE_INDEX)) { nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result H_ERRNO_VAR); diff --git a/nss/getaddrinfo.c b/nss/getaddrinfo.c index 4f6ac3358a..233801052e 100644 --- a/nss/getaddrinfo.c +++ b/nss/getaddrinfo.c @@ -81,7 +81,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#ifdef USE_NSCD +# include +# include +#endif #include #include @@ -485,13 +488,9 @@ static int get_nscd_addresses (const char *name, const struct addrinfo *req, struct gaih_result *res) { - if (__nss_not_use_nscd_hosts > 0 - && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) - __nss_not_use_nscd_hosts = 0; - res->at = NULL; - if (__nss_not_use_nscd_hosts || __nss_database_custom[NSS_DBSIDX_hosts]) + if (!__nscd_use_database (hstdb)) return 0; /* Try to use nscd. */ @@ -508,14 +507,6 @@ get_nscd_addresses (const char *name, const struct addrinfo *req, return -EAI_AGAIN; return -EAI_NONAME; } - if (__nss_not_use_nscd_hosts == 0) - { - if (h_errno == NETDB_INTERNAL && errno == ENOMEM) - return -EAI_MEMORY; - if (h_errno == TRY_AGAIN) - return -EAI_AGAIN; - return -EAI_SYSTEM; - } return 0; } diff --git a/nss/getnetgrent_r.c b/nss/getnetgrent_r.c index d391e2ac66..569087d3b0 100644 --- a/nss/getnetgrent_r.c +++ b/nss/getnetgrent_r.c @@ -27,6 +27,7 @@ #include "nsswitch.h" #include #include +#include /* Protect above variable against multiple uses at the same time. */ @@ -150,12 +151,7 @@ static int nscd_setnetgrent (const char *group) { #ifdef USE_NSCD - if (__nss_not_use_nscd_netgroup > 0 - && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY) - __nss_not_use_nscd_netgroup = 0; - - if (!__nss_not_use_nscd_netgroup - && !__nss_database_custom[NSS_DBSIDX_netgroup]) + if (__nscd_use_database (netgrdb)) return __nscd_setnetgrent (group, &dataset); #endif return -1; @@ -357,12 +353,7 @@ innetgr (const char *netgroup, const char *host, const char *user, const char *domain) { #ifdef USE_NSCD - if (__nss_not_use_nscd_netgroup > 0 - && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY) - __nss_not_use_nscd_netgroup = 0; - - if (!__nss_not_use_nscd_netgroup - && !__nss_database_custom[NSS_DBSIDX_netgroup]) + if (__nscd_use_database (netgrdb)) { int result = __nscd_innetgr (netgroup, host, user, domain); if (result >= 0) diff --git a/nss/initgroups.c b/nss/initgroups.c index f4106226ec..95691542fb 100644 --- a/nss/initgroups.c +++ b/nss/initgroups.c @@ -29,6 +29,7 @@ #include #include "../nscd/nscd-client.h" +#include "../nscd/nscd-dbtype.h" #include "../nscd/nscd_proto.h" /* Type of the lookup function. */ @@ -47,18 +48,11 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, gid_t **groupsp, long int limit) { #ifdef USE_NSCD - if (__nss_not_use_nscd_group > 0 - && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY) - __nss_not_use_nscd_group = 0; - if (!__nss_not_use_nscd_group - && !__nss_database_custom[NSS_DBSIDX_group]) + if (__nscd_use_database (grpdb)) { int n = __nscd_getgrouplist (user, group, size, groupsp, limit); if (n >= 0) return n; - - /* nscd is not usable. */ - __nss_not_use_nscd_group = 1; } #endif diff --git a/nss/nss_database.c b/nss/nss_database.c index 076d5a63fe..5861454467 100644 --- a/nss/nss_database.c +++ b/nss/nss_database.c @@ -28,6 +28,10 @@ #include #include #include +#ifdef USE_NSCD +# include +# include +#endif struct nss_database_state { @@ -256,7 +260,24 @@ __nss_configure_lookup (const char *dbname, const char *service_line) local->data.services[db] = result; #ifdef USE_NSCD - __nss_database_custom[db] = true; + switch (db) + { + case nss_database_group: + __nscd_disable_database (grpdb); + break; + case nss_database_hosts: + __nscd_disable_database (hstdb); + break; + case nss_database_netgroup: + __nscd_disable_database (netgrdb); + break; + case nss_database_passwd: + __nscd_disable_database (pwddb); + break; + case nss_database_services: + __nscd_disable_database (servdb); + break; + } #endif return 0; diff --git a/nss/nss_module.c b/nss/nss_module.c index cb8fde38b4..fbbc6a266a 100644 --- a/nss/nss_module.c +++ b/nss/nss_module.c @@ -33,6 +33,7 @@ #include #include #include +#include /* Suffix after .so of NSS service modules. This is a bit of magic, but we assume LIBNSS_FILES_SO looks like "libnss_files.so.2" and we @@ -395,11 +396,8 @@ __nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) cb1 (netgrdb, &netgr_traced_file.file); /* Disable all uses of NSCD. */ - __nss_not_use_nscd_passwd = -1; - __nss_not_use_nscd_group = -1; - __nss_not_use_nscd_hosts = -1; - __nss_not_use_nscd_services = -1; - __nss_not_use_nscd_netgroup = -1; + for (int i = 0; i < lastdb; ++i) + __nscd_disable_database (i); } #endif diff --git a/nss/nsswitch.c b/nss/nsswitch.c index 97cedff826..ff69ede948 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -42,11 +42,6 @@ #include #include -#ifdef USE_NSCD -/* Flags whether custom rules for database is set. */ -bool __nss_database_custom[NSS_DBSIDX_max]; -#endif - /*__libc_lock_define_initialized (static, lock)*/ /* -1 == not found diff --git a/nss/nsswitch.h b/nss/nsswitch.h index 1b18794fee..b7cfb4f602 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -62,19 +62,15 @@ typedef struct /* To access the action based on the status value use this macro. */ #define nss_next_action(ni, status) nss_action_get (ni, status) - #ifdef USE_NSCD -/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM. */ -enum - { -# define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg, -# include "databases.def" -# undef DEFINE_DATABASE - NSS_DBSIDX_max - }; - -/* Flags whether custom rules for database is set. */ -extern bool __nss_database_custom[NSS_DBSIDX_max] attribute_hidden; +/* Compile-time mapping of NSS databases to nscd dbtype values from + . This is used to update nscd usage counters + in nscd-enabled builds if getXbyY_r routines are called. */ +# define NSS_DBSIDX_group grpdb +# define NSS_DBSIDX_hosts hstdb +# define NSS_DBSIDX_netgroup netgrdb +# define NSS_DBSIDX_passwd pwddb +# define NSS_DBSIDX_services servdb #endif /* Warning for NSS functions, which don't require dlopen if glibc From patchwork Fri Mar 20 20:42:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132114 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id AE6444C318B3 for ; Fri, 20 Mar 2026 20:47:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AE6444C318B3 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=F/FtdsHe 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 ESMTP id 2035E4C91743 for ; Fri, 20 Mar 2026 20:42:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2035E4C91743 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 2035E4C91743 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=1774039335; cv=none; b=R5I1oRE9pFi1+3A6ZnYZt9N3twy5rI6czqSjkOVt4+j28FEpVekUWwj7f9jveYMeX2aqhMqnt5S0Qs68wco9wjoJS7zYrPyiuX6ME5OooVSF8foHqnVdnTEPIAoY3Uwa6qh9nRSrBjFvbSNXIDofpyiDOAu6Tq0Lv7aWv39jKzw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039335; c=relaxed/simple; bh=g9G7WCIePnAJx0LEyUAQPmXYkCv8Qe1WTkK/Q5rL49Q=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=B8CwKMahl+sRk97y5IargZtwxQpKanrLR+rPi6ebmWaqzD9ySWrXx8P5xVPJb7n+dNgJwS3xjaLELPWK5UdfwLKeYe/7oodpxZ68ZQdM2+X+XeI0DNsrpYhnlmnZQnk0HceX2aFa0R7xWxH17L/gRUpL9bgDyT92CtBh2x/gq/c= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2035E4C91743 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039334; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=a9JiwP2geoGyy/yorpP0QiMpIFrh05ep9htnwtGHJWs=; b=F/FtdsHeobqWq+iI9+PlfYVh7mcRHcmhjpKDXoQkMA+FjtlCVYgA9JagBcR7OM1XIU/wed mBQvdCzx8OFms9SbXRLDpC88dvjGmgC+Ccv07vDYW1ll0RmNW5ta8VOFlZC1c4H3JawZBi hOc+svP81Gxuy1zk8ezoCUwi/+ulczY= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-630-qiAQpAhyN9Ct3aU7U754CQ-1; Fri, 20 Mar 2026 16:42:13 -0400 X-MC-Unique: qiAQpAhyN9Ct3aU7U754CQ-1 X-Mimecast-MFC-AGG-ID: qiAQpAhyN9Ct3aU7U754CQ_1774039332 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7B9AE1800365 for ; Fri, 20 Mar 2026 20:42:12 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C77CD1800361 for ; Fri, 20 Mar 2026 20:42:11 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 09/23] Add In-Reply-To: Message-ID: References: X-From-Line: c952e4d26e1ab3a234ed2f28489d6d081162b74f Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:09 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: UDv-2zh3bk9fbdXZ7KOMUD6NG0XmxAGKAa7EgO0isvI_1774039332 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, PROLO_LEO1, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This is tailored towards nscd client code parsing needs. Concurrent modification is not supported because the nscd clients need to be changed to make a copy of the data before parsing it (following the software TM snapshot protocol). Place the implementation into include/ because it might be useful beyond the nscd client (say for parsing DNS packets). --- include/parse_buffer.h | 213 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 include/parse_buffer.h diff --git a/include/parse_buffer.h b/include/parse_buffer.h new file mode 100644 index 0000000000..b45e40af6d --- /dev/null +++ b/include/parse_buffer.h @@ -0,0 +1,213 @@ +/* Binary parsing of a fixed-size buffer. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef PARSE_BUFFER_H +#define PARSE_BUFFER_H + +/* Helper functions for parsing binary buffers. + + The helpers perform buffer bounds checking on all accesses. If an + out-of-bounds access is detected, zero or NULL is returned, and the + parse buffer is marked as failed. Accessed do not need to be + aligned. All data uses native endianness. Concurrent modification + of the buffer is not necessarily supported. */ + +#include +#include +#include +#include + +struct parse_buffer +{ + const void *start; + size_t length; +}; + +/* Create a parse buffer for LENGTH bytes at START. If LENGTH is zero, + the new parse buffer is immediately marked as failed. */ +static inline struct parse_buffer +parse_buffer_create (const void *start, size_t length) +{ + return (struct parse_buffer) { start, length }; +} + +/* Mark *PB as failed. After that, parse_buffer_has_failed will + return true. */ +static inline void +parse_buffer_mark_failed (struct parse_buffer *pb) +{ + pb->length = 0; +} + +/* Return true if *PB has been marked as failed. */ +static inline bool +parse_buffer_has_failed (const struct parse_buffer *pb) +{ + return pb->length == 0; +} + +/* Internal function for checking that NEEDED bytes are available in + *PB at OFFSET. Return false on failure and fail *PB. A zero value + for NEEDED is considered failure. */ +static inline bool +__parse_buffer_check_size (struct parse_buffer *pb, + size_t offset, size_t needed) +{ + size_t last_byte; + if (needed == 0 + || __builtin_add_overflow (offset, needed - 1, &last_byte) + || last_byte >= pb->length) + { + parse_buffer_mark_failed (pb); + return false; + } + return true; +} + +/* Extract an unsigned 8-bit value at OFFSET. If *PB contains only + OFFSET or fewer bytes, fail *PB and return 0. */ +static inline uint8_t +parse_buffer_u8 (struct parse_buffer *pb, size_t offset) +{ + if (offset >= pb->length) + { + parse_buffer_mark_failed (pb); + return 0; + } + return ((uint8_t *) pb->start)[offset]; +} + +/* Extract an unsigned 16-bit value at OFFSET. If 2 bytes are not + available, fail *PB and return 0. */ +static inline uint16_t +parse_buffer_u16 (struct parse_buffer *pb, size_t offset) +{ + uint16_t result = 0; + if (__parse_buffer_check_size (pb, offset, sizeof (result))) + memcpy (&result, (uint8_t *) pb->start + offset, sizeof (result)); + return result; +} + +/* Extract an unsigned 32-bit value at OFFSET. If 4 bytes are not + available, fail *PB and return 0. */ +static inline uint32_t +parse_buffer_u32 (struct parse_buffer *pb, size_t offset) +{ + uint32_t result = 0; + if (__parse_buffer_check_size (pb, offset, sizeof (result))) + memcpy (&result, (uint8_t *) pb->start + offset, sizeof (result)); + return result; +} + +/* Extract an unsigned 64-bit value at OFFSET. If 8 bytes are not + available, fail *PB and return 0. */ +static inline uint64_t +parse_buffer_u64 (struct parse_buffer *pb, size_t offset) +{ + uint64_t result = 0; + if (__parse_buffer_check_size (pb, offset, sizeof (result))) + memcpy (&result, (uint8_t *) pb->start + offset, sizeof (result)); + return result; +} + +/* Extract a signed 32-bit value at OFFSET. If 4 bytes are not + available, fail *PB and return 0. */ +static inline int32_t +parse_buffer_s32 (struct parse_buffer *pb, size_t offset) +{ + /* Rely on GCC extension for converting to signed. */ + return parse_buffer_u32 (pb, offset); +} + +/* Extract a signed 64-bit value at OFFSET. If 8 bytes are not + available, fail *PB and return 0. */ +static inline int64_t +parse_buffer_s64 (struct parse_buffer *pb, size_t offset) +{ + /* Rely on GCC extension for converting to signed. */ + return parse_buffer_u64 (pb, offset); +} + +/* Extract an unsigned 32-bit value at *OFFSET and increment *OFFSET + by 4. If 4 bytes are not available, fail *PB and return 0. */ +static inline uint32_t +parse_buffer_u32_advance (struct parse_buffer *pb, size_t *offset) +{ + uint32_t result = 0; + if (__parse_buffer_check_size (pb, *offset, sizeof (result))) + { + memcpy (&result, (uint8_t *) pb->start + *offset, sizeof (result)); + *offset += sizeof (result); + } + return result; +} + +/* Return A + B. On overflow, return 0 and mark *PB as failed. */ +static inline size_t +parse_buffer_add (struct parse_buffer *pb, size_t a, size_t b) +{ + size_t result; + if (__builtin_add_overflow (a, b, &result)) + { + parse_buffer_mark_failed (pb); + return 0; + } + return result; +} + +/* Extract field MEMBER of the struct type STYP from *PB and return + its value. The struct starts at OFFSET. Fail *PB and return zero + if the struct field is not available in *PB (the full struct does + not need to be available). */ +#define parse_buffer_field(pb, offset, styp, member) \ + (_Generic ((styp) { }.member, \ + uint8_t: parse_buffer_u8, \ + uint16_t: parse_buffer_u16, \ + uint32_t: parse_buffer_u32, \ + uint64_t: parse_buffer_u64, \ + int32_t: parse_buffer_s32, \ + int64_t: parse_buffer_s64) \ + (pb, parse_buffer_add (pb, offset, offsetof (styp, member)))) + +/* Extract a null-terminated string from a field of size REGION_LENGTH + bytes at *OFFSET in *PB. If REGION_LENGTH bytes are not available + or the region does not contain a null byte, fail *PB and return + NULL. *OFFSET is incremented by REGION_LENGTH on success (not just + the size of the string). + + Note: The return type should be const char *, but NSS structures + use char * for strings. To avoid excessive casts, the return type + used here is char *. */ +static inline char * +parse_buffer_sized_cstring_advance (struct parse_buffer *pb, size_t *offset, + size_t region_length) +{ + if (!__parse_buffer_check_size (pb, *offset, region_length)) + return NULL; + const char *result_start = (const char *) pb->start + *offset; + size_t result_length = __strnlen (result_start, region_length); + if (result_length == region_length) + { + parse_buffer_mark_failed (pb); + return NULL; + } + *offset += region_length; + return (char *) result_start; +} + +#endif /* PARSE_BUFFER_H */ From patchwork Fri Mar 20 20:42:14 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132112 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id B020A4BAD16A for ; Fri, 20 Mar 2026 20:46:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B020A4BAD16A Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Cv4ODHoT 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 ESMTP id B2CB14BBCD92 for ; Fri, 20 Mar 2026 20:42:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B2CB14BBCD92 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 B2CB14BBCD92 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=1774039339; cv=none; b=e7QvyUMh5pMAomfdLepnd1kIX3CXNNY337ekIzN5dm3H5aWx3SQBe/jkY2Fuins6lDHKX/1ltegAw+njDCtNw7WrbRPhfXHZRWlXFI23hPfCsa3LEeJu/2+V5dwRY6Z/qyqIGl7TJdl3Fq0deS5iJ7p6Qc+mEfZX0l7AGHO5zbM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039339; c=relaxed/simple; bh=1Pjg7xhRgXM5g/Nwk1HaFgbx52iz1nFUULrFJtWeFr8=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=LdoJu0zwAisg9u4myfj5Y6B0ceMJA7z2K5l9uEBJidIX0Ez7WL2BmZ7g+ExJKdFDkjmMq6vIaAt/8t6bAr+At3npBZxjH8l2Som0b46wnRdECRA5Emrz45m0mfY8m3Xuvh5aXZ8FaEmG2X+3hnt07/KDM9X6YW6MV6E4+V/3xXQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B2CB14BBCD92 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039339; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=AYNza4EfqaxWkNUv+vHHDBTpIfByc1k+/OYkjirYy+k=; b=Cv4ODHoT8lQNa2O0HqGd4OFgpARtOhl3aCTxsYSPgg7W9nszPP6mNts1SdOlBhT46SmPbR d3ZNoNXBRqAS51B30+qT79B64WjCXtxQT8rPnes1HtRxnCuqOfb4imWp5TmbPZ4RB5bWI5 SBNPlpQri6CyTuep3C4HIX/j6B2PUUI= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-642-1--qXNXdPe2uD1blzX5vbw-1; Fri, 20 Mar 2026 16:42:18 -0400 X-MC-Unique: 1--qXNXdPe2uD1blzX5vbw-1 X-Mimecast-MFC-AGG-ID: 1--qXNXdPe2uD1blzX5vbw_1774039337 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 645A2195608B for ; Fri, 20 Mar 2026 20:42:17 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AE0741955F21 for ; Fri, 20 Mar 2026 20:42:16 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 10/23] nscd: Use uint8_t instead of bitfield in struct hashentry In-Reply-To: Message-ID: References: X-From-Line: f50f77798e80eb5692678ac9c87e5ac05e9bfea6 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:14 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 46mFrMybstBq0-Zd1lqtFWB2jVJjcYlrTw-FGe2faKQ_1774039337 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 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_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This enables access through --- nscd/nscd-client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h index dd7421c5d1..c507933acb 100644 --- a/nscd/nscd-client.h +++ b/nscd/nscd-client.h @@ -283,7 +283,7 @@ datahead_init_neg (struct datahead *head, nscd_ssize_t allocsize, /* Structure for one hash table entry. */ struct hashentry { - request_type type:8; /* Which type of dataset. */ + uint8_t type; /* Type of dataset; see request_type. */ bool first; /* True if this was the original key. */ nscd_ssize_t len; /* Length of key. */ ref_t key; /* Pointer to key. */ From patchwork Fri Mar 20 20:42:18 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132119 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 2F42D4C9175D for ; Fri, 20 Mar 2026 20:51:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2F42D4C9175D Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=LdT/qiAX 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 ESMTP id 70FB64C91741 for ; Fri, 20 Mar 2026 20:42:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 70FB64C91741 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 70FB64C91741 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=1774039344; cv=none; b=Icp5KVFZJ3ew6uKwzcLuWqLRJwyYDlmRLtFSslDSbpSbF88QfMcXfZKvdjidijKaPVATZyg0RJK0N6wjQvTdp5Div3p2n8oQ9DAsG8RkZcrlbBu6UBk3dSzz85Ij13B29Bmimxoq+RVawDZZYYjtWKkTlL2gSRBi+uIYTiMWizs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039344; c=relaxed/simple; bh=DNzGPsurP78OG4HhE1yVoUQjsXddS+JG8V2LH+MNzt8=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=Amf9qIYFWvl0IlDXs0np9AXJBJI3qxZWVqmg159mGmtWw4alJLDICpaTSFBqqHCpvBtlTqxY62tIQ24/ZvWWZg7MHPMmlpipXETzk4LLRsGS6nxXt7V1wuGD0DE4Pux/rC0dlvcR/AVo4wtoZppYrP+eC+mMbcVOgzfrcs+UBrI= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 70FB64C91741 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039344; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Q8uKancDflZLzKKC3OaGmnyyO/5fWQBr0uIpvIAadLY=; b=LdT/qiAX9JMJYlSOFsa03Aun6b5n+88C5JirwXbjS0qIQ4jr3yuhetMQUpqO5bHbIO3Ymc MfdKdIc8A1oF1aRAUFcHSrrnbJPicd8WkWnAwR+PlmX6nAVdAOd16Nd/ZawDbW0E0vC0PY wbyAR2LjUMtAQinW8qMSsIUCV3tuKW0= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-668-8jWi70LtOrejYq0u4OICpQ-1; Fri, 20 Mar 2026 16:42:22 -0400 X-MC-Unique: 8jWi70LtOrejYq0u4OICpQ-1 X-Mimecast-MFC-AGG-ID: 8jWi70LtOrejYq0u4OICpQ_1774039342 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1D06C1800281 for ; Fri, 20 Mar 2026 20:42:22 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 66DD6180075C for ; Fri, 20 Mar 2026 20:42:21 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 11/23] nscd: Add for nscd client usage In-Reply-To: Message-ID: References: X-From-Line: a216bb6a62ae3bffec9ef07887c950b324cb462a Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:18 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: eALQTA1UK83608b62T0Su_G7IHycsMweCsPAezwcv8k_1774039342 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This is very specific for parsing the shared nscd mapping. There is only enough functionality to follow the hash chain and create a consistent snapshot of the data stored at a key. Parsing the data itself should be handled through . --- nscd/concurrent_buffer.h | 197 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 nscd/concurrent_buffer.h diff --git a/nscd/concurrent_buffer.h b/nscd/concurrent_buffer.h new file mode 100644 index 0000000000..925b9f83d1 --- /dev/null +++ b/nscd/concurrent_buffer.h @@ -0,0 +1,197 @@ +/* Parsing of concurrently modified nscd cache structures. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef CONCURRENT_BUFFER_H +#define CONCURRENT_BUFFER_H + +/* Helper functions for parsing buffers that are concurrently modified. + + The helpers perform buffer bounds checking on all accesses. If an + out-of-bounds access is detected, zero or NULL is returned, and the + buffer is marked as failed. Unaligned access attempts are treated + as failure. + + Also see for a different kind of parser buffer + that does not support concurrent access. */ + +#include +#include +#include +#include + +struct concurrent_buffer +{ + const void *start; + size_t length; +}; + +/* Create a concurrent parse buffer for LENGTH bytes at START. If + LENGTH is zero, the new buffer is immediately marked as failed. */ +static inline struct concurrent_buffer +cb_create (const void *start, size_t length) +{ + return (struct concurrent_buffer) { start, length }; +} + +/* Mark *CB as failed. After that, cb_has_failed will return true. */ +static inline void +cb_mark_failed (struct concurrent_buffer *cb) +{ + cb->length = 0; +} + +/* Return true if *CB has been marked as failed. */ +static inline bool +cb_has_failed (const struct concurrent_buffer *cb) +{ + return cb->length == 0; +} + +/* Check that NEEDED bytes are available in *CB at OFFSET. Return + false on failure and fail *CB. A zero value for NEEDED is + considered failure. */ +static inline bool +cb_available (struct concurrent_buffer *cb, size_t offset, size_t needed) +{ + size_t last_byte; + if (needed == 0 + || __builtin_add_overflow (offset, needed - 1, &last_byte) + || last_byte >= cb->length) + { + cb_mark_failed (cb); + return false; + } + return true; +} + +/* Check that OFFSET leaves room for SIZE bytes in *CB, and that + OFFSET is a multiple of SIZE. */ +static inline bool +__cb_check_size_alignment (struct concurrent_buffer *cb, + size_t offset, size_t size) +{ + if (cb_available (cb, offset, size) + && (offset % size) == 0) + return true; + else + { + cb_mark_failed (cb); + return false; + } +} + +/* Extract an unsigned 8-bit value at OFFSET. If *CB contains only + OFFSET or fewer bytes, fail *CB and return 0. */ +static inline uint8_t +cb_u8 (struct concurrent_buffer *cb, size_t offset) +{ + if (offset >= cb->length) + { + cb_mark_failed (cb); + return 0; + } + /* Relaxed MO is sufficient. We cannot use atomics because one-byte + inline atomics are not supported on all glibc targets. */ + return *((volatile uint8_t *) cb->start + offset); +} + +/* Extract an unsigned 32-bit value at OFFSET. If 4 bytes are not + available, fail *CB and return 0. */ +static inline uint32_t +cb_u32 (struct concurrent_buffer *cb, size_t offset) +{ + if (__cb_check_size_alignment (cb, offset, 4)) + return atomic_load_relaxed ((uint32_t *) ((char *) cb->start + offset)); + else + return 0; +} + +/* Extract an unsigned 64-bit value at OFFSET. If 8 bytes are not + available, fail *CB and return 0. Always fail if 64-bit atomics + are unavailable. */ +static inline uint64_t +cb_u64 (struct concurrent_buffer *cb, size_t offset) +{ +#if HAVE_64B_ATOMICS + if (__cb_check_size_alignment (cb, offset, 8)) + return atomic_load_relaxed ((uint64_t *) ((char *) cb->start + offset)); + else + return 0; +#else + cb_mark_failed (cb); + return 0; +#endif +} + +/* Extract a signed 32-bit value at OFFSET. If 4 bytes are not + available, fail *CB and return 0. */ +static inline int32_t +cb_s32 (struct concurrent_buffer *cb, size_t offset) +{ + /* Rely on GCC extension for converting to signed. */ + return cb_u32 (cb, offset); +} + +/* Extract a signed 64-bit value at OFFSET. If 8 bytes are not + available, fail *CB and return 0. Always fail if 64-bit atomics + are unavailable. */ +static inline int64_t +cb_s64 (struct concurrent_buffer *cb, size_t offset) +{ + /* Rely on GCC extension for converting to signed. */ + return cb_u64 (cb, offset); +} + +/* Return A + B. On overflow, return 0 and mark *CB as failed. */ +static inline size_t +cb_add (struct concurrent_buffer *cb, size_t a, size_t b) +{ + size_t result; + if (__builtin_add_overflow (a, b, &result)) + { + cb_mark_failed (cb); + return 0; + } + return result; +} + +/* Extract field MEMBER of the struct type STYP from *CB and return + its value. The struct starts at OFFSET. Fail *CB and return zero + if the struct field is not available in *CB (the full struct does + not need to be available). */ +#define cb_field(cb, offset, styp, member) \ + (_Generic ((styp) { }.member, \ + uint8_t: cb_u8, \ + uint32_t: cb_u32, \ + int32_t: cb_s32, \ + int64_t: cb_s64) \ + (cb, cb_add (cb, offset, offsetof (styp, member)))) + +/* Return true if the LENGTH bytes at OFFSET match TO_COMPARE, false + otherwise. If LENGTH bytes are not available, mark *CB as failed. + If the comparison fails, *CB is not marked as failed. */ +static inline bool +cb_memeq (struct concurrent_buffer *cb, size_t offset, + const void *to_compare, size_t length) +{ + if (! cb_available (cb, offset, length)) + return false; + return memcmp ((char *) cb->start + offset, to_compare, length) == 0; +} + +#endif /* CONCURRENT_BUFFER_H */ From patchwork Fri Mar 20 20:42:23 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132117 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 593B74C91761 for ; Fri, 20 Mar 2026 20:49:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 593B74C91761 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=T/g8iJPJ 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.129.124]) by sourceware.org (Postfix) with ESMTP id 534E04BBCD92 for ; Fri, 20 Mar 2026 20:42:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 534E04BBCD92 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 534E04BBCD92 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039349; cv=none; b=US+j7O9fk+tur24LB/0dq+FMuT3dqnk9BAjuiA8/0Q1UxpiOF97fnFtUg4CjxKzWpX+E26oHMfFMIdYXMRxySXph+dMqb8kxpBQue6F4qlc9UUe9dHNfziN/Pq+Elyj5EQo36YbuEDumMN2cb8R+un9Z0qfPw0TbUZszYQNT/gU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039349; c=relaxed/simple; bh=xHs9lP2H/I5VTikdxIWKMRcviZxkW1H+mMO/qOt9EDw=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=FyW6fBkoxV84K6brlfK5HyC22xYgCfFQwu82nwxk52OMgepKzIs+Zndc1f1XJtdtv5SV54GHnhBlnhfnpD3KKIqO6Tm9VS36FEjsxXnmN0RsWwS+9epjE4dKXoHU1qCNCFxz1xNkyF78nLPP5WtHYzY5kxVEzElIXR9f2AQH/sI= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 534E04BBCD92 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039349; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Y1K5UlfvGnoqyDkScz4N7E5A3MZ8mJSOJlNybqmJ1DQ=; b=T/g8iJPJKw9ddRnfcuUdPGFkNfPSxhO2xv3TbTiAz2VmwQplbE7Z5u/eDC15UlvrCQ38Nz ZJ4Df7gzjgTNgXyiMUKtaopQjk4crVbzfJZHl7vb8CDPtP9yv6U/oekJJg3qxsC/CMhwVY qQwkeGHPimT8jlNwvHJsTIul9ZFEEYE= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-511-0FR7D0MoOwiEW9VVDO0v4A-1; Fri, 20 Mar 2026 16:42:27 -0400 X-MC-Unique: 0FR7D0MoOwiEW9VVDO0v4A-1 X-Mimecast-MFC-AGG-ID: 0FR7D0MoOwiEW9VVDO0v4A_1774039347 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D9C64195608E for ; Fri, 20 Mar 2026 20:42:26 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 31C921800351 for ; Fri, 20 Mar 2026 20:42:25 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 12/23] nscd: Rewrite __nscd_cache_search using In-Reply-To: Message-ID: <687d72c9ba728fcfb579355a92b636f7ca360bc0.1774037705.git.fweimer@redhat.com> References: X-From-Line: 687d72c9ba728fcfb579355a92b636f7ca360bc0 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:23 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: PyhNMc4v2g87OdJZAenkoZbrq7MbvVAZG7XfR0rcqzs_1774039347 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.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_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This makes it somewhat clearer what is going on. This still does not implement a proper software TM snapshot. --- nscd/nscd_helper.c | 85 ++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 52 deletions(-) diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index 2a60c3572e..9bd0e7818e 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -41,6 +41,7 @@ #include "nscd-client.h" #include "nscd-dbtype.h" #include "nscd_proto.h" +#include "concurrent_buffer.h" /* Extra time we wait if the socket is still receiving data. This value is in milliseconds. Note that the other side is nscd on the @@ -527,71 +528,51 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen, const struct mapped_database *mapped, size_t datalen) { unsigned long int hash = __nss_hash (key, keylen) % mapped->head->module; - size_t datasize = mapped->datasize; + + struct concurrent_buffer cb = cb_create (mapped->data, mapped->datasize); ref_t trail = mapped->head->array[hash]; ref_t work = trail; - size_t loop_cnt = datasize / (MINIMUM_HASHENTRY_SIZE - + offsetof (struct datahead, data) / 2); + size_t loop_cnt = mapped->datasize / (MINIMUM_HASHENTRY_SIZE + + offsetof (struct datahead, data) / 2); int tick = 0; - while (work != ENDREF && work + MINIMUM_HASHENTRY_SIZE <= datasize) + while (work != ENDREF) { - struct hashentry *here = (struct hashentry *) (mapped->data + work); - ref_t here_key, here_packet; - - /* Although during garbage collection when moving struct hashentry - records around we first copy from old to new location and then - adjust pointer from previous hashentry to it, there is no barrier - between those memory writes!!! This is extremely risky on any - modern CPU which can reorder memory accesses very aggressively. - Check alignment, both as a partial consistency check and to avoid - crashes on targets which require atomic loads to be aligned. */ - if ((uintptr_t) here & (__alignof__ (*here) - 1)) - return NULL; - - if (type == here->type - && keylen == here->len - && (here_key = atomic_load_relaxed (&here->key)) + keylen <= datasize - && memcmp (key, mapped->data + here_key, keylen) == 0 - && ((here_packet = atomic_load_relaxed (&here->packet)) - + sizeof (struct datahead) <= datasize)) + /* First compare type and key. */ + if (type == cb_field (&cb, work, struct hashentry, type) + && keylen == cb_field (&cb, work, struct hashentry, len)) { - /* We found the entry. Increment the appropriate counter. */ - struct datahead *dh - = (struct datahead *) (mapped->data + here_packet); - - if ((uintptr_t) dh & (__alignof__ (*dh) - 1)) - return NULL; - - /* See whether we must ignore the entry or whether something - is wrong because garbage collection is in progress. */ - if (dh->usable - && here_packet + dh->allocsize <= datasize - && (here_packet + offsetof (struct datahead, data) + datalen - <= datasize)) - return dh; + ref_t here_key = cb_field (&cb, work, struct hashentry, key); + if (cb_memeq (&cb, here_key, key, keylen)) + { + /* Data found. Now validate the data reference. */ + ref_t here_packet = cb_field (&cb, work, + struct hashentry, packet); + if ((here_packet & (__alignof__ (struct datahead) - 1)) == 0 + && cb_field (&cb, here_packet, struct datahead, usable)) + { + size_t allocsize = cb_field (&cb, here_packet, + struct datahead, allocsize); + if (cb_available (&cb, here_packet, allocsize)) + /* We found the entry. */ + return (struct datahead *) (mapped->data + here_packet); + } + } } - work = atomic_load_relaxed (&here->next); + work = cb_field (&cb, work, struct hashentry, next); + if (cb_has_failed (&cb)) + return NULL; + /* Prevent endless loops. This should never happen but perhaps - the database got corrupted, accidentally or deliberately. */ + the database got corrupted, accidentally or deliberately. + Use both a loop count and a Floyd-style cycle detector + (work is the hare, and trail is the tortoise). */ if (work == trail || loop_cnt-- == 0) break; if (tick) - { - struct hashentry *trailelem; - trailelem = (struct hashentry *) (mapped->data + trail); - - /* We have to redo the checks. Maybe the data changed. */ - if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1)) - return NULL; - - if (trail + MINIMUM_HASHENTRY_SIZE > datasize) - return NULL; - - trail = atomic_load_relaxed (&trailelem->next); - } + trail = cb_field (&cb, trail, struct hashentry, next); tick = 1 - tick; } From patchwork Fri Mar 20 20:42:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132116 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id A2BC84BB3B9C for ; Fri, 20 Mar 2026 20:48:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A2BC84BB3B9C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Vdqe0L9h 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 ESMTP id 298DD4C515F6 for ; Fri, 20 Mar 2026 20:42:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 298DD4C515F6 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 298DD4C515F6 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=1774039354; cv=none; b=LWNxMy4URm6gk9Y0eXNx6mhvIC2/mFeo+NdLxVS+88F89vC24q2rNIn/VU/XgxnwbjprCOWZApeGt6q9x3sY0S7urZHv1N8PnrLvoYMtJze1v7UDwPSCB7TDmCuUNYsPqDp6TTYY2nLg0edK3MrYYRH8fhIujnaLqgQQKqfSpDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039354; c=relaxed/simple; bh=fBrrUgy2OLa16bmm+AjDdwRH0q7trfZTK9+8lc5rOxE=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=D+Wf6voI6m+Bg/6YL8y34q/xr7Eey4yJdMrvJFOxSqx64+pjG7a3bBD5ZLxiEE9FScl//xXqnXIrkQl59Ik5ReknyqYG2KX6FARz29HoAX5ytu4RXwAQvc7R89r3HxYE5KNHj/ok0gjV2Dz+PZ1uzMZRdV5VH5a8W84oy1esBMw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 298DD4C515F6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039353; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=deJQLeyZ0fVQ3n14q3rifgiSAW1BaLCGUk+aLMSGrXk=; b=Vdqe0L9h5o3WnfexyZqAAL9fwiRMOdxVGct69MZprdBva7dJUA58YdcVzIrJz7fEy2EV1j ybeDLP2ZdJgOvqMjoMdL1EH0ubAz6vzap2Egp3BW+08G+P1NSakkPgMSKdIGcHGpA3UmdN 92GMZorNMZu8/Mcl8cyiBAJyqGAOx2c= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-416-mBq_8I2qMUagYJKrVsPCog-1; Fri, 20 Mar 2026 16:42:32 -0400 X-MC-Unique: mBq_8I2qMUagYJKrVsPCog-1 X-Mimecast-MFC-AGG-ID: mBq_8I2qMUagYJKrVsPCog_1774039351 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BC1FD19560AA for ; Fri, 20 Mar 2026 20:42:31 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 12ABE30002DF for ; Fri, 20 Mar 2026 20:42:30 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 13/23] nscd: Introduce __nscd_read_from_socket client function In-Reply-To: Message-ID: <1b7650609687533628085fe716ac9666f5c400bd.1774037705.git.fweimer@redhat.com> References: X-From-Line: 1b7650609687533628085fe716ac9666f5c400bd Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:28 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: uNfZUfC7QTfO8DsvTYpW5a1Mgio8_EE-XeRegNgPn9M_1774039351 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 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_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 --- nscd/nscd-client.h | 20 ++++++++++++++++- nscd/nscd_helper.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h index c507933acb..10284e8ef2 100644 --- a/nscd/nscd-client.h +++ b/nscd/nscd-client.h @@ -366,11 +366,29 @@ struct mapped_database __libc_rwlock_define (, lock); }; -/* Open socket connection to nscd server. */ +/* Open socket connection to nscd server, send the request, and read + the start of the response (update to RESPONSELEN bytes). If the + procided response buffer is exceeded, the socket is left open, so + that more data can be read. */ extern int __nscd_open_socket (const char *key, size_t keylen, request_type type, void *response, size_t responselen) attribute_hidden; +/* Open a socket to nscd, send the request, and read the full + response. *RESPONSE is grown as necessary. + + A non-negative return value indicates the number of response bytes + stored at RESPONSE->data. The response includes only the struct + *_response_header and the data that follows it, not struct + datahead. + + On error, return a negative errno code. */ +struct scratch_buffer; +ssize_t __nscd_read_from_socket (const char *key, size_t keylen, + request_type type, + struct scratch_buffer *response) + attribute_hidden; + /* Acquire reference to the mapping for DB (see ). On success, return a pointer to the mapping descriptor, and lock the mapping. diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index 9bd0e7818e..ed2d8d09da 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "nscd-client.h" #include "nscd-dbtype.h" @@ -612,3 +613,55 @@ __nscd_open_socket (const char *key, size_t keylen, request_type type, return -1; } + +ssize_t +__nscd_read_from_socket (const char *key, size_t keylen, request_type type, + struct scratch_buffer *response) +{ + if (keylen > MAXKEYLEN) + return -ENAMETOOLONG; + + int sock = open_socket (type, key, keylen); + if (sock < 0) + return sock; + + /* The nscd stream protocol does not size information in a way that + is independent of request type. However, there is only one + request per connection, so the code below simply reads all data + that is available before end of stream. */ + + ssize_t ret = 0; /* Number of bytes read, or -1 on error. */ + while (true) + { + /* Wait for data. Give up on timeout. */ + if (wait_on_socket (sock, 5 * 1000) == 0) + break; + size_t remaining = response->length - ret; + ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response->data + ret, + remaining)); + if (nbytes < 0) + { + ret = -errno; + break; + } + if (nbytes == 0) + /* The end of the stream marks the end of packet. We cannot + tell if the data was truncated because nscd went away + unexpectedly. This will be recognized by the caller during + packet parsing. */ + break; + + /* Try reading more data in the next iteration after growing the + buffer. */ + ret += nbytes; + if (ret == response->length && !scratch_buffer_grow_preserve (response)) + { + ret = -ENOMEM; + break; + } + } + + __close_nocancel_nostatus (sock); + + return ret; +} From patchwork Fri Mar 20 20:42:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132118 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id BAD7B4BB58EF for ; Fri, 20 Mar 2026 20:50:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BAD7B4BB58EF Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=XnEDX3l9 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.129.124]) by sourceware.org (Postfix) with ESMTP id E4D824C91769 for ; Fri, 20 Mar 2026 20:42:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E4D824C91769 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 E4D824C91769 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039361; cv=none; b=q8Y2DP3JnTznJaNilDwufvRAbI9Msxdkh36tPwUWVcXegxoOIMqn9UEBiD3HO09rpEvgqKZBa29Tf+am/KCdad1vJ4sWZx2YNQp85w0XZ3TCFXePuObRUM9o7G2RQFYo+ATKlZwWoiPhn0XzFaXm0BnL5dAwSKnAHwWhz3sKmIo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039361; c=relaxed/simple; bh=9smY937Lq8LyIIUaFAqYnlfrDi/EMeiHdBWlGvcgMUY=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=PFsFg+6wJRw3F9hBPemprp7XThV0svAqiAMFAaVlntoiopdYV66Y0/uknNMXNUtMuDruI85+x+fYSrS2XUVy0iBYzilFbTbImG4Sa8JCYWiHjA4PlyK3xI+38dF8+QUtbwUi4ZVTRDsAo6ls2kBycKp3cRSvzlaRjz4FX7rNsvw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E4D824C91769 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039360; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=r6NLC0DnDEAa/Ezw5ZwsYFVFeB/hdk0RxKOrbyhlyBw=; b=XnEDX3l9KIilwjHo31WhOhAmfzYsfInnba07Dzpq82Y1Jxw5rsE1PI6FATX59cUflDMGUd 1VNHMph+44711s7PTBKmsvlxfj7klQ5ey/mJFL6CGdQeqh/rkvT2AHqtlm9t5KropAjkM1 BOrK1hJE2TEIT01wpVzso6n1nC8eZ+8= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-551-6r_lUF7yMeKsR6HuIOWUPA-1; Fri, 20 Mar 2026 16:42:39 -0400 X-MC-Unique: 6r_lUF7yMeKsR6HuIOWUPA-1 X-Mimecast-MFC-AGG-ID: 6r_lUF7yMeKsR6HuIOWUPA_1774039358 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 668EE1800365 for ; Fri, 20 Mar 2026 20:42:38 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AFD1B30001A1 for ; Fri, 20 Mar 2026 20:42:37 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 14/23] nscd: Consistant snapshot with client function __nscd_read_from_cache In-Reply-To: Message-ID: References: X-From-Line: e3f4fb69071aa1bd0e11d5020a48c3b18f970fbc Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:35 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: sAk-r3ecxGy92pAxlnqqxBsJmT1BnoPIb1vpvUQFV3Q_1774039358 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.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_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Reuse the same software TM protocol that we use for _dl_find_object, with a minor tweak: for newly added records, we rely on loads carrying a dependency on the next pointer. This means the GC cycle versioning is only needed for cache pruning and actual GC, which move data around or make it available for subsequent allocation. --- nscd/cache.c | 41 +++++++++++--- nscd/mem.c | 7 +-- nscd/nscd-client.h | 40 ++++++++++++- nscd/nscd.h | 4 ++ nscd/nscd_helper.c | 137 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 214 insertions(+), 15 deletions(-) diff --git a/nscd/cache.c b/nscd/cache.c index 3f8be16281..7e133f5bae 100644 --- a/nscd/cache.c +++ b/nscd/cache.c @@ -176,8 +176,10 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet, newp->packet = (char *) packet - table->data; assert ((newp->packet & BLOCK_ALIGN_M1) == 0); - /* Put the new entry in the first position. */ - /* TODO Review concurrency. Use atomic_exchange_release. */ + /* Put the new entry in the first position. + + The load in __nscd_read_from_cache carries a dependency + on the release store from the CAS below. */ newp->next = atomic_load_relaxed (&table->head->array[hash]); while (!atomic_compare_exchange_weak_release (&table->head->array[hash], (ref_t *) &newp->next, @@ -231,6 +233,30 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet, return 0; } +/* This follows the software TM protocol in dl-find_object.c + (_dlfo_mappings_begin_update and _dlfo_mappings_end_update). Also + see __nscd_cache_read_start_version and __nscd_cache_read_success + in nscd_helper.c. */ + +void +__nscd_begin_gc (struct database_dyn *table) +{ + uint32_t gc_cycle = atomic_load_relaxed (&table->head->gc_cycle) + 1; + assert ((gc_cycle & 1) == 1); + atomic_store_relaxed (&table->head->gc_cycle, gc_cycle); + atomic_thread_fence_release (); +} + +void +__nscd_end_gc (struct database_dyn *table) +{ + atomic_thread_fence_release (); + uint32_t gc_cycle = atomic_load_relaxed (&table->head->gc_cycle) + 1; + assert ((gc_cycle & 1) == 0); + atomic_store_relaxed (&table->head->gc_cycle, gc_cycle); + atomic_thread_fence_release (); +} + /* Walk through the table and remove all entries which lifetime ended. We have a problem here. To actually remove the entries we must get @@ -448,10 +474,10 @@ prune_cache (struct database_dyn *table, time_t now, int fd) pthread_rwlock_wrlock (&table->lock); } - /* Now we start modifying the data. Make sure all readers of the - data are aware of this and temporarily don't use the data. */ - atomic_fetch_add_relaxed (&table->head->gc_cycle, 1); - assert ((table->head->gc_cycle & 1) == 1); + /* Now we start modifying the data. Make sure all readers of + the data are aware of this and temporarily don't use the + data. */ + __nscd_begin_gc (table); while (first <= last) { @@ -494,8 +520,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd) } /* Now we are done modifying the data. */ - atomic_fetch_add_relaxed (&table->head->gc_cycle, 1); - assert ((table->head->gc_cycle & 1) == 0); + __nscd_end_gc (table); /* It's all done. */ pthread_rwlock_unlock (&table->lock); diff --git a/nscd/mem.c b/nscd/mem.c index 4f1350b3fd..14a2ab855a 100644 --- a/nscd/mem.c +++ b/nscd/mem.c @@ -259,9 +259,7 @@ gc (struct database_dyn *db) /* Now we start modifying the data. Make sure all readers of the data are aware of this and temporarily don't use the data. */ - atomic_fetch_add_relaxed (&db->head->gc_cycle, 1); - assert ((db->head->gc_cycle & 1) == 1); - + __nscd_begin_gc (db); /* We do not perform the move operations right away since the he_data array is not sorted by the address of the data. */ @@ -485,8 +483,7 @@ gc (struct database_dyn *db) /* Now we are done modifying the data. */ - atomic_fetch_add_relaxed (&db->head->gc_cycle, 1); - assert ((db->head->gc_cycle & 1) == 0); + __nscd_end_gc (db); /* We are done. */ out: diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h index 10284e8ef2..9761750951 100644 --- a/nscd/nscd-client.h +++ b/nscd/nscd-client.h @@ -210,8 +210,8 @@ typedef uint64_t nscd_time_t; /* Head of record in data part of database. */ struct datahead { - nscd_ssize_t allocsize; /* Allocated Bytes. */ - nscd_ssize_t recsize; /* Size of the record. */ + nscd_ssize_t allocsize; /* Allocated bytes (including this header). */ + nscd_ssize_t recsize; /* Size of the record (data part). */ nscd_time_t timeout; /* Time when this entry becomes invalid. */ uint8_t notfound; /* Nonzero if data has not been found. */ uint8_t nreloads; /* Reloads without use. */ @@ -389,6 +389,26 @@ ssize_t __nscd_read_from_socket (const char *key, size_t keylen, struct scratch_buffer *response) attribute_hidden; +/* Use the mapping MAPPED to look up KEY of size KEYLEN. Grow + *RESPONSE as necessary. + + On success, the number of bytes in RESPONSE->data is returned. + RESPONSE->data points to the payload data from the mapping + (after struct datahead). + + A return value of zero means that the mapping was processed + successfully, but the key was not found in it. + + On failure, a negative error code is return: -EINPROGRESS means + that a garbage collection is in progress, and the socket should be + used instead. -ENOMEM means that local (malloc) memory allocation + failed; this should be reported up to the caller. -EMSGSIZE denotes + a corrupted mapping. */ +ssize_t +__nscd_read_from_cache (const char *key, size_t keylen, request_type type, + struct scratch_buffer *response, + const struct mapped_database *mapped) attribute_hidden; + /* Acquire reference to the mapping for DB (see ). On success, return a pointer to the mapping descriptor, and lock the mapping. @@ -414,6 +434,22 @@ bool __nscd_map_ref_retry_or_drop (struct mapped_database **mapped, int *gc_cycle, int *nretries, int retval) attribute_hidden; + +/* Like __nscd_map_ref_retry_or_drop, but without comparing gc_cycle + against the original value. Instead, the retry decision is based + on *RET: the values -EINPROGRESS and -EMSGSIZE indicate that + another attempt is not needed. Other negative error codes are used + to set errno (to the negated/positive value) and do not result in a + retry, and *RET is set to -1. + + If there is no retry, return false, and unlock the mapping + if *USE_MAPPING. + + Must be called after __nscd_get_map_ref. */ +bool __nscd_map_retry (struct mapped_database *mapped, + bool *use_mapping, int *nretries, + ssize_t *ret) attribute_hidden; + /* Search the mapped database. */ extern struct datahead *__nscd_cache_search (request_type type, const char *key, diff --git a/nscd/nscd.h b/nscd/nscd.h index fffcb7a719..db9cd24c13 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -262,6 +262,10 @@ extern void send_stats (int fd, struct database_dyn dbs[lastdb]); extern int receive_print_stats (void) __attribute__ ((__noreturn__)); /* cache.c */ +/* Software TM protocol. Used in gc and prune_cache. */ +void __nscd_begin_gc (struct database_dyn *) attribute_hidden; +void __nscd_end_gc (struct database_dyn *) attribute_hidden; + extern struct datahead *cache_search (request_type, const void *key, size_t len, struct database_dyn *table, uid_t owner); diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index ed2d8d09da..88bfb463c2 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -513,6 +513,32 @@ __nscd_map_ref_retry_or_drop (struct mapped_database **mapped, return false; } +bool +__nscd_map_retry (struct mapped_database *mapped, + bool *use_mapping, int *nretries, + ssize_t *ret) +{ + if (*use_mapping && (*ret == -EINPROGRESS || *ret == -EMSGSIZE)) + { + if (++*nretries == 5) + { + __libc_rwlock_unlock (mapped->lock); + *use_mapping = false; + } + return true; + } + + if (*use_mapping) + __libc_rwlock_unlock (mapped->lock); + + if (*ret < 0) + { + __set_errno (-*ret); + *ret = -1; + } + return false; +} + /* Using sizeof (hashentry) is not always correct to determine the size of the data structure as found in the nscd cache. The program could be a 64-bit process and nscd could be a 32-bit process. In this case @@ -580,6 +606,117 @@ __nscd_cache_search (request_type type, const char *key, size_t keylen, return NULL; } +/* TM version at the start of the read operation. See +_dlfo_read_start_version. */ +static inline uint32_t +__nscd_cache_read_start_version (const struct mapped_database *mapped) +{ + return atomic_load_acquire (&mapped->head->gc_cycle); +} + +/* Return true if the read was successful, given the start version. + See _dlfo_read_success. */ +static inline bool +__nscd_cache_read_success (const struct mapped_database *mapped, + uint32_t start_version) +{ + atomic_thread_fence_acquire (); + return __nscd_cache_read_start_version (mapped) == start_version; +} + + +ssize_t +__nscd_read_from_cache (const char *key, size_t keylen, request_type type, + struct scratch_buffer *response, + const struct mapped_database *mapped) +{ + if (keylen > MAXKEYLEN) + return -ENAMETOOLONG; + + unsigned long int hash = __nss_hash (key, keylen) % mapped->head->module; + + retry:; + struct concurrent_buffer cb = cb_create (mapped->data, mapped->datasize); + uint32_t start_version = __nscd_cache_read_start_version (mapped); + if (start_version & 1) + /* Garbage collection is in progress. */ + return -EINPROGRESS; + + ref_t trail = mapped->head->array[hash]; + ref_t work = trail; + size_t loop_cnt = mapped->datasize / (MINIMUM_HASHENTRY_SIZE + + offsetof (struct datahead, data) / 2); + int tick = 0; + + while (work != ENDREF) + { + /* First compare type and key. */ + if (type == cb_field (&cb, work, struct hashentry, type) + && keylen == cb_field (&cb, work, struct hashentry, len)) + { + ref_t here_key = cb_field (&cb, work, struct hashentry, key); + if (cb_memeq (&cb, here_key, key, keylen)) + { + /* Data found. Now validate the data reference. */ + ref_t here_packet = cb_field (&cb, work, + struct hashentry, packet); + if ((here_packet & (__alignof__ (struct datahead) - 1)) == 0 + && cb_field (&cb, here_packet, struct datahead, usable)) + { + size_t recsize = cb_field (&cb, here_packet, + struct datahead, recsize); + /* Intermediate validation: we must verify that the + size is genuine before passing it to malloc. */ + if (!__nscd_cache_read_success (mapped, start_version)) + /* This will bail out if a GC cycle has started. */ + goto retry; + /* Include struct datahead part and data part, not + the full allocation (with unused padding at end). */ + size_t data_offset = offsetof (struct datahead, data); + size_t entrysize = data_offset + recsize; + if (!scratch_buffer_set_array_size (response, recsize, 1)) + return -ENOMEM; + if (!cb_available (&cb, here_packet, entrysize)) + /* The entry size was derived from validated data, + so if there is not enough data available, the + mapping is corrupted. */ + return -EMSGSIZE; + memcpy (response->data, + mapped->data + here_packet + data_offset, + recsize); + /* Validate again after copying, to make sure we + produced a consistent snapshot. */ + if (!__nscd_cache_read_success (mapped, start_version)) + goto retry; + return recsize; + } + } + } + + work = cb_field (&cb, work, struct hashentry, next); + if (!__nscd_cache_read_success (mapped, start_version)) + goto retry; + if (cb_has_failed (&cb)) + /* Mapping is corrupted because data is inconsistent, but + validated. */ + return -EMSGSIZE; + + /* Prevent endless loops. This should never happen but perhaps + the database got corrupted, accidentally or deliberately. + Use both a loop count and a Floyd-style cycle detector + (work is the hare, and trail is the tortoise). */ + if (work == trail || loop_cnt-- == 0) + break; + if (tick) + trail = cb_field (&cb, trail, struct hashentry, next); + tick = 1 - tick; + } + + if (!__nscd_cache_read_success (mapped, start_version)) + goto retry; + /* Negative result. */ + return 0; +} /* Create a socket connected to a name. */ int From patchwork Fri Mar 20 20:42:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132121 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id D79CB4B358A4 for ; Fri, 20 Mar 2026 20:53:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D79CB4B358A4 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=FpLC7/t5 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 ESMTP id 8C78B4C91741 for ; Fri, 20 Mar 2026 20:42:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8C78B4C91741 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 8C78B4C91741 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=1774039365; cv=none; b=LYAsMSCihSpzYQWZoAJoH9ZegLDRcwFPqgp4Xljds1ZmejYHb1js4KxMCIynZ4PtshaFAiZBoq+MGnNvltfHjSbHNNZ+n1EiypBYf9KPDTtcymWu7pVRo8p5lSqOltaIA2uFpZSnW9A1REmg6G5UoqJBVZ/ohAeiTznVBZEE16k= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039365; c=relaxed/simple; bh=n/kTBxMYHanGAamGpPWcvbYbTNLbwTCIWVVVZV0FIPs=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=C0SGZptzdWAGNPRPwFqF9wWNP9sAnKfvQGTXl5tNBGYF6tMH8wAYatVjBYaxaI5yluLTpfUdnRIcNpCWzYGOc8sseI+KXZBIgMGpj0JV+ofTDn93nu1wjsZA1zoxUYnvnb2fohDWAMiTyv6uQIKR/kl2Xz6U8AyWN9+2sWhsoGU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8C78B4C91741 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039365; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=02jcPJ1yELIHhaf0K682ogK1YkZMBb3EfXE2zlXulvA=; b=FpLC7/t5UcbINsJnhHYWwuVkJbbxlvaPIJlwvDbC4TfWIIfvMSfZoiowA/QKDYf06rShfh jAloou3eJ9S46/loS4a0v+bCloYw2B5ttYzVtfNl+sfGTX6tQUdStOtpRXbJhNR82YEt5m D+8JpG8gthGhPlP3rJBjrODXIaBBX78= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-556-iKR-vcB-NdqwpkS1pq8pmQ-1; Fri, 20 Mar 2026 16:42:44 -0400 X-MC-Unique: iKR-vcB-NdqwpkS1pq8pmQ-1 X-Mimecast-MFC-AGG-ID: iKR-vcB-NdqwpkS1pq8pmQ_1774039363 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 177881800464 for ; Fri, 20 Mar 2026 20:42:43 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 61D3D1953944 for ; Fri, 20 Mar 2026 20:42:42 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 15/23] nscd: Add __nscd_generic_get for generic lookup In-Reply-To: Message-ID: References: X-From-Line: ab41313a347c99db3b9fe67225f75e3d7ca73d7d Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:40 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: P0_4MxaaFdhk8rdUyJyLZpBq3wB-DdKJfnhzAY7Ofsg_1774039363 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 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_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Implement passwd and group handling only at this point. --- nscd/nscd_helper.c | 318 +++++++++++++++++++++++++++++++++++++++++++++ nss/nss_generic.h | 16 +++ 2 files changed, 334 insertions(+) diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c index 88bfb463c2..b113403f16 100644 --- a/nscd/nscd_helper.c +++ b/nscd/nscd_helper.c @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include #include "nscd-client.h" #include "nscd-dbtype.h" @@ -802,3 +805,318 @@ __nscd_read_from_socket (const char *key, size_t keylen, request_type type, return ret; } + +/* Used to implement __nscd_parse_and_copy. */ +static int __nscd_parse_and_copy_group (enum nss_lookup_type, + void *, ssize_t, void **); +static int __nscd_parse_and_copy_passwd (enum nss_lookup_type, + void *, ssize_t, void **); + +/* Use __nss_generic_dup to copy NSS data according to LT at BUFFER + (of LENGTH bytes) to *RESULT, or NULL if there is no data. Return + 0 for success (including a negative result), or a negative error + code: -ENOENT for no data available,, -EMSGSIZE for a parse + failure, and -ENOMEM for a memory allocation error. */ +static int +__nscd_parse_and_copy (enum nss_lookup_type lt, + void *buffer, ssize_t length, void **result) +{ + switch (lt) + { + case nss_lookup_getgrnam: + case nss_lookup_getgrgid: + return __nscd_parse_and_copy_group (lt, buffer, length, result); + case nss_lookup_getpwuid: + case nss_lookup_getpwnam: + return __nscd_parse_and_copy_passwd (lt, buffer, length, result); + } + __builtin_unreachable (); +} + +/* Use the nscd shared memory cache to retrieve data. On success, + return true and write a __nss_generic_dup-allocated NSS struct + pointer to *RESULT (positive result), or write NULL to *RESULT + (negative result). On failurem return false. Failure can mean: + the data is not in the mapping, the mapping is being concurrently + modified, or there was a resource shortage. *BUFFER can be used + for temporary storage (but not for data in the returned result). */ +static bool +__nscd_try_cache (unsigned int db, request_type type, + const char *key, size_t keylen, enum nss_lookup_type lt, + struct scratch_buffer *buffer, void **result) +{ + assert (db < lastdb); + struct mapped_database *mapped = &__nscd_mapped_databases[db]; + bool found = false; + + for (int retries = 0; ; ++retries) + { + __libc_rwlock_rdlock (mapped->lock); + + /* Check if the mapping is usable. If not, try to replace it. */ + if (mapped->mapsize == 0 + || (mapped->head->nscd_certainly_running == 0 + && mapped->head->timestamp + MAPPING_TIMEOUT < time_now ()) + || mapped->head->data_size > mapped->datasize) + { + /* Mapping is not usable as-is. Attempt to replace it. */ + __libc_rwlock_unlock (mapped->lock); + __nscd_get_mapping (db); + if (mapped->mapsize == 0) + /* Could not get mapping. */ + break; + } + + ssize_t ret = __nscd_read_from_cache (key, keylen, type, buffer, + mapped); + if (ret > 0) + { + ret = __nscd_parse_and_copy (lt, buffer->data, ret, result); + if (ret == 0) + { + /* We got the data (result can be NULL for negative). */ + found = true; + break; + } + else if (ret != -EMSGSIZE) + /* Some other error. Give up. */ + break; + /* Else fall through and retry. */ + } + else if (ret != -EINPROGRESS && ret != -EMSGSIZE) + /* An error that does not go away with retrying. */ + break; + + if (retries == 5) + /* Stop retrying. */ + break; + + __libc_rwlock_unlock (mapped->lock); + } + + __libc_rwlock_unlock (mapped->lock); + return found; +} + +/* Use the nscd shared memory cache to retrieve data. On success, + write a pointer to an NSS struct to *RESULT, allocated using + __nss_generic_dup according to LT, or write NULL to *RESULT + (negative result) and return true. On failure, return false. + Failure can mean failure to connect to nscd, or a parse error in + the data returned from nscd. */ +static bool +__nscd_try_socket (request_type type, const char *key, size_t keylen, + enum nss_lookup_type lt, struct scratch_buffer *buffer, + void **result) +{ + ssize_t length = __nscd_read_from_socket (key, keylen, type, buffer); + /* The length can be negative. Rely on the check in the parse function. */ + int ret = __nscd_parse_and_copy (lt, buffer->data, length, result); + return ret == 0; +} + +/* Common tail of __nscd_parse_and_copy_* implementations. Return 0 + on success, -ENOMEM on failure, and -EMSGSIZE on parse error. */ +static inline int +__nscd_parse_and_copy_tail (enum nss_lookup_type lt, struct parse_buffer pb, + const void *nss_struct, void **result) +{ + if (!parse_buffer_has_failed (&pb)) + { + *result = __nss_generic_dup (lt, nss_struct); + if (*result != NULL) + return 0; + else + return -ENOMEM; + } + else + /* Parse error. */ + return -EMSGSIZE; +} + +static int +__nscd_parse_and_copy_group (enum nss_lookup_type lt, + void *buffer, ssize_t length, void **result) +{ + if (length < 0) + { + __nscd_defer_database (NSS_DBSIDX_group); + return -ENOENT; + } + + struct parse_buffer pb = parse_buffer_create (buffer, length); + + int32_t gr_found = parse_buffer_field (&pb, 0, gr_response_header, found); + if (gr_found == 1) + { + uint32_t gr_mem_cnt + = parse_buffer_field (&pb, 0, gr_response_header, gr_mem_cnt); + + /* Paranoia check to avoid overflow. */ + if (gr_mem_cnt >= INT_MAX / 4) + return -EMSGSIZE; + + /* Skip over the array with the group member name lengths. */ + size_t pos = (sizeof (gr_response_header) + + gr_mem_cnt * sizeof (uint32_t)); + struct group grp; + grp.gr_name = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, gr_response_header, gr_name_len)); + grp.gr_passwd = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, gr_response_header, gr_passwd_len)); + grp.gr_gid = parse_buffer_field (&pb, 0, + gr_response_header, gr_gid); + grp.gr_mem = __libc_reallocarray (NULL, gr_mem_cnt + 1, + sizeof (*grp.gr_mem)); + if (grp.gr_mem == NULL) + return -ENOMEM; + + /* Need to free grp.gr_mem before returning after this point. */ + int ret = 0; + + size_t lenpos = sizeof (gr_response_header); + for (uint32_t i = 0; i < gr_mem_cnt; ++i) + grp.gr_mem[i] = parse_buffer_sized_cstring_advance + (&pb, &pos, parse_buffer_u32_advance (&pb, &lenpos)); + grp.gr_mem[gr_mem_cnt] = NULL; + + ret = __nscd_parse_and_copy_tail (lt, pb, &grp, result); + free (grp.gr_mem); + return ret; + } + else if (gr_found == -1) + { + /* The daemon does not cache this database. */ + __nscd_defer_database (NSS_DBSIDX_group); + return -ENOENT; + } + else if (parse_buffer_has_failed (&pb)) + return -EMSGSIZE; + else + { + *result = NULL; + return 0; + } +} + + +/* Common tail of __nscd_generic_get. */ +static bool +__nscd_generic_get_tail (enum nss_lookup_type lt, unsigned int db, + request_type type, + const char *nscd_key, size_t nscd_keylen, + void **result) +{ + bool ok = true; + struct scratch_buffer buffer; + scratch_buffer_init (&buffer); + + /* Try the mapping first. */ + bool cache_hit = __nscd_try_cache (db, type, nscd_key, nscd_keylen, + lt, &buffer, result); + + /* If the cache did not produce data, try the socket. The socket + may produce a successful negative result (*result == NULL). */ + if (!cache_hit) + ok = __nscd_try_socket (type, nscd_key, nscd_keylen, lt, &buffer, + result); + + scratch_buffer_free (&buffer); + return ok; +} + +#define NSCD_NUMBER_BUFFER_LENGTH 20 + +static int +__nscd_fmt_num (char storage[static NSCD_NUMBER_BUFFER_LENGTH], int number) +{ + return __snprintf (storage, NSCD_NUMBER_BUFFER_LENGTH, "%d", number) + 1; +} + +bool +__nscd_generic_get (enum nss_lookup_type lt, const void *key, void **result) +{ + /* Storage for keys that need to be converted. */ + char storage[20]; + + int8_t db = __nscd_database_for_lookup[lt]; + if (db < 0 || !__nscd_use_database (db)) + return false; + + switch (lt) + { + case nss_lookup_getgrgid: + return __nscd_generic_get_tail (lt, db, GETGRBYGID, storage, + __nscd_fmt_num (storage, + *(const gid_t *) key), + result); + case nss_lookup_getgrnam: + return __nscd_generic_get_tail (lt, db, GETGRBYNAME, + key, strlen (key) + 1, + result); + case nss_lookup_getpwnam: + return __nscd_generic_get_tail (lt, db, GETPWBYNAME, + key, strlen (key) + 1, + result); + case nss_lookup_getpwuid: + return __nscd_generic_get_tail (lt, db, GETPWBYUID, storage, + __nscd_fmt_num (storage, + *(const uid_t *) key), + result); + } + __builtin_unreachable (); +} + +static int +__nscd_parse_and_copy_passwd (enum nss_lookup_type lt, + void *buffer, ssize_t length, void **result) +{ + if (length < 0) + { + __nscd_defer_database (NSS_DBSIDX_passwd); + return -ENOENT; + } + + struct parse_buffer pb = parse_buffer_create (buffer, length); + + int32_t pw_found = parse_buffer_field (&pb, 0, pw_response_header, found); + if (pw_found == 1) + { + size_t pos = sizeof (pw_response_header); + struct passwd pwd; + pwd.pw_name = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, pw_response_header, pw_name_len)); + pwd.pw_passwd = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, pw_response_header, pw_passwd_len)); + pwd.pw_uid = parse_buffer_field (&pb, 0, pw_response_header, pw_uid); + pwd.pw_gid = parse_buffer_field (&pb, 0, pw_response_header, pw_gid); + pwd.pw_gecos = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, pw_response_header, pw_gecos_len)); + pwd.pw_dir = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, pw_response_header, pw_dir_len)); + pwd.pw_shell = parse_buffer_sized_cstring_advance + (&pb, &pos, + parse_buffer_field (&pb, 0, pw_response_header, pw_shell_len)); + + return __nscd_parse_and_copy_tail (lt, pb, &pwd, result); + } + else if (pw_found == -1) + { + /* The daemon does not cache this database. */ + __nscd_defer_database (NSS_DBSIDX_passwd); + return -ENOENT; + } + else if (parse_buffer_has_failed (&pb)) + return -EMSGSIZE; + else + { + *result = NULL; + return 0; + } +} diff --git a/nss/nss_generic.h b/nss/nss_generic.h index fcddf8bf54..8a5b2cb896 100644 --- a/nss/nss_generic.h +++ b/nss/nss_generic.h @@ -64,4 +64,20 @@ void *__nss_generic_dup (enum nss_lookup_type lt, const void *source) each lookup type, or -1 if the lookup has no corresponding database. */ extern int8_t __nscd_database_for_lookup[nss_lookup_MAX] attribute_hidden; +/* Interpreted according to enum nss_lookup_type. Typically a string + or a pointer to an integer. */ +typedef const void *nss_lookup_key; + +/* Query the nscd daemon for KEY according to LT. On success, return + true, and write a NSS struct pointer allocated using + __nss_generic_dup to *RESULT (positive result), or a null pointer + (negative result). On failure, return false. The caller is + expected to attempt the NSS operation directly after a failure. + + Failure is also possible if nscd lookup has been deferred; the + implementation calls __nscd_use_database as a first step to check + if nscd should actually be used. */ +bool __nscd_generic_get (enum nss_lookup_type lt, nss_lookup_key key, + void **result); + #endif /* NSS_GENERIC_H */ From patchwork Fri Mar 20 20:42:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132123 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id E629A4C515F9 for ; Fri, 20 Mar 2026 20:56:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E629A4C515F9 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=jBdZtP91 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.129.124]) by sourceware.org (Postfix) with ESMTP id F26AD4C31829 for ; Fri, 20 Mar 2026 20:42:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F26AD4C31829 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 F26AD4C31829 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039372; cv=none; b=BUE6E9CVaPUThaR5lRz0aCYJ4kA542a5GigSrj6aNDT+h7Qv2d69i2UOeETu/mhv8XzbHmRlGrbwuO/wYDjUCnBPL56vVSi6Xx5Xz7i5qQTkP5IAFXKutNLxJ8Hu7oVhx6N5SYqQ74UfhseXRqltaaE1jVIle2cKv0v1ejxTpLo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039372; c=relaxed/simple; bh=iEyHHITNzFTURvLTTv2sUOLBLrh/1yW5RawHML1+XlY=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=P/a5Anm96frMei+Af7Cgglv2sADGajmJxWNU3bVsRaYmy4//aWW5pHjQDAMp0sO/Td1yWeyMTvjcIotvthMzLCIytrwWkNCRJs1Mu6gpzIO395c1k/jgbBmN0cgZt+V4VGa18UHjx18Ri5MUyOGXwRN3Y0uzJqqrlSKgXqEIinE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F26AD4C31829 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039371; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=/ixXoNMyCYjxRaAIpcDzY60CI1lyQHSfuC12ZQX5v9M=; b=jBdZtP91q4iBzcVBmYuW3hd3FnTIUQCdsXNVgO+zbueRxGDzCg8IsctnT0GHuSiQNMlSPy z24wAFFxhpRxzznjor3rduSfnbyVvy9bnH8nNObkye/fSwIZAQ/Mc162b3bYyYCMgmOroQ WKDbYJ5+G090Kv4GZtrcdvXc+UwY0cg= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-609-tghvaDmrPK2Hxz0-ksJxew-1; Fri, 20 Mar 2026 16:42:50 -0400 X-MC-Unique: tghvaDmrPK2Hxz0-ksJxew-1 X-Mimecast-MFC-AGG-ID: tghvaDmrPK2Hxz0-ksJxew_1774039369 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3EB721956055 for ; Fri, 20 Mar 2026 20:42:49 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 849391955F21 for ; Fri, 20 Mar 2026 20:42:48 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 16/23] nscd: Convert group client to __nscd_generic_get In-Reply-To: Message-ID: <0d040554d5c810bd6aa53720b1678f564a061d1e.1774037705.git.fweimer@redhat.com> References: X-From-Line: 0d040554d5c810bd6aa53720b1678f564a061d1e Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:46 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: cbNqPftaaGj0KHV4tg3QjYIw5ho6jjokL8fuwXynTQg_1774039369 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, PROLO_LEO1, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 --- nscd/nscd_getgr_r.c | 250 ++++---------------------------------------- 1 file changed, 19 insertions(+), 231 deletions(-) diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c index f77650b25f..daf046bcbf 100644 --- a/nscd/nscd_getgr_r.c +++ b/nscd/nscd_getgr_r.c @@ -31,21 +31,21 @@ #include #include <_itoa.h> #include +#include #include "nscd-client.h" #include "nscd-dbtype.h" #include "nscd_proto.h" -static int nscd_getgr_r (const char *key, size_t keylen, request_type type, - struct group *resultbuf, char *buffer, - size_t buflen, struct group **result); - +static int nscd_getgr_r (enum nss_lookup_type lt, const void *key, + struct group *resultbuf, char *buffer, size_t buflen, + struct group **result); int __nscd_getgrnam_r (const char *name, struct group *resultbuf, char *buffer, size_t buflen, struct group **result) { - return nscd_getgr_r (name, strlen (name) + 1, GETGRBYNAME, resultbuf, + return nscd_getgr_r (nss_lookup_getgrnam, name, resultbuf, buffer, buflen, result); } @@ -54,241 +54,29 @@ int __nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer, size_t buflen, struct group **result) { - char buf[3 * sizeof (gid_t)]; - buf[sizeof (buf) - 1] = '\0'; - char *cp = _itoa_word (gid, buf + sizeof (buf) - 1, 10, 0); - - return nscd_getgr_r (cp, buf + sizeof (buf) - cp, GETGRBYGID, resultbuf, + return nscd_getgr_r (nss_lookup_getgrgid, &gid, resultbuf, buffer, buflen, result); } static int -nscd_getgr_r (const char *key, size_t keylen, request_type type, +nscd_getgr_r (enum nss_lookup_type lt, const void *key, struct group *resultbuf, char *buffer, size_t buflen, struct group **result) { - int gc_cycle; - int nretries = 0; - const uint32_t *len = NULL; - struct scratch_buffer lenbuf; - scratch_buffer_init (&lenbuf); - - /* If the mapping is available, try to search there instead of - communicating with the nscd. */ - struct mapped_database *map = __nscd_get_map_ref (grpdb, &gc_cycle); - retry:; - const char *gr_name = NULL; - size_t gr_name_len = 0; - int retval = -1; - const char *recend = (const char *) ~UINTMAX_C (0); - gr_response_header gr_resp; - - if (map != NULL) + void *result1; + bool ok = __nscd_generic_get (lt, key, &result1); + if (ok) { - struct datahead *found = __nscd_cache_search (type, key, keylen, map, - sizeof gr_resp); - if (found != NULL) - { - len = (const uint32_t *) (&found->data[0].grdata + 1); - gr_resp = found->data[0].grdata; - gr_name = ((const char *) len - + gr_resp.gr_mem_cnt * sizeof (uint32_t)); - gr_name_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len; - recend = (const char *) found->data + found->recsize; - /* Now check if we can trust gr_resp fields. If GC is - in progress, it can contain anything. */ - if (map->head->gc_cycle != gc_cycle) - { - retval = -2; - goto out; - } - - /* The alignment is always sufficient, unless GC is in progress. */ - assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0); - } - } - - int sock = -1; - if (gr_name == NULL) - { - sock = __nscd_open_socket (key, keylen, type, &gr_resp, - sizeof (gr_resp)); - if (sock == -1) - { - __nscd_defer_database (grpdb); - goto out; - } - } - - /* No value found so far. */ - *result = NULL; - - if (__glibc_unlikely (gr_resp.found == -1)) - { - /* The daemon does not cache this database. */ - __nscd_defer_database (grpdb); - goto out_close; - } - - if (gr_resp.found == 1) - { - struct iovec vec[2]; - char *p = buffer; - size_t total_len; - uintptr_t align; - nscd_ssize_t cnt; - - /* Now allocate the buffer the array for the group members. We must - align the pointer. */ - align = ((__alignof__ (char *) - ((uintptr_t) p)) - & (__alignof__ (char *) - 1)); - total_len = (align + (1 + gr_resp.gr_mem_cnt) * sizeof (char *) - + gr_resp.gr_name_len + gr_resp.gr_passwd_len); - if (__glibc_unlikely (buflen < total_len)) - { - no_room: - __set_errno (ERANGE); - retval = ERANGE; - goto out_close; - } - buflen -= total_len; - - p += align; - resultbuf->gr_mem = (char **) p; - p += (1 + gr_resp.gr_mem_cnt) * sizeof (char *); - - /* Set pointers for strings. */ - resultbuf->gr_name = p; - p += gr_resp.gr_name_len; - resultbuf->gr_passwd = p; - p += gr_resp.gr_passwd_len; - - /* Fill in what we know now. */ - resultbuf->gr_gid = gr_resp.gr_gid; - - /* Read the length information, group name, and password. */ - if (gr_name == NULL) - { - /* Handle a simple, usual case: no group members. */ - if (__glibc_likely (gr_resp.gr_mem_cnt == 0)) - { - size_t n = gr_resp.gr_name_len + gr_resp.gr_passwd_len; - if (__builtin_expect (__readall (sock, resultbuf->gr_name, n) - != (ssize_t) n, 0)) - goto out_close; - } - else - { - /* Allocate array to store lengths. */ - if (!scratch_buffer_set_array_size - (&lenbuf, gr_resp.gr_mem_cnt, sizeof (uint32_t))) - goto out_close; - len = lenbuf.data; - - vec[0].iov_base = (void *) len; - vec[0].iov_len = gr_resp.gr_mem_cnt * sizeof (uint32_t); - vec[1].iov_base = resultbuf->gr_name; - vec[1].iov_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len; - total_len = vec[0].iov_len + vec[1].iov_len; - - /* Get this data. */ - size_t n = __readvall (sock, vec, 2); - if (__glibc_unlikely (n != total_len)) - goto out_close; - } - } - else - /* We already have the data. Just copy the group name and - password. */ - memcpy (resultbuf->gr_name, gr_name, - gr_resp.gr_name_len + gr_resp.gr_passwd_len); - - /* Clear the terminating entry. */ - resultbuf->gr_mem[gr_resp.gr_mem_cnt] = NULL; - - /* Prepare reading the group members. */ - total_len = 0; - for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt) + if (result1 == NULL) { - resultbuf->gr_mem[cnt] = p; - total_len += len[cnt]; - p += len[cnt]; + *result = NULL; + return 0; } - - if (__glibc_unlikely (gr_name + gr_name_len + total_len > recend)) - { - /* len array might contain garbage during nscd GC cycle, - retry rather than fail in that case. */ - if (gr_name != NULL && map->head->gc_cycle != gc_cycle) - retval = -2; - goto out_close; - } - if (__glibc_unlikely (total_len > buflen)) - { - /* len array might contain garbage during nscd GC cycle, - retry rather than fail in that case. */ - if (gr_name != NULL && map->head->gc_cycle != gc_cycle) - { - retval = -2; - goto out_close; - } - else - goto no_room; - } - - retval = 0; - - /* If there are no group members TOTAL_LEN is zero. */ - if (gr_name == NULL) - { - if (total_len > 0 - && __builtin_expect (__readall (sock, resultbuf->gr_mem[0], - total_len) != total_len, 0)) - { - /* The `errno' to some value != ERANGE. */ - __set_errno (ENOENT); - retval = ENOENT; - } - else - *result = resultbuf; - } - else - { - /* Copy the group member names. */ - memcpy (resultbuf->gr_mem[0], gr_name + gr_name_len, total_len); - - /* Try to detect corrupt databases. */ - if (resultbuf->gr_name[gr_name_len - 1] != '\0' - || resultbuf->gr_passwd[gr_resp.gr_passwd_len - 1] != '\0' - || ({for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt) - if (resultbuf->gr_mem[cnt][len[cnt] - 1] != '\0') - break; - cnt < gr_resp.gr_mem_cnt; })) - { - /* We cannot use the database. */ - retval = map != NULL && map->head->gc_cycle != gc_cycle ? -2 : -1; - goto out_close; - } - - *result = resultbuf; - } - } - else - { - /* Set errno to 0 to indicate no error, just no found record. */ - __set_errno (0); - /* Even though we have not found anything, the result is zero. */ - retval = 0; + int ret = __nss_generic_copy (lt, result1, resultbuf, buffer, buflen); + free (result1); + if (ret == 0) + *result = resultbuf; + return ret; } - - out_close: - if (sock != -1) - __close_nocancel_nostatus (sock); - out: - if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) - goto retry; - - scratch_buffer_free (&lenbuf); - - return retval; + return -1; } From patchwork Fri Mar 20 20:42:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132125 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 7CA574C9174F for ; Fri, 20 Mar 2026 20:58:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7CA574C9174F Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=H0G3Rq7t 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.129.124]) by sourceware.org (Postfix) with ESMTP id 3E67E4C31843 for ; Fri, 20 Mar 2026 20:42:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3E67E4C31843 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 3E67E4C31843 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039376; cv=none; b=VnV0VIpuQvRyAzu96gNtlALNsI6KaXZs+cb3NtnPSWpTxeH49/gAhypJFtpaQaSNfLGUdxND2PVVUin9GX6fO79TdLnoo/m0FDQpqOlF7fq6T3cKA6ayEvnj4S+oPIoDa2d/YVJ2SypTnJeyT1UpQ1rQpks8dvcnMqbESkWB+9I= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039376; c=relaxed/simple; bh=kJn+ZWFyuCXOQtEJ43EBYQcXpG/1EVeKZZq/G3Yc4eI=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=VmKJatGN8aXMJ83/qe6kWST+tpcQPISU7MKAFo/rRGoVzYXD0VKeseHJmp1HfkyadSDZIaoXZpWn6SAy/7GXnhRhN6zPHy6fm9Wl6H5KZh6cFMNBPvFv0wwlpeDGc61Mj/tNmuIFoYVhkHKaCFhacwGFcstf7c9Si+yylyNTG5g= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3E67E4C31843 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039375; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=myyibIa5dKUPMuZWDrlux6FLeGYYTJBVZMtjGA6yz24=; b=H0G3Rq7tLCjrlC0yR1W255L8c3cUD5q7iUSwOSraTieMpLtRmLOBmbrWBWBYPQZSJ+ZVDI J9r0aCtZmwuSRHZaDFwozpyHG4MqL4wawWEX2Rc+Sq2qEJR4p4Pi2Nz0oDGpQhlgYfuz9S 9Ek/2V85KUeSLkQpVLKtyWE0ZvRjzxw= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-515-0DCo1pqsPpivMfrAw71xVA-1; Fri, 20 Mar 2026 16:42:54 -0400 X-MC-Unique: 0DCo1pqsPpivMfrAw71xVA-1 X-Mimecast-MFC-AGG-ID: 0DCo1pqsPpivMfrAw71xVA_1774039374 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0659F19560AA for ; Fri, 20 Mar 2026 20:42:54 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 50A141953944 for ; Fri, 20 Mar 2026 20:42:53 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 17/23] nscd: Convert passwd client to __nscd_generic_get In-Reply-To: Message-ID: References: X-From-Line: dc974c5044755a818cd015e82088a649c4141c39 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:50 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: NUkC5ttWl5nx-GHjakhdlxhnl8kRRzDvG-jFDOmAKGk_1774039374 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.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_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 --- nscd/nscd_getpw_r.c | 165 +++++--------------------------------------- 1 file changed, 19 insertions(+), 146 deletions(-) diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c index 8ce1009fe0..97a752fa48 100644 --- a/nscd/nscd_getpw_r.c +++ b/nscd/nscd_getpw_r.c @@ -29,23 +29,21 @@ #include #include #include <_itoa.h> +#include #include "nscd-client.h" #include "nscd-dbtype.h" #include "nscd_proto.h" -static int nscd_getpw_r (const char *key, size_t keylen, request_type type, - struct passwd *resultbuf, char *buffer, - size_t buflen, struct passwd **result); +static int nscd_getpw_r (enum nss_lookup_type lt, const void *key, + struct passwd *resultbuf, char *buffer, size_t buflen, + struct passwd **result); int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result) { - if (name == NULL) - return -1; - - return nscd_getpw_r (name, strlen (name) + 1, GETPWBYNAME, resultbuf, + return nscd_getpw_r (nss_lookup_getpwnam, name, resultbuf, buffer, buflen, result); } @@ -53,155 +51,30 @@ int __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result) { - char buf[3 * sizeof (uid_t)]; - buf[sizeof (buf) - 1] = '\0'; - char *cp = _itoa_word (uid, buf + sizeof (buf) - 1, 10, 0); - - return nscd_getpw_r (cp, buf + sizeof (buf) - cp, GETPWBYUID, resultbuf, + return nscd_getpw_r (nss_lookup_getpwuid, &uid, resultbuf, buffer, buflen, result); } static int -nscd_getpw_r (const char *key, size_t keylen, request_type type, +nscd_getpw_r (enum nss_lookup_type lt, const void *key, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result) { - int gc_cycle; - int nretries = 0; - - /* If the mapping is available, try to search there instead of - communicating with the nscd. */ - struct mapped_database *map = __nscd_get_map_ref (pwddb, &gc_cycle); - - retry:; - const char *pw_name = NULL; - int retval = -1; - const char *recend = (const char *) ~UINTMAX_C (0); - pw_response_header pw_resp; - - if (map != NULL) + void *result1; + bool ok = __nscd_generic_get (lt, key, &result1); + if (ok) { - struct datahead *found = __nscd_cache_search (type, key, keylen, map, - sizeof pw_resp); - if (found != NULL) + if (result1 == NULL) { - pw_name = (const char *) (&found->data[0].pwdata + 1); - pw_resp = found->data[0].pwdata; - recend = (const char *) found->data + found->recsize; - /* Now check if we can trust pw_resp fields. If GC is - in progress, it can contain anything. */ - if (map->head->gc_cycle != gc_cycle) - { - retval = -2; - goto out; - } + *result = NULL; + return 0; } + int ret = __nss_generic_copy (lt, result1, resultbuf, buffer, buflen); + free (result1); + if (ret == 0) + *result = resultbuf; + return ret; } - - int sock = -1; - if (pw_name == NULL) - { - sock = __nscd_open_socket (key, keylen, type, &pw_resp, - sizeof (pw_resp)); - if (sock == -1) - { - __nscd_defer_database (pwddb); - goto out; - } - } - - /* No value found so far. */ - *result = NULL; - - if (__glibc_unlikely (pw_resp.found == -1)) - { - /* The daemon does not cache this database. */ - __nscd_defer_database (pwddb); - goto out_close; - } - - if (pw_resp.found == 1) - { - /* Set the information we already have. */ - resultbuf->pw_uid = pw_resp.pw_uid; - resultbuf->pw_gid = pw_resp.pw_gid; - - char *p = buffer; - /* get pw_name */ - resultbuf->pw_name = p; - p += pw_resp.pw_name_len; - /* get pw_passwd */ - resultbuf->pw_passwd = p; - p += pw_resp.pw_passwd_len; - /* get pw_gecos */ - resultbuf->pw_gecos = p; - p += pw_resp.pw_gecos_len; - /* get pw_dir */ - resultbuf->pw_dir = p; - p += pw_resp.pw_dir_len; - /* get pw_pshell */ - resultbuf->pw_shell = p; - p += pw_resp.pw_shell_len; - - ssize_t total = p - buffer; - if (__glibc_unlikely (pw_name + total > recend)) - goto out_close; - if (__glibc_unlikely (buflen < total)) - { - __set_errno (ERANGE); - retval = ERANGE; - goto out_close; - } - - retval = 0; - if (pw_name == NULL) - { - ssize_t nbytes = __readall (sock, buffer, total); - - if (__glibc_unlikely (nbytes != total)) - { - /* The `errno' to some value != ERANGE. */ - __set_errno (ENOENT); - retval = ENOENT; - } - else - *result = resultbuf; - } - else - { - /* Copy the various strings. */ - memcpy (resultbuf->pw_name, pw_name, total); - - /* Try to detect corrupt databases. */ - if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0' - || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0' - || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0' - || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0' - || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0') - { - /* We cannot use the database. */ - retval = map->head->gc_cycle != gc_cycle ? -2 : -1; - goto out_close; - } - - *result = resultbuf; - } - } - else - { - /* Set errno to 0 to indicate no error, just no found record. */ - __set_errno (0); - /* Even though we have not found anything, the result is zero. */ - retval = 0; - } - - out_close: - if (sock != -1) - __close_nocancel_nostatus (sock); - out: - if (__nscd_map_ref_retry_or_drop (&map, &gc_cycle, &nretries, retval)) - goto retry; - - return retval; + return -1; } From patchwork Fri Mar 20 20:42:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132126 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id AE57C4B1A2EC for ; Fri, 20 Mar 2026 20:59:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AE57C4B1A2EC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IQ682c6V 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.129.124]) by sourceware.org (Postfix) with ESMTP id 46A674C91758 for ; Fri, 20 Mar 2026 20:43:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 46A674C91758 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 46A674C91758 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039382; cv=none; b=UuGGPnOeJW3dfUcTo1esx0RMHDebn81U5oyJGhkA5eNJoWkm+o39+ZOz5E1nSm0UAUyhPUKKjdg85eS8VpM6j2Z9BMqsZVa+08nKdWiw2xC1GpOZ+RKjFWXlIIYppu0xAXFGE8AN9lp+j13xwKTSkVtvLnnEpvE/MDXeDVqBr7w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039382; c=relaxed/simple; bh=GoJfQ/c8ztWl0bX7BbmXN0O1t9yaQaq5wTbeRmCQx3U=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=JH6h7DjMXk5htu+dF/V1qfXf6eNBq9bEa5yEx4hcHY2t6qj9FR60W4Z9v40kPvWpD6ksLWScGizEAQSI3r6ZfUD63nZCJEjc/94VL5c60QRxpIlDAOkYVYvmEWMPkxHAznESbOpG5lp/UtPNpQL+PpwasTZid2AWG284rg0+j1U= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 46A674C91758 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039381; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=v74DBEgJNwF1nc6U4UxhWmbkIesabxBc+Qn6JtVJPkc=; b=IQ682c6VtcjRL88uszkKBQ1Nn1Ouhk9441qp28L1g0Jf53kMTXvYGNr3y3G3vRoNlOxrnG ikLhndm32OzIqETgJn4I199oC7/TijkYs/jfqYNjJ7VR4XENdbWxO5rlidVSnYZtG7WzTO LfIff62J0Hj0wf5hEA6bHwqEsXO5i3A= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-655-R_cK6Tn3PFOOuVCK3aMurQ-1; Fri, 20 Mar 2026 16:43:00 -0400 X-MC-Unique: R_cK6Tn3PFOOuVCK3aMurQ-1 X-Mimecast-MFC-AGG-ID: R_cK6Tn3PFOOuVCK3aMurQ_1774039379 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id BF71E195604F for ; Fri, 20 Mar 2026 20:42:59 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9ADCA180035F for ; Fri, 20 Mar 2026 20:42:58 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 18/23] Extract from ldconfig In-Reply-To: Message-ID: References: X-From-Line: abe48c306f4e2d58a4b03ee7a535dc456daae454 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:42:56 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: OVjTHJ0nuokTJjhFpNuHxd_RuVTMGT0m4dv8XO3v0Ek_1774039379 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 And make it usable in other parts of the library. The type safety mechanism follows the dynarray approach. The previous implementation now lives in elf/cachestrings.h and elf/cachestrings.c and is layered on top of and . The internal support routines are built for libsupport, so that they can be used in tests. --- elf/Makefile | 4 +- elf/cache.c | 28 +-- elf/cachestrings.c | 149 +++++++++++++ elf/{stringtable.h => cachestrings.h} | 40 ++-- elf/stringtable.c | 209 ------------------ elf/{tst-stringtable.c => tst-cachestrings.c} | 128 ++++++----- include/stringtable-skeleton.h | 129 +++++++++++ include/stringtable.h | 55 +++++ misc/Makefile | 3 + misc/fnv1a.c | 32 +++ misc/stringtable_add.c | 128 +++++++++++ misc/stringtable_free.c | 44 ++++ support/Makefile | 1 + .../support_stringtable.c | 23 +- 14 files changed, 648 insertions(+), 325 deletions(-) create mode 100644 elf/cachestrings.c rename elf/{stringtable.h => cachestrings.h} (53%) delete mode 100644 elf/stringtable.c rename elf/{tst-stringtable.c => tst-cachestrings.c} (54%) create mode 100644 include/stringtable-skeleton.h create mode 100644 include/stringtable.h create mode 100644 misc/fnv1a.c create mode 100644 misc/stringtable_add.c create mode 100644 misc/stringtable_free.c rename elf/stringtable_free.c => support/support_stringtable.c (56%) diff --git a/elf/Makefile b/elf/Makefile index 7f039b5563..cfe4b3f9a5 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -219,11 +219,11 @@ install-rootsbin += ldconfig ldconfig-modules := \ cache \ + cachestrings \ chroot_canon \ ldconfig-parse \ readlib \ static-stubs \ - stringtable \ xmalloc \ xstrdup \ # ldconfig-modules @@ -309,11 +309,11 @@ tests := \ tst-array4 \ tst-array5 \ tst-auxv \ + tst-cachestrings \ tst-decorate-maps \ tst-dl-hash \ tst-env-setuid \ tst-leaks1 \ - tst-stringtable \ tst-tls9 \ tst-tunables-enable_secure-env \ # tests diff --git a/elf/cache.c b/elf/cache.c index a6dc85dc0f..d8bc2f7135 100644 --- a/elf/cache.c +++ b/elf/cache.c @@ -35,10 +35,10 @@ #include #include #include -#include +#include /* Used to store library names, paths, and other strings. */ -static struct stringtable strings; +static struct cachestrings strings; /* Keeping track of "glibc-hwcaps" subdirectories. During cache construction, a linear search by name is performed to deduplicate @@ -48,7 +48,7 @@ struct glibc_hwcaps_subdirectory struct glibc_hwcaps_subdirectory *next; /* Interned string with the subdirectory name. */ - struct stringtable_entry *name; + struct cachestrings_entry *name; /* Array index in the cache_extension_tag_glibc_hwcaps section in the stored cached file. This is computed after all the @@ -63,7 +63,7 @@ struct glibc_hwcaps_subdirectory const char * glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir) { - return dir->name->string; + return dir->name->E.string; } /* Linked list of known hwcaps subdirectory names. */ @@ -72,7 +72,7 @@ static struct glibc_hwcaps_subdirectory *hwcaps; struct glibc_hwcaps_subdirectory * new_glibc_hwcaps_subdirectory (const char *name) { - struct stringtable_entry *name_interned = stringtable_add (&strings, name); + struct cachestrings_entry *name_interned = cachestrings_add (&strings, name); for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next) if (p->name == name_interned) return p; @@ -141,8 +141,8 @@ assign_glibc_hwcaps_indices (void) struct cache_entry { - struct stringtable_entry *lib; /* Library name. */ - struct stringtable_entry *path; /* Path to find library. */ + struct cachestrings_entry *lib; /* Library name. */ + struct cachestrings_entry *path; /* Path to find library. */ int flags; /* Flags to indicate kind of library. */ unsigned int isa_level; /* Required ISA level. */ @@ -412,7 +412,7 @@ static int compare (const struct cache_entry *e1, const struct cache_entry *e2) { /* We need to swap entries here to get the correct sort order. */ - int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string); + int res = _dl_cache_libcmp (e2->lib->E.string, e1->lib->E.string); if (res == 0) { if (e1->flags < e2->flags) @@ -519,7 +519,7 @@ compute_hwcap_value (struct cache_entry *entry) { if (entry->isa_level > DL_CACHE_HWCAP_ISA_LEVEL_MASK) error (EXIT_FAILURE, 0, _("%s: ISA level is too high (%d > %d)"), - entry->path->string, entry->isa_level, + entry->path->E.string, entry->isa_level, DL_CACHE_HWCAP_ISA_LEVEL_MASK); return (DL_CACHE_HWCAP_EXTENSION | (((uint64_t) entry->isa_level) << 32) @@ -548,8 +548,8 @@ save_cache (const char *cache_name) ++cache_entry_old_count; } - struct stringtable_finalized strings_finalized; - stringtable_finalize (&strings, &strings_finalized); + struct cachestrings_finalized strings_finalized; + cachestrings_finalize (&strings, &strings_finalized); /* Create the on disk cache structure. */ struct cache_file *file_entries = NULL; @@ -758,16 +758,16 @@ add_to_cache (const char *path, const char *filename, const char *soname, { struct cache_entry *new_entry = xmalloc (sizeof (*new_entry)); - struct stringtable_entry *path_interned; + struct cachestrings_entry *path_interned; { char *p; if (asprintf (&p, "%s/%s", path, filename) < 0) error (EXIT_FAILURE, errno, _("Could not create library path")); - path_interned = stringtable_add (&strings, p); + path_interned = cachestrings_add (&strings, p); free (p); } - new_entry->lib = stringtable_add (&strings, soname); + new_entry->lib = cachestrings_add (&strings, soname); new_entry->path = path_interned; new_entry->flags = flags; new_entry->isa_level = isa_level; diff --git a/elf/cachestrings.c b/elf/cachestrings.c new file mode 100644 index 0000000000..c17c48bce6 --- /dev/null +++ b/elf/cachestrings.c @@ -0,0 +1,149 @@ +/* String tables for ld.so.cache construction. Implementation. + Copyright (C) 2020-2026 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 + +#define STRINGTABLE_ENTRY cachestrings_entry +#define STRINGTABLE_STRUCT cachestrings +#define STRINGTABLE_PREFIX cache_s_table_ +#include + +struct cachestrings_entry * +cachestrings_add (struct cachestrings *table, const char *string) +{ + struct cachestrings_entry *e = cache_s_table_add (table, string); + if (e == NULL) + error (EXIT_FAILURE, errno, _("String table is too large")); + return e; +} + +void +cachestrings_free (struct cachestrings *table) +{ + cache_s_table_free (table); +} + +/* Sort reversed strings in reverse lexicographic order. This is used + for tail merging. */ +static int +finalize_compare (const void *l, const void *r) +{ + struct cachestrings_entry *left = *(struct cachestrings_entry **) l; + struct cachestrings_entry *right = *(struct cachestrings_entry **) r; + size_t to_compare; + if (left->E.length < right->E.length) + to_compare = left->E.length; + else + to_compare = right->E.length; + for (size_t i = 1; i <= to_compare; ++i) + { + unsigned char lch = left->E.string[left->E.length - i]; + unsigned char rch = right->E.string[right->E.length - i]; + if (lch != rch) + return rch - lch; + } + if (left->E.length == right->E.length) + return 0; + else if (left->E.length < right->E.length) + /* Longer strings should come first. */ + return 1; + else + return -1; +} + +/* Add E to the array (identified via CLOSURE). */ +static void +cache_s_table_cb_list (struct cachestrings_entry *e, void *closure) +{ + struct cachestrings_entry ***pptr = closure; + **pptr = e; + ++*pptr; +} + +/* Copy the string of E into the result buffer (a struct + cachestrings_finalized *). */ +static void +cache_s_table_cb_store (struct cachestrings_entry *e, void *closure) +{ + struct cachestrings_finalized *result = closure; + if (result->strings[e->offset] == '\0') + memcpy (&result->strings[e->offset], e->E.string, e->E.length + 1); +} + +void +cachestrings_finalize (struct cachestrings *table, + struct cachestrings_finalized *result) +{ + size_t table_count = table->T.count; + if (table_count == 0) + { + result->strings = xstrdup (""); + result->size = 0; + return; + } + + /* Optimize the order of the strings. */ + struct cachestrings_entry **array + = xcalloc (table_count, sizeof (*array)); + { + struct cachestrings_entry **tmp = array; + cache_s_table_foreach (table, cache_s_table_cb_list, &tmp); + assert (tmp == array + table_count); + } + qsort (array, table_count, sizeof (*array), finalize_compare); + + /* Assign offsets, using tail merging (sharing suffixes) if possible. */ + array[0]->offset = 0; + for (uint32_t j = 1; j < table_count; ++j) + { + struct cachestrings_entry *previous = array[j - 1]; + struct cachestrings_entry *current = array[j]; + if (previous->E.length >= current->E.length + && memcmp (&previous->E.string[previous->E.length + - current->E.length], + current->E.string, current->E.length) == 0) + current->offset = (previous->offset + previous->E.length + - current->E.length); + else if (__builtin_add_overflow (previous->offset, + previous->E.length + 1, + ¤t->offset)) + error (EXIT_FAILURE, 0, _("String table is too large")); + } + + /* Allocate the result string. */ + { + struct cachestrings_entry *last = array[table_count - 1]; + if (__builtin_add_overflow (last->offset, last->E.length + 1, + &result->size)) + error (EXIT_FAILURE, 0, _("String table is too large")); + } + /* The strings are copied from the hash table, so the array is no + longer needed. */ + free (array); + result->strings = xcalloc (result->size, 1); + + /* Copy the strings. */ + cache_s_table_foreach (table, cache_s_table_cb_store, result); +} diff --git a/elf/stringtable.h b/elf/cachestrings.h similarity index 53% rename from elf/stringtable.h rename to elf/cachestrings.h index 3f78ec43aa..c57c5100d1 100644 --- a/elf/stringtable.h +++ b/elf/cachestrings.h @@ -15,37 +15,35 @@ You should have received a copy of the GNU General Public License along with this program; if not, see . */ -#ifndef _STRINGTABLE_H -#define _STRINGTABLE_H +#ifndef CACHESTRINGS_H +#define CACHESTRINGS_H #include #include +#include -/* An entry in the string table. Only the length and string fields are - expected to be used outside the string table code. */ -struct stringtable_entry +/* An entry in the string table. Only the entry.length and + entry.string fields are expected to be used outside the string + table code. */ +struct cachestrings_entry { - struct stringtable_entry *next; /* For collision resolution. */ - uint32_t length; /* Length of then string. */ - uint32_t offset; /* From start of finalized table. */ - char string[]; /* Null-terminated string. */ + size_t offset; /* From start of finalized table. */ + struct stringtable_entry E; }; -/* A string table. Zero-initialization produces a valid atable. */ -struct stringtable +/* String table for use with ldconfig cache strings. */ +struct cachestrings { - struct stringtable_entry **entries; /* Array of hash table buckets. */ - uint32_t count; /* Number of elements in the table. */ - uint32_t allocated; /* Length of the entries array. */ + struct stringtable T; }; /* Adds STRING to TABLE. May return the address of an existing entry. */ -struct stringtable_entry *stringtable_add (struct stringtable *table, - const char *string); +struct cachestrings_entry *cachestrings_add (struct cachestrings *table, + const char *string); /* Result of stringtable_finalize. SIZE bytes at STRINGS should be written to the file. */ -struct stringtable_finalized +struct cachestrings_finalized { char *strings; size_t size; @@ -53,12 +51,12 @@ struct stringtable_finalized /* Assigns offsets to string table entries and computes the serialized form of the string table. */ -void stringtable_finalize (struct stringtable *table, - struct stringtable_finalized *result); +void cachestrings_finalize (struct cachestrings *, + struct cachestrings_finalized *); /* Deallocate the string table (but not the TABLE pointer itself). (The table can be re-used for adding more strings without initialization.) */ -void stringtable_free (struct stringtable *table); +void cachestrings_free (struct cachestrings *table); -#endif /* _STRINGTABLE_H */ +#endif /* CACHESTRINGS_H */ diff --git a/elf/stringtable.c b/elf/stringtable.c deleted file mode 100644 index c59b417c2d..0000000000 --- a/elf/stringtable.c +++ /dev/null @@ -1,209 +0,0 @@ -/* String tables for ld.so.cache construction. Implementation. - Copyright (C) 2020-2026 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 - -static void -stringtable_init (struct stringtable *table) -{ - table->count = 0; - - /* This needs to be a power of two. 128 is sufficient to keep track - of 42 DSOs without resizing (assuming two strings per DSOs). - glibc itself comes with more than 20 DSOs, so 64 would likely to - be too small. */ - table->allocated = 128; - - table->entries = xcalloc (table->allocated, sizeof (table->entries[0])); -} - -/* 32-bit FNV-1a hash function. */ -static uint32_t -fnv1a (const char *string, size_t length) -{ - const unsigned char *p = (const unsigned char *) string; - uint32_t hash = 2166136261U; - for (size_t i = 0; i < length; ++i) - { - hash ^= p[i]; - hash *= 16777619U; - } - return hash; -} - -/* Double the capacity of the hash table. */ -static void -stringtable_rehash (struct stringtable *table) -{ - /* This computation cannot overflow because the old total in-memory - size of the hash table is larger than the computed value. */ - uint32_t new_allocated = table->allocated * 2; - struct stringtable_entry **new_entries - = xcalloc (new_allocated, sizeof (table->entries[0])); - - uint32_t mask = new_allocated - 1; - for (uint32_t i = 0; i < table->allocated; ++i) - for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) - { - struct stringtable_entry *next = e->next; - uint32_t hash = fnv1a (e->string, e->length); - uint32_t new_index = hash & mask; - e->next = new_entries[new_index]; - new_entries[new_index] = e; - e = next; - } - - free (table->entries); - table->entries = new_entries; - table->allocated = new_allocated; -} - -struct stringtable_entry * -stringtable_add (struct stringtable *table, const char *string) -{ - /* Check for a zero-initialized table. */ - if (table->allocated == 0) - stringtable_init (table); - - size_t length = strlen (string); - if (length > (1U << 30)) - error (EXIT_FAILURE, 0, _("String table string is too long")); - uint32_t hash = fnv1a (string, length); - - /* Return a previously-existing entry. */ - for (struct stringtable_entry *e - = table->entries[hash & (table->allocated - 1)]; - e != NULL; e = e->next) - if (e->length == length && memcmp (e->string, string, length) == 0) - return e; - - /* Increase the size of the table if necessary. Keep utilization - below two thirds. */ - if (table->count >= (1U << 30)) - error (EXIT_FAILURE, 0, _("String table has too many entries")); - if (table->count * 3 > table->allocated * 2) - stringtable_rehash (table); - - /* Add the new table entry. */ - ++table->count; - struct stringtable_entry *e - = xmalloc (offsetof (struct stringtable_entry, string) + length + 1); - uint32_t index = hash & (table->allocated - 1); - e->next = table->entries[index]; - table->entries[index] = e; - e->length = length; - e->offset = 0; - memcpy (e->string, string, length + 1); - return e; -} - -/* Sort reversed strings in reverse lexicographic order. This is used - for tail merging. */ -static int -finalize_compare (const void *l, const void *r) -{ - struct stringtable_entry *left = *(struct stringtable_entry **) l; - struct stringtable_entry *right = *(struct stringtable_entry **) r; - size_t to_compare; - if (left->length < right->length) - to_compare = left->length; - else - to_compare = right->length; - for (size_t i = 1; i <= to_compare; ++i) - { - unsigned char lch = left->string[left->length - i]; - unsigned char rch = right->string[right->length - i]; - if (lch != rch) - return rch - lch; - } - if (left->length == right->length) - return 0; - else if (left->length < right->length) - /* Longer strings should come first. */ - return 1; - else - return -1; -} - -void -stringtable_finalize (struct stringtable *table, - struct stringtable_finalized *result) -{ - if (table->count == 0) - { - result->strings = xstrdup (""); - result->size = 0; - return; - } - - /* Optimize the order of the strings. */ - struct stringtable_entry **array = xcalloc (table->count, sizeof (*array)); - { - size_t j = 0; - for (uint32_t i = 0; i < table->allocated; ++i) - for (struct stringtable_entry *e = table->entries[i]; e != NULL; - e = e->next) - { - array[j] = e; - ++j; - } - assert (j == table->count); - } - qsort (array, table->count, sizeof (*array), finalize_compare); - - /* Assign offsets, using tail merging (sharing suffixes) if possible. */ - array[0]->offset = 0; - for (uint32_t j = 1; j < table->count; ++j) - { - struct stringtable_entry *previous = array[j - 1]; - struct stringtable_entry *current = array[j]; - if (previous->length >= current->length - && memcmp (&previous->string[previous->length - current->length], - current->string, current->length) == 0) - current->offset = (previous->offset + previous->length - - current->length); - else if (__builtin_add_overflow (previous->offset, - previous->length + 1, - ¤t->offset)) - error (EXIT_FAILURE, 0, _("String table is too large")); - } - - /* Allocate the result string. */ - { - struct stringtable_entry *last = array[table->count - 1]; - if (__builtin_add_overflow (last->offset, last->length + 1, - &result->size)) - error (EXIT_FAILURE, 0, _("String table is too large")); - } - /* The strings are copied from the hash table, so the array is no - longer needed. */ - free (array); - result->strings = xcalloc (result->size, 1); - - /* Copy the strings. */ - for (uint32_t i = 0; i < table->allocated; ++i) - for (struct stringtable_entry *e = table->entries[i]; e != NULL; - e = e->next) - if (result->strings[e->offset] == '\0') - memcpy (&result->strings[e->offset], e->string, e->length + 1); -} diff --git a/elf/tst-stringtable.c b/elf/tst-cachestrings.c similarity index 54% rename from elf/tst-stringtable.c rename to elf/tst-cachestrings.c index 1f0727f38f..88196618ce 100644 --- a/elf/tst-stringtable.c +++ b/elf/tst-cachestrings.c @@ -19,7 +19,8 @@ #include #if __GNUC_PREREQ (5, 0) #include -#include +#define attribute_hidden +#include #include #include @@ -28,72 +29,75 @@ do_test (void) { /* Empty string table. */ { - struct stringtable s = { 0, }; - struct stringtable_finalized f; - stringtable_finalize (&s, &f); + struct cachestrings s = { 0, }; + struct cachestrings_finalized f; + cachestrings_finalize (&s, &f); TEST_COMPARE_STRING (f.strings, ""); TEST_COMPARE (f.size, 0); free (f.strings); - stringtable_free (&s); + cachestrings_free (&s); } /* String table with one empty string. */ { - struct stringtable s = { 0, }; - struct stringtable_entry *e = stringtable_add (&s, ""); - TEST_COMPARE_STRING (e->string, ""); - TEST_COMPARE (e->length, 0); - TEST_COMPARE (s.count, 1); - - struct stringtable_finalized f; - stringtable_finalize (&s, &f); + struct cachestrings s = { 0, }; + struct cachestrings_entry *e = cachestrings_add (&s, ""); + TEST_COMPARE_STRING (e->E.string, ""); + TEST_COMPARE (e->E.length, 0); + TEST_COMPARE (e->offset, 0); + TEST_COMPARE (s.T.count, 1); + + struct cachestrings_finalized f; + cachestrings_finalize (&s, &f); TEST_COMPARE (e->offset, 0); TEST_COMPARE_STRING (f.strings, ""); TEST_COMPARE (f.size, 1); free (f.strings); - stringtable_free (&s); + cachestrings_free (&s); } /* String table with one non-empty string. */ { - struct stringtable s = { 0, }; - struct stringtable_entry *e = stringtable_add (&s, "name"); - TEST_COMPARE_STRING (e->string, "name"); - TEST_COMPARE (e->length, 4); - TEST_COMPARE (s.count, 1); - - struct stringtable_finalized f; - stringtable_finalize (&s, &f); + struct cachestrings s = { 0, }; + struct cachestrings_entry *e = cachestrings_add (&s, "name"); + TEST_COMPARE_STRING (e->E.string, "name"); + TEST_COMPARE (e->E.length, 4); + TEST_COMPARE (e->offset, 0); + TEST_COMPARE (s.T.count, 1); + + struct cachestrings_finalized f; + cachestrings_finalize (&s, &f); TEST_COMPARE (e->offset, 0); TEST_COMPARE_STRING (f.strings, "name"); TEST_COMPARE (f.size, 5); free (f.strings); - stringtable_free (&s); + cachestrings_free (&s); } /* Two strings, one is a prefix of the other. Tail-merging can only happen in one way in this case. */ { - struct stringtable s = { 0, }; - struct stringtable_entry *suffix = stringtable_add (&s, "suffix"); - TEST_COMPARE_STRING (suffix->string, "suffix"); - TEST_COMPARE (suffix->length, 6); - TEST_COMPARE (s.count, 1); - - struct stringtable_entry *prefix - = stringtable_add (&s, "prefix-suffix"); - TEST_COMPARE_STRING (prefix->string, "prefix-suffix"); - TEST_COMPARE (prefix->length, strlen ("prefix-suffix")); - TEST_COMPARE (s.count, 2); - - struct stringtable_finalized f; - stringtable_finalize (&s, &f); + struct cachestrings s = { 0, }; + struct cachestrings_entry *suffix + = cachestrings_add (&s, "suffix"); + TEST_COMPARE_STRING (suffix->E.string, "suffix"); + TEST_COMPARE (suffix->E.length, 6); + TEST_COMPARE (s.T.count, 1); + + struct cachestrings_entry *prefix + = cachestrings_add (&s, "prefix-suffix"); + TEST_COMPARE_STRING (prefix->E.string, "prefix-suffix"); + TEST_COMPARE (prefix->E.length, strlen ("prefix-suffix")); + TEST_COMPARE (s.T.count, 2); + + struct cachestrings_finalized f; + cachestrings_finalize (&s, &f); TEST_COMPARE (prefix->offset, 0); TEST_COMPARE (suffix->offset, strlen ("prefix-")); TEST_COMPARE_STRING (f.strings, "prefix-suffix"); TEST_COMPARE (f.size, sizeof ("prefix-suffix")); free (f.strings); - stringtable_free (&s); + cachestrings_free (&s); } /* String table with various shared prefixes. Triggers hash @@ -101,38 +105,40 @@ do_test (void) { enum { count = 1500 }; char *strings[2 * count]; - struct stringtable_entry *entries[2 * count]; - struct stringtable s = { 0, }; + struct cachestrings_entry *entries[2 * count]; + struct cachestrings s = { 0, }; for (int i = 0; i < count; ++i) { strings[i] = xasprintf ("%d", i); - entries[i] = stringtable_add (&s, strings[i]); - TEST_COMPARE (entries[i]->length, strlen (strings[i])); - TEST_COMPARE_STRING (entries[i]->string, strings[i]); + entries[i] = cachestrings_add (&s, strings[i]); + TEST_COMPARE (entries[i]->E.length, strlen (strings[i])); + TEST_COMPARE_STRING (entries[i]->E.string, strings[i]); strings[i + count] = xasprintf ("prefix/%d", i); - entries[i + count] = stringtable_add (&s, strings[i + count]); - TEST_COMPARE (entries[i + count]->length, strlen (strings[i + count])); - TEST_COMPARE_STRING (entries[i + count]->string, strings[i + count]); + entries[i + count] = cachestrings_add (&s, strings[i + count]); + TEST_COMPARE (entries[i + count]->E.length, + strlen (strings[i + count])); + TEST_COMPARE_STRING (entries[i + count]->E.string, + strings[i + count]); } - struct stringtable_finalized f; - stringtable_finalize (&s, &f); + struct cachestrings_finalized f; + cachestrings_finalize (&s, &f); for (int i = 0; i < 2 * count; ++i) { - TEST_COMPARE (entries[i]->length, strlen (strings[i])); - TEST_COMPARE_STRING (entries[i]->string, strings[i]); + TEST_COMPARE (entries[i]->E.length, strlen (strings[i])); + TEST_COMPARE_STRING (entries[i]->E.string, strings[i]); TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]); free (strings[i]); } free (f.strings); - stringtable_free (&s); + cachestrings_free (&s); } /* Verify that maximum tail merging happens. */ { - struct stringtable s = { 0, }; + struct cachestrings s = { 0, }; const char *strings[] = { "", "a", @@ -146,14 +152,14 @@ do_test (void) "ba", "baa", }; - struct stringtable_entry *entries[array_length (strings)]; + struct cachestrings_entry *entries[array_length (strings)]; for (int i = 0; i < array_length (strings); ++i) - entries[i] = stringtable_add (&s, strings[i]); + entries[i] = cachestrings_add (&s, strings[i]); for (int i = 0; i < array_length (strings); ++i) - TEST_COMPARE_STRING (entries[i]->string, strings[i]); + TEST_COMPARE_STRING (entries[i]->E.string, strings[i]); - struct stringtable_finalized f; - stringtable_finalize (&s, &f); + struct cachestrings_finalized f; + cachestrings_finalize (&s, &f); /* There are only four different strings, "aaa", "ba", "baa", "bb". The rest is shared in an unspecified fashion. */ @@ -161,12 +167,12 @@ do_test (void) for (int i = 0; i < array_length (strings); ++i) { - TEST_COMPARE_STRING (entries[i]->string, strings[i]); + TEST_COMPARE_STRING (entries[i]->E.string, strings[i]); TEST_COMPARE_STRING (f.strings + entries[i]->offset, strings[i]); } free (f.strings); - stringtable_free (&s); + cachestrings_free (&s); } return 0; @@ -178,8 +184,8 @@ do_test (void) possible to link against the actual build because it was built for use in ldconfig. */ #define _(arg) arg -#include "stringtable.c" -#include "stringtable_free.c" +#define __set_errno(code) (void) (errno = (code)) +#include "cachestrings.c" #else #include diff --git a/include/stringtable-skeleton.h b/include/stringtable-skeleton.h new file mode 100644 index 0000000000..041cf8e3aa --- /dev/null +++ b/include/stringtable-skeleton.h @@ -0,0 +1,129 @@ +/* Template for defining string tables. + Copyright (C) 2020-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* To use the stringtable facility, you need to include + and define the parameter macros. + + The tables are intrusive: you need to define your own types, + embedding struct stringtable_entry and struct stringtable. + + A minimal example looks like this: + + #include + + struct table_entry + { + struct stringtable_entry E; + }; + + struct table + { + struct stringtable T; + }; + + #define STRINGTABLE_ENTRY table_entry + #define STRINGTABLE_STRUCT table + #define STRINGTABLE_PREFIX table_ + #include + + The struct STRINGTABLE_ENTRY type must have a + + struct stringtable_entry E; + + member at the end. + + The struct STRINGTABLE_STRUCT type must have a + + struct stringtable T; + + member (not necessarily at the end). The T member must be + zero-initialized before the functions described below are called. + + Including defines the following functions: + + STRINGTABLE_ENTRY * + STRINGTABLE_PREFIX_add (struct STRINGTABLE_STRUCT *table, + const char *string); + + Add STRING to TABLE. Returns NULL on memory allocation failure. + + void STRINGTABLE_PREFIX_free (struct STRINGTABLE_STRUCT *table); + + Deallocate TABLE and all its entries. + + void STRINGTABLE_PREFIX_foreach (struct STRINGTABLE_STRUCT *table, + void (*cb) (struct STRINGTABLE_ENTRY *, + void *), + void *closure); + + Iterate over all entries in TABLE, calling CB for each entry + with CLOSURE as the second argument. +*/ + +#include +#include +#include + +#define STRINGTABLE_ENTRY_OFFSET (offsetof (struct STRINGTABLE_ENTRY, E)) + +_Static_assert (STRINGTABLE_ENTRY_OFFSET + sizeof (struct stringtable_entry) + == sizeof (struct STRINGTABLE_ENTRY), + "entry member must come last"); + +#define STRINGTABLE_CONCAT0(prefix, name) prefix##name +#define STRINGTABLE_CONCAT1(prefix, name) STRINGTABLE_CONCAT0(prefix, name) +#define STRINGTABLE_NAME(name) STRINGTABLE_CONCAT1(STRINGTABLE_PREFIX, name) + + +__attribute__ ((unused)) static struct STRINGTABLE_ENTRY * +STRINGTABLE_NAME(add) (struct STRINGTABLE_STRUCT *table, + const char *string) +{ + return __stringtable_add (&table->T, string, STRINGTABLE_ENTRY_OFFSET); +} + +__attribute__ ((unused)) static void +STRINGTABLE_NAME(free) (struct STRINGTABLE_STRUCT *table) +{ + __stringtable_free (&table->T, STRINGTABLE_ENTRY_OFFSET); +} + +static inline void +STRINGTABLE_NAME(foreach) (struct STRINGTABLE_STRUCT *table, + void (*callback) (struct STRINGTABLE_ENTRY *, + void *), + void *closure) +{ + struct stringtable_entry **p = table->T.entries; + if (p == NULL) + return; + struct stringtable_entry **end = p + table->T.allocated; + for (; p != end; ++p) + for (struct stringtable_entry *e = *p; e != NULL; e = e->next) + callback ((struct STRINGTABLE_ENTRY *) ((char *) e - + STRINGTABLE_ENTRY_OFFSET), + closure); +} + +#undef STRINGTABLE_CONCAT0 +#undef STRINGTABLE_CONCAT1 +#undef STRINGTABLE_NAME +#undef STRINGTABLE_ENTRY_OFFSET +#undef STRINGTABLE_ENTRY +#undef STRINGTABLE_STRUCT +#undef STRINGTABLE_PREFIX diff --git a/include/stringtable.h b/include/stringtable.h new file mode 100644 index 0000000000..e0933289e6 --- /dev/null +++ b/include/stringtable.h @@ -0,0 +1,55 @@ +/* Support facilities for string tables. + Copyright (C) 2020-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* See for a way to use this file. */ + +#ifndef STRINGTABLE_H +#define STRINGTABLE_H + +#include +#include + +/* Common part of hash table entries. Used for the E member. */ +struct stringtable_entry +{ + struct stringtable_entry *next; /* For collision resolution. */ + uint32_t length; /* Length of the string. */ + char string[]; /* Null-terminated string. */ +}; + +/* Common fields of a string table. Used for the T member. + Zero-initialization produces a valid table. */ +struct stringtable +{ + struct stringtable_entry **entries; /* Array of hash table buckets. */ + uint32_t count; /* Number of elements in the table. */ + uint32_t allocated; /* Length of the entries array. */ +}; + +/* 32-bit FNV-1a hash function. */ +uint32_t __fnv1a (const char *string, size_t length) attribute_hidden; + +/* Internal functions. ENTRY_OFFSET is the offset of the + stringtable_entry structs from the start of the malloc + allocation. */ +void *__stringtable_add (struct stringtable *, const char *, + size_t entry_offset) attribute_hidden; +void __stringtable_free (struct stringtable *, size_t entry_offset) + attribute_hidden; + +#endif /* STRINGTABLE_H */ diff --git a/misc/Makefile b/misc/Makefile index fc44de9934..856cf38ae7 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -99,6 +99,7 @@ routines := \ fdatasync \ fgetxattr \ flistxattr \ + fnv1a \ fremovexattr \ fsetxattr \ fstab \ @@ -187,6 +188,8 @@ routines := \ setxattr \ single_threaded \ sstk \ + stringtable_add \ + stringtable_free \ stty \ swapoff \ swapon \ diff --git a/misc/fnv1a.c b/misc/fnv1a.c new file mode 100644 index 0000000000..bc091f6515 --- /dev/null +++ b/misc/fnv1a.c @@ -0,0 +1,32 @@ +/* Simple hash function, used in string tables. + Copyright (C) 2020-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +uint32_t +__fnv1a (const char *string, size_t length) +{ + const unsigned char *p = (const unsigned char *) string; + uint32_t hash = 2166136261U; + for (size_t i = 0; i < length; ++i) + { + hash ^= p[i]; + hash *= 16777619U; + } + return hash; +} diff --git a/misc/stringtable_add.c b/misc/stringtable_add.c new file mode 100644 index 0000000000..c39a699270 --- /dev/null +++ b/misc/stringtable_add.c @@ -0,0 +1,128 @@ +/* Generic implementation for adding strings to string tables. + Copyright (C) 2020-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +static bool +__stringtable_init (struct stringtable *table) +{ + table->count = 0; + + /* This needs to be a power of two. */ + table->allocated = 16; + + table->entries = calloc (table->allocated, sizeof (table->entries[0])); + return table->entries != NULL; +} + +/* Double the capacity of the hash table. */ +static bool +__stringtable_rehash (struct stringtable *table) +{ + uint32_t new_allocated = table->allocated * 2; + if (new_allocated < table->allocated) + { + __set_errno (ENOMEM); + return false; + } + + struct stringtable_entry **new_entries + = calloc (new_allocated, sizeof (table->entries[0])); + if (new_entries == NULL) + return false; + + uint32_t mask = new_allocated - 1; + for (uint32_t i = 0; i < table->allocated; ++i) + for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) + { + struct stringtable_entry *next = e->next; + uint32_t hash = __fnv1a (e->string, e->length); + uint32_t new_index = hash & mask; + e->next = new_entries[new_index]; + new_entries[new_index] = e; + e = next; + } + + free (table->entries); + table->entries = new_entries; + table->allocated = new_allocated; + return true; +} + +void * +__stringtable_add (struct stringtable *table, const char *string, + size_t entry_offset) +{ + /* Check for a zero-initialized table. */ + if (table->allocated == 0 && !__stringtable_init (table)) + return NULL; + + size_t length = strlen (string); + if (length != (uint32_t) length) + { + /* String is too long to store. */ + __set_errno (ENOMEM); + return NULL; + } + + uint32_t hash = __fnv1a (string, length); + + /* Return a previously-existing entry. */ + for (struct stringtable_entry *e + = table->entries[hash & (table->allocated - 1)]; + e != NULL; e = e->next) + if (e->length == length && memcmp (e->string, string, length) == 0) + return (char *) e - entry_offset; + + /* Increase the size of the table if necessary. Keep utilization + below two thirds. */ + if (table->count >= UINT32_MAX / 3) + { + __set_errno (ENOMEM); + return NULL; + } + if (table->count * 3 > table->allocated * 2) + if (!__stringtable_rehash (table)) + return NULL; + + /* Add the new table entry. No overflow is possible because length + must be less than half of the address space size. */ + char *base = malloc (entry_offset + + offsetof (struct stringtable_entry, string) + + length + 1); + if (base == NULL) + return NULL; + /* Extra data is zero-initialized. */ + memset (base, 0, entry_offset); + + struct stringtable_entry *e + = (struct stringtable_entry *) (base + entry_offset); + e->length = length; + memcpy (e->string, string, length + 1); + + ++table->count; + uint32_t index = hash & (table->allocated - 1); + e->next = table->entries[index]; + table->entries[index] = e; + return (char *) e - entry_offset; +} diff --git a/misc/stringtable_free.c b/misc/stringtable_free.c new file mode 100644 index 0000000000..00e477f340 --- /dev/null +++ b/misc/stringtable_free.c @@ -0,0 +1,44 @@ +/* Generic implementation for freeing string tables. + Copyright (C) 2020-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include + +void +__stringtable_free (struct stringtable *table, + size_t entry_offset) +{ + size_t allocated = table->allocated; + for (size_t i = 0; i < allocated; ++i) + { + struct stringtable_entry *e = table->entries[i]; + while (e != NULL) + { + struct stringtable_entry *next = e->next; + /* The allocated pointer is at an offset before the entry. */ + free ((char *) e - entry_offset); + e = next; + } + } + free (table->entries); + table->entries = NULL; + table->allocated = 0; + table->count = 0; +} diff --git a/support/Makefile b/support/Makefile index 1dae2802cf..2d10be3166 100644 --- a/support/Makefile +++ b/support/Makefile @@ -114,6 +114,7 @@ libsupport-routines = \ support_spawn_wrap \ support_stack_alloc \ support_stat_nanoseconds \ + support_stringtable \ support_subprocess \ support_test_compare_blob \ support_test_compare_failure \ diff --git a/elf/stringtable_free.c b/support/support_stringtable.c similarity index 56% rename from elf/stringtable_free.c rename to support/support_stringtable.c index 6ac73f6a8a..b809516fa9 100644 --- a/elf/stringtable_free.c +++ b/support/support_stringtable.c @@ -1,5 +1,5 @@ -/* String tables for ld.so.cache construction. Deallocation (for tests only). - Copyright (C) 2020-2026 Free Software Foundation, Inc. +/* Separate build of stringtables for use in tests. + Copyright (C) 2026 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 @@ -15,19 +15,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, see . */ -#include -#include - -void -stringtable_free (struct stringtable *table) -{ - for (uint32_t i = 0; i < table->allocated; ++i) - for (struct stringtable_entry *e = table->entries[i]; e != NULL; ) - { - struct stringtable_entry *next = e->next; - free (e); - e = next; - } - free (table->entries); - *table = (struct stringtable) { 0, }; -} +#include +#include +#include From patchwork Fri Mar 20 20:43:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132120 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 94A574AB0FBC for ; Fri, 20 Mar 2026 20:52:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 94A574AB0FBC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=fL61vG/B 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 ESMTP id 908F54C515F4 for ; Fri, 20 Mar 2026 20:43:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 908F54C515F4 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 908F54C515F4 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=1774039388; cv=none; b=H9FkabDzImzQsOxjkfjgBzaMb4WkmJDlVUKLCngJPpy0qN9A+3Y0/FLQ6QLYiBejdYoaFB7xnXx+RHoB2mUPy9kytVgkxYdHvwf4JIVTP3aj2RPOuO8Hsbj5ELF459U0ymKX1Djt+1JCC/ytO9kOA2OwI+GokT5CuiZIJAj48kU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039388; c=relaxed/simple; bh=ypsTDXa/rgfrarGbWGel82OHkQuE/fpbhkELxhOS4wg=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=xx6w+f9I3AHDLY1y/4RLKbOBdu7uVEnupEAV9mZ94y3RalxpgVhrUtVpHvcyonUww0TU7oxZcreYXi62sMelHs2hYi/5PeWX+3meMxLMMcM6pitC+NnNB39NF56D8WVBaVpIJdKF4J1wOeIuPS+zJK2RqtDeRfD0HiuzeE2JiXQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 908F54C515F4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039388; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Z6mYcQWI9v8e9EMWxx5odeHummT1yc2Wixp7h7O5LPQ=; b=fL61vG/BAmUdKg03D0JSElo3IyV+4auXen+iUlydl5g0pkBFOkF4b3z6bfvD0QB2ivnksT dEsTGJd38cY4OdAc5jFf7hYFnj2cg6zWwYw7W2w3dVSmvMZYACALxBtAd4VZvz1z3sC2tF N4w+qbfJWEaJPYSIL/V7QhzZwmZl99s= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-668-s02eJmWsNQqgo2P1_Fo8Zw-1; Fri, 20 Mar 2026 16:43:06 -0400 X-MC-Unique: s02eJmWsNQqgo2P1_Fo8Zw-1 X-Mimecast-MFC-AGG-ID: s02eJmWsNQqgo2P1_Fo8Zw_1774039386 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 20DF11944F05 for ; Fri, 20 Mar 2026 20:43:06 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 52A331953944 for ; Fri, 20 Mar 2026 20:43:05 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 19/23] nss: Low-level functionality for merging group lists In-Reply-To: Message-ID: <0fe187adee88605e0796966e9ef9b898a34d94f3.1774037705.git.fweimer@redhat.com> References: X-From-Line: 0fe187adee88605e0796966e9ef9b898a34d94f3 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:43:02 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ecMlNWrjA5swuFmMaKd6e93eKyjGdU9hIWYFOZpDycQ_1774039386 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Use to deduplicate members, with a single-linked list to preserve ordering. --- nss/Makefile | 2 + nss/nss_group_members.c | 80 +++++++++++++++++++++++++++++++++++++ nss/nss_group_members.h | 61 ++++++++++++++++++++++++++++ nss/tst-nss_group_members.c | 77 +++++++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 nss/nss_group_members.c create mode 100644 nss/nss_group_members.h create mode 100644 nss/tst-nss_group_members.c diff --git a/nss/Makefile b/nss/Makefile index ec68954f3b..82f5a5d68f 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -89,6 +89,7 @@ routines += \ getgrnam_r \ grp-merge \ initgroups \ + nss_group_members \ putgrent \ # routines @@ -315,6 +316,7 @@ tests-internal := \ tst-field \ tst-nss_generic_copy \ tst-nss_generic_dup \ + tst-nss_group_members \ tst-rfc3484 \ tst-rfc3484-2 \ tst-rfc3484-3 \ diff --git a/nss/nss_group_members.c b/nss/nss_group_members.c new file mode 100644 index 0000000000..aafbc8e65b --- /dev/null +++ b/nss/nss_group_members.c @@ -0,0 +1,80 @@ +/* Support for merging group member lists. Implementation. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void +__nss_group_members_init (struct nss_group_members *table) +{ + *table = (struct nss_group_members) + { + .tail = &table->head, + }; +} + +void +__nss_group_members_free (struct nss_group_members *table) +{ + __nss_group_members__free (table); + __nss_group_members_init (table); +} + +bool +__nss_group_members_add (struct nss_group_members *table, + const struct group *grp) +{ + if (grp->gr_mem == NULL) + return true; + for (char **p = grp->gr_mem; *p != NULL; ++p) + { + struct nss_group_members_entry *e = __nss_group_members__add (table, *p); + if (e == NULL) + return false; + /* If the element is freshly inserted, e->order is NULL. + However, e->order may be NULL if e is not freshly inserted + and e is the last element in the ordering chain, which has no + successor. */ + if (e->order == NULL && &e->order != table->tail) + { + *table->tail = e; + table->tail = &e->order; + } + } + return true; +} + +char ** +__nss_group_members (const struct nss_group_members *table) +{ + char **list = malloc ((table->T.count + 1) * sizeof (*list)); + if (list == NULL) + return NULL; + + size_t i = 0; + for (struct nss_group_members_entry *p = table->head; p != NULL; + p = p->order, ++i) + list[i] = p->E.string; + assert (i == table->T.count); + list[i] = NULL; + + return list; +} diff --git a/nss/nss_group_members.h b/nss/nss_group_members.h new file mode 100644 index 0000000000..19bfccfc31 --- /dev/null +++ b/nss/nss_group_members.h @@ -0,0 +1,61 @@ +/* Support for merging group member lists. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef NSS_GROUP_MEMBERS_H +#define NSS_GROUP_MEMBERS_H + +#include +#include + +struct nss_group_members_entry +{ + struct nss_group_members_entry *order; + struct stringtable_entry E; +}; + +struct nss_group_members +{ + struct stringtable T; + struct nss_group_members_entry *head; + struct nss_group_members_entry **tail; +}; + +#define STRINGTABLE_ENTRY nss_group_members_entry +#define STRINGTABLE_STRUCT nss_group_members +#define STRINGTABLE_PREFIX __nss_group_members__ +#include + +/* Initialize a group members table. */ +void __nss_group_members_init (struct nss_group_members *) attribute_hidden; + +/* Deallocate a group members table. The table is initialized afterwards. */ +void __nss_group_members_free (struct nss_group_members *) attribute_hidden; + +/* Add the members from GRP to TABLE. Returns true on success, false + on memory allocation failure. */ +struct group; +bool __nss_group_members_add (struct nss_group_members *table, + const struct group *grp) attribute_hidden; + +/* Return a NULL-terminated array of strings, in the order they have + been added to the table. The strings point into the table. The + returned pointer should be passed to free. Return NULL on memory + allocation failure. */ +char **__nss_group_members (const struct nss_group_members *) attribute_hidden; + +#endif /* NSS_GROUP_MEMBERS_H */ diff --git a/nss/tst-nss_group_members.c b/nss/tst-nss_group_members.c new file mode 100644 index 0000000000..43f26ff27b --- /dev/null +++ b/nss/tst-nss_group_members.c @@ -0,0 +1,77 @@ +/* Test infrastructure for merging group member lists. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + struct nss_group_members t; + __nss_group_members_init (&t); + + for (unsigned int count = 0; count < 100; ++count) + { + struct group grp = { }; + grp.gr_mem = xcalloc (count + 1, sizeof (*grp.gr_mem)); + for (unsigned int i = 0; i < count; ++i) + grp.gr_mem[i] = xasprintf ("user%d", i); + + /* This contains the expected list for the result. */ + struct group *grp_copy = __nss_generic_dup (nss_lookup_getgrgid, &grp); + + TEST_VERIFY (__nss_group_members_add (&t, &grp)); + + for (unsigned int i = 0; i < count; ++i) + free (grp.gr_mem[i]); + + /* Add some duplicates in a random-looking order. */ + for (unsigned int i = 0; i < count / 2; ++i) + grp.gr_mem[i] = xasprintf ("user%d", (i * 0x9e3779b9) % count); + grp.gr_mem[count / 2] = NULL; + + /* Merge. */ + TEST_VERIFY (__nss_group_members_add (&t, &grp)); + + for (unsigned int i = 0; i < count / 2; ++i) + free (grp.gr_mem[i]); + free (grp.gr_mem); + + /* Compare the results. */ + char **list = __nss_group_members (&t); + for (unsigned int i = 0; i <= count; ++i) + TEST_COMPARE_STRING (list[i], grp_copy->gr_mem[i]); + + free (list); + __nss_group_members_free (&t); + free (grp_copy); + } + + return 0; +} + +#include + +/* Re-compile the support code because it is not exported from libc. */ +#include +#include +#include From patchwork Fri Mar 20 20:43:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132127 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 2852A4B1A2EC for ; Fri, 20 Mar 2026 21:01:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2852A4B1A2EC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=JCjxDdqj 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 ESMTP id 7C3544C31829 for ; Fri, 20 Mar 2026 20:43:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7C3544C31829 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 7C3544C31829 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=1774039393; cv=none; b=mvdDcO+9uYLdu7a1EjgOt0puWguscJvpyHiklmSHtvC3h9/bASy0xzAJ3VDPczO/hOfiOmFFf/nZh+O756VaNU0TQrMNk+BOtmlZKTvuG5NHecgb/s0ZLsTjF9xL4DvVQ62krguzcrPJcqENhiRqOwzHGWaHIiQWLlCyHl4jRMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039393; c=relaxed/simple; bh=Zq/PD37SKiCZBfotkJZVIsk2wMBBO/c2Db5C3vVq8PQ=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=itCk1rVhLPKX2nGcWe7o+6IVZTO2trcIpZnXu0ojRahykozp2W4BEuFFODsCmb9mzuN0Ao9tDaljzOqrfmy5gw4u83d/pX9i67cuMX2Im2qYPlfDxEhZSMNBwdZAuX91bWU6NH9lExAjKcKRQHo4oLPCGjKEOyPGF7qNf6KOdOg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7C3544C31829 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039393; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=+7CjCAy3Z/1WLdlHPDgvu+UIocawe3gv6YKQ52MZPxA=; b=JCjxDdqjfGc8NC2OZ41ltDKfw7wPoSBG/cZosQJDBlvtgnPanoK1usbfjqR9n/8ExH4wxX tt+d1G6nLl4u4nbT6WRSqY+PMxCkDE6iaVTEXq8D4k0fb/8za9ofOtOyPvTx3cOP8NAQjS L3bKfMeizmJ8ja56CsWSJEq/X8iomLs= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-298-igqAylliOaqtc8cVoLwGWg-1; Fri, 20 Mar 2026 16:43:11 -0400 X-MC-Unique: igqAylliOaqtc8cVoLwGWg-1 X-Mimecast-MFC-AGG-ID: igqAylliOaqtc8cVoLwGWg_1774039391 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F0AA6180035C for ; Fri, 20 Mar 2026 20:43:10 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0FC601955F21 for ; Fri, 20 Mar 2026 20:43:09 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 20/23] nss: Convert passwd database to new NSS framework In-Reply-To: Message-ID: <162212a5d39eff5a369280ec19116f6abeac0c37.1774037705.git.fweimer@redhat.com> References: X-From-Line: 162212a5d39eff5a369280ec19116f6abeac0c37 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:43:07 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: GWmpp8rDWKeFArjnjKomOw5tajxaFMfNbeqcGFNS8oE_1774039391 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This framework moves the ERANGE down a couple of layers. The intent is to migrate to an interface eventually where NSS service modules allocate data for the response size they need. The need for the function-specific GLIBC_2.1.2 versioned symbol is rather unfortunate. With out the existing preprocessor approach in nss/getXXbyYY_r.c, this adds a lot of duplicated code. A future version could use compile-time code generation (outside of the preprocessor) to generate the _r function wrappers and the code for the compatibility code. The advantage over the preprocessor approach is that the resulting code will still be straightforward to debug because line-based breakpoints work exactly as expected. --- include/set-freeres.h | 4 +-- malloc/set-freeres.c | 7 +--- nscd/nscd_proto.h | 2 ++ nss/Makefile | 7 ++++ nss/getpwnam.c | 14 ++++---- nss/getpwnam_r.c | 33 +++++++++++++++---- nss/getpwuid.c | 14 ++++---- nss/getpwuid_r.c | 33 +++++++++++++++---- nss/nss_generic.h | 63 ++++++++++++++++++++++++++++++++++++ nss/nss_generic_get.c | 61 +++++++++++++++++++++++++++++++++++ nss/nss_generic_get_r.c | 45 ++++++++++++++++++++++++++ nss/nss_generic_lookup.c | 51 +++++++++++++++++++++++++++++ nss/nss_generic_next.c | 60 +++++++++++++++++++++++++++++++++++ nss/nss_generic_storage.h | 30 ++++++++++++++++++ nss/nss_getX.c | 53 +++++++++++++++++++++++++++++++ nss/nss_getX_r.c | 45 ++++++++++++++++++++++++++ nss/nss_getXinfo.c | 67 +++++++++++++++++++++++++++++++++++++++ 17 files changed, 551 insertions(+), 38 deletions(-) create mode 100644 nss/nss_generic_get.c create mode 100644 nss/nss_generic_get_r.c create mode 100644 nss/nss_generic_lookup.c create mode 100644 nss/nss_generic_next.c create mode 100644 nss/nss_generic_storage.h create mode 100644 nss/nss_getX.c create mode 100644 nss/nss_getX_r.c create mode 100644 nss/nss_getXinfo.c diff --git a/include/set-freeres.h b/include/set-freeres.h index 55093aa89d..c9d2c8ae55 100644 --- a/include/set-freeres.h +++ b/include/set-freeres.h @@ -68,6 +68,8 @@ extern void __nss_module_freeres (void) attribute_hidden; extern void __nss_action_freeres (void) attribute_hidden; /* From nss/nss_database.c */ extern void __nss_database_freeres (void) attribute_hidden; +/* From nss/nss-generic.h. */ +void __nss_generic_freeres (void) attribute_hidden; /* From libio/genops.c */ extern int _IO_cleanup (void) attribute_hidden;; /* From dlfcn/dlerror.c */ @@ -102,8 +104,6 @@ extern printf_va_arg_function ** __libc_reg_type_freemem_ptr /* From nss/getXXbyYY.c */ extern char * __libc_getgrgid_freemem_ptr attribute_hidden; extern char * __libc_getgrnam_freemem_ptr attribute_hidden; -extern char * __libc_getpwnam_freemem_ptr attribute_hidden; -extern char * __libc_getpwuid_freemem_ptr attribute_hidden; extern char * __libc_getspnam_freemem_ptr attribute_hidden; extern char * __libc_getaliasbyname_freemem_ptr attribute_hidden; extern char * __libc_gethostbyaddr_freemem_ptr attribute_hidden; diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c index 39fd7d4d27..8112a2f664 100644 --- a/malloc/set-freeres.c +++ b/malloc/set-freeres.c @@ -74,8 +74,6 @@ # pragma weak __libc_reg_type_freemem_ptr # pragma weak __libc_getgrgid_freemem_ptr # pragma weak __libc_getgrnam_freemem_ptr -# pragma weak __libc_getpwnam_freemem_ptr -# pragma weak __libc_getpwuid_freemem_ptr # pragma weak __libc_getspnam_freemem_ptr # pragma weak __libc_getaliasbyname_freemem_ptr # pragma weak __libc_gethostbyaddr_freemem_ptr @@ -124,6 +122,7 @@ __libc_freeres (void) call_function_static_weak (__nss_module_freeres); call_function_static_weak (__nss_action_freeres); call_function_static_weak (__nss_database_freeres); + call_function_static_weak (__nss_generic_freeres); _IO_cleanup (); @@ -188,10 +187,6 @@ __libc_freeres (void) call_free_static_weak (__libc_reg_printf_freemem_ptr); call_free_static_weak (__libc_reg_type_freemem_ptr); - call_free_static_weak (__libc_getgrgid_freemem_ptr); - call_free_static_weak (__libc_getgrnam_freemem_ptr); - call_free_static_weak (__libc_getpwnam_freemem_ptr); - call_free_static_weak (__libc_getpwuid_freemem_ptr); call_free_static_weak (__libc_getspnam_freemem_ptr); call_free_static_weak (__libc_getaliasbyname_freemem_ptr); call_free_static_weak (__libc_gethostbyaddr_freemem_ptr); diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h index 6c4a318bc0..da3156b0ff 100644 --- a/nscd/nscd_proto.h +++ b/nscd/nscd_proto.h @@ -42,9 +42,11 @@ void __nscd_disable_database (unsigned int db) attribute_hidden; extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result) attribute_hidden; +int __nscd_getpwnam (const char *name, struct passwd **) attribute_hidden; extern int __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer, size_t buflen, struct passwd **result) attribute_hidden; +int __nscd_getpwuid (uid_t uid, struct passwd **result) attribute_hidden; extern int __nscd_getgrnam_r (const char *name, struct group *resultbuf, char *buffer, size_t buflen, struct group **result) attribute_hidden; diff --git a/nss/Makefile b/nss/Makefile index 82f5a5d68f..a13f6fa10c 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -47,7 +47,14 @@ routines = \ nss_files_functions \ nss_generic_copy \ nss_generic_dup \ + nss_generic_get \ + nss_generic_get_r \ + nss_generic_lookup \ + nss_generic_next \ nss_generic_nscd \ + nss_getX \ + nss_getX_r \ + nss_getXinfo \ nss_hash \ nss_module \ nss_parse_line_result \ diff --git a/nss/getpwnam.c b/nss/getpwnam.c index 36d5a43fd6..55578f7fc0 100644 --- a/nss/getpwnam.c +++ b/nss/getpwnam.c @@ -17,12 +17,10 @@ #include +#include -#define LOOKUP_TYPE struct passwd -#define FUNCTION_NAME getpwnam -#define DATABASE_NAME passwd -#define ADD_PARAMS const char *name -#define ADD_VARIABLES name -#define BUFLEN NSS_BUFLEN_PASSWD - -#include "../nss/getXXbyYY.c" +struct passwd * +getpwnam (const char *name) +{ + return __nss_getX (nss_lookup_getpwnam, name); +} diff --git a/nss/getpwnam_r.c b/nss/getpwnam_r.c index 1ba6ba53c9..2bb0bfa5e1 100644 --- a/nss/getpwnam_r.c +++ b/nss/getpwnam_r.c @@ -17,12 +17,31 @@ #include +#include +#include -#define LOOKUP_TYPE struct passwd -#define FUNCTION_NAME getpwnam -#define DATABASE_NAME passwd -#define ADD_PARAMS const char *name -#define ADD_VARIABLES name -#define BUFLEN NSS_BUFLEN_PASSWD +int +___getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t length, struct passwd **result) +{ + void *ptr = pwd; + int ret = __nss_getX_r (nss_lookup_getpwnam, name, &ptr, buffer, length); + *result = ptr; + return ret; +} +strong_alias (___getpwnam_r, __getpwnam_r) +versioned_symbol (libc, ___getpwnam_r, getpwnam_r, GLIBC_2_1_2); -#include +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2) +int +attribute_compat_text_section +__old_getpwnam_r (const char *name, struct passwd *pwd, + char *buffer, size_t length, struct passwd **result) +{ + int ret = __getpwnam_r (name, pwd, buffer, length, result); + if (ret != 0 || result == NULL) + ret = -1; + return ret; +} +compat_symbol (libc, __old_getpwnam_r, getpwnam_r, GLIBC_2_0); +#endif diff --git a/nss/getpwuid.c b/nss/getpwuid.c index 9002dbbc34..96cccdcd89 100644 --- a/nss/getpwuid.c +++ b/nss/getpwuid.c @@ -17,12 +17,10 @@ #include +#include -#define LOOKUP_TYPE struct passwd -#define FUNCTION_NAME getpwuid -#define DATABASE_NAME passwd -#define ADD_PARAMS uid_t uid -#define ADD_VARIABLES uid -#define BUFLEN NSS_BUFLEN_PASSWD - -#include "../nss/getXXbyYY.c" +struct passwd * +getpwuid (uid_t uid) +{ + return __nss_getX (nss_lookup_getpwuid, &uid); +} diff --git a/nss/getpwuid_r.c b/nss/getpwuid_r.c index 7c6f3970fa..d99846bb57 100644 --- a/nss/getpwuid_r.c +++ b/nss/getpwuid_r.c @@ -17,12 +17,31 @@ #include +#include +#include -#define LOOKUP_TYPE struct passwd -#define FUNCTION_NAME getpwuid -#define DATABASE_NAME passwd -#define ADD_PARAMS uid_t uid -#define ADD_VARIABLES uid -#define BUFLEN NSS_BUFLEN_PASSWD +int +___getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t length, struct passwd **result) +{ + void *ptr = pwd; + int ret = __nss_getX_r (nss_lookup_getpwuid, &uid, &ptr, buffer, length); + *result = ptr; + return ret; +} +strong_alias (___getpwuid_r, __getpwuid_r) +versioned_symbol (libc, ___getpwuid_r, getpwuid_r, GLIBC_2_1_2); -#include +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2) +int +attribute_compat_text_section +__old_getpwuid_r (uid_t uid, struct passwd *pwd, + char *buffer, size_t length, struct passwd **result) +{ + int ret = __getpwuid_r (uid, pwd, buffer, length, result); + if (ret != 0 || result == NULL) + ret = -1; + return ret; +} +compat_symbol (libc, __old_getpwuid_r, getpwuid_r, GLIBC_2_0); +#endif diff --git a/nss/nss_generic.h b/nss/nss_generic.h index 8a5b2cb896..107ebb2003 100644 --- a/nss/nss_generic.h +++ b/nss/nss_generic.h @@ -80,4 +80,67 @@ typedef const void *nss_lookup_key; bool __nscd_generic_get (enum nss_lookup_type lt, nss_lookup_key key, void **result); +/* Invokes the NSS module function SERVICE_FUNCTION of type LT using + KEY. The caller must initialize *RESULT to point to storage of + the appropriate NSS struct for LT. Upon return, the function + may write NULL to *RESULT and return with an error + (including triggering the ERANGE protocol), or leave *RESULT + unchanged and fill the struct with data, potentially using + LENGTH bytes at BUFFER for additional storage. */ +enum nss_status __nss_generic_get_r (enum nss_lookup_type lt, + nss_lookup_key key, + void *service_function, + void **result, + char *buffer, + size_t length) attribute_hidden; + +/* Like __nss_generic_get_r, but handles the ERANGE protocol. + *RESULT is not read, but overwritten with a malloc-allocated + pointer or NULL. */ +enum nss_status __nss_generic_get (enum nss_lookup_type lt, + nss_lookup_key key, + void *service_function, + void **result) attribute_hidden; + +/* Returns the pointer to the first service lookup function for lookup + type LT, or NULL if there are no service modules. Updates *NIP + accordingly. */ +void *__nss_generic_lookup (enum nss_lookup_type lt, nss_action_list *ni) + attribute_hidden; + +/* See __nss_next2 in . The function names are selected + based on the type LT. */ +int __nss_generic_next (enum nss_lookup_type lt, nss_action_list *ni, + void *fctp, int status, int all_values) + attribute_hidden; + +/* Perform a group lookup with merging. On success, return zero and + write a malloc-allocated struct group pointer to *RESULT (positive + result) or NULL (negative result). On failure, return -1 and write + NULL to *RESULT, and set errno accordingly. */ +int __nss_getXinfo (enum nss_lookup_type lt, + nss_lookup_key key, void **result) attribute_hidden; + +/* Like __nss_getXinfo, but LT must be nss_lookup_getgrgid or + nss_lookup_getgrnam. This function does not contact nscd and is + used in the implementation of __nss_getXInfo. */ +int __nss_getgrXinfo (enum nss_lookup_type lt, + nss_lookup_key key, void **result) attribute_hidden; + +/* Implementation of the non-_r public interface. RESULT must be the + address of the global variable. It is freed before the lookup + starts. Returns NULL on failure, and a pointer to the NSS struct + appropriate for LT on success. Negative lookup returns NULL and + does not set errno. Other errors set errno. */ +void *__nss_getX (enum nss_lookup_type lt, nss_lookup_key key) + attribute_hidden; + +/* Implementation of the _r public interface. The caller must + initialize *RESULT with the address of the result structure passed + to the _r function. Return 0 on success and error code on + failure (including ERANGE). */ +int __nss_getX_r (enum nss_lookup_type lt, nss_lookup_key key, + void **result, char *buffer, size_t length) + attribute_hidden; + #endif /* NSS_GENERIC_H */ diff --git a/nss/nss_generic_get.c b/nss/nss_generic_get.c new file mode 100644 index 0000000000..3319a2b9c0 --- /dev/null +++ b/nss/nss_generic_get.c @@ -0,0 +1,61 @@ +/* Implementation of the ERANGE protocol for service module functions. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +enum nss_status +__nss_generic_get (enum nss_lookup_type lt, + nss_lookup_key key, + void *service_function, + void **result) +{ + struct scratch_buffer buf; + scratch_buffer_init (&buf); + + *result = NULL; + while (true) + { + union nss_generic_storage storage; + void *ptr = &storage; + enum nss_status status = __nss_generic_get_r (lt, key, + service_function, &ptr, + buf.data, buf.length); + if (status == NSS_STATUS_TRYAGAIN && errno == ERANGE) + { + if (!scratch_buffer_grow (&buf)) + return status; + } + else + { + if (status == NSS_STATUS_SUCCESS) + { + if (ptr != NULL) + { + ptr = __nss_generic_dup (lt, ptr); + if (ptr == NULL) + status = NSS_STATUS_TRYAGAIN; + *result = ptr; + } + } + scratch_buffer_free (&buf); + return status; + } + } +} diff --git a/nss/nss_generic_get_r.c b/nss/nss_generic_get_r.c new file mode 100644 index 0000000000..12fedee10f --- /dev/null +++ b/nss/nss_generic_get_r.c @@ -0,0 +1,45 @@ +/* Lookup-independent call to an NSS service function. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +enum nss_status +__nss_generic_get_r (enum nss_lookup_type lt, + nss_lookup_key key, + void *service_function, + void **result, + char *buffer, + size_t length) +{ + switch (lt) + { + case nss_lookup_getgrgid: + return ((nss_getgrgid_r *) service_function) + (*(const gid_t *) key, *result, buffer, length, &errno); + case nss_lookup_getgrnam: + return ((nss_getgrnam_r *) service_function) + (key, *result, buffer, length, &errno); + case nss_lookup_getpwnam: + return ((nss_getpwnam_r *) service_function) + (key, *result, buffer, length, &errno); + case nss_lookup_getpwuid: + return ((nss_getpwuid_r *) service_function) + (*(const uid_t *) key, *result, buffer, length, &errno); + } + __builtin_unreachable (); +} diff --git a/nss/nss_generic_lookup.c b/nss/nss_generic_lookup.c new file mode 100644 index 0000000000..f9e41311bc --- /dev/null +++ b/nss/nss_generic_lookup.c @@ -0,0 +1,51 @@ +/* Type-generic lookup of the first NSS service module function. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void * +__nss_generic_lookup (enum nss_lookup_type lt, nss_action_list *ni) +{ + int database; + const char *fct_name; + const char *fct2_name = NULL; + + switch (lt) + { +#define DEFINE_LOOKUP(name, dbname, function, nscddb) \ + case nss_lookup_##name: \ + database = nss_database_##dbname; \ + fct_name = function; \ + break; +#include +#undef DEFINE_LOOKUP + default: + abort (); + } + + if (! __nss_database_get (database, ni)) + return NULL; + + assert (*ni != NULL); + void *fct; + if (__nss_lookup (ni, fct_name, fct2_name, &fct) == 0) + return fct; + else + return NULL; +} diff --git a/nss/nss_generic_next.c b/nss/nss_generic_next.c new file mode 100644 index 0000000000..abc5a61e11 --- /dev/null +++ b/nss/nss_generic_next.c @@ -0,0 +1,60 @@ +/* Type-generic next NSS service module function lookup. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +int +__nss_generic_next (enum nss_lookup_type lt, nss_action_list *ni, + void *fctp, int status, int all_values) +{ + /* Extract the database index and function name from . */ + int database; + const char *fct_name; + + switch (lt) + { +#define DEFINE_LOOKUP(name, dbname, function, nscddb) \ + case nss_lookup_##name: \ + database = nss_database_##dbname; \ + fct_name = function; \ + break; +#include +#undef DEFINE_LOOKUP + default: + abort (); + } + + /* No secondary functions yet. */ + const char *fct2_name = NULL; + + int ret; + if (*ni == NULL) + { + /* First call. Ignore status and all_values. */ + if (! __nss_database_get (database, ni)) + return -1; + + assert (*ni != NULL); + ret = __nss_lookup (ni, fct_name, fct2_name, fctp); + } + else + ret = __nss_next2 (ni, fct_name, fct2_name, fctp, status, all_values); + + return ret; +} diff --git a/nss/nss_generic_storage.h b/nss/nss_generic_storage.h new file mode 100644 index 0000000000..334f51be70 --- /dev/null +++ b/nss/nss_generic_storage.h @@ -0,0 +1,30 @@ +/* Type that can hold all NSS structs. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef NSS_GENERIC_STORAGE +#define NSS_GENERIC_STORAGE + +#include +#include + +union nss_generic_storage +{ + struct passwd pwd; +}; + +#endif /* NSS_GENERIC_STORAGE */ diff --git a/nss/nss_getX.c b/nss/nss_getX.c new file mode 100644 index 0000000000..8595e5e3b0 --- /dev/null +++ b/nss/nss_getX.c @@ -0,0 +1,53 @@ +/* Type-generic implementation of public non-_r NSS legacy functions. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +static void *__nss_generic_allocation[nss_lookup_MAX]; +static __libc_lock_t __nss_generic_lock[nss_lookup_MAX]; + +void * +__nss_getX (enum nss_lookup_type lt, nss_lookup_key key) +{ + __libc_lock_lock (__nss_generic_lock[lt]); + free (__nss_generic_allocation[lt]); + __nss_generic_allocation[lt] = NULL; + + /* Preserve errno (possibly 0) if ret == 0. */ + int saved_errno = errno; + void *result; + int ret = __nss_getXinfo (lt, key, &result); + __nss_generic_allocation[lt] = result; + + __libc_lock_unlock (__nss_generic_lock[lt]); + if (ret == 0) + __set_errno (saved_errno); + + return result; +} + +void +__nss_generic_freeres (void) +{ + for (int i = 0; i < array_length (__nss_generic_allocation); ++i) + free (__nss_generic_allocation[i]); +} diff --git a/nss/nss_getX_r.c b/nss/nss_getX_r.c new file mode 100644 index 0000000000..b0d488c889 --- /dev/null +++ b/nss/nss_getX_r.c @@ -0,0 +1,45 @@ +/* Type-generic implementation of public NSS get*_r functions. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +__nss_getX_r (enum nss_lookup_type lt, nss_lookup_key key, + void **result, char *buffer, size_t length) +{ + void *storage = *result; + *result = NULL; + + void *allocated; + int ret = __nss_getXinfo (lt, key, &allocated); + if (ret == 0) + { + if (allocated != NULL) + { + ret = __nss_generic_copy (lt, allocated, storage, buffer, length); + if (ret == 0) + *result = storage; + free (allocated); + } + return ret; + } + else + return errno; +} diff --git a/nss/nss_getXinfo.c b/nss/nss_getXinfo.c new file mode 100644 index 0000000000..0b2588c9fd --- /dev/null +++ b/nss/nss_getXinfo.c @@ -0,0 +1,67 @@ +/* Generic malloc-compatible version of NSS get functions. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +int +__nss_getXinfo (enum nss_lookup_type lt, nss_lookup_key key, void **result) +{ +#ifdef USE_NSCD + if (__nscd_generic_get (lt, key, result)) + return 0; +#endif + + nss_action_list nip = NULL; + void *fct; + int no_more = __nss_generic_next (lt, &nip, &fct, 0, 0); + enum nss_status status = NSS_STATUS_UNAVAIL; + + *result = NULL; + while (no_more == 0) + { + void *ptr; + status = __nss_generic_get (lt, key, fct, &ptr); + if (status == NSS_STATUS_SUCCESS) + { + free (*result); + *result = ptr; + } + + /* MERGE is invalid for most databases. */ + if ((nss_next_action (nip, status) == NSS_ACTION_MERGE + && status == NSS_STATUS_SUCCESS)) + { + __set_errno (EINVAL); + status = NSS_STATUS_UNAVAIL; + break; + } + + no_more = __nss_generic_next (lt, &nip, &fct, status, 0); + } + + if (status != NSS_STATUS_SUCCESS) + { + free (*result); + *result = NULL; + } + + if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) + return 0; + else + return errno; +} From patchwork Fri Mar 20 20:43:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132128 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 5AE444BB3BB0 for ; Fri, 20 Mar 2026 21:02:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5AE444BB3BB0 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=GameSssn 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.129.124]) by sourceware.org (Postfix) with ESMTP id 3EFAD4C900E9 for ; Fri, 20 Mar 2026 20:43:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3EFAD4C900E9 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 3EFAD4C900E9 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039398; cv=none; b=VZZYiiFsViS5q2zLmy2ngjk2mglmnaYqQWEc0gT1vtUX4l4ad039GZw7Tz6ktee0/k77IeYRlXAVTCFUybeDCEbfl0l4AsJzmiSeJJgwxx6yf7Mt+2yfJPMPKtbpinR5BVjILmBXFlx0N37yJvFy5ET+bToWmaRj8n7Ik8Fuu6Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039398; c=relaxed/simple; bh=7hiUF7sIiLqHqvWbcjVA0x1VMGGoh2XOelVj+YrYpW4=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=HX0mBbtlOKFeujlGNqz15o8Rt7ztaiXcxwudS9pSEmnH8TRIgFbjRec/+N+3Vy9Ef+lazg0zbQjncxdxocjfHQV70LWJWSfjpU4MCO2tEGgZkO7oXZMpKeBpmGeMbbK+ciPmXZL7lrNVFrguiz0HnXpZVbmExBsUJDTazBz6Zh8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3EFAD4C900E9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039397; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=1C5lCRWxe7CZV7OF1A4aSPB6ujoU5gDBuhhuHqavbaE=; b=GameSssnH+qAiCv5HmCRVrt9cNapFmXlObCP+06BLj9vRTJDJT/Gkz1Oj4p9XVpzqbjK23 1vLMeEIRLFTEy9XAhj8Dcy596im5r47/1UyDfIEmAyr0YOuog+ZKl2w5f9pNzed79PBDKz nn8ujUbmaWiCOQorr4+3z6yzDy5/bu4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-433-T1RY1IAgNlC5EJzNpParRg-1; Fri, 20 Mar 2026 16:43:16 -0400 X-MC-Unique: T1RY1IAgNlC5EJzNpParRg-1 X-Mimecast-MFC-AGG-ID: T1RY1IAgNlC5EJzNpParRg_1774039395 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CA5C019560B4 for ; Fri, 20 Mar 2026 20:43:15 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 209CB1800351 for ; Fri, 20 Mar 2026 20:43:14 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 21/23] nss: Convert group database to new NSS framework In-Reply-To: Message-ID: <72689059aa04427db5099d308dfe964a73f8a917.1774037705.git.fweimer@redhat.com> References: X-From-Line: 72689059aa04427db5099d308dfe964a73f8a917 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:43:12 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: u7oM9YSovvJ9rCHEeoQs0tafmOkDwrnxLDlJNFFUglM_1774039395 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Group merging is reimplemented and includes deduplication, which is why nss/tst-nss-test4 needs to be adjusted. --- include/set-freeres.h | 2 - nss/Makefile | 1 + nss/getgrgid.c | 14 ++- nss/getgrgid_r.c | 36 +++++--- nss/getgrnam.c | 14 ++- nss/getgrnam_r.c | 40 ++++++--- nss/nss_generic_storage.h | 1 + nss/nss_getXinfo.c | 10 +++ nss/nss_getgrXinfo.c | 176 ++++++++++++++++++++++++++++++++++++++ nss/tst-nss-test4.c | 12 +-- 10 files changed, 260 insertions(+), 46 deletions(-) create mode 100644 nss/nss_getgrXinfo.c diff --git a/include/set-freeres.h b/include/set-freeres.h index c9d2c8ae55..7806266077 100644 --- a/include/set-freeres.h +++ b/include/set-freeres.h @@ -102,8 +102,6 @@ extern printf_arginfo_size_function ** __libc_reg_printf_freemem_ptr extern printf_va_arg_function ** __libc_reg_type_freemem_ptr attribute_hidden; /* From nss/getXXbyYY.c */ -extern char * __libc_getgrgid_freemem_ptr attribute_hidden; -extern char * __libc_getgrnam_freemem_ptr attribute_hidden; extern char * __libc_getspnam_freemem_ptr attribute_hidden; extern char * __libc_getaliasbyname_freemem_ptr attribute_hidden; extern char * __libc_gethostbyaddr_freemem_ptr attribute_hidden; diff --git a/nss/Makefile b/nss/Makefile index a13f6fa10c..504f573478 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -55,6 +55,7 @@ routines = \ nss_getX \ nss_getX_r \ nss_getXinfo \ + nss_getgrXinfo \ nss_hash \ nss_module \ nss_parse_line_result \ diff --git a/nss/getgrgid.c b/nss/getgrgid.c index 3053e22517..9a15e3c505 100644 --- a/nss/getgrgid.c +++ b/nss/getgrgid.c @@ -17,12 +17,10 @@ #include +#include -#define LOOKUP_TYPE struct group -#define FUNCTION_NAME getgrgid -#define DATABASE_NAME group -#define ADD_PARAMS gid_t gid -#define ADD_VARIABLES gid -#define BUFLEN NSS_BUFLEN_GROUP - -#include "../nss/getXXbyYY.c" +struct group * +getgrgid (gid_t gid) +{ + return __nss_getX (nss_lookup_getgrgid, &gid); +} diff --git a/nss/getgrgid_r.c b/nss/getgrgid_r.c index af15accd10..7d4e693ccc 100644 --- a/nss/getgrgid_r.c +++ b/nss/getgrgid_r.c @@ -17,15 +17,31 @@ #include -#include +#include +#include -#define LOOKUP_TYPE struct group -#define FUNCTION_NAME getgrgid -#define DATABASE_NAME group -#define ADD_PARAMS gid_t gid -#define ADD_VARIABLES gid -#define BUFLEN NSS_BUFLEN_GROUP -#define DEEPCOPY_FN __copy_grp -#define MERGE_FN __merge_grp +int +___getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t length, struct group **result) +{ + void *ptr = grp; + int ret = __nss_getX_r (nss_lookup_getgrgid, &gid, &ptr, buffer, length); + *result = ptr; + return ret; +} +strong_alias (___getgrgid_r, __getgrgid_r) +versioned_symbol (libc, ___getgrgid_r, getgrgid_r, GLIBC_2_1_2); -#include +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2) +int +attribute_compat_text_section +__old_getgrgid_r (gid_t gid, struct group *grp, + char *buffer, size_t length, struct group **result) +{ + int ret = __getgrgid_r (gid, grp, buffer, length, result); + if (ret != 0 || result == NULL) + ret = -1; + return ret; +} +compat_symbol (libc, __old_getgrgid_r, getgrgid_r, GLIBC_2_0); +#endif diff --git a/nss/getgrnam.c b/nss/getgrnam.c index f10e79d50d..19e990a7cd 100644 --- a/nss/getgrnam.c +++ b/nss/getgrnam.c @@ -17,12 +17,10 @@ #include +#include -#define LOOKUP_TYPE struct group -#define FUNCTION_NAME getgrnam -#define DATABASE_NAME group -#define ADD_PARAMS const char *name -#define ADD_VARIABLES name -#define BUFLEN NSS_BUFLEN_GROUP - -#include "../nss/getXXbyYY.c" +struct group * +getgrnam (const char *name) +{ + return __nss_getX (nss_lookup_getgrnam, name); +} diff --git a/nss/getgrnam_r.c b/nss/getgrnam_r.c index 44c7b87a34..358046c5db 100644 --- a/nss/getgrnam_r.c +++ b/nss/getgrnam_r.c @@ -17,15 +17,31 @@ #include -#include - -#define LOOKUP_TYPE struct group -#define FUNCTION_NAME getgrnam -#define DATABASE_NAME group -#define ADD_PARAMS const char *name -#define ADD_VARIABLES name - -#define DEEPCOPY_FN __copy_grp -#define MERGE_FN __merge_grp - -#include +#include +#include + +int +___getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t length, struct group **result) +{ + void *ptr = grp; + int ret = __nss_getX_r (nss_lookup_getgrnam, name, &ptr, buffer, length); + *result = ptr; + return ret; +} +strong_alias (___getgrnam_r, __getgrnam_r) +versioned_symbol (libc, ___getgrnam_r, getgrnam_r, GLIBC_2_1_2); + +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2) +int +attribute_compat_text_section +__old_getgrnam_r (const char *name, struct group *grp, + char *buffer, size_t length, struct group **result) +{ + int ret = __getgrnam_r (name, grp, buffer, length, result); + if (ret != 0 || result == NULL) + ret = -1; + return ret; +} +compat_symbol (libc, __old_getgrnam_r, getgrnam_r, GLIBC_2_0); +#endif diff --git a/nss/nss_generic_storage.h b/nss/nss_generic_storage.h index 334f51be70..2d46136c9a 100644 --- a/nss/nss_generic_storage.h +++ b/nss/nss_generic_storage.h @@ -24,6 +24,7 @@ union nss_generic_storage { + struct group grp; struct passwd pwd; }; diff --git a/nss/nss_getXinfo.c b/nss/nss_getXinfo.c index 0b2588c9fd..96836dc4c2 100644 --- a/nss/nss_getXinfo.c +++ b/nss/nss_getXinfo.c @@ -26,6 +26,16 @@ __nss_getXinfo (enum nss_lookup_type lt, nss_lookup_key key, void **result) return 0; #endif + switch (lt) + { + case nss_lookup_getgrgid: + case nss_lookup_getgrnam: + /* Group lookups are handled separately to implement merging. */ + return __nss_getgrXinfo (lt, key, result); + default: + break; + } + nss_action_list nip = NULL; void *fct; int no_more = __nss_generic_next (lt, &nip, &fct, 0, 0); diff --git a/nss/nss_getgrXinfo.c b/nss/nss_getgrXinfo.c new file mode 100644 index 0000000000..795d12d63e --- /dev/null +++ b/nss/nss_getgrXinfo.c @@ -0,0 +1,176 @@ +/* Implementation of the getgrXinfo family of functions. + Copyright (C) 1996-2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline bool +__nss_status_has_result (enum nss_status status) +{ + return status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND; +} + +static int +__nss_status_to_posix_result (enum nss_status status) +{ + /* Treat NSS_STATUS_UNAVAIL like NSS_STATUS_NOTFOUND. Some NSS + modules return NSS_STATUS_UNAVAIL if they have disabled + themselves. */ + if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND + || status == NSS_STATUS_UNAVAIL) + return 0; + else + { + /* Paranoia, to avoid endless loops. */ + if (errno == ERANGE) + __set_errno (EINVAL); + return -1; + } +} + +int +__nss_getgrXinfo (enum nss_lookup_type lt, + nss_lookup_key key, + void **result) +{ + /* Default if no service modules are available. */ + enum nss_status status = NSS_STATUS_UNAVAIL; + *result = NULL; + + /* For merging. If table is not empty, then it supersedes the group + members in first_result. */ + struct group *first_result = NULL; + struct nss_group_members table = { }; + __nss_group_members_init (&table); + + /* With better error reporting (especially from dlopen), we could + check for NSS initialization errors here and report them. */ + nss_action_list nip; + void *fct = __nss_generic_lookup (lt, &nip); + + int no_more = fct == NULL; + bool do_merge = false; + while (no_more == 0) + { + void *ptr; + status = __nss_generic_get (lt, key, fct, &ptr); + struct group *grp = ptr; + + if (status == NSS_STATUS_SUCCESS) + { + assert (grp != NULL); + /* We have result data. It may need to be merged. We only + support merging members of groups with identical names + and GID values. If we hit this, the grp result overrides + the first result. */ + if (do_merge && first_result != NULL + && grp->gr_gid == first_result->gr_gid + && strcmp (grp->gr_name, first_result->gr_name) == 0) + { + /* Perform the merge. If no members have been merged yet, + process first_result as well. */ + if ((table.T.count == 0 + && !__nss_group_members_add (&table, first_result)) + || !__nss_group_members_add (&table, grp)) + { + __nss_group_members_free (&table); + free (grp); + free (first_result); + return -1; + } + free (grp); + } + else + { + /* No merge or different data. New result replaces + previous result. */ + free (first_result); + first_result = grp; + __nss_group_members_free (&table); + } + } + else if (status == NSS_STATUS_TRYAGAIN) + { + free (first_result); + __nss_group_members_free (&table); + return -1; + } + else if (first_result != NULL) + { + /* If the result wasn't SUCCESS, use the stored data in + first_result/table and set the status back to + NSS_STATUS_SUCCESS to match the previous pass through + the loop. + + * If the next action is CONTINUE, it will overwrite the value + currently in the buffer and return the new value. + * If the next action is RETURN, we'll return the previously- + acquired values. + * If the next action is MERGE, then it will be added to the + buffer saved from the previous source. */ + status = NSS_STATUS_SUCCESS; + } + + do_merge = (nss_next_action (nip, status) == NSS_ACTION_MERGE + && status == NSS_STATUS_SUCCESS); + no_more = __nss_generic_next (lt, &nip, &fct, status, 0); + } + + + if (table.T.count > 0) + { + /* We have something to merge. */ + struct group *merged_allocated; + { + struct group merged = *first_result; + merged.gr_mem = __nss_group_members (&table); + if (merged.gr_mem == NULL) + { + __nss_group_members_free (&table); + free (first_result); + return -1; + } + + /* Make a consolidated copy of the entire group information. */ + merged_allocated = __nss_generic_dup (lt, &merged); + + free (merged.gr_mem); + } + + __nss_group_members_free (&table); + free (first_result); + first_result = merged_allocated; + + if (first_result == NULL) + return -1; + } + else + /* No merging necessary. We can use first_result. */ + __nss_group_members_free (&table); + + *result = first_result; + return __nss_status_to_posix_result (status); +} diff --git a/nss/tst-nss-test4.c b/nss/tst-nss-test4.c index 72e33f3d6d..332ec2e217 100644 --- a/nss/tst-nss-test4.c +++ b/nss/tst-nss-test4.c @@ -100,9 +100,7 @@ do_test (void) /* At least 3 service modules are needed to reproduce BZ#33361. */ __nss_configure_lookup ("group", "test1 [SUCCESS=merge] test2 files"); - /* Test increasing sizes of group_2 to see if we fail, starting with - member_cnt == 1 to ensure we always check for no de-duplication - e.g. { "foo", NULL } */ + /* Test increasing sizes of group_2 to see if we fail. */ for (member_cnt = 1; member_cnt < array_length (group_2); member_cnt++) { verbose_printf ("Outer loop - member_cnt is %d\n", member_cnt); @@ -127,15 +125,17 @@ do_test (void) verbose_printf ("MERGED LIST of [%d] is %s\n", i, merge_1[i]); } - /* Add group_2 to the merge list */ - int group2_index = 0; + /* Add group_2 to the merge list. Skip the duplicate "foo" + group at the start. */ + int group2_index = 1; for (i = array_length (group_1) - 1; i < array_length (group_1) - 1 + member_cnt; i++) { merge_1[i] = xasprintf ("%s", group_2[group2_index++]); verbose_printf ("MERGED LIST of [%d] is %s\n", i, merge_1[i]); } - merge_1[array_length(group_1) - 1 + member_cnt]= NULL; + /* Skipping the "foo" group reduced the member count by 1. */ + merge_1[array_length(group_1) - 1 + member_cnt - 1]= NULL; align_mask = __alignof__ (struct group) - 1; align_mem_mask = __alignof__ (char *) - 1; From patchwork Fri Mar 20 20:43:17 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132111 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 157F64C900C3 for ; Fri, 20 Mar 2026 20:46:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 157F64C900C3 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=HD8CK5HE 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.129.124]) by sourceware.org (Postfix) with ESMTP id 6EE724C31843 for ; Fri, 20 Mar 2026 20:43:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6EE724C31843 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 6EE724C31843 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039403; cv=none; b=gViyB6NXG0/ZXh0ZCZZUJP+zS0fHgNjaI/G/zRKv6fGVYPkLcfGu9fHxB6/UgsMYGRg1mMc3R7pkVyEGjjemN2gq4HJTN5JtyvOOSKEy5eOX0nksrjwyuv4+eBiPV4VPJdvmMBrtIbi53RCZzy6l4gasjq7PQaIFwNQT7bLsODI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039403; c=relaxed/simple; bh=wca09xcUQ55HGDhaM36WCYTIqCWM9wJmMd4HLkfR4P4=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=SBtQapYy+88z5LAQaLpsDtLKknybeHFzZHH9Yx3nr4U7o8d3Z5dL1aaI9yidcV5mLMcmTs6+jKKkUq8kzNQO3aQSulBIjAf5oNmsWT95YVzWf3R8TkqaqTC7orzOvTUyHJD/rNf34UnVFe+8JXd0axPJBFTek0jtpGUIryKuWnc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6EE724C31843 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039403; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=ktSoUe5Mv5wbOd0Tr1e1Aw87PdVzGfxM2KnTsFoKJvA=; b=HD8CK5HELNKdyG+BAyO9TNCUSr5L+ZgC5XXGxWqC6Q//qiPmklT0y/DHRGcCBad+bEUHDl FhU5Yr8b5g2kruZyTpvH5DFAvUc85BOTn7UZxEt9crPN57VTLeGn1akINqg9qFfvgYH5xr JHanpCTviQ+xEz3LnIm0YbDGj87HXIY= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-287-7zVFspqJNBuQE5CqB85ycw-1; Fri, 20 Mar 2026 16:43:21 -0400 X-MC-Unique: 7zVFspqJNBuQE5CqB85ycw-1 X-Mimecast-MFC-AGG-ID: 7zVFspqJNBuQE5CqB85ycw_1774039400 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A300B180047F for ; Fri, 20 Mar 2026 20:43:20 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id ED91D1953944 for ; Fri, 20 Mar 2026 20:43:19 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 22/23] nscd: Remove most of the rebuilds of existing libc functions In-Reply-To: Message-ID: References: X-From-Line: a43dcac8810f29ab99ee968ffcd0bbfa86cf0fff Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:43:17 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: mEBScQb7vPXVbyAGjIwL4lkHkpwLmCA90s6LQ3Jpwec_1774039400 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.5 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, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 With __nscd_disable_database, the databases are already disabled. Keep the struct hostent functions because the *2_r and *3_r variants are not exported from libc. --- nscd/Makefile | 6 ------ nscd/getgrgid_r.c | 34 ---------------------------------- nscd/getgrnam_r.c | 33 --------------------------------- nscd/getpwnam_r.c | 30 ------------------------------ nscd/getpwuid_r.c | 30 ------------------------------ nscd/getsrvbynm_r.c | 29 ----------------------------- nscd/getsrvbypt_r.c | 29 ----------------------------- nscd/grpcache.c | 4 ++-- nscd/pwdcache.c | 4 ++-- nscd/servicescache.c | 4 ++-- 10 files changed, 6 insertions(+), 197 deletions(-) delete mode 100644 nscd/getgrgid_r.c delete mode 100644 nscd/getgrnam_r.c delete mode 100644 nscd/getpwnam_r.c delete mode 100644 nscd/getpwuid_r.c delete mode 100644 nscd/getsrvbynm_r.c delete mode 100644 nscd/getsrvbypt_r.c diff --git a/nscd/Makefile b/nscd/Makefile index 2578b00e27..58a2d01e00 100644 --- a/nscd/Makefile +++ b/nscd/Makefile @@ -46,14 +46,8 @@ nscd-modules := \ cachedumper \ connections \ dbg_log \ - getgrgid_r \ - getgrnam_r \ gethstbyad_r \ gethstbynm3_r \ - getpwnam_r \ - getpwuid_r \ - getsrvbynm_r \ - getsrvbypt_r \ grpcache \ hstcache \ initgrcache \ diff --git a/nscd/getgrgid_r.c b/nscd/getgrgid_r.c deleted file mode 100644 index 3fa0717d88..0000000000 --- a/nscd/getgrgid_r.c +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 1996-2026 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 - -#define LOOKUP_TYPE struct group -#define FUNCTION_NAME getgrgid -#define DATABASE_NAME group -#define ADD_PARAMS gid_t gid -#define ADD_VARIABLES gid -#define BUFLEN NSS_BUFLEN_GROUP - -#define DEEPCOPY_FN __copy_grp -#define MERGE_FN __merge_grp - -/* We are nscd, so we don't want to be talking to ourselves. */ -#undef USE_NSCD - -#include diff --git a/nscd/getgrnam_r.c b/nscd/getgrnam_r.c deleted file mode 100644 index 7be4374408..0000000000 --- a/nscd/getgrnam_r.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 1996-2026 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 - -#define LOOKUP_TYPE struct group -#define FUNCTION_NAME getgrnam -#define DATABASE_NAME group -#define ADD_PARAMS const char *name -#define ADD_VARIABLES name - -#define DEEPCOPY_FN __copy_grp -#define MERGE_FN __merge_grp - -/* We are nscd, so we don't want to be talking to ourselves. */ -#undef USE_NSCD - -#include diff --git a/nscd/getpwnam_r.c b/nscd/getpwnam_r.c deleted file mode 100644 index e63b7fb0c1..0000000000 --- a/nscd/getpwnam_r.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 1996-2026 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 - - -#define LOOKUP_TYPE struct passwd -#define FUNCTION_NAME getpwnam -#define DATABASE_NAME passwd -#define ADD_PARAMS const char *name -#define ADD_VARIABLES name -#define BUFLEN NSS_BUFLEN_PASSWD - -/* We are nscd, so we don't want to be talking to ourselves. */ -#undef USE_NSCD - -#include diff --git a/nscd/getpwuid_r.c b/nscd/getpwuid_r.c deleted file mode 100644 index 3ea5f806f8..0000000000 --- a/nscd/getpwuid_r.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 1996-2026 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 - - -#define LOOKUP_TYPE struct passwd -#define FUNCTION_NAME getpwuid -#define DATABASE_NAME passwd -#define ADD_PARAMS uid_t uid -#define ADD_VARIABLES uid -#define BUFLEN NSS_BUFLEN_PASSWD - -/* We are nscd, so we don't want to be talking to ourselves. */ -#undef USE_NSCD - -#include diff --git a/nscd/getsrvbynm_r.c b/nscd/getsrvbynm_r.c deleted file mode 100644 index 4ac934815c..0000000000 --- a/nscd/getsrvbynm_r.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 1996-2026 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 - - -#define LOOKUP_TYPE struct servent -#define FUNCTION_NAME getservbyname -#define DATABASE_NAME services -#define ADD_PARAMS const char *name, const char *proto -#define ADD_VARIABLES name, proto - -/* We are nscd, so we don't want to be talking to ourselves. */ -#undef USE_NSCD - -#include "../nss/getXXbyYY_r.c" diff --git a/nscd/getsrvbypt_r.c b/nscd/getsrvbypt_r.c deleted file mode 100644 index 9ca0fec407..0000000000 --- a/nscd/getsrvbypt_r.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 1996-2026 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 - - -#define LOOKUP_TYPE struct servent -#define FUNCTION_NAME getservbyport -#define DATABASE_NAME services -#define ADD_PARAMS int port, const char *proto -#define ADD_VARIABLES port, proto - -/* We are nscd, so we don't want to be talking to ourselves. */ -#undef USE_NSCD - -#include "../nss/getXXbyYY_r.c" diff --git a/nscd/grpcache.c b/nscd/grpcache.c index a05f6fb6e6..1e060724f6 100644 --- a/nscd/grpcache.c +++ b/nscd/grpcache.c @@ -401,9 +401,9 @@ lookup (int type, union keytype key, struct group *resultbufp, char *buffer, size_t buflen, struct group **grp) { if (type == GETGRBYNAME) - return __getgrnam_r (key.v, resultbufp, buffer, buflen, grp); + return getgrnam_r (key.v, resultbufp, buffer, buflen, grp); else - return __getgrgid_r (key.g, resultbufp, buffer, buflen, grp); + return getgrgid_r (key.g, resultbufp, buffer, buflen, grp); } diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c index 715775be2f..66f9ff09a2 100644 --- a/nscd/pwdcache.c +++ b/nscd/pwdcache.c @@ -379,9 +379,9 @@ lookup (int type, union keytype key, struct passwd *resultbufp, char *buffer, size_t buflen, struct passwd **pwd) { if (type == GETPWBYNAME) - return __getpwnam_r (key.v, resultbufp, buffer, buflen, pwd); + return getpwnam_r (key.v, resultbufp, buffer, buflen, pwd); else - return __getpwuid_r (key.u, resultbufp, buffer, buflen, pwd); + return getpwuid_r (key.u, resultbufp, buffer, buflen, pwd); } diff --git a/nscd/servicescache.c b/nscd/servicescache.c index aa8a80d483..46cf1a9e3b 100644 --- a/nscd/servicescache.c +++ b/nscd/servicescache.c @@ -329,10 +329,10 @@ lookup (int type, char *key, struct servent *resultbufp, char *buffer, } if (type == GETSERVBYNAME) - return __getservbyname_r (key, proto, resultbufp, buffer, buflen, serv); + return getservbyname_r (key, proto, resultbufp, buffer, buflen, serv); assert (type == GETSERVBYPORT); - return __getservbyport_r (atol (key), proto, resultbufp, buffer, buflen, + return getservbyport_r (atol (key), proto, resultbufp, buffer, buflen, serv); } From patchwork Fri Mar 20 20:43:24 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132115 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 8D3FB4C31829 for ; Fri, 20 Mar 2026 20:48:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8D3FB4C31829 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=YAkVOvWb 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.129.124]) by sourceware.org (Postfix) with ESMTP id A21404C91764 for ; Fri, 20 Mar 2026 20:43:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A21404C91764 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine 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 A21404C91764 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039409; cv=none; b=Hr3jZKcPYhQanrcmRAlK+kdGPSrfSnC9T7I8tI4qpvI6Cggmb30YKitqfZ8mFR0gJZDaFMWPN5DDxW76jrjGGz80KxdzGz9VUC45juelqbXZMiILG29smm6rsfTy8FFp7m8J8jkFKGhBoLfdeyIAf1VpXUwKllthc3F495MdCtM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039409; c=relaxed/simple; bh=DnuMewCirxbkQrMDVRozUtjVhfFIY1RNeKbWFd1B5gU=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=I/KSnWGPQ33GvoJcLzV6FUKqYaJwjuzYWC81Zw2TB+ylHKERUT7+puwDLoHQKkuldYsEHUTb+X8nasqlD9+scaqFUNV5R1V9+sG37aTPhTHHmJ8q50Zu5mj7eUy+DoWMptNLahVa5AZ+5psT7cPKPRACKg+uRxAEQESxgphldzw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A21404C91764 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039409; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=4EHu5uJFvYOcEevJSc2dRcTsxk7ZH1JNFCmj/zp2EZI=; b=YAkVOvWbldCOOq35KkWoj4fFPrI8gOmQq4u0a8Q+phYJiR4ED5tShxEqMsCfk3/Y+hEal+ kbndbgLYhnnCaZgQZ+s6IYNR1QWQ1CAPZAolqr6qqGALl1Wrz9CCxA1vt84oKlh2VTos6c V90TsA2lPNS44KxOZARhYIDqHNkl91M= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-107-pyPeUhTeP3Wl9h0H8qv7AQ-1; Fri, 20 Mar 2026 16:43:27 -0400 X-MC-Unique: pyPeUhTeP3Wl9h0H8qv7AQ-1 X-Mimecast-MFC-AGG-ID: pyPeUhTeP3Wl9h0H8qv7AQ_1774039407 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 25D821800561 for ; Fri, 20 Mar 2026 20:43:27 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6EF7030001A1 for ; Fri, 20 Mar 2026 20:43:26 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 23/23] nss: Remove old group merge code In-Reply-To: Message-ID: <05e0a557343d05d4406b3776e13af4b1147b1541.1774037705.git.fweimer@redhat.com> References: X-From-Line: 05e0a557343d05d4406b3776e13af4b1147b1541 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:43:24 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: T8VhelOJw0-khlwSF8hocpNNzLOJa-fNsZ7Y4EF7xsM_1774039407 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 --- nss/Makefile | 1 - nss/getXXbyYY_r.c | 107 ++----------------------- nss/grp-merge.c | 200 ---------------------------------------------- nss/grp-merge.h | 35 -------- 4 files changed, 7 insertions(+), 336 deletions(-) delete mode 100644 nss/grp-merge.c delete mode 100644 nss/grp-merge.h diff --git a/nss/Makefile b/nss/Makefile index 504f573478..36cf9aa63c 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -95,7 +95,6 @@ routines += \ getgrgid_r \ getgrnam \ getgrnam_r \ - grp-merge \ initgroups \ nss_group_members \ putgrent \ diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index 9527b6722d..aa262634f9 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -126,47 +126,6 @@ #endif -/* Set defaults for merge functions that haven't been defined. */ -#ifndef DEEPCOPY_FN -static inline int -__copy_einval (LOOKUP_TYPE a, - const size_t b, - LOOKUP_TYPE *c, - char *d, - char **e) -{ - return EINVAL; -} -# define DEEPCOPY_FN __copy_einval -#endif - -#ifndef MERGE_FN -static inline int -__merge_einval (LOOKUP_TYPE *a, - char *b, - char *c, - size_t d, - LOOKUP_TYPE *e, - char *f) -{ - return EINVAL; -} -# define MERGE_FN __merge_einval -#endif - -#define CHECK_MERGE(err, status) \ - ({ \ - if (err) \ - { \ - __set_errno (err); \ - if (err == ERANGE) \ - status = NSS_STATUS_TRYAGAIN; \ - else \ - status = NSS_STATUS_UNAVAIL; \ - break; \ - } \ - }) - /* Type of the lookup function we need here. */ typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, size_t, int * H_ERRNO_PARM @@ -184,12 +143,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, EXTRA_PARAMS) { nss_action_list nip; - int do_merge = 0; - LOOKUP_TYPE mergegrp; - char *mergebuf = NULL; - char *endptr = NULL; void *fct; - int no_more, err; + int no_more; enum nss_status status = NSS_STATUS_UNAVAIL; #ifdef USE_NSCD int nscd_status; @@ -273,66 +228,18 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, && errno == ERANGE) break; - if (do_merge) - { - - if (status == NSS_STATUS_SUCCESS) - { - /* The previous loop saved a buffer for merging. - Perform the merge now. */ - err = MERGE_FN (&mergegrp, mergebuf, endptr, buflen, resbuf, - buffer); - CHECK_MERGE (err,status); - do_merge = 0; - } - else - { - /* If the result wasn't SUCCESS, copy the saved buffer back - into the result buffer and set the status back to - NSS_STATUS_SUCCESS to match the previous pass through the - loop. - * If the next action is CONTINUE, it will overwrite the value - currently in the buffer and return the new value. - * If the next action is RETURN, we'll return the previously- - acquired values. - * If the next action is MERGE, then it will be added to the - buffer saved from the previous source. */ - err = DEEPCOPY_FN (mergegrp, buflen, resbuf, buffer, NULL); - CHECK_MERGE (err, status); - status = NSS_STATUS_SUCCESS; - } - } - - /* If we were are configured to merge this value with the next one, - save the current value of the group struct. */ - if (nss_next_action (nip, status) == NSS_ACTION_MERGE - && status == NSS_STATUS_SUCCESS) + /* MERGE is invalid for most databases. */ + if ((nss_next_action (nip, status) == NSS_ACTION_MERGE + && status == NSS_STATUS_SUCCESS)) { - /* Copy the current values into a buffer to be merged with the next - set of retrieved values. */ - if (mergebuf == NULL) - { - /* Only allocate once and reuse it for as many merges as we need - to perform. */ - mergebuf = malloc (buflen); - if (mergebuf == NULL) - { - __set_errno (ENOMEM); - status = NSS_STATUS_UNAVAIL; - break; - } - } - - err = DEEPCOPY_FN (*resbuf, buflen, &mergegrp, mergebuf, &endptr); - CHECK_MERGE (err, status); - do_merge = 1; + __set_errno (EINVAL); + status = NSS_STATUS_UNAVAIL; + break; } no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING, REENTRANT2_NAME_STRING, &fct, status, 0); } - free (mergebuf); - mergebuf = NULL; #ifdef HANDLE_DIGITS_DOTS done: diff --git a/nss/grp-merge.c b/nss/grp-merge.c deleted file mode 100644 index 0a99882097..0000000000 --- a/nss/grp-merge.c +++ /dev/null @@ -1,200 +0,0 @@ -/* Group merging implementation. - Copyright (C) 2016-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include -#include -#include -#include -#include - -#define BUFCHECK(size) \ - ({ \ - do \ - { \ - if (c + (size) > buflen) \ - { \ - free (members); \ - return ERANGE; \ - } \ - } \ - while (0); \ - }) - -int -__copy_grp (const struct group srcgrp, const size_t buflen, - struct group *destgrp, char *destbuf, char **endptr) -{ - size_t i; - size_t c = 0; - size_t len; - size_t memcount; - char **members = NULL; - - /* Copy the GID. */ - destgrp->gr_gid = srcgrp.gr_gid; - - /* Copy the name. */ - len = strlen (srcgrp.gr_name) + 1; - BUFCHECK (len); - memcpy (&destbuf[c], srcgrp.gr_name, len); - destgrp->gr_name = &destbuf[c]; - c += len; - - /* Copy the password. */ - len = strlen (srcgrp.gr_passwd) + 1; - BUFCHECK (len); - memcpy (&destbuf[c], srcgrp.gr_passwd, len); - destgrp->gr_passwd = &destbuf[c]; - c += len; - - /* Count all of the members. */ - for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++) - ; - - /* Allocate a temporary holding area for the pointers to the member - contents, including space for a NULL-terminator. */ - members = malloc (sizeof (char *) * (memcount + 1)); - if (members == NULL) - return ENOMEM; - - /* Copy all of the group members to destbuf and add a pointer to each of - them into the 'members' array. */ - for (i = 0; srcgrp.gr_mem[i]; i++) - { - len = strlen (srcgrp.gr_mem[i]) + 1; - BUFCHECK (len); - memcpy (&destbuf[c], srcgrp.gr_mem[i], len); - members[i] = &destbuf[c]; - c += len; - } - members[i] = NULL; - - /* Align for pointers. We can't simply align C because we need to - align destbuf[c]. */ - if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0) - { - uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1); - c += __alignof__(char **) - mis_align; - } - - /* Copy the pointers from the members array into the buffer and assign them - to the gr_mem member of destgrp. */ - destgrp->gr_mem = (char **) &destbuf[c]; - len = sizeof (char *) * (memcount + 1); - BUFCHECK (len); - memcpy (&destbuf[c], members, len); - c += len; - free (members); - members = NULL; - - /* Save the count of members at the end. */ - BUFCHECK (sizeof (size_t)); - memcpy (&destbuf[c], &memcount, sizeof (size_t)); - c += sizeof (size_t); - - if (endptr) - *endptr = destbuf + c; - return 0; -} -libc_hidden_def (__copy_grp) - -/* Check that the name, GID and passwd fields match, then - copy in the gr_mem array. */ -int -__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, - size_t buflen, struct group *mergegrp, char *mergebuf) -{ - size_t c, i, len; - size_t savedmemcount; - size_t memcount; - size_t membersize; - char **members = NULL; - - /* We only support merging members of groups with identical names and - GID values. If we hit this case, we need to overwrite the current - buffer with the saved one (which is functionally equivalent to - treating the new lookup as NSS_STATUS_NOTFOUND). */ - if (mergegrp->gr_gid != savedgrp->gr_gid - || strcmp (mergegrp->gr_name, savedgrp->gr_name)) - return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL); - - /* Get the count of group members from the last sizeof (size_t) bytes in the - mergegrp buffer. */ - savedmemcount = *(size_t *) (savedend - sizeof (size_t)); - - /* Get the count of new members to add. */ - for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++) - ; - - /* Create a temporary array to hold the pointers to the member values from - both the saved and merge groups. */ - membersize = savedmemcount + memcount + 1; - members = malloc (sizeof (char *) * membersize); - if (members == NULL) - return ENOMEM; - - /* Copy in the existing member pointers from the saved group - Note: this is not NULL-terminated yet. */ - memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount); - - /* Back up into the savedbuf until we get back to the NULL-terminator of the - group member list. (This means walking back savedmemcount + 1 (char *) pointers - and the member count value. - The value of c is going to be the used length of the buffer backed up by - the member count and further backed up by the size of the pointers. */ - c = savedend - savedbuf - - sizeof (size_t) - - sizeof (char *) * (savedmemcount + 1); - - /* Add all the new group members, overwriting the old NULL-terminator while - adding the new pointers to the temporary array. */ - for (i = 0; mergegrp->gr_mem[i]; i++) - { - len = strlen (mergegrp->gr_mem[i]) + 1; - BUFCHECK (len); - memcpy (&savedbuf[c], mergegrp->gr_mem[i], len); - members[savedmemcount + i] = &savedbuf[c]; - c += len; - } - /* Add the NULL-terminator. */ - members[savedmemcount + memcount] = NULL; - - /* Align for pointers. We can't simply align C because we need to - align savedbuf[c]. */ - if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0) - { - uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1); - c += __alignof__(char **) - mis_align; - } - - /* Copy the member array back into the buffer after the member list and free - the member array. */ - savedgrp->gr_mem = (char **) &savedbuf[c]; - len = sizeof (char *) * membersize; - BUFCHECK (len); - memcpy (&savedbuf[c], members, len); - c += len; - - free (members); - members = NULL; - - /* Finally, copy the results back into mergebuf, since that's the buffer - that we were provided by the caller. */ - return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL); -} -libc_hidden_def (__merge_grp) diff --git a/nss/grp-merge.h b/nss/grp-merge.h deleted file mode 100644 index ba985c556e..0000000000 --- a/nss/grp-merge.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Group merging implementation. - Copyright (C) 2016-2026 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#ifndef _GRP_MERGE_H -#define _GRP_MERGE_H 1 - -#include - -/* Duplicate a grp struct (and its members). When no longer needed, the - calling function must free(newbuf). */ -int -__copy_grp (const struct group srcgrp, const size_t buflen, - struct group *destgrp, char *destbuf, char **endptr); - -/* Merge the member lists of two grp structs together. */ -int -__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, - size_t buflen, struct group *mergegrp, char *mergebuf); - -#endif /* _GRP_MERGE_H */