-
Notifications
You must be signed in to change notification settings - Fork 288
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CP-40444: Add swtpm-wrapper to the repository
Relevant messages from its changelog: CP-35104: Add swtpm-wrapper for proper logging CP-35054: Start SWTPM daemon deprivilideged CP-40195: Only call swtpm_setup for manufacture swtpm_setup is run as root and handles guest data on subsequent boots after TPM manufacture. Avoid running it completely after the initial manufacture to avoid any possible security issues. The '.lock' will only be present after running swtpm_setup so run chown conditionally. At the same time, handle errors from chown rather than silently ignoring them. CA-369317: Don't ignore errors from swtpm_setup Signed-off-by: Pau Ruiz Safont <[email protected]>
- Loading branch information
Showing
2 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
#! /usr/bin/python | ||
# | ||
# Copyright (C) 2022 Citrix Systems R&D Ltd. | ||
# | ||
# This program is free software; you can redistribute it and/or modify | ||
# it under the terms of the GNU Lesser General Public License as published | ||
# by the Free Software Foundation; version 2.1 only. with the special | ||
# exception on linking described in file LICENSE. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU Lesser General Public License for more details. | ||
|
||
from __future__ import print_function | ||
import os | ||
import stat | ||
import sys | ||
import pwd | ||
import grp | ||
import subprocess | ||
import ctypes | ||
import ctypes.util | ||
from resource import getrlimit, RLIMIT_CORE, RLIMIT_FSIZE, setrlimit | ||
|
||
|
||
STATE_FILE = 'tpm2-00.permall' | ||
|
||
CLONE_NEWNS = 0x00020000 # mount namespace | ||
CLONE_NEWNET = 0x40000000 # network namespace | ||
CLONE_NEWIPC = 0x08000000 # IPC namespace | ||
|
||
# Set cgroup_slice to the name of the cgroup slice the swtpm process | ||
# should live in. | ||
# - None means leave in the same slice as the parent process. | ||
# - '' means move it into the default slice. | ||
# - 'system.slice' means move it into the system slice, etc. | ||
# If the nominated slice does not already exist, the process will be | ||
# left in its parent's slice. | ||
cgroup_slice = '' | ||
|
||
def unshare(flags): | ||
libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) | ||
unshare_prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True) | ||
unshare = unshare_prototype(('unshare', libc)) | ||
ret = unshare(flags) | ||
if ret < 0: | ||
raise OSError(ctypes.get_errno(), os.strerror(ctypes.get_errno())) | ||
|
||
def enable_core_dumps(): | ||
|
||
limit = 64 * 1024 * 1024 | ||
oldlimits = getrlimit(RLIMIT_CORE) | ||
hardlimit = oldlimits[1] | ||
if limit > hardlimit: | ||
hardlimit = limit | ||
setrlimit(RLIMIT_CORE, (limit, hardlimit)) | ||
return limit | ||
|
||
def prepare_exec(): | ||
"""Set up the execution environment for SWTPM.""" | ||
|
||
if cgroup_slice is not None: | ||
# Move to nominated cgroup slice | ||
print("Moving to cgroup slice '%s'" % cgroup_slice) | ||
try: | ||
# Note the default slice uses /sys/fs/cgroup/cpu/tasks but | ||
# other.slice uses /sys/fs/cgroup/cpu/other.slice/tasks. | ||
g = open("/sys/fs/cgroup/cpu/%s/tasks" % cgroup_slice, 'w') | ||
g.write(str(os.getpid())) | ||
g.close() | ||
except IOError as e: | ||
print("Warning: writing pid to '%s' tasks file: %s" \ | ||
% (cgroup_slice, e)) | ||
|
||
core_dump_limit = enable_core_dumps() | ||
print("core dump limit: %d" % core_dump_limit) | ||
|
||
limit = 256 * 1024 | ||
setrlimit(RLIMIT_FSIZE, (limit, limit)) | ||
|
||
flags = CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET | ||
unshare(flags) | ||
|
||
sys.stdout.flush() | ||
sys.stderr.flush() | ||
|
||
def main(argv): | ||
print("Arguments: %s" % " ".join(argv[1:])) | ||
|
||
if len(argv) < 3: | ||
return | ||
|
||
domid = int(argv[1]) | ||
tpm_dir = argv[2] | ||
tpm_path = tpm_dir | ||
depriv = True | ||
|
||
n= 3 | ||
while n < len(argv): | ||
if argv[n] == "-priv": | ||
depriv = False | ||
continue | ||
n += 1 | ||
|
||
tpm_env = dict(os.environ) | ||
tpm_env["LD_LIBRARY_PATH"] = "/usr/lib:" | ||
|
||
if not os.path.exists(os.path.join(tpm_dir, STATE_FILE)): | ||
# Initial manufacture | ||
|
||
tpm_exe = '/usr/bin/swtpm_setup' | ||
tpm_args = ["swtpm_setup", "--tpm2", "--tpm-state", tpm_dir, "--createek", "--create-ek-cert", "--create-platform-cert", "--lock-nvram", "--not-overwrite"] | ||
subprocess.check_call(tpm_args, executable=tpm_exe, env=tpm_env) | ||
|
||
tpm_exe = '/usr/bin/swtpm' | ||
uid = pwd.getpwnam('swtpm_base').pw_uid + domid | ||
tpm_args = [] | ||
|
||
if depriv: | ||
tpm_args = ["--chroot", tpm_dir, | ||
"--runas", str(uid)] | ||
try: | ||
dev_dir = os.path.join(tpm_dir, "dev") | ||
if not os.path.isdir(dev_dir): | ||
os.mkdir(dev_dir) | ||
|
||
urandom = os.path.join(dev_dir, "urandom") | ||
if not os.path.exists(urandom): | ||
os.mknod(urandom, 0666 | stat.S_IFCHR, os.makedev(1, 9)) | ||
|
||
os.chown(tpm_dir, uid, uid) | ||
if os.path.exists(os.path.join(tpm_dir, ".lock")): | ||
os.chown(os.path.join(tpm_dir, ".lock"), uid, uid) | ||
os.chown(os.path.join(tpm_dir, STATE_FILE), uid, uid) | ||
|
||
except OSError as error: | ||
print(error) | ||
return | ||
|
||
tpm_path = '/' | ||
|
||
swtpm_sock = os.path.join(tpm_path, "swtpm-sock") | ||
swtpm_pid = os.path.join(tpm_path, "swtpm-%d.pid" % domid) | ||
|
||
tpm_args = ["swtpm-%d" % domid, "socket", | ||
"--tpm2", | ||
"--tpmstate", "dir=%s" % tpm_path, | ||
"--ctrl", "type=unixio,path=%s" % swtpm_sock, | ||
"--log", "level=1", | ||
"--pid", "file=%s" % swtpm_pid, | ||
"-t"] + tpm_args | ||
|
||
swtpm = subprocess.Popen(tpm_args,executable=tpm_exe, preexec_fn=prepare_exec(), env=tpm_env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | ||
print("Exec: %s %s" % (tpm_exe, " ".join(tpm_args))) | ||
|
||
sys.stdout.flush() | ||
sys.stderr.flush() | ||
|
||
# Redirect output from SWTPM to logger | ||
os.dup2(swtpm.stdout.fileno(), 0) | ||
swtpm.stdout.close() | ||
|
||
os.execvp('logger', ['logger', '-p', 'daemon.info', '-t', | ||
'swtpm-%d[%d]' % (domid, swtpm.pid)]) | ||
|
||
if __name__ == '__main__': | ||
raise SystemExit(main(sys.argv)) |