-
Notifications
You must be signed in to change notification settings - Fork 16
/
change-kernel-flags
305 lines (292 loc) · 11.6 KB
/
change-kernel-flags
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
#!/bin/sh
# Script to change the kernel flags.
# This script needs to be run as root in a
# Crosh shell.
# trap function for cleaning up file.
settrap() {
trap "set +e; trap - INT HUP TERM 0; $1 exit 2" INT HUP TERM
trap "set +e; trap - INT HUP TERM 0; $1" 0
}
# error function to gracefully exit.
error() {
ecode="$1"
shift
echo "$*" 1>&2
exit "$ecode"
}
verifykernel() {
dev_debug_vboot -c -k $1 | awk '/^Kernel / {
if ( $3 != "OK" ) {
# Kernel has no valid header
exit 2
}
}
/^ Verify / && $4 ~ /^kern_subkey_[AB].vbpubk:$/ {
if ( $5 == "OK" ) {
# kernel is verified with at least one of the vbpubk keys
exit 3
} else {
exit 4
}
}'
return $?
}
# check if script is run as root
uid=`id -u $USERNAME`
if [ $uid -ne 0 ]; then
error 1 "$0 must be run as root"
fi
APPLICATION="${0##*/}"
# Default kernel flags. Check if we have support for vmx, so we add that too.
KERNEL_FLAGS="lsm.module_locking=0"
# removing below default flag since it seems to cause some problems on the
# newest chromeos update.
#if grep -q '^flags\s*:.* vmx ' /proc/cpuinfo; then
# KERNEL_FLAGS="$KERNEL_FLAGS disablevmx=off"
#fi
KERNEL_BACKUP_DIR="/mnt/stateful_partition/backups"
USAGE="$APPLICATION [options] name [...]
Change kernel flags of the chromeos kernel
Note: This script needs to be run in a crosh shell!
Options:
-i Print out info about the kernel partitions.
-f KERNEL_FLAGS Add different kernel flags then default =
\""$KERNEL_FLAGS"\".
-r Revert the kernel flag changes by copying back a
previously created backup kernel.
-d KERNEL_BACKUP_DIR Dir where the backup kernels are. default =
\"$KERNEL_BACKUP_DIR\".
-h print this help text.
"
INFO=""
REVERT=""
# Process arguments
while getopts 'f:ird:h' f; do
case "$f" in
f) KERNEL_FLAGS="$OPTARG";;
i) INFO='y';;
r) REVERT='y';;
d) KERNEL_BACKUP_DIR="$OPTARG";;
#k) KERNEL_PART="$OPTARG";;
h) echo "$USAGE"
exit 0;;
\?) echo "$USAGE"
exit 0;;
esac
done
# root device for example /dev/sda /dev/mmcblk0
dev=`rootdev -s -d`
# fixed kernel uuid provided by google to identify kernel partitions.
kern_uuid="FE3A2A5D-4F32-41A7-B725-ACCC3285A309"
# Loop through kernel partitions to get boot priority
firstpriority=-1
for part in `cgpt show $dev -qn |grep "$kern_uuid" | \
awk '/^ / { print $3 }'`; do
priority="`cgpt show -i"$part" -P "$dev"`"
if [ $priority -gt $firstpriority ]; then
firstpriority=$priority
bootpartition=$part
fi
done
# Get info about the kernel partitions. TODO: needs a bit of work.
# for example error exiting. Give less, but more relevant info.
if [ "$INFO" = "y" ]; then
# list info about kernels
echo "Check if the kernel partitions are signed with vbpubk:\n"
dev_debug_vboot -c -i $dev
echo "\nShow kernel details about the installed kernels.\n"
for part in `cgpt show $dev -qn |grep "$kern_uuid" | \
awk '/^ / { print $3 }'`; do
vbutil_kernel --verify $dev$part --verbose
done
echo "\ncrosssystem dev_boot* flags settings:\n"
crossystem |grep --color=never dev_boot
exit 0
fi
# Revert the kernel flag changes by copying back a backup kernel.
if [ "$REVERT" = "y" ]; then
if [ ! -d "$KERNEL_BACKUP_DIR" ]; then
error 1 "$KERNEL_BACKUP_DIR not found."
fi
# Use label to only list kernels that are from that partition backed up
# TODO: Maybe we should list all the backup kernel files?
label=`cgpt show -i"$bootpartition" -l "$dev"`
label=${label#KERN-}
i=0
crtimeold=0
echo "List of backup kernel files in \"$KERNEL_BACKUP_DIR\"\n"
for bkname in "$KERNEL_BACKUP_DIR"/*$label*.bin; do
if [ -f "$bkname" ]; then
i=$((i+1))
verifykernel "$bkname"
# Process awk exit codes.
case $? in
2) # Do not add kernels to the list with no valid header
continue
;;
3) v=1
# Keep track of which is the latest backup.
# This will only work for filenames in format
# kernel_[A,B]_YYYYMMDD_HHMMSS.bin. This will be the case
# when backed up with make_dev_ssd.sh.
crtime=`echo ${bkname%.*} | cut -d "_" -f4-5 | sed 's/_//'`
if [ "$crtime" -gt "$crtimeold" 2>/dev/null ]; then
prefer="$i"
crtimeold="$crtime"
fi
echo "[$i] "${bkname##*/}" --> Verified"
;;
4) v=0
echo "[$i] "${bkname##*/}" --> Not verified"
;;
*) error 1 "dev_debug_vboot failed"
;;
esac
# list of verified [01],kernel filename
bknames=${bknames## }" $v,${bkname##*/}"
fi
done
if [ "$i" -eq 0 ]; then
error 2 "No backup kernels found in $KERNEL_BACKUP_DIR"
else
if [ -n "$prefer" ]; then
echo "\nYou probably want number [$prefer], it is the latest"
echo "verified kernel. Choose that if you are not sure."
fi
echo "\n[C] Cancel\n"
fi
read -p "Choice: " choice
# Do some magic stuff here to dd back the kernel.
if [ "$choice" -ge "1" -a "$choice" -le "$i" 2>/dev/null ]; then
i=0
for f in $bknames; do
i=$((i+1))
if [ "$i" -eq "$choice" ]; then
if [ "${f%%,*}" -eq 1 ]; then
ver="Verified"
else
ver="NOT verified"
fi
echo \
"Are you sure you want to put back \"${f##*,}\" on partition
$bootpartition which is a $ver chromeos kernel?\n"
read -p "Your answer (y/N)?" YES
if [ "${YES#[Yy]}" = "$YES" ]; then
echo "Exiting with no changes"
else
echo \
"Do not interrupt this operation, if you still do for some reason
then rerun this script and try again, else you may end up with a
corrupted partition."
# We fill the partition first with zeros so when a backup
# is created we will have no leftovers from a previously
# dd.
dd if="/dev/null" \
of="$dev$bootpartition" bs=512 || error 1 \
"Something went wrong, please try again dd zero failed"
sync
dd if="$KERNEL_BACKUP_DIR/${f##*,}" \
of="$dev$bootpartition" bs=512 || error 1 \
"Something went wrong, please try again. dd failed"
sync
verifykernel "$dev$bootpartition"
case $? in
2) # kernels with no valid header
error 1 \
"We have no valid header, please try again."
;;
3) echo "Kernel $dev$bootpartition is verified.\n"
crossystem dev_boot_signed_only=1 || error 1 \
"dev_boot_signed_only=1 could not be set"
# TODO: Remove this when crouton is fixed
crossystem dev_boot_usb=0 dev_boot_legacy=0 || \
error 1 \
"dev_boot_usb=0 dev_boot_legacy=0 could not be set"
crossystem | grep --color=never dev_boot || \
error 1 \
"crossystem failed"
;;
4) echo "Kernel $dev$bootpartition is not verified.\n"
crossystem dev_boot_signed_only=0 || error 1 \
"dev_boot_signed_only=1 could not be set"
# TODO: Remove this when crouton is fixed
crossystem dev_boot_usb=1 dev_boot_legacy=1 || \
error 1 \
"dev_boot_usb=0 dev_boot_legacy=0 could not be set"
crossystem | grep --color=never dev_boot || \
error 1 \
"crossystem failed"
;;
*) error 1 "dev_debug_vboot failed"
;;
esac
echo "\nOk, all done now"
echo "Reboot to make the changes take effect."
fi
fi
done
else
echo "Operation canceled."
fi
exit 0
fi
# Create temporary file for the kernel config file.
KERNEL_FLAGSFILE="`mktemp --tmpdir=/tmp "$APPLICATION.XXX.$bootpartition"`"
echo $KERNEL_FLAGSFILE
settrap "rm -f '$KERNEL_FLAGSFILE';"
/usr/share/vboot/bin/make_dev_ssd.sh --save_config \
"${KERNEL_FLAGSFILE%.$bootpartition}" --partitions "$bootpartition" \
|| error 1 "make_dev_ssd.sh --save_config Failed"
# TODO: remove trailing spaces from file cosmetic
# Check if we already have all the flags in the kernel cmdline
# that will be booted on a reboot.
for f in $KERNEL_FLAGS; do
if cat "$KERNEL_FLAGSFILE" | grep -q "$f"; then
echo "\"$f\"\tis already added to the kernel cmdline."
else
tmp_kernel_flags=${tmp_kernel_flags## }" $f"
# Check if the flag already exists then replace it else add it.
# This will of course not work for every flag, but only for
# "FLAG=value". We will present the user with the complete cmdline,
# so he/she can check if everything is ok.
if cat "$KERNEL_FLAGSFILE" | grep -q "${f%=*}="; then
sed -i -e "s/${f%=*}=[^ ]*/$f/" "$KERNEL_FLAGSFILE"
else
sed -i -e "s/$/ $f/" "$KERNEL_FLAGSFILE"
fi
fi
done
# TODO: Perhaps we should also check existing /proc/cmdline to see if the
# device al ready is rebooted to apply the changes.
if [ -n "$tmp_kernel_flags" ]; then
echo "\nKernel flags added or changed are:\n\"$tmp_kernel_flags\"\n"
echo "Full cmdline is:"
cat "$KERNEL_FLAGSFILE"
echo ""
read -p "Do you want to apply those changes (y/N)?" YES
if [ "${YES#[Yy]}" = "$YES" ]; then
echo "Exiting with no changes"
else
crossystem dev_boot_signed_only=0 || error 1 \
"dev_boot_signed_only=0 could not be set"
# For now we also need to set dev_boot_usb=1 dev_boot_legacy=1 to
# prevent crouton for turning it back on.
# TODO: Remove this when crouton checks if it safely can
# be turned back on.
crossystem dev_boot_usb=1 dev_boot_legacy=1 || error 1 \
"dev_boot_usb=1 dev_boot_legacy=1 could not be set"
/usr/share/vboot/bin/make_dev_ssd.sh --set_config \
"${KERNEL_FLAGSFILE%.$bootpartition}" --partitions \
"$bootpartition" || error 1 "make_dev_ssd.sh --set_config Failed"
crossystem | grep --color=never dev_boot || error 1 "crossystem failed"
echo "\nReboot to make the changes take effect."
fi
else
echo "\n\"$KERNEL_FLAGS\" are already added to the kernel cmdline."
echo "If you wish to revert the original kernel, run \"$APPLICATION -r\""
echo "which will give you the option to copy back the original kernel"
echo "from an earlier created backup.\n"
fi
# Cleanup
rm -f "$KERNEL_FLAGSFILE"
exit 0