1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2024 SkunkWerks GmbH 5# 6# This software was developed by Igor Ostapenko <igoro@FreeBSD.org> 7# under sponsorship from SkunkWerks GmbH. 8# 9 10setup() 11{ 12 # Check if we have enough buffer space for testing 13 if [ $(sysctl -n security.jail.meta_maxbufsize) -lt 128 ]; then 14 atf_skip "sysctl security.jail.meta_maxbufsize must be 128+ for testing." 15 fi 16} 17 18atf_test_case "jail_create" "cleanup" 19jail_create_head() 20{ 21 atf_set descr 'Test that metadata can be set upon jail creation with jail(8)' 22 atf_set require.user root 23 atf_set execenv jail 24} 25jail_create_body() 26{ 27 setup 28 29 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 30 jls -jj 31 32 atf_check -s exit:0 \ 33 jail -c name=j persist meta="a b c" env="C B A" 34 35 atf_check -s exit:0 -o inline:"a b c\n" \ 36 jls -jj meta 37 atf_check -s exit:0 -o inline:"C B A\n" \ 38 jls -jj env 39} 40jail_create_cleanup() 41{ 42 jail -r j 43 return 0 44} 45 46atf_test_case "jail_modify" "cleanup" 47jail_modify_head() 48{ 49 atf_set descr 'Test that metadata can be modified after jail creation with jail(8)' 50 atf_set require.user root 51 atf_set execenv jail 52} 53jail_modify_body() 54{ 55 setup 56 57 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 58 jls -jj 59 60 atf_check -s exit:0 \ 61 jail -c name=j persist meta="a b c" env="CAB" 62 63 atf_check -s exit:0 -o inline:"a b c\n" \ 64 jls -jj meta 65 atf_check -s exit:0 -o inline:"CAB\n" \ 66 jls -jj env 67 68 atf_check -s exit:0 \ 69 jail -m name=j meta="t1=A t2=B" env="CAB2" 70 71 atf_check -s exit:0 -o inline:"t1=A t2=B\n" \ 72 jls -jj meta 73 atf_check -s exit:0 -o inline:"CAB2\n" \ 74 jls -jj env 75} 76jail_modify_cleanup() 77{ 78 jail -r j 79 return 0 80} 81 82atf_test_case "jail_add" "cleanup" 83jail_add_head() 84{ 85 atf_set descr 'Test that metadata can be added to an existing jail with jail(8)' 86 atf_set require.user root 87 atf_set execenv jail 88} 89jail_add_body() 90{ 91 setup 92 93 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 94 jls -jj 95 96 atf_check -s exit:0 \ 97 jail -c name=j persist host.hostname=jail1 98 99 atf_check -s exit:0 -o inline:'""\n' \ 100 jls -jj meta 101 atf_check -s exit:0 -o inline:'""\n' \ 102 jls -jj env 103 104 atf_check -s exit:0 \ 105 jail -m name=j meta="$(jot 3 1 3)" env="$(jot 2 11 12)" 106 107 atf_check -s exit:0 -o inline:"1\n2\n3\n" \ 108 jls -jj meta 109 atf_check -s exit:0 -o inline:"11\n12\n" \ 110 jls -jj env 111} 112jail_add_cleanup() 113{ 114 jail -r j 115 return 0 116} 117 118atf_test_case "jail_reset" "cleanup" 119jail_reset_head() 120{ 121 atf_set descr 'Test that metadata can be reset to an empty string with jail(8)' 122 atf_set require.user root 123 atf_set execenv jail 124} 125jail_reset_body() 126{ 127 setup 128 129 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 130 jls -jj 131 132 atf_check -s exit:0 \ 133 jail -c name=j persist meta="123" env="456" 134 135 atf_check -s exit:0 -o inline:"123\n" \ 136 jls -jj meta 137 atf_check -s exit:0 -o inline:"456\n" \ 138 jls -jj env 139 140 atf_check -s exit:0 \ 141 jail -m name=j meta= env= 142 143 atf_check -s exit:0 -o inline:'""\n' \ 144 jls -jj meta 145 atf_check -s exit:0 -o inline:'""\n' \ 146 jls -jj env 147} 148jail_reset_cleanup() 149{ 150 jail -r j 151 return 0 152} 153 154atf_test_case "jls_libxo_json" "cleanup" 155jls_libxo_json_head() 156{ 157 atf_set descr 'Test that metadata can be read with jls(8) using libxo JSON' 158 atf_set require.user root 159 atf_set execenv jail 160} 161jls_libxo_json_body() 162{ 163 setup 164 165 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 166 jls -jj 167 168 atf_check -s exit:0 \ 169 jail -c name=j persist meta="a b c" env="1 2 3" 170 171 atf_check -s exit:0 -o inline:'{"__version": "2", "jail-information": {"jail": [{"name":"j","meta":"a b c"}]}}\n' \ 172 jls -jj --libxo json name meta 173 atf_check -s exit:0 -o inline:'{"__version": "2", "jail-information": {"jail": [{"env":"1 2 3"}]}}\n' \ 174 jls -jj --libxo json env 175} 176jls_libxo_json_cleanup() 177{ 178 jail -r j 179 return 0 180} 181 182atf_test_case "flua_create" "cleanup" 183flua_create_head() 184{ 185 atf_set descr 'Test that metadata can be set upon jail creation with flua' 186 atf_set require.user root 187 atf_set execenv jail 188} 189flua_create_body() 190{ 191 setup 192 193 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 194 jls -jj 195 196 atf_check -s exit:0 \ 197 /usr/libexec/flua -ljail -e 'jail.setparams("j", {["meta"]="t1 t2=v2", ["env"]="BAC", ["persist"]="true"}, jail.CREATE)' 198 199 atf_check -s exit:0 -o inline:"t1 t2=v2\n" \ 200 /usr/libexec/flua -ljail -e 'jid, res = jail.getparams("j", {"meta"}); print(res["meta"])' 201 atf_check -s exit:0 -o inline:"BAC\n" \ 202 /usr/libexec/flua -ljail -e 'jid, res = jail.getparams("j", {"env"}); print(res["env"])' 203} 204flua_create_cleanup() 205{ 206 jail -r j 207 return 0 208} 209 210atf_test_case "flua_modify" "cleanup" 211flua_modify_head() 212{ 213 atf_set descr 'Test that metadata can be changed with flua after jail creation' 214 atf_set require.user root 215 atf_set execenv jail 216} 217flua_modify_body() 218{ 219 setup 220 221 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 222 jls -jj 223 224 atf_check -s exit:0 \ 225 jail -c name=j persist meta="ABC" env="123" 226 227 atf_check -s exit:0 -o inline:"ABC\n" \ 228 jls -jj meta 229 atf_check -s exit:0 -o inline:"123\n" \ 230 jls -jj env 231 232 atf_check -s exit:0 \ 233 /usr/libexec/flua -ljail -e 'jail.setparams("j", {["meta"]="t1 t2=v", ["env"]="4"}, jail.UPDATE)' 234 235 atf_check -s exit:0 -o inline:"t1 t2=v\n" \ 236 jls -jj meta 237 atf_check -s exit:0 -o inline:"4\n" \ 238 jls -jj env 239} 240flua_modify_cleanup() 241{ 242 jail -r j 243 return 0 244} 245 246atf_test_case "env_readable_by_jail" "cleanup" 247env_readable_by_jail_head() 248{ 249 atf_set descr 'Test that a jail can read its own env parameter via sysctl(8)' 250 atf_set require.user root 251 atf_set execenv jail 252} 253env_readable_by_jail_body() 254{ 255 setup 256 257 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 258 jls -jj 259 260 atf_check -s exit:0 \ 261 jail -c name=j persist meta="a b c" env="CBA" 262 263 atf_check -s exit:0 -o inline:"a b c\n" \ 264 jls -jj meta 265 atf_check -s exit:0 -o inline:"CBA\n" \ 266 jls -jj env 267 268 atf_check -s exit:0 -o inline:"CBA\n" \ 269 jexec j sysctl -n security.jail.env 270} 271env_readable_by_jail_cleanup() 272{ 273 jail -r j 274 return 0 275} 276 277atf_test_case "not_inheritable" "cleanup" 278not_inheritable_head() 279{ 280 atf_set descr 'Test that a jail does not inherit metadata from its parent jail' 281 atf_set require.user root 282 atf_set execenv jail 283} 284not_inheritable_body() 285{ 286 setup 287 288 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 289 jls -j parent 290 291 atf_check -s exit:0 \ 292 jail -c name=parent children.max=1 persist meta="abc" env="cba" 293 294 jexec parent jail -c name=child persist 295 296 atf_check -s exit:0 -o inline:"abc\n" \ 297 jls -j parent meta 298 atf_check -s exit:0 -o inline:'""\n' \ 299 jls -j parent.child meta 300 301 atf_check -s exit:0 -o inline:"cba\n" \ 302 jexec parent sysctl -n security.jail.env 303 atf_check -s exit:0 -o inline:"\n" \ 304 jexec parent.child sysctl -n security.jail.env 305} 306not_inheritable_cleanup() 307{ 308 jail -r parent.child 309 jail -r parent 310 return 0 311} 312 313atf_test_case "maxbufsize" "cleanup" 314maxbufsize_head() 315{ 316 atf_set descr 'Test that metadata buffer maximum size can be changed' 317 atf_set require.user root 318 atf_set is.exclusive true 319} 320maxbufsize_body() 321{ 322 setup 323 324 jn=jailmeta_maxbufsize 325 326 atf_check -s not-exit:0 -e match:"not found" -o ignore \ 327 jls -j $jn 328 329 # the size counts string length and the trailing \0 char 330 origmax=$(sysctl -n security.jail.meta_maxbufsize) 331 332 # must be fine with current max 333 atf_check -s exit:0 \ 334 jail -c name=$jn persist meta="$(printf %$((origmax-1))s)" 335 atf_check -s exit:0 -o inline:"${origmax}\n" \ 336 jls -j $jn meta | wc -c 337 # 338 atf_check -s exit:0 \ 339 jail -m name=$jn env="$(printf %$((origmax-1))s)" 340 atf_check -s exit:0 -o inline:"${origmax}\n" \ 341 jls -j $jn env | wc -c 342 343 # should not allow exceeding current max 344 atf_check -s not-exit:0 -e match:"too large" \ 345 jail -m name=$jn meta="$(printf %${origmax}s)" 346 # 347 atf_check -s not-exit:0 -e match:"too large" \ 348 jail -m name=$jn env="$(printf %${origmax}s)" 349 350 # should allow the same size with increased max 351 newmax=$((origmax + 1)) 352 sysctl security.jail.meta_maxbufsize=$newmax 353 atf_check -s exit:0 \ 354 jail -m name=$jn meta="$(printf %${origmax}s)" 355 atf_check -s exit:0 -o inline:"${origmax}\n" \ 356 jls -j $jn meta | wc -c 357 # 358 atf_check -s exit:0 \ 359 jail -m name=$jn env="$(printf %${origmax}s)" 360 atf_check -s exit:0 -o inline:"${origmax}\n" \ 361 jls -j $jn env | wc -c 362 363 # decrease back to the original max 364 sysctl security.jail.meta_maxbufsize=$origmax 365 atf_check -s not-exit:0 -e match:"too large" \ 366 jail -m name=$jn meta="$(printf %${origmax}s)" 367 # 368 atf_check -s not-exit:0 -e match:"too large" \ 369 jail -m name=$jn env="$(printf %${origmax}s)" 370 371 # the previously set long meta is still readable as is 372 # due to the soft limit remains higher than the hard limit 373 atf_check_equal '${newmax}' '$(sysctl -n security.jail.param.meta)' 374 atf_check_equal '${newmax}' '$(sysctl -n security.jail.param.env)' 375 atf_check -s exit:0 -o inline:"${origmax}\n" \ 376 jls -j $jn meta | wc -c 377 # 378 atf_check -s exit:0 -o inline:"${origmax}\n" \ 379 jls -j $jn env | wc -c 380} 381maxbufsize_cleanup() 382{ 383 jail -r jailmeta_maxbufsize 384 return 0 385} 386 387atf_test_case "keyvalue" "cleanup" 388keyvalue_head() 389{ 390 atf_set descr 'Test that metadata can be handled as a set of key=value\n strings using jail(8), jls(8), and flua' 391 atf_set require.user root 392 atf_set execenv jail 393} 394keyvalue_generic() 395{ 396 local meta=$1 397 398 atf_check -sexit:0 -oinline:'""\n' jls -jj $meta 399 400 # Note: each sub-case depends on the results of the previous ones 401 402 # Should be able to extract a key added manually 403 atf_check -sexit:0 jail -m name=j $meta="a=1" 404 atf_check -sexit:0 -oinline:'a=1\n' jls -jj $meta 405 atf_check -sexit:0 -oinline:'1\n' jls -jj $meta.a 406 atf_check -sexit:0 jail -m name=j $meta="$(printf 'a=2\nb=3')" 407 atf_check -sexit:0 -oinline:'a=2\nb=3\n' jls -jj $meta 408 atf_check -sexit:0 -oinline:'2\n' jls -jj $meta.a 409 atf_check -sexit:0 -oinline:'3\n' jls -jj $meta.b 410 411 # Should provide nothing for a non-found key 412 atf_check -sexit:0 -oinline:'\n' jls -jj $meta.c 413 414 # Should be able to lookup multiple keys at once 415 atf_check -sexit:0 -oinline:'3 2\n' jls -jj $meta.b $meta.a 416 417 # Should be able to lookup keys and the whole buffer at once 418 atf_check -sexit:0 -oinline:'3 a=2\nb=3 2\n' jls -jj $meta.b $meta $meta.a 419 420 # Should be able to lookup a key using libxo-based JSON output 421 s='{"__version": "2", "jail-information": {"jail": [{"'$meta'.b":"3"}]}}\n' 422 atf_check -s exit:0 -o inline:"$s" jls -jj --libxo json $meta.b 423 424 # Should provide nothing for a non-found key using libxo-based JSON output 425 s='{"__version": "2", "jail-information": {"jail": [{}]}}\n' 426 atf_check -s exit:0 -o inline:"$s" jls -jj --libxo json $meta.c $meta.d 427 428 # Should be able to lookup a key using flua 429 atf_check -s exit:0 -o inline:"2\n" \ 430 /usr/libexec/flua -ljail -e 'jid, res = jail.getparams("j", {"'$meta'.a"}); print(res["'$meta'.a"])' 431 432 # Should provide nil for a non-found key using flua 433 atf_check -s exit:0 -o inline:"true\n" \ 434 /usr/libexec/flua -ljail -e 'jid, res = jail.getparams("j", {"'$meta'.meta"}); print(res["'$meta'.meta"] == nil)' 435 436 # Should allow resetting a buffer 437 atf_check -sexit:0 jail -m name=j $meta= 438 atf_check -sexit:0 -oinline:' "" \n' jls -jj $meta.c $meta $meta.a 439 440 # Should allow adding a new key 441 atf_check -sexit:0 jail -m name=j $meta.a=1 442 atf_check -sexit:0 -oinline:'1\n' jls -jj $meta.a 443 atf_check -sexit:0 -oinline:'a=1\n' jls -jj $meta 444 445 # Should allow adding multiple new keys at once 446 atf_check -sexit:0 jail -m name=j $meta.c=3 $meta.b=2 447 atf_check -sexit:0 -oinline:'3\n' jls -jj $meta.c 448 atf_check -sexit:0 -oinline:'2\n' jls -jj $meta.b 449 atf_check -sexit:0 -oinline:'b=2\nc=3\na=1\n' jls -jj $meta 450 451 # Should replace existing keys 452 atf_check -sexit:0 jail -m name=j $meta.a=A $meta.c=C 453 atf_check -sexit:0 -oinline:'A\n' jls -jj $meta.a 454 atf_check -sexit:0 -oinline:'C\n' jls -jj $meta.c 455 atf_check -sexit:0 -oinline:'c=C\na=A\nb=2\n' jls -jj $meta 456 457 # Should treat empty value correctly 458 atf_check -sexit:0 jail -m name=j $meta.a= 459 atf_check -sexit:0 -oinline:'""\n' jls -jj $meta.a 460 atf_check -sexit:0 -oinline:'a=\nc=C\nb=2\n' jls -jj $meta 461 462 # Should treat NULL value as a key removal 463 atf_check -sexit:0 -oinline:'2\n' jls -jj $meta.b 464 atf_check -sexit:0 jail -m name=j $meta.b 465 atf_check -sexit:0 -oinline:'\n' jls -jj $meta.b 466 atf_check -sexit:0 -oinline:'a=\nc=C\n' jls -jj $meta 467 468 # Should allow changing the whole buffer and per key at once (order matters) 469 atf_check -sexit:0 jail -m name=j $meta.a=1 $meta=ttt $meta.b=2 470 atf_check -sexit:0 -oinline:'\n' jls -jj $meta.a 471 atf_check -sexit:0 -oinline:'2\n' jls -jj $meta.b 472 atf_check -sexit:0 -oinline:'b=2\nttt\n' jls -jj $meta 473 474 # Should treat only the first equal sign as syntax 475 atf_check -sexit:0 jail -m name=j $meta.b== 476 atf_check -sexit:0 -oinline:'=\n' jls -jj $meta.b 477 atf_check -sexit:0 -oinline:'b==\nttt\n' jls -jj $meta 478 479 # Should allow adding or modifying keys using flua 480 atf_check -s exit:0 \ 481 /usr/libexec/flua -ljail -e 'jail.setparams("j", {["'$meta.b'"]="ttt", ["'$meta'.c"]="C"}, jail.UPDATE)' 482 atf_check -sexit:0 -oinline:'ttt\n' jls -jj $meta.b 483 atf_check -sexit:0 -oinline:'C\n' jls -jj $meta.c 484 485 # Should allow key removal using flua 486 atf_check -s exit:0 \ 487 /usr/libexec/flua -ljail -e 'jail.setparams("j", {["'$meta.c'"] = {}}, jail.UPDATE)' 488 atf_check -sexit:0 -oinline:'\n' jls -jj $meta.c 489 atf_check -s exit:0 \ 490 /usr/libexec/flua -ljail -e 'jail.setparams("j", {["'$meta.b'"] = false}, jail.UPDATE)' 491 atf_check -sexit:0 -oinline:'\n' jls -jj $meta.b 492 493 # Should respectively support "jls -s" for a missing key 494 atf_check -sexit:0 -oinline:''$meta'.missing\n' jls -jj -s $meta.missing 495} 496keyvalue_body() 497{ 498 setup 499 500 atf_check -s exit:0 \ 501 jail -c name=j persist meta env 502 503 keyvalue_generic "meta" 504 keyvalue_generic "env" 505} 506keyvalue_cleanup() 507{ 508 jail -r j 509 return 0 510} 511 512atf_test_case "keyvalue_contention" "cleanup" 513keyvalue_contention_head() 514{ 515 atf_set descr 'Try to stress metadata read/write mechanism with some contention' 516 atf_set require.user root 517 atf_set execenv jail 518 atf_set timeout 30 519} 520keyvalue_stresser() 521{ 522 local jailname=$1 523 local modifier=$2 524 525 while true 526 do 527 jail -m name=$jailname $modifier 528 done 529} 530keyvalue_contention_body() 531{ 532 setup 533 534 atf_check -s exit:0 jail -c name=j persist meta env 535 536 keyvalue_stresser "j" "meta.a=1" & 537 apid=$! 538 keyvalue_stresser "j" "meta.b=2" & 539 bpid=$! 540 keyvalue_stresser "j" "env.c=3" & 541 cpid=$! 542 keyvalue_stresser "j" "env.d=4" & 543 dpid=$! 544 545 for it in $(jot 8) 546 do 547 jail -m name=j meta='meta=META' env='env=ENV' 548 sleep 1 549 atf_check -sexit:0 -oinline:'1\n' jls -jj meta.a 550 atf_check -sexit:0 -oinline:'2\n' jls -jj meta.b 551 atf_check -sexit:0 -oinline:'3\n' jls -jj env.c 552 atf_check -sexit:0 -oinline:'4\n' jls -jj env.d 553 atf_check -sexit:0 -oinline:'META\n' jls -jj meta.meta 554 atf_check -sexit:0 -oinline:'ENV\n' jls -jj env.env 555 done 556 557 # TODO: Think of adding a stresser on the kernel side which does 558 # osd_set() w/o allprison lock. It could test the compare 559 # and swap mechanism in jm_osd_method_set(). 560 561 kill -9 $apid $bpid $cpid $dpid 562} 563keyvalue_contention_cleanup() 564{ 565 jail -r j 566 return 0 567} 568 569atf_init_test_cases() 570{ 571 atf_add_test_case "jail_create" 572 atf_add_test_case "jail_modify" 573 atf_add_test_case "jail_add" 574 atf_add_test_case "jail_reset" 575 576 atf_add_test_case "jls_libxo_json" 577 578 atf_add_test_case "flua_create" 579 atf_add_test_case "flua_modify" 580 581 atf_add_test_case "env_readable_by_jail" 582 atf_add_test_case "not_inheritable" 583 584 atf_add_test_case "maxbufsize" 585 586 atf_add_test_case "keyvalue" 587 atf_add_test_case "keyvalue_contention" 588} 589