Skip to content

Commit 5dba9f2

Browse files
committed
initramfs: fix running on root-only readable initrd filesystem
Signed-off-by: Oldřich Jedlička <[email protected]>
1 parent 1c21d5b commit 5dba9f2

File tree

14 files changed

+116
-56
lines changed

14 files changed

+116
-56
lines changed

meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ project('clevis', 'c', license: 'GPL3+',
66
libexecdir = join_paths(get_option('prefix'), get_option('libexecdir'))
77
sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
88
bindir = join_paths(get_option('prefix'), get_option('bindir'))
9+
libdir = join_paths(get_option('prefix'), get_option('libdir'))
910

1011
data = configuration_data()
1112
data.set('libexecdir', libexecdir)
1213
data.set('sysconfdir', sysconfdir)
1314
data.set('bindir', bindir)
15+
data.set('libdir', libdir)
1416

1517
add_project_arguments(
1618
'-Wall',

src/initramfs-tools/hooks/clevis.in

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@ fi
9999
if [ -x @bindir@/clevis-decrypt-tpm1 ]; then
100100
copy_exec @bindir@/clevis-decrypt-tpm1 || die 1 "@bindir@/clevis-decrypt-tpm1 not found"
101101
copy_exec @libexecdir@/clevis-luks-tpm1-functions || die 1 "@libexecdir@/clevis-luks-tpm1-functions not found"
102+
copy_exec @libdir@/libclevis-tpm1-tcsd-preload.so || die 1 "@libdir@/libclevis-tpm1-tcsd-preload.so not found"
102103

103104
tcsd_bin=$(find_binary "tcsd")
104105
# libgcc_s.so.* is no longer installed for gcc 2.34+ (no link to libpthread)
105106
libgcc_s=$(find_library "libgcc_s.so.[1-9]")
106107
tpm_version_bin=$(find_binary "tpm_version")
107108
tpm_unsealdata_bin=$(find_binary "tpm_unsealdata")
108-
stdbuf_bin=$(find_binary "stdbuf")
109-
libstdbuf_bin=$(find_library "coreutils/libstdbuf.so*")
110109

111110
copy_exec "${tpm_version_bin}" || die 1 "Unable to copy ${tpm_version_bin}"
112111
copy_exec "${tpm_unsealdata_bin}" || die 1 "Unable to copy ${tpm_unsealdata_bin}"
@@ -115,14 +114,19 @@ if [ -x @bindir@/clevis-decrypt-tpm1 ]; then
115114
copy_exec "${libgcc_s}" || die 1 "Unable to copy ${libgcc_s}"
116115
copy_file config /etc/tcsd.conf || dia 2 "Unable to copy /etc/tcsd.conf"
117116

118-
copy_exec "${stdbuf_bin}" || die 1 "Unable to copy ${stdbuf_bin}"
119-
copy_exec "${libstdbuf_bin}" || die 1 "Unable to copy ${libstdbuf_bin}"
120-
121117
mkdir -p "${DESTDIR}/var/lib/tpm" || die 2 "Unable to create /var/lib/tpm"
122118
cp /var/lib/tpm/* "${DESTDIR}/var/lib/tpm/" || die 2 "Unable to copy /var/lib/tpm"
123119
chown -R tss:tss "${DESTDIR}/var/lib/tpm" || die 2 "Unable to change owner of /var/lib/tpm"
124120
chmod -R u=rwX,go= "${DESTDIR}/var/lib/tpm" || die 2 "Unable to change permissions of /var/lib/tpm"
125121

122+
if (( $(umask) & 0004 )); then
123+
# Root-only readable initrd filesystem, we need to run as root
124+
# shellcheck disable=SC2154 # $verbose is a dracut variable
125+
[ "${verbose}" = "y" ] && echo "Forcing tcsd to run as root"
126+
sed -i 's/^\([ ]*remote_ops\)/#\1/' "${DESTDIR}/etc/tcsd.conf"
127+
echo "TCSD_NO_PRIVILEGE_DROP=1" >> "${DESTDIR}/conf/conf.d/clevis"
128+
fi
129+
126130
mkdir -p "${DESTDIR}/lib/udev/rules.d" || die 2 "Unable to create /lib/udev/rules.d"
127131
# shellcheck disable=SC2043
128132
for rule in 60-tpm-udev.rules; do

src/initramfs-tools/scripts/local-top/clevis.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ do_configure_tpm1() {
282282

283283
wait_for_udev 10
284284

285+
# shellcheck disable=SC2034 # setting default value
286+
TCSD_NO_PRIVILEGE_DROP=0
287+
[ -f /conf/conf.d/clevis ] && . /conf/conf.d/clevis
288+
285289
if ! tcsd_output=$(start_tcsd 2>&1); then
286290
if [ -n "$tcsd_output" ]; then
287291
log_failure_msg "failed to start TCSD: $tcsd_output"

src/luks/clevis-luks-tpm1-functions renamed to src/luks/clevis-luks-tpm1-functions.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ start_tcsd() {
6363
# available for debugging, so start TCSD in foreground mode, but as a
6464
# background job. Unfortunatelly the redirected output to pipe is
6565
# block-buffered (see `man 3 setbuf`), so in order to see any output we
66-
# need to set it to line-buffered with stdbuf tool
67-
stdbuf -oL tcsd -f >$fifo_file 2>&1 &
66+
# need to set it to line-buffered with LD_PRELOAD library
67+
TCSD_NO_PRIVILEGE_DROP=${TCSD_NO_PRIVILEGE_DROP:-0} LD_PRELOAD="@libdir@/libclevis-tpm1-tcsd-preload.so" tcsd -f >$fifo_file 2>&1 &
6868
tcsd_pid=$!
6969

7070
wait $sleep_pid 2>/dev/null

src/luks/dracut/clevis-pin-tpm1/module-setup.sh.in

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ require_nonempty_dir() {
6464
check() {
6565
local _module_name="${moddir##*/[0-9][0-9]}"
6666

67-
require_binaries clevis-decrypt-tpm1 tpm_version tpm_unsealdata tcsd stdbuf || return 1
67+
require_binaries clevis-decrypt-tpm1 tpm_version tpm_unsealdata tcsd || return 1
6868
if [[ $hostonly ]]; then
6969
require_nonempty_dir /var/lib/tpm || return 1
7070
else
@@ -96,13 +96,9 @@ install() {
9696
systemctl -q --root "$initdir" add-wants cryptsetup.target tcsd.service
9797
else
9898
inst_multiple \
99-
awk chmod chown mkfifo mktemp ip ps stdbuf \
99+
awk chmod chown mkfifo mktemp ip ps \
100+
@libdir@/libclevis-tpm1-tcsd-preload.so \
100101
@libexecdir@/clevis-luks-tpm1-functions
101-
if [ -f /usr/libexec/coreutils/libstdbuf.so ]; then
102-
inst_multiple /usr/libexec/coreutils/libstdbuf.so*
103-
else
104-
inst_libdir_file 'coreutils/libstdbuf.so*'
105-
fi
106102
fi
107103

108104
inst_multiple \

src/luks/dracut/clevis/clevis-password-unlocker.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ do_configure_tpm1() {
168168

169169
info "Starting TCSD daemon"
170170

171-
if ! tcsd_output=$(start_tcsd 2>&1); then
171+
if ! tcsd_output=$(TCSD_NO_PRIVILEGE_DROP=0 start_tcsd 2>&1); then
172172
if [ -n "$tcsd_output" ]; then
173173
echo "Unable to start TCSD: $tcsd_output" | vwarn
174174
else

src/luks/dracut/clevis/meson.build

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,36 @@ dracut = dependency('dracut', required: false)
33
if dracut.found()
44
dracutdir = dracut.get_pkgconfig_variable('dracutmodulesdir') + '/60' + meson.project_name()
55

6+
dracut_data = configuration_data()
7+
dracut_data.merge_from(data)
8+
dracut_data.set('SYSTEMD_REPLY_PASS', sd_reply_pass.path())
9+
610
configure_file(
711
input: 'module-setup.sh.in',
812
output: 'module-setup.sh',
913
install_dir: dracutdir,
10-
configuration: data,
14+
configuration: dracut_data,
1115
)
1216

1317
configure_file(
1418
input: 'clevis-cleanup.in',
1519
output: 'clevis-cleanup',
1620
install_dir: dracutdir,
17-
configuration: data,
21+
configuration: dracut_data,
1822
)
1923

2024
configure_file(
2125
input: 'clevis-password-unlocker.in',
2226
output: 'clevis-password-unlocker',
2327
install_dir: dracutdir,
24-
configuration: data,
28+
configuration: dracut_data,
2529
)
2630

2731
configure_file(
2832
input: 'clevis-password-unlocker-prepare.in',
2933
output: 'clevis-password-unlocker-prepare',
3034
install_dir: dracutdir,
31-
configuration: data,
35+
configuration: dracut_data,
3236
)
3337

3438
install_data('clevis-cleanup-hook.sh', install_dir: dracutdir)

src/luks/meson.build

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,31 @@ clevis_luks_common_functions = configure_file(
2828
configuration: luksmeta_data
2929
)
3030

31+
clevis_luks_tpm1_functions = configure_file(
32+
input: 'clevis-luks-tpm1-functions.in',
33+
output: 'clevis-luks-tpm1-functions',
34+
configuration: data
35+
)
36+
3137
clevis_luks_unbind = configure_file(input: 'clevis-luks-unbind.in',
3238
output: 'clevis-luks-unbind',
3339
configuration: luksmeta_data)
3440

41+
# SystemD dependencies checked here, used both in systemd and dracut subdirs
42+
systemd = dependency('systemd', required: false)
43+
systemdutildir = systemd.found() ? systemd.get_pkgconfig_variable('systemdutildir', default: '') : ''
44+
45+
sd_reply_pass = find_program(
46+
(systemdutildir != '') ? join_paths(systemdutildir, 'systemd-reply-password') : '',
47+
join_paths(get_option('prefix'), get_option('libdir'), 'systemd', 'systemd-reply-password'),
48+
join_paths(get_option('prefix'), 'lib', 'systemd', 'systemd-reply-password'),
49+
join_paths('/', 'usr', get_option('libdir'), 'systemd', 'systemd-reply-password'),
50+
join_paths('/', 'usr', 'lib', 'systemd', 'systemd-reply-password'),
51+
required: false
52+
)
53+
3554
if libcryptsetup.found() and luksmeta.found()
3655
subdir('systemd')
37-
# systemd should come before dracut in order to set up
38-
# variables like SYSTEMD_REPLY_PASS.
3956
subdir('dracut')
4057
subdir('udisks2')
4158

@@ -67,7 +84,7 @@ if libcryptsetup.found() and luksmeta.found()
6784
bins += join_paths(meson.current_source_dir(), 'clevis-luks-pass')
6885
mans += join_paths(meson.current_source_dir(), 'clevis-luks-pass.1')
6986

70-
install_data('clevis-luks-tpm1-functions', install_dir: libexecdir)
87+
install_data(clevis_luks_tpm1_functions, install_dir: libexecdir)
7188
else
7289
warning('Will not install LUKS support due to missing dependencies!')
7390
endif

src/luks/systemd/meson.build

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
1-
systemd = dependency('systemd', required: false)
2-
systemdutildir = systemd.found() ? systemd.get_pkgconfig_variable('systemdutildir', default: '') : ''
3-
4-
sd_reply_pass = find_program(
5-
(systemdutildir != '') ? join_paths(systemdutildir, 'systemd-reply-password') : '',
6-
join_paths(get_option('prefix'), get_option('libdir'), 'systemd', 'systemd-reply-password'),
7-
join_paths(get_option('prefix'), 'lib', 'systemd', 'systemd-reply-password'),
8-
join_paths('/', 'usr', get_option('libdir'), 'systemd', 'systemd-reply-password'),
9-
join_paths('/', 'usr', 'lib', 'systemd', 'systemd-reply-password'),
10-
required: false
11-
)
12-
131
if systemd.found() and sd_reply_pass.found()
14-
data.set('SYSTEMD_REPLY_PASS', sd_reply_pass.path())
2+
systemd_data = configuration_data()
3+
systemd_data.merge_from(data)
4+
systemd_data.set('SYSTEMD_REPLY_PASS', sd_reply_pass.path())
155

166
unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
177
tcsdoverridedir = join_paths(unitdir, 'tcsd.service.d')
@@ -20,31 +10,31 @@ if systemd.found() and sd_reply_pass.found()
2010
input: 'clevis-luks-askpass.service.in',
2111
output: 'clevis-luks-askpass.service',
2212
install_dir: unitdir,
23-
configuration: data,
13+
configuration: systemd_data,
2414
)
2515
configure_file(
2616
input: 'clevis-luks-pkcs11-askpass.service.in',
2717
output: 'clevis-luks-pkcs11-askpass.service',
2818
install_dir: unitdir,
29-
configuration: data,
19+
configuration: systemd_data,
3020
)
3121
configure_file(
3222
input: 'clevis-luks-askpass.in',
3323
output: 'clevis-luks-askpass',
3424
install_dir: libexecdir,
35-
configuration: data
25+
configuration: systemd_data
3626
)
3727
configure_file(
3828
input: 'clevis-luks-pkcs11-askpass.in',
3929
output: 'clevis-luks-pkcs11-askpass',
4030
install_dir: libexecdir,
41-
configuration: data
31+
configuration: systemd_data
4232
)
4333
configure_file(
4434
input: 'clevis-luks-pkcs11-askpin.in',
4535
output: 'clevis-luks-pkcs11-askpin',
4636
install_dir: libexecdir,
47-
configuration: data
37+
configuration: systemd_data
4838
)
4939

5040
install_data('clevis-luks-askpass.path', install_dir: unitdir)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#define _GNU_SOURCE
2+
3+
#include <dlfcn.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <unistd.h>
7+
8+
#define TCSD_NO_PRIVILEGE_DROP_ENV "TCSD_NO_PRIVILEGE_DROP"
9+
10+
static int no_privilege_drop(void) {
11+
char *no_privilege_drop_env = getenv(TCSD_NO_PRIVILEGE_DROP_ENV);
12+
return (no_privilege_drop_env != NULL
13+
&& no_privilege_drop_env[0] != '\0'
14+
&& no_privilege_drop_env[0] != '0');
15+
}
16+
17+
int setuid(uid_t uid) {
18+
static int (*real_setuid)(uid_t) = NULL;
19+
if (no_privilege_drop()) {
20+
return 0;
21+
} else {
22+
if (!real_setuid) {
23+
real_setuid = dlsym(RTLD_NEXT, "setuid");
24+
}
25+
return real_setuid(uid);
26+
}
27+
}
28+
29+
int setgid(gid_t gid) {
30+
static int (*real_setgid)(uid_t) = NULL;
31+
if (no_privilege_drop()) {
32+
return 0;
33+
} else {
34+
if (!real_setgid) {
35+
real_setgid = dlsym(RTLD_NEXT, "setgid");
36+
}
37+
return real_setgid(gid);
38+
}
39+
return 0;
40+
}
41+
42+
static void __attribute ((constructor))
43+
set_line_buffering (void)
44+
{
45+
setvbuf(stdout, NULL, _IOLBF, 0);
46+
}

0 commit comments

Comments
 (0)