NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
bin/58876: mtree: Produces a different checksum when verifying
>Number: 58876
>Category: bin
>Synopsis: mtree: Produces a different checksum when verifying
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Dec 05 16:40:02 +0000 2024
>Originator: Jose Luis Duran
>Release: Not applicable to NetBSD
>Organization:
FreeBSD
>Environment:
NOTE: This bug is not present on NetBSD, only on FreeBSD. FreeBSD uses mtree from NetBSD.
>Description:
A bug report was opened[^1] stating that a user following the procedure described in the FreeBSD handbook[^2] to generate and verify an mtree-based specification file produced non-matching checksums. Everything is working fine, except that the output produces two different checksums.
Prior to FreeBSD using NetBSD's mtree, a commit fixed this issue[^3]. This fix is not present on NetBSD, as the issue is not manifested on NetBSD.
[^1]: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=231072
[^2]: https://docs.freebsd.org/en/books/handbook/security/#security-ids-generate-spec-file
[^3]: https://cgit.freebsd.org/src/commit/?id=afe54b5818317b574a1b4b0f88c1643efc2c8da2
>How-To-Repeat:
On FreeBSD:
# mtree -s 123456789 -c -K cksum,sha512 -p /bin > /home/user/.bin_chksum_mtree
mtree: /bin checksum: 1461382254
# mtree -s 123456789 -p /bin < /home/user/.bin_chksum_mtree >> /home/user/.bin_chksum_output
mtree: /bin checksum: 3158826036
The resulting file is empty (there is no mismatch), however the checksum is different.
>Fix:
Use a fix similar to the one proposed in the pull request, rather than the original FreeBSD fix, as I *think* it blends better with the current code, but feel free to re-arrange it as you see fit.
The idea is to traverse the existing directory tree in lexical order, to allow a direct comparison between different runs regardless of the order of what readdir(3) returns.
Move dcmp() next to nodecmp(), as these two functions go hand-in-hand, and pass it as the compar() argument to fts_open(3) in vwalk(), just like in cwalk().
The proposed patch is attached:
Subject: [PATCH] mtree: Traverse in lexical order
When applying a spec, traverse the existing directory tree in lexical
order. This allows a direct comparison between the output of two
different runs, regardless of the order in which readdir(3) returns
directory entries.
FreeBSD PR: 231072
---
usr.sbin/mtree/create.c | 28 ----------------------------
usr.sbin/mtree/extern.h | 7 +++++++
usr.sbin/mtree/spec.c | 21 +++++++++++++++++++++
usr.sbin/mtree/verify.c | 2 +-
4 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/usr.sbin/mtree/create.c b/usr.sbin/mtree/create.c
index bb5d2f21ad80..4962b51050ec 100644
--- a/usr.sbin/mtree/create.c
+++ b/usr.sbin/mtree/create.c
@@ -84,13 +84,6 @@ static uid_t uid;
static mode_t mode;
static u_long flags;
-#if defined(__FreeBSD__) && !defined(HAVE_NBTOOL_CONFIG_H)
-#define FTS_CONST const
-#else
-#define FTS_CONST
-#endif
-
-static int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
static void output(FILE *, int, int *, const char *, ...)
__printflike(4, 5);
static int statd(FILE *, FTS *, FTSENT *, uid_t *, gid_t *, mode_t *,
@@ -444,27 +437,6 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode,
return (0);
}
-/*
- * dcmp --
- * used as a comparison function passed to fts_open() to control
- * the order in which fts_read() returns results. We make
- * directories sort after non-directories, but otherwise sort in
- * strcmp() order.
- *
- * Keep this in sync with nodecmp() in spec.c.
- */
-static int
-dcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *b)
-{
-
- if (S_ISDIR((*a)->fts_statp->st_mode)) {
- if (!S_ISDIR((*b)->fts_statp->st_mode))
- return (1);
- } else if (S_ISDIR((*b)->fts_statp->st_mode))
- return (-1);
- return (strcmp((*a)->fts_name, (*b)->fts_name));
-}
-
void
output(FILE *fp, int indent, int *offset, const char *fmt, ...)
{
diff --git a/usr.sbin/mtree/extern.h b/usr.sbin/mtree/extern.h
index da34e99f1a9a..bb82bd19f8bd 100644
--- a/usr.sbin/mtree/extern.h
+++ b/usr.sbin/mtree/extern.h
@@ -49,6 +49,12 @@
#include <netdb.h>
#endif
+#if defined(__FreeBSD__) && !defined(HAVE_NBTOOL_CONFIG_H)
+#define FTS_CONST const
+#else
+#define FTS_CONST
+#endif
+
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
@@ -64,6 +70,7 @@ int check_excludes(const char *, const char *);
int compare(NODE *, FTSENT *);
int crc(int, uint32_t *, uint32_t *);
void cwalk(FILE *);
+int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
void dump_nodes(FILE *, const char *, NODE *, int);
void init_excludes(void);
int matchtags(NODE *);
diff --git a/usr.sbin/mtree/spec.c b/usr.sbin/mtree/spec.c
index 25eac4b55ade..045fcea55ccb 100644
--- a/usr.sbin/mtree/spec.c
+++ b/usr.sbin/mtree/spec.c
@@ -855,3 +855,24 @@ nodecmp(const NODE *a, const NODE *b)
return -1;
return strcmp(a->name, b->name);
}
+
+/*
+ * dcmp --
+ * used as a comparison function passed to fts_open() to control
+ * the order in which fts_read() returns results. We make
+ * directories sort after non-directories, but otherwise sort in
+ * strcmp() order.
+ *
+ * Keep this in sync with nodecmp() above.
+ */
+int
+dcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *b)
+{
+
+ if (S_ISDIR((*a)->fts_statp->st_mode)) {
+ if (!S_ISDIR((*b)->fts_statp->st_mode))
+ return (1);
+ } else if (S_ISDIR((*b)->fts_statp->st_mode))
+ return (-1);
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/mtree/verify.c
index 2430fb1b8066..520a329006ba 100644
--- a/usr.sbin/mtree/verify.c
+++ b/usr.sbin/mtree/verify.c
@@ -86,7 +86,7 @@ vwalk(void)
argv[0] = dot;
argv[1] = NULL;
- if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
+ if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL)
mtree_err("fts_open: %s", strerror(errno));
level = root;
specdepth = rval = 0;
--
Jose Luis Duran
Home |
Main Index |
Thread Index |
Old Index