git: d1a465f02b14 - main - jailmeta: reject empty keys in metadata lookups
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 30 Oct 2026 21:53:24 UTC
The branch main has been updated by igoro:
URL: https://cgit.FreeBSD.org/src/commit/?id=d1a465f02b14c9eed8a87c31092bb9251dc053c1
commit d1a465f02b14c9eed8a87c31092bb9251dc053c1
Author: Yura Tkachenko <yura.tkachenko@gmail.com>
AuthorDate: 2026-10-30 20:20:24 +0000
Commit: Igor Ostapenko <igoro@FreeBSD.org>
CommitDate: 2026-10-30 21:45:43 +0000
jailmeta: reject empty keys in metadata lookups
Reject empty keys in metadata lookups with EINVAL to prevent an infinite
loop while holding allprison_lock and pr_mtx. Add tests for empty-key
reads and writes with empty and populated meta/env buffers, trailing
newlines, and empty final values.
Reviewed by: igoro, jamie
MFC after: 3 days
Differential Revision: https://reviews.freebsd.org/D61025
---
sys/kern/kern_jailmeta.c | 4 ++++
tests/sys/kern/jailmeta.sh | 28 ++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/sys/kern/kern_jailmeta.c b/sys/kern/kern_jailmeta.c
index 91bb7155820d..83d773ca6caa 100644
--- a/sys/kern/kern_jailmeta.c
+++ b/sys/kern/kern_jailmeta.c
@@ -436,6 +436,10 @@ jm_osd_method_get(void *obj, void *data, const struct meta *meta)
p = osd;
key = opt->name + strlen(meta->name) + 1;
keylen = strlen(key);
+ if (keylen < 1) {
+ error = EINVAL;
+ break;
+ }
while ((p = strstr(p, key)) != NULL) {
if ((p == osd || *(p - 1) == '\n')
&& p[keylen] == '=') {
diff --git a/tests/sys/kern/jailmeta.sh b/tests/sys/kern/jailmeta.sh
index f030e44b14c3..236690ffddcb 100644
--- a/tests/sys/kern/jailmeta.sh
+++ b/tests/sys/kern/jailmeta.sh
@@ -397,12 +397,28 @@ keyvalue_generic()
atf_check -sexit:0 -oinline:'""\n' jls -jj $meta
+ # Reject empty keys even when the metadata buffer is empty.
+ atf_check -s exit:1 -o empty -e match:'Invalid argument' \
+ jls -jj "${meta}."
+ atf_check -s exit:1 -o empty -e match:'Invalid argument' \
+ jail -m name=j "${meta}.=value"
+ atf_check -s exit:0 -o inline:'""\n' jls -jj "$meta"
+
# Note: each sub-case depends on the results of the previous ones
# Should be able to extract a key added manually
atf_check -sexit:0 jail -m name=j $meta="a=1"
atf_check -sexit:0 -oinline:'a=1\n' jls -jj $meta
atf_check -sexit:0 -oinline:'1\n' jls -jj $meta.a
+
+ # Reject empty keys with populated metadata; failed writes preserve it.
+ atf_check -s exit:1 -o empty -e match:'Invalid argument' \
+ jls -jj "${meta}."
+ atf_check -s exit:1 -o empty -e match:'Invalid argument' \
+ jail -m name=j "${meta}.=value"
+ atf_check -s exit:0 -o inline:'a=1\n' jls -jj "$meta"
+ atf_check -s exit:0 -o inline:'1\n' jls -jj "${meta}.a"
+
atf_check -sexit:0 jail -m name=j $meta="$(printf 'a=2\nb=3')"
atf_check -sexit:0 -oinline:'a=2\nb=3\n' jls -jj $meta
atf_check -sexit:0 -oinline:'2\n' jls -jj $meta.a
@@ -492,6 +508,18 @@ keyvalue_generic()
# Should respectively support "jls -s" for a missing key
atf_check -sexit:0 -oinline:''$meta'.missing\n' jls -jj -s $meta.missing
+
+ # Preserve the trailing newline despite command substitution.
+ local value
+ value=$(printf 'a=1\nb=2\n.')
+ value=${value%.}
+ atf_check -s exit:0 jail -m name=j "${meta}=$value"
+ atf_check -s exit:0 -o inline:'1\n' jls -jj "${meta}.a"
+ atf_check -s exit:0 -o inline:'2\n' jls -jj "${meta}.b"
+
+ # An empty value on the final line needs only its terminating NUL.
+ atf_check -s exit:0 jail -m name=j "${meta}=a="
+ atf_check -s exit:0 -o inline:'""\n' jls -jj "${meta}.a"
}
keyvalue_body()
{