I was looking why the output of `md5 /compat/linux/proc/cpuinfo` is different from `cat /compat/linux/proc/cpuinfo | md5` and came across this code in sbin/md5/md5.c: ``` char block[4096]; ... while ((len = fread(block, 1, sizeof(block), f)) > 0) { ``` ``` The issue is a truncated read as confirmed by truss and GNU wc: ``` $ sudo truss md5 /compat/linux/proc/cpuinfo ... read(3,"processor\t: 0\nvendor_id\t: Gen"...,4096) = 3549 (0xddd) ... ``` It obviously affects all tools using libc when comparing the output of wc vs. GNU wc: ``` $ wc -m /compat/linux/proc/cpuinfo 3549 /compat/linux/proc/cpuinfo $ gwc -m /compat/linux/proc/cpuinfo 3685 /compat/linux/proc/cpuinfo ```
Could you please provide minimal C repro? It is not clear to me in what way read(2) from stdio (fread(3)) is different from read(2) issued by gnu wc.
I figured out the problematic code at: ``` /* * XXX Enter capability mode on the last argv file. * When a casper file service or other approach is * available, switch to that and enter capability mode * earlier. */ if (*(argv + 1) == NULL) { #ifdef HAVE_CAPSICUM cap_rights_init(&rights, CAP_READ, CAP_FSTAT); if (caph_rights_limit(fileno(f), &rights) < 0 || caph_enter() < 0) err(1, "capsicum"); #endif } ``` So md5 works if I pass /dev/null as the last argument: $ md5 /compat/linux/proc/cpuinfo MD5 (/compat/linux/proc/cpuinfo) = 36966b53dc9e57113b2b7637d8b51720 $ md5 /compat/linux/proc/cpuinfo /dev/null MD5 (/compat/linux/proc/cpuinfo) = 142e18c701aa58b0e691920e2bf98e56 MD5 (/dev/null) = d41d8cd98f00b204e9800998ecf8427e
Adding `#undef HAVE_CAPSICUM` fixed it for me.
As for wc(1), it's another story as it calls stat(1) and just shows st_size if S_ISREG(). I will suggest a patch soon.
(In reply to Ricardo Branco from comment #4) wc(1) also fails because of capsicum as this patch is not enough: ``` - if (S_ISREG(sb.st_mode)) { + /* Don't do it on pseudo-filesystems that advertize a zero size */ + if (S_ISREG(sb.st_mode) && sb.st_size > 0) { ``` It now returns the result of a truncated read: ``` $ /usr/obj/usr/src/amd64.amd64/usr.bin/wc/wc -m /compat/linux/proc/cpuinfo 3549 /compat/linux/proc/cpuinfo ```
(In reply to Ricardo Branco from comment #5) The problem is mostly specific to cpuinfo. The handler calls kernel_sysctl() to read the HW_MODEL sysctl (I guess because cpu_model[] is static?), and that's not permitted in capability mode. Probably the best solution is to simply permit reading HW_MODEL in capability mode.
In particular, the file is legitimately different when read from within a capsicum sandbox: > model name : AMD Ryzen 9 7950X3D 16-Core Processor 655c655 < model name : unknown so the difference in output is "expected".
If you are able and willing to test a kernel patch, please give this a try: https://reviews.freebsd.org/D43281
(In reply to Mark Johnston from comment #8) I tested the patch and it works. Please don't close this bug until https://github.com/freebsd/freebsd-src/pull/984#issuecomment-1874667265 is addressed. Cheers, R
(In reply to Ricardo Branco from comment #9) Thanks! Do you plan to work on the md5 issue?
(In reply to Mark Johnston from comment #10) Yes.
Hopefully fixed by https://github.com/freebsd/freebsd-src/pull/988
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=d74a742704eb81f0c6f4aa83e4cb0de26a81c400 commit d74a742704eb81f0c6f4aa83e4cb0de26a81c400 Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2024-01-04 13:25:05 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2024-01-04 13:39:53 +0000 linprocfs: Avoid using a sysctl to get the CPU model string This will fail if the reading process is in capability mode. Just copy the string directly. PR: 276043 Reviewed by: emaste, imp, kib Reported and tested by: Ricardo Branco <rbranco@suse.com> MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D43281 sys/compat/linprocfs/linprocfs.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
A commit in branch stable/14 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=b2dfbd772e887d722da0aad1ea9c1ce14e65f47d commit b2dfbd772e887d722da0aad1ea9c1ce14e65f47d Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2024-01-04 13:25:05 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2024-01-11 14:19:07 +0000 linprocfs: Avoid using a sysctl to get the CPU model string This will fail if the reading process is in capability mode. Just copy the string directly. PR: 276043 Reviewed by: emaste, imp, kib Reported and tested by: Ricardo Branco <rbranco@suse.com> MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D43281 (cherry picked from commit d74a742704eb81f0c6f4aa83e4cb0de26a81c400) sys/compat/linprocfs/linprocfs.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=e3212b779ae2938428e087ac05c52e484cf2a6c2 commit e3212b779ae2938428e087ac05c52e484cf2a6c2 Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2024-01-04 13:25:05 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2024-01-11 14:33:15 +0000 linprocfs: Avoid using a sysctl to get the CPU model string This will fail if the reading process is in capability mode. Just copy the string directly. PR: 276043 Reviewed by: emaste, imp, kib Reported and tested by: Ricardo Branco <rbranco@suse.com> MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D43281 (cherry picked from commit d74a742704eb81f0c6f4aa83e4cb0de26a81c400) sys/compat/linprocfs/linprocfs.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
Kind remind that the issue is not solved until a fix like https://github.com/freebsd/freebsd-src/pull/984#issuecomment-1874667265 is merged. Do I create another bug or reopen this one?
Sorry I meant this fix: https://github.com/freebsd/freebsd-src/pull/988
My PR was merged. I wish to thank everyone involved in the resolution of this bug. The unlikely coincidence of a restricted path as the last argument made me research & fix like 3 or 4 other bugs related to some tools not being able to read files in procfs.