From nobody Thu Apr 30 21:07:10 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4g66Dt4vD6z6cGcK for ; Thu, 30 Apr 2026 21:07:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4g66Dt2GN1z3YNW for ; Thu, 30 Apr 2026 21:07:10 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1777583230; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vrekEqmD2TXlA6u/CqJaWAZPGzttGOVb02s0mR5yIC4=; b=MUB33DiRy0z7UUScwv2BJyfpn9ZwmBBUuS+KHuWQnZSs+jWJqyWIeW/lMcIkyU7YkpY4CE h7vnfq8qEm6GEuP4XEAK5k6PABOINgHkBeae0OL/lHr2Lk9wf2ZMBxSHHDL81K6wfzEjqI TEPuqfBW6clrSwPzHUH4xwpbDGSarE/6BvtfNkFtuyucHh6Hn1CVN/47N3IcFa070t/oGM BHK6Uc1mXONuw+lG8EgOQ7/rgWTnJqJfD+zJ9haLTb9CE8kSjIQud9m1ZDLFfGbGAHqwsd pn8hNu2NygqbsvbyVbcClan5Z+5E2XOe35ahb6nZuA95hUPgw/JdSJhToVlIuA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1777583230; a=rsa-sha256; cv=none; b=ny2QiuROXGDOy/WoyI8mZAhOUR+AcT1FsoIfjGe4cvcW8Xcka9FCJCAP+g2ioGs8kX1Rru ZRrkoNjFNQhw9AtPAGJ1NgSK2PUr6umqp8pvTYBMJfWKyimh9eAP4xxbilJ044Th960cUC ndbH8pwtwHfOwlk17DsMvjMApO1sup8XHT0Z06ktyZeLE275PJ8TS0X4AFUBJqPsRNRwHO Jp5zBksbqa0Iv+uaxN6sGsE/UOOgCeQtNJ6sV/0RunQZjzxk1eRdHUmg5idk17R5tTyGVb Cx60eO0nTr7fTAPMVFVk6kVqg153WbZOMCmPwFhZtiYQ7SJUkaDv+UoDJ6VQmg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1777583230; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vrekEqmD2TXlA6u/CqJaWAZPGzttGOVb02s0mR5yIC4=; b=PuQQbEsyBbDEURRmFJH6KYhGsW9tImXVQuYQBsVgcPbqTW8eBIy46LJbrsz6Yv9IiWjUd3 5dpOSAAEC0h6upri33AHV7APsgL0SdlxfBJAJE7AYXGDf2UZ3Cq7lckgaUPeyeD1vQcssG dbVo+ZbAPjEhUn3kaHkVIadSsnQHdDBFSyvAnitdnXhf4drmLPQUhg3dWBCdLqbBiuSdR+ bIish/vH8ZCGS1U9+/wU4RTCQeF55WWL4KY0GTqvj5oPzY5gfAO+IQlVw2uslyWbIIScub vIN9Sztuc954MBoWqwSCQVGd1dA6CgjHhNTS+M1JdIt5U3hc3IvgWgMqNwjjTg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4g66Dt1YN8zD5t for ; Thu, 30 Apr 2026 21:07:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 44ec8 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 30 Apr 2026 21:07:10 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav Subject: git: 69588094a112 - stable/14 - md5: Encode non-printable filenames List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 69588094a11287d48bea2f9e0ebf1968f35e09c6 Auto-Submitted: auto-generated Date: Thu, 30 Apr 2026 21:07:10 +0000 Message-Id: <69f3c47e.44ec8.60c79c3b@gitrepo.freebsd.org> The branch stable/14 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=69588094a11287d48bea2f9e0ebf1968f35e09c6 commit 69588094a11287d48bea2f9e0ebf1968f35e09c6 Author: Dag-Erling Smørgrav AuthorDate: 2026-04-29 18:41:05 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2026-04-30 21:07:05 +0000 md5: Encode non-printable filenames Encode filenames in the VIS_CSTYLE | VIS_OCTAL style regardless of output mode. When reading filenames from a checksum file, attempt to decode them, and use the decoded name unless the decoded name does not exist but the undecoded one does. This breaks compatibility with GNU coreutils, which unfortunately uses a non-reversible encoding when outputting filenames containing non-printable characters. While here, drop a sentence about preimage attacks against MD5 and SHA1 from the manual page, as I no longer trust it to be true. MFC after: 1 week Reviewed by: bcr, markj Differential Revision: https://reviews.freebsd.org/D56615 (cherry picked from commit 70fde0ed6bbbb1f84c440190ba1e5435f8c90e13) --- sbin/md5/md5.1 | 30 ++++++++++++++++++++++-------- sbin/md5/md5.c | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/sbin/md5/md5.1 b/sbin/md5/md5.1 index b530292c8269..82515dec6714 100644 --- a/sbin/md5/md5.1 +++ b/sbin/md5/md5.1 @@ -1,4 +1,4 @@ -.Dd March 12, 2024 +.Dd April 6, 2026 .Dt MD5 1 .Os .Sh NAME @@ -84,11 +84,18 @@ If no files are listed on the command line, or a file name is given as .Pa - , input is taken from stdin instead. .Pp +The utility's different modes have different output formats, but in +all cases, filenames containing unprintable characters are encoded as +described in +.Xr vis 3 +using the +.Dv VIS_CSTYLE \&| Dv VIS_OCTAL +style. +.Pp It is conjectured that it is computationally infeasible to produce two messages having the same message digest, or to produce any message having a given prespecified target message digest. -The SHA-224 , SHA-256 , SHA-384 , SHA-512, RIPEMD-160, -and SKEIN +The SHA-224, SHA-256, SHA-384, SHA-512, RIPEMD-160, and SKEIN algorithms are intended for digital signature applications, where a large file must be .Dq compressed @@ -99,10 +106,6 @@ key under a public-key cryptosystem such as RSA. The MD5 and SHA-1 algorithms have been proven to be vulnerable to practical collision attacks and should not be relied upon to produce unique outputs, .Em nor should they be used as part of a cryptographic signature scheme. -As of 2017-03-02, there is no publicly known method to -.Em reverse -either algorithm, i.e., to find an input that produces a specific -output. .Pp SHA-512t256 is a version of SHA-512 truncated to only 256 bits. On 64-bit hardware, this algorithm is approximately 50% faster than SHA-256 but @@ -385,7 +388,8 @@ is printed instead of .Xr sha256 3 , .Xr sha384 3 , .Xr sha512 3 , -.Xr skein 3 +.Xr skein 3 , +.Xr vis 3 .Rs .%A R. Rivest .%T The MD5 Message-Digest Algorithm @@ -411,6 +415,16 @@ Secure Hash Standard (SHS): .Pp The RIPEMD-160 page: .Pa https://homes.esat.kuleuven.be/~bosselae/ripemd160.html +.Sh CAVEATS +The encoding used for file names containing non-printable characters +is incompatible with that used by GNU coreutils. +The encoding used by GNU coreutils is non-reversible, in that certain +non-printable characters are encoded while others are simply omitted. +The encoding used by this utility, on the other hand, is fully +reversible. +.Pp +If interoperability with GNU coreutils is required, it is recommended +to ensure that all file names contain only printable characters. .Sh BUGS In bits mode, the original .Nm shasum diff --git a/sbin/md5/md5.c b/sbin/md5/md5.c index b8afa736e229..6183dae93fdf 100644 --- a/sbin/md5/md5.c +++ b/sbin/md5/md5.c @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef HAVE_CAPSICUM #include @@ -315,6 +316,7 @@ gnu_check(const char *checksumsfile) const char *digestname; size_t digestnamelen; size_t hashstrlen; + size_t filenamelen; struct stat st; if (strcmp(checksumsfile, "-") == 0) @@ -344,12 +346,14 @@ gnu_check(const char *checksumsfile) strncmp(hashstr - 4, ") = ", 4) == 0 && strspn(hashstr, "0123456789ABCDEFabcdef") == hashstrlen) { *(hashstr - 4) = '\0'; + filenamelen = hashstr - 4 - filename; } else if ((size_t)linelen >= hashstrlen + 3 && strspn(linebuf, "0123456789ABCDEFabcdef") == hashstrlen && linebuf[hashstrlen] == ' ') { linebuf[hashstrlen] = '\0'; hashstr = linebuf; filename = linebuf + hashstrlen + 1; + filenamelen = linelen - hashstrlen - 1; } else { if (wflag) { warnx("%s: %d: improperly formatted " @@ -366,17 +370,23 @@ gnu_check(const char *checksumsfile) if ((*filename == '*' || *filename == ' ' || *filename == 'U' || *filename == '^') && - lstat(filename, &st) != 0 && - lstat(filename + 1, &st) == 0) { - rec->filename = strdup(filename + 1); + lstat(filename, &st) != 0) { rec->input_mode = (enum input_mode)*filename; + filename++; + filenamelen--; } else { - rec->filename = strdup(filename); rec->input_mode = input_mode; } + rec->filename = malloc(filenamelen + 1); + if (rec->filename == NULL) + errx(1, "malloc failed"); + if (strnunvis(rec->filename, filenamelen + 1, filename) < 0 || + (lstat(rec->filename, &st) != 0 && lstat(filename, &st) == 0)) + memcpy(rec->filename, filename, filenamelen + 1); // XXX + rec->chksum = strdup(hashstr); - if (rec->chksum == NULL || rec->filename == NULL) + if (rec->chksum == NULL) errx(1, "malloc failed"); rec->next = NULL; *next = rec; @@ -387,6 +397,15 @@ gnu_check(const char *checksumsfile) fclose(inp); } +static int +safename(char *namebuf, size_t bufsize, const char *name) +{ + int vis_mode = VIS_NL | VIS_TAB | VIS_GLOB | VIS_SHELL; + int vis_style = VIS_CSTYLE | VIS_OCTAL; + + return (strnvis(namebuf, bufsize, name, vis_mode | vis_style)); +} + /* Main driver. Arguments (may be any combination): @@ -634,7 +653,13 @@ main(int argc, char *argv[]) } if (f == NULL) { if (errno != ENOENT || !(cflag && ignoreMissing)) { - warn("%s", filename); + char namebuf[MAXPATHLEN * 4]; + int serrno = errno; + + if (safename(namebuf, sizeof(namebuf), filename) < 0) + warnc(ENAMETOOLONG, NULL); + else + warnc(serrno, "%s", namebuf); failed = true; } continue; @@ -764,8 +789,12 @@ MDInput(const Algorithm_t *alg, FILE *f, char *buf, bool tee) static void MDOutput(const Algorithm_t *alg, char *p, const char *name) { + char namebuf[MAXPATHLEN * 4]; bool checkfailed = false; + if (safename(namebuf, sizeof(namebuf), name) < 0) + errc(1, ENAMETOOLONG, NULL); + name = namebuf; if (p == NULL) { warn("%s", name); failed = true;