-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvmware-sign-modules
More file actions
204 lines (176 loc) · 7.41 KB
/
Copy pathvmware-sign-modules
File metadata and controls
204 lines (176 loc) · 7.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#!/bin/bash
# ============================================================
# VMware Kernel Module Auto-Fix
# ============================================================
# Installs as: /etc/kernel/postinst.d/vmware-sign-modules
# Runs automatically after every kernel update on Debian/Ubuntu
#
# Config via environment variables (set in the hook file itself,
# or in /etc/default/vmware-sign-modules):
# MOK_PRIV_DIR — path to MOK key directory (default: /root/.vmware-keys)
# LOG_FILE — log location (default: /var/log/vmware-hook.log)
# MAX_RETRIES — retry attempts for headers/signing (default: 3)
# RETRY_DELAY — seconds between retries (default: 30)
set -euo pipefail
# ── Configuration ────────────────────────────────────────────
KERNEL_VERSION="${1:-}"
MOK_PRIV_DIR="${MOK_PRIV_DIR:-/root/.vmware-keys}"
MOK_PRIV="${MOK_PRIV_DIR}/MOK.priv"
MOK_DER="${MOK_PRIV_DIR}/MOK.der"
LOG="${LOG_FILE:-/var/log/vmware-hook.log}"
MAX_RETRIES="${MAX_RETRIES:-3}"
RETRY_DELAY="${RETRY_DELAY:-30}"
log() { echo "[$(date)] $*" | tee -a "$LOG"; }
# ── Guard ───────────────────────────────────────────────────
if [[ -z "$KERNEL_VERSION" ]]; then
log "ERROR: No kernel version passed. Aborting."
exit 1
fi
if [[ ! -f /usr/bin/vmware ]]; then
log "VMware not installed. Nothing to do."
exit 0
fi
HEADER_DIR="/lib/modules/${KERNEL_VERSION}/build"
SIGN_TOOL="${HEADER_DIR}/scripts/sign-file"
MOD_DIR="/lib/modules/${KERNEL_VERSION}/misc"
MOD_SRC="/usr/lib/vmware/modules/source"
# ── Detect Secure Boot ──────────────────────────────────────
SECURE_BOOT=0
if command -v mokutil &>/dev/null; then
if mokutil --sb-state 2>/dev/null | grep -q "SecureBoot enabled"; then
SECURE_BOOT=1
fi
fi
log "========================================"
log "Kernel ${KERNEL_VERSION} — building VMware modules"
log "Secure Boot: $([ $SECURE_BOOT -eq 1 ] && echo 'ENABLED' || echo 'disabled — skipping signing')"
log "========================================"
# ── Step 1: Wait for kernel headers ─────────────────────────
for i in $(seq 1 $MAX_RETRIES); do
if [[ -d "$HEADER_DIR" ]]; then
log "Headers found at $HEADER_DIR"
break
fi
if [[ $i -eq $MAX_RETRIES ]]; then
log "ERROR: Headers not ready after ${MAX_RETRIES} attempts."
exit 1
fi
log "Headers not ready yet (attempt $i). Waiting ${RETRY_DELAY}s..."
sleep "$RETRY_DELAY"
done
# ── Step 2: Compile modules against the NEW kernel ──────────
# CRITICAL: We compile against ${KERNEL_VERSION} (the kernel being
# installed), NOT the running kernel. vmware-modconfig uses uname -r
# which is still the OLD kernel during package postinst, so modules
# would land in the wrong /lib/modules/ tree. We bypass it entirely
# and use the kernel build system directly.
log "Compiling modules for kernel ${KERNEL_VERSION}..."
mkdir -p "$MOD_DIR"
for mod in vmmon vmnet; do
src_tar="${MOD_SRC}/${mod}.tar"
if [[ ! -f "$src_tar" ]]; then
log "ERROR: ${src_tar} not found — is VMware Workstation installed?"
exit 1
fi
workdir=$(mktemp -d /tmp/vmware-build-XXXXXX)
tar xf "$src_tar" -C "$workdir"
# Find the extracted source directory (typically vmmon-only/)
mod_src_dir=$(find "$workdir" -maxdepth 2 -name 'Makefile' -printf '%h\n' 2>/dev/null | head -1)
if [[ -z "$mod_src_dir" ]]; then
log "ERROR: Could not find ${mod} source Makefile in tarball"
rm -rf "$workdir"
exit 1
fi
log " Building ${mod}..."
if make -C "$BUILD_DIR" M="$mod_src_dir" modules >> "$LOG" 2>&1; then
if [[ -f "${mod_src_dir}/${mod}.ko" ]]; then
cp "${mod_src_dir}/${mod}.ko" "${MOD_DIR}/"
log " ${mod}: compiled and installed OK"
else
log "ERROR: ${mod}.ko not produced by build"
rm -rf "$workdir"
exit 1
fi
else
log "ERROR: ${mod} compilation failed (see log for details)"
rm -rf "$workdir"
exit 1
fi
rm -rf "$workdir"
done
# ── Step 3: Sign modules (Secure Boot only) ─────────────────
if [[ $SECURE_BOOT -eq 1 ]]; then
if [[ ! -f "$MOK_PRIV" || ! -f "$MOK_DER" ]]; then
log "ERROR: Secure Boot is ON but no MOK keys at ${MOK_PRIV_DIR}/"
log "Generate keys: sudo openssl req -new -x509 -newkey rsa:2048 \\"
log " -keyout ${MOK_PRIV} -outform DER -out ${MOK_DER} -nodes -days 36500 \\"
log " -subj '/CN=VMware-MOK'"
log "Then enroll: sudo mokutil --import ${MOK_DER} && reboot"
exit 1
fi
for attempt in $(seq 1 $MAX_RETRIES); do
log "Signing attempt $attempt of $MAX_RETRIES..."
if [[ ! -f "$SIGN_TOOL" ]]; then
if [[ $attempt -lt $MAX_RETRIES ]]; then
log "sign-file not ready. Waiting ${RETRY_DELAY}s..."
sleep "$RETRY_DELAY"
continue
fi
log "ERROR: sign-file not found at $SIGN_TOOL"
exit 1
fi
all_ok=true
for mod in "${MOD_DIR}/vmmon.ko" "${MOD_DIR}/vmnet.ko"; do
modname=$(basename "$mod" .ko)
if [[ -f "$mod" ]]; then
if "$SIGN_TOOL" sha256 "$MOK_PRIV" "$MOK_DER" "$mod" >> "$LOG" 2>&1; then
log " ${modname} signed OK"
else
log " ${modname} signing FAILED"
all_ok=false
fi
else
log " ${modname} not found at $mod"
all_ok=false
fi
done
if $all_ok; then
log "All modules signed (attempt $attempt)"
break
elif [[ $attempt -eq $MAX_RETRIES ]]; then
log "ERROR: Signing failed after $MAX_RETRIES attempts"
exit 1
fi
sleep "$RETRY_DELAY"
done
# ── Verify signatures actually took effect ───────────────
log "Verifying signatures..."
for mod in "${MOD_DIR}/vmmon.ko" "${MOD_DIR}/vmnet.ko"; do
if [[ -f "$mod" ]]; then
sig=$(modinfo -F sig_id "$mod" 2>/dev/null)
if [[ -n "$sig" ]]; then
log " $(basename $mod): signed ($sig)"
else
log " $(basename $mod): STILL UNSIGNED! Signing failed silently."
exit 1
fi
fi
done
else
log "Secure Boot disabled — skipping module signing"
fi
# ── Step 4: Update module dependencies ──────────────────────
if depmod "$KERNEL_VERSION" >> "$LOG" 2>&1; then
log "depmod OK"
else
log "ERROR: depmod failed for kernel ${KERNEL_VERSION}"
exit 1
fi
# ── Step 5: Ensure services start on next boot ──────────────
systemctl reset-failed vmware vmware-USBArbitrator 2>/dev/null || true
systemctl enable vmware 2>/dev/null || true
systemctl enable vmware-USBArbitrator 2>/dev/null || true
log "Services reset and enabled for next boot"
log "========================================"
log "Done. VMware will start automatically on next boot."
log "========================================"