From patchwork Thu Jan 2 17:05:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam James X-Patchwork-Id: 2029116 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4YPCls1YtHz1yT6 for ; Fri, 3 Jan 2025 04:06:16 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 64ED93858D3C for ; Thu, 2 Jan 2025 17:06:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 64ED93858D3C X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from smtp.gentoo.org (dev.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) by sourceware.org (Postfix) with ESMTP id 64BA13858D33 for ; Thu, 2 Jan 2025 17:05:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 64BA13858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gentoo.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gentoo.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 64BA13858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:470:ea4a:1:5054:ff:fec7:86e4 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1735837546; cv=none; b=mHmv/rR0yQKH88NrmaYDrl+h+q8wZgXQbM4FhWVOSEszERYSUmxdgqsfKy6eOXsLjFC3/C8W0NjB0NxZcp/egsQ8UzzwhOoV3GLF+kHNjitnZGeYjVKPRDekGYI7Saz1rxaKxz2l1qDCmqHuD+bf0dtUK7kinJ/vayYO9t7qVCA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1735837546; c=relaxed/simple; bh=7bPOOwrc6LNL2oe269N3tjH91xIVy4tI+dGv27Xw5vs=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=JkCsd41JS59Q1muLm8fgJl8LMdAczOfPAxLNO6ifKtd/MkeaMO5n8ThgSDOxvu07xTKDbTm+DILjdcmUeTCayEejgekE5UmB00pnBu7XVLeVHEzdD/f7hlY/VHByPBLNJ57WcVxlFmTRnbj9B38suzFnb2Lk1ViCpbYqLseP+LE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 64BA13858D33 From: Sam James To: libc-alpha@sourceware.org Cc: Sam James , Adhemerval Zanella , Florian Weimer Subject: [COMMITTED] stdlib: random_r: fix unaligned access in initstate and initstate_r [BZ #30584] Date: Thu, 2 Jan 2025 17:05:25 +0000 Message-ID: X-Mailer: git-send-email 2.47.1 MIME-Version: 1.0 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~incoming=patchwork.ozlabs.org@sourceware.org The initstate{,_r} interfaces are documented in BSD as needing an aligned array of 32-bit values, but neither POSIX nor glibc's own documentation require it to be aligned. glibc's documentation says it "should" be a power of 2, but not must. Use memcpy to read and write to `state` to handle such an unaligned argument. Co-authored-by: Adhemerval Zanella Reviewed-by: Florian Weimer --- stdlib/Makefile | 1 + stdlib/random_r.c | 42 +++++++++++++++++++++++++++---------- stdlib/tst-random-bz30584.c | 38 +++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 stdlib/tst-random-bz30584.c Range-diff: 1: 4201889422 ! 1: d5bceac99d stdlib: random_r: fix unaligned access in initstate and initstate_r [BZ #30584] @@ Commit message argument. Co-authored-by: Adhemerval Zanella + Reviewed-by: Florian Weimer ## stdlib/Makefile ## @@ stdlib/Makefile: tests := \ @@ stdlib/random_r.c: static const struct random_poly_info random_poly_info = }; +static inline int32_t -+read_state (int32_t *b, size_t idx) ++read_state (int32_t *b, int idx) +{ + int32_t r; -+ memcpy (&r, &b[idx], sizeof (int32_t)); ++ memcpy (&r, (char *) b + idx * 4, sizeof (int32_t)); + return r; +} +static inline void -+write_state (int32_t *b, size_t idx, int32_t v) ++write_state (int32_t *b, int idx, int32_t v) +{ -+ memcpy (&b[idx], &v, sizeof (int32_t)); ++ /* Use literal 4 to avoid conversion to an unsigned type and pointer ++ wraparound. */ ++ memcpy ((char *) b + idx * 4, &v, 4); +} diff --git a/stdlib/Makefile b/stdlib/Makefile index cad1a2e244..374643e753 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -300,6 +300,7 @@ tests := \ tst-rand48-2 \ tst-random \ tst-random2 \ + tst-random-bz30584 \ tst-realpath \ tst-realpath-toolong \ tst-secure-getenv \ diff --git a/stdlib/random_r.c b/stdlib/random_r.c index c37284c82d..605e96983c 100644 --- a/stdlib/random_r.c +++ b/stdlib/random_r.c @@ -55,6 +55,7 @@ #include #include #include +#include /* An improved random number generation package. In addition to the standard @@ -146,7 +147,21 @@ static const struct random_poly_info random_poly_info = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } }; +static inline int32_t +read_state (int32_t *b, int idx) +{ + int32_t r; + memcpy (&r, (char *) b + idx * 4, sizeof (int32_t)); + return r; +} +static inline void +write_state (int32_t *b, int idx, int32_t v) +{ + /* Use literal 4 to avoid conversion to an unsigned type and pointer + wraparound. */ + memcpy ((char *) b + idx * 4, &v, 4); +} /* Initialize the random number generator based on the given seed. If the @@ -177,7 +192,7 @@ __srandom_r (unsigned int seed, struct random_data *buf) /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ if (seed == 0) seed = 1; - state[0] = seed; + write_state (state, 0, seed); if (type == TYPE_0) goto done; @@ -194,7 +209,7 @@ __srandom_r (unsigned int seed, struct random_data *buf) word = 16807 * lo - 2836 * hi; if (word < 0) word += 2147483647; - *++dst = word; + write_state (++dst, 0, word); } buf->fptr = &state[buf->rand_sep]; @@ -238,9 +253,10 @@ __initstate_r (unsigned int seed, char *arg_state, size_t n, { int old_type = buf->rand_type; if (old_type == TYPE_0) - old_state[-1] = TYPE_0; + write_state (old_state, -1, TYPE_0); else - old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type; + write_state (old_state, -1, (MAX_TYPES * (buf->rptr - old_state)) + + old_type); } int type; @@ -270,9 +286,9 @@ __initstate_r (unsigned int seed, char *arg_state, size_t n, __srandom_r (seed, buf); - state[-1] = TYPE_0; + write_state (state, -1, TYPE_0); if (type != TYPE_0) - state[-1] = (buf->rptr - state) * MAX_TYPES + type; + write_state (state, -1, (buf->rptr - state) * MAX_TYPES + type); return 0; @@ -307,9 +323,10 @@ __setstate_r (char *arg_state, struct random_data *buf) old_type = buf->rand_type; old_state = buf->state; if (old_type == TYPE_0) - old_state[-1] = TYPE_0; + write_state (old_state, -1, TYPE_0); else - old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type; + write_state (old_state, -1, (MAX_TYPES * (buf->rptr - old_state)) + + old_type); type = new_state[-1] % MAX_TYPES; if (type < TYPE_0 || type > TYPE_4) @@ -361,8 +378,9 @@ __random_r (struct random_data *buf, int32_t *result) if (buf->rand_type == TYPE_0) { - int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff; - state[0] = val; + int32_t val = ((read_state(state, 0) * 1103515245U) + 12345U) + & 0x7fffffff; + write_state (state, 0, val); *result = val; } else @@ -372,7 +390,9 @@ __random_r (struct random_data *buf, int32_t *result) int32_t *end_ptr = buf->end_ptr; uint32_t val; - val = *fptr += (uint32_t) *rptr; + val = read_state (rptr, 0); + int32_t t = read_state (fptr, 0); + write_state (fptr, 0, t + val); /* Chucking least random bit. */ *result = val >> 1; ++fptr; diff --git a/stdlib/tst-random-bz30584.c b/stdlib/tst-random-bz30584.c new file mode 100644 index 0000000000..0a9b013f26 --- /dev/null +++ b/stdlib/tst-random-bz30584.c @@ -0,0 +1,38 @@ +/* Test program for initstate(), initstate_r() for BZ #30584. + Copyright (C) 2024 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; see the file COPYING.LIB. If + not, see . */ + +#include +#include + +static int +do_test (void) +{ + struct random_data rand_state = { .state = NULL }; + _Alignas (double) char buf[128 + sizeof (int32_t)]; + + /* Test initstate_r with an unaligned `state` array. */ + initstate_r (time (NULL), buf + 1, sizeof buf, &rand_state); + + /* Ditto initstate. */ + initstate (time (NULL), buf + 1, sizeof buf); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c"