-
-
Save Freaky/2560975d3c94246b86f464b8be75c967 to your computer and use it in GitHub Desktop.
| #!/bin/sh | |
| # | |
| # PROVIDE: zenbleed_workaround | |
| # REQUIRE: root mountcritlocal microcode_update | |
| # BEFORE: SERVERS | |
| # KEYWORD: nojail resume | |
| # Source: https://gist.github.com/Freaky/2560975d3c94246b86f464b8be75c967 | |
| # | |
| # Copyright (c) 2023 Thomas Hurst <[email protected]> | |
| # License: https://opensource.org/license/mit/ | |
| . /etc/rc.subr | |
| name="zenbleed_workaround" | |
| desc="Zenbleed MSR chicken bit workaround" | |
| rcvar="zenbleed_workaround_enable" | |
| extra_commands="resume" | |
| start_precmd="check_zen2" | |
| resume_precmd="${start_precmd}" | |
| stop_precmd="${start_precmd}" | |
| start_cmd="workaround_zenbleed" | |
| resume_cmd="${start_cmd}" | |
| stop_cmd="restore_zenbleed" | |
| load_rc_config "${name}" | |
| : "${zenbleed_workaround_enable:=NO}" | |
| CPUCTL="/usr/sbin/cpucontrol" | |
| check_zen2() { | |
| if ! kldstat -q -m cpuctl; then | |
| if ! kldload cpuctl > /dev/null 2>&1; then | |
| warn "Can't load cpuctl module." | |
| return 1 | |
| fi | |
| fi | |
| authenticamd="0x68747541 0x444d4163 0x69746e65" | |
| if ! ${CPUCTL} -i 0x0 /dev/cpuctl0 | grep -q "$authenticamd"; then | |
| warn "Not an AMD processor, ignoring" | |
| return 1 | |
| fi | |
| cpuid=$(${CPUCTL} -i 0x1 /dev/cpuctl0 | awk '{ print $4 }') | |
| family=$(( ((cpuid & 0xf00) >> 8) + ((cpuid & 0x0ff00000) >> 20) )) | |
| model=$(( (cpuid & 0xf0) >> 4 | (cpuid & 0x000f0000) >> 12 )) | |
| # Zen 2 is Family 23 Model 49 - 160 | |
| if ! { [ $family -eq 23 ] && [ $model -ge 49 ] && [ $model -le 160 ]; } then | |
| warn "Not a Zen 2 processor, ignoring" | |
| return 1 | |
| fi | |
| hmicrocode=$(${CPUCTL} -m 0x8b /dev/cpuctl0 | awk '{ print $4 }') | |
| microcode=$((hmicrocode)) | |
| # Numbers sourced from Linux patch: | |
| # https://freshbsd.org/linux/linux/commit/0a9266b79cacdd02b888aed1308c308ad6d4ee4e | |
| if [ $model -ge $((0x30)) ] && [ $model -le $((0x3f)) ] && [ $microcode -ge $((0x0830107a)) ] || | |
| [ $model -ge $((0x60)) ] && [ $model -le $((0x67)) ] && [ $microcode -ge $((0x0860010b)) ] || | |
| [ $model -ge $((0x68)) ] && [ $model -le $((0x6f)) ] && [ $microcode -ge $((0x08608105)) ] || | |
| [ $model -ge $((0x70)) ] && [ $model -le $((0x7f)) ] && [ $microcode -ge $((0x08701032)) ] || | |
| [ $model -ge $((0xa0)) ] && [ $model -le $((0xaf)) ] && [ $microcode -ge $((0x08a00008)) ]; then | |
| warn "Known-good microcode detected: ${hmicrocode}, ignoring" | |
| return 1 | |
| fi | |
| } | |
| check_date() { | |
| # Start whinging mid-December | |
| if [ "$(/bin/date +%s)" -ge 1702684800 ]; then | |
| warn "Zenbleed should be resolved by updated AMD microcode, please check." | |
| warn "Updated microcode is provided by sysutils/devcpu-data" | |
| fi | |
| } | |
| workaround_zenbleed() { | |
| check_date | |
| check_startmsgs && echo "Applying Zenbleed MSR workaround" | |
| for D in /dev/cpuctl* | |
| do | |
| ${CPUCTL} -m "0xc0011029|=0x200" "$D" | |
| done | |
| } | |
| restore_zenbleed() { | |
| check_startmsgs && echo "Removing Zenbleed MSR workaround" | |
| for D in /dev/cpuctl* | |
| do | |
| ${CPUCTL} -m "0xc0011029&=~0x200" "$D" | |
| done | |
| } | |
| run_rc_command "$1" | |
Thanks. I added a resume command (just pointing at start_cmd, no need to run restart or indirect it through a function I can see), and made it slightly less chatty.
Discovered via https://discord.com/channels/727023752348434432/827065966416363570/1135689521338515578.
For those of us who were not previously in the know: https://en.wikipedia.org/wiki/Transient_execution_CPU_vulnerability (redirected from Zenbleed).
Proof of concept BSD port: https://git.hardenedbsd.org/shawn.webb/zenbleed (be sure to co the shawn.webb/bsd/main branch)
Thanks. I added a resume command (just pointing at start_cmd, no need to run restart or indirect it through a function I can see), and made it slightly less chatty.
Did you check that it will still check for the correct cpu ?
For me it seems like it will only check at start, not after resume.
So you can have a case where it will not initially start (like on an intel cpu), but after resume it will set the bit.
But maybe I don't really know how resume works, maybe it check if it succeed before resuming it.
Good point. I added a resume_precmd.
I added known-good microcode checks (just EPYC "Rome" CPUs right now I believe), and a warning that appears if you use the script after mid December.
Hello nice works, I have noticed that after resume the chicken bit is reset.
So it could be great to have the resume clause in this script. Here a slight modification:
I think that a jail should not have access to this kind of power, thus nojail.
Here we add the resume extra commands that will simply restart zenbleed_workaround
And then
Here the simple diff