# Add solaris-specific #pragma init and fini. # Add NULL pointer check. # Except for the #pragmas, this patch is suitable for upstream use. # +++ src/tspi/rpc/hosttable.c 2014-04-24 11:05:44.000000000 -0700 --- src/tspi/rpc/hosttable.c 2016-04-18 13:55:57.988441566 -0700 @@ -21,8 +21,8 @@ static struct host_table *ht = NULL; -TSS_RESULT -host_table_init() +static TSS_RESULT +host_table_init(void) { ht = calloc(1, sizeof(struct host_table)); if (ht == NULL) { @@ -35,9 +35,8 @@ return TSS_SUCCESS; } -#ifdef SOLARIS -#pragma init(_init) -void _init(void) +#ifdef SOLARIS && !defined(__GNUC__) +static void my_init(void) #else static void __attribute__ ((constructor)) my_init(void) #endif @@ -46,11 +45,14 @@ __tspi_obj_list_init(); } -void +static void host_table_final() { struct host_table_entry *hte, *next = NULL; + if (ht == NULL) /* no host table to free */ + return; + MUTEX_LOCK(ht->lock); for (hte = ht->entries; hte; hte = next) { @@ -69,9 +71,8 @@ ht = NULL; } -#ifdef SOLARIS -#pragma fini(_fini) -void _fini(void) +#ifdef SOLARIS && !defined(__GNUC__) +static void my_fini(void) #else static void __attribute__ ((destructor)) my_fini(void) #endif @@ -79,6 +80,11 @@ host_table_final(); } +#ifdef SOLARIS +#pragma init(my_init) +#pragma fini(my_fini) +#endif + TSS_RESULT __tspi_add_table_entry(TSS_HCONTEXT tspContext, BYTE *host, int type, struct host_table_entry **ret) { # Use PIC instead of PIE for Solaris. # The Solaris linker doesn't support the GNU '-z relro'. # This change was implemented in-house and is not suitable for use upstream. # --- src/tcs/Makefile.am 2014-04-24 11:05:44.000000000 -0700 +++ src/tcs/Makefile.am 2016-04-19 17:12:43.154159741 -0700 @@ -2,7 +2,7 @@ CFLAGS+=-I${top_srcdir}/src/include libtcs_a_LIBADD=${top_builddir}/src/tddl/libtddl.a -libtcs_a_CFLAGS=-DAPPID=\"TCSD\ TCS\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -fPIE -DPIE +libtcs_a_CFLAGS=-DAPPID=\"TCSD\ TCS\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -fPIC libtcs_a_SOURCES=log.c \ tcs_caps.c \ --- src/tddl/Makefile.am 2014-04-24 11:05:44.000000000 -0700 +++ src/tddl/Makefile.am 2016-04-19 17:10:48.959752840 -0700 @@ -1,4 +1,4 @@ lib_LIBRARIES=libtddl.a libtddl_a_SOURCES=tddl.c -libtddl_a_CFLAGS=-DAPPID=\"TCSD\ TDDL\" -I${top_srcdir}/src/include -fPIE -DPIE +libtddl_a_CFLAGS=-DAPPID=\"TCSD\ TDDL\" -I${top_srcdir}/src/include -fPIC diff -r 2732f8472839 configure.ac --- configure.ac Mon Oct 04 16:42:25 2021 +0200 +++ configure.ac Mon Oct 04 16:44:57 2021 +0200 @@ -43,6 +43,7 @@ ;; *solaris*) CFLAGS="$CFLAGS -DSOLARIS" + TCSD_LDFLAGS="-fPIC -Wl,-z,now" ;; *) TCSD_LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now" diff -r 2732f8472839 src/tcsd/Makefile.am --- src/tcsd/Makefile.am Mon Oct 04 16:42:25 2021 +0200 +++ src/tcsd/Makefile.am Mon Oct 04 16:44:57 2021 +0200 @@ -1,6 +1,6 @@ sbin_PROGRAMS=tcsd -tcsd_CFLAGS=-DAPPID=\"TCSD\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -I${top_srcdir}/src/include -fPIE -DPIE +tcsd_CFLAGS=-DAPPID=\"TCSD\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -I${top_srcdir}/src/include -fPIC tcsd_LDADD=${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a -lpthread @CRYPTOLIB@ tcsd_LDFLAGS=@TCSD_LDFLAGS@ tcsd_SOURCES=svrside.c tcsd_conf.c tcsd_threads.c platform.c # Add or change Solaris-specific file and directory names. # This change was implemented in-house and is not suitable for upstream use. # --- src/include/tcsd.h 2014-04-24 11:05:44.000000000 -0700 +++ src/include/tcsd.h 2016-04-22 11:29:09.043084190 -0700 @@ -50,15 +50,27 @@ int disable_ipv6; }; +#ifdef SOLARIS +#define TCSD_DEFAULT_CONFIG_FILE "/etc/security/tcsd.conf" +#else #define TCSD_DEFAULT_CONFIG_FILE ETC_PREFIX "/tcsd.conf" +#endif extern char *tcsd_config_file; #define TSS_USER_NAME "tss" #define TSS_GROUP_NAME "tss" #define TCSD_DEFAULT_MAX_THREADS 10 +#ifdef SOLARIS +#define TCSD_DEFAULT_SYSTEM_PS_DIR "/var/tpm/system" +#define TCSD_DEFAULT_SYSTEM_PS_FILE "/var/tpm/system/system.data" +#define TCSD_DEFAULT_SOCKET "/var/tpm/tcsd-socket" +#else #define TCSD_DEFAULT_SYSTEM_PS_FILE VAR_PREFIX "/lib/tpm/system.data" #define TCSD_DEFAULT_SYSTEM_PS_DIR VAR_PREFIX "/lib/tpm" +#define TCSD_DEFAULT_SOCKET VAR_PREFIX "/run/tpm/tpmd_socket:0" + +#endif /* SOLARIS */ #define TCSD_DEFAULT_FIRMWARE_LOG_FILE "/sys/kernel/security/tpm0/binary_bios_measurements" #define TCSD_DEFAULT_KERNEL_LOG_FILE "/sys/kernel/security/ima/binary_runtime_measurements" #define TCSD_DEFAULT_FIRMWARE_PCRS 0x00000000 --- src/include/tspps.h.old 2009-09-08 07:39:30.000000000 -0700 +++ src/include/tspps.h 2010-09-16 08:09:37.980051068 -0700 @@ -13,13 +13,17 @@ #define PASSWD_BUFSIZE 4096 +#ifdef SOLARIS +#define TSS_USER_PS_DIR "/var/user/" +#else #define TSS_USER_PS_DIR ".trousers" +#endif #define TSS_USER_PS_FILE "user.data" TSS_RESULT get_file(int *); int put_file(int); -inline TSS_RESULT read_data(int, void *, UINT32); -inline TSS_RESULT write_data(int, void *, UINT32); +TSS_RESULT read_data(int, void *, UINT32); +TSS_RESULT write_data(int, void *, UINT32); UINT32 psfile_get_num_keys(int); TSS_RESULT psfile_get_parent_uuid_by_uuid(int, TSS_UUID *, TSS_UUID *); TSS_RESULT psfile_remove_key_by_uuid(int, TSS_UUID *); # Add ability to connect to UNIX socket and make it the default. # Drop Solaris privileges for security. # Add -h and --help options. # Update the event log file during startup and shutdown. # This change was implemented in-house and is suitable for upstream use. # --- src/tcsd/svrside.c 2014-04-24 11:05:44.000000000 -0700 +++ src/tcsd/svrside.c 2016-04-26 15:49:54.940330002 -0700 @@ -28,6 +28,16 @@ #include #include #include + +#ifdef SOLARIS +#include +#include +#endif +#ifndef HAVE_DAEMON +#include +#include +#endif + #include "trousers/tss.h" #include "trousers_types.h" #include "tcs_tsp.h" @@ -54,6 +64,204 @@ #define MAX_IP_PROTO 2 #define INVALID_ADDR_STR "" +#ifdef SOLARIS +extern int get_device_fd(void); + +#define TPM_IOCTL_GETEVTABLE 1 +struct tpm_evtable_ioblk { + uint32_t buflen; + caddr_t buf; +}; + +static int +store_eventlog(char *filename, struct tpm_evtable_ioblk *evlog) +{ + int fd; + unsigned int bytes = 0; + + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600); + if (fd == -1) { + LogError("Error opening logfile %s: %s", filename, + strerror(errno)); + return (-1); + } + while (bytes < evlog->buflen) { + int n; + n = write(fd, evlog->buf, evlog->buflen - bytes); + if (n == -1 && errno != EAGAIN) { + LogError("Error writing logfile %s: %s", + filename, strerror(errno)); + close(fd); + return (-1); + } + if (n != -1) + bytes += n; + } + close(fd); + + return (0); +} + +static int +get_event_log_from_kernel(void) +{ + int fd = get_device_fd(); + struct tpm_evtable_ioblk ioblk; + + if (fd == -1) + return (-1); + + (void) memset(&ioblk, 0, sizeof (ioblk)); + if (ioctl(fd, TPM_IOCTL_GETEVTABLE, &ioblk)) { + LogDebug("Cannot get event log from kernel: %s", + strerror(errno)); + return (-1); + } + if (ioblk.buflen == 0) + return (0); + + ioblk.buf = calloc(1, ioblk.buflen); + if (ioblk.buf == NULL) { + return (-1); + } + if (ioctl(fd, TPM_IOCTL_GETEVTABLE, &ioblk)) { + free(ioblk.buf); + LogDebug("Cannot get event log from kernel: %s", + strerror(errno)); + return (-1); + } + + return (store_eventlog(tcsd_options.firmware_log_file, &ioblk)); +} + +/* + * For Solaris, make the tcsd privilege aware and drop + * risky privileges if they are not needed. + */ +static int +drop_privs(void) +{ + priv_set_t *myprivs; + int rv; + + /* + * Drop unneeded privs such as fork/exec. + * + * Get "basic" privs and remove the ones we don't want. + */ + if ((myprivs = priv_str_to_set("basic", ",", NULL)) == NULL) { + LogError("priv_str_to_set failed: %s", strerror(errno)); + return (1); + } else { + (void) priv_delset(myprivs, PRIV_PROC_EXEC); + (void) priv_delset(myprivs, PRIV_PROC_FORK); + (void) priv_delset(myprivs, PRIV_FILE_LINK_ANY); + (void) priv_delset(myprivs, PRIV_PROC_INFO); + (void) priv_delset(myprivs, PRIV_PROC_SESSION); + (void) priv_delset(myprivs, PRIV_PROC_SETID); + + /* for auditing */ + (void) priv_addset(myprivs, PRIV_PROC_AUDIT); + + if ((rv = setppriv(PRIV_SET, PRIV_PERMITTED, myprivs))) + return (rv); + if ((rv = setppriv(PRIV_SET, PRIV_LIMIT, myprivs))) + return (rv); + if ((rv = setppriv(PRIV_SET, PRIV_INHERITABLE, myprivs))) + return (rv); + + (void) priv_freeset(myprivs); + } + return (0); +} +#endif /* SOLARIS */ + +#ifndef HAVE_DAEMON +static int +daemon(int nochdir, int noclose) { + int rv, fd; + + if (!noclose) { + closelog(); + closefrom(0); + } + + switch (fork()) { + case -1: /* failure: parent process */ + return (-1); + case 0: /* success: child process */ + break; + default: /* success: parent process */ + exit (0); + } + + /* Create a new SID for the child process */ + if (setsid() == -1) + return (-1); + /* Prevent cwd from being left open and unremovable */ + if (!nochdir) + (void) chdir("/"); + (void) umask(0); + return (0); +} +#endif /* !HAVE_DAEMON */ + + +static int +setup_unix_socket(struct srv_sock_info ssi[]) +{ + struct sockaddr_un serv_addr; + int sd, opt; + + ssi->sd = -1; + + // Initialization of UNIX socket. + sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sd < 0) { + LogWarn("Failed UNIX socket: %s", strerror(errno)); + goto err; + } + + memset(&serv_addr, 0, sizeof (serv_addr)); + serv_addr.sun_family = AF_UNIX; + strncpy(serv_addr.sun_path, TCSD_DEFAULT_SOCKET, + sizeof(serv_addr.sun_path)); + /* Remove previous stale server socket, if any */ + (void) unlink(TCSD_DEFAULT_SOCKET); + + LogDebug("Connecting to UNIX Domain socket %s", + TCSD_DEFAULT_SOCKET); + + + if (bind(sd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) { + LogWarn("Failed UNIX socket bind: %s", strerror(errno)); + goto err; + } + + if (listen(sd, TCSD_MAX_SOCKETS_QUEUED) < 0) { + LogWarn("Failed UNIX socket listen: %s", strerror(errno)); + goto err; + } + + if (chmod(serv_addr.sun_path, 0666) < 0) { + LogError("Failed chmod %s: %s", serv_addr.sun_path, + strerror(errno)); + return (-1); + } + + ssi->domain = AF_UNIX; + ssi->sd = sd; + ssi->addr_len = sizeof (serv_addr); + + return (0); + + err: + if (sd != -1) + close(sd); + + return (-1); +} + static void close_server_socks(struct srv_sock_info *socks_info) { int i, rv; @@ -83,6 +291,10 @@ auth_mgr_final(); (void)req_mgr_final(); conf_file_final(&tcsd_options); +#ifdef SOLARIS + /* Not fatal if this fails */ + (void) get_event_log_from_kernel(); +#endif EVENT_LOG_final(); } @@ -199,6 +411,10 @@ (void)req_mgr_final(); return result; } +#ifdef SOLARIS + /* Not fatal if this fails */ + (void) get_event_log_from_kernel(); +#endif result = owner_evict_init(); if (result != TSS_SUCCESS) { @@ -352,6 +568,13 @@ int i=0; ssi[0].sd = ssi[1].sd = -1; + + // By default, use UNIX socket + if (tcsd_options.port == 0) { + return (setup_unix_socket(&ssi[0])); + } + + // Use TCP/IP socket // Only enqueue sockets successfully bound or that weren't disabled. if (tcsd_options.disable_ipv4) { LogWarn("IPv4 support disabled by configuration option"); @@ -380,11 +603,17 @@ if (getnameinfo((struct sockaddr *)client_addr, socklen, buf, sizeof(buf), NULL, 0, 0) != 0) { - LogWarn("Could not retrieve client address info"); - return NULL; - } else { - return strdup(buf); + if (tcsd_options.port == 0) { /* UNIX socket (always local) */ + if (gethostname(buf, sizeof (buf)) != 0) { + strcpy(buf, "localhost"); + } + } else { + LogWarn("Could not retrieve client address info"); + return NULL; + } } + + return (strdup(buf)); } void prepare_for_select(struct srv_sock_info *socks_info, int *num_fds, @@ -491,6 +720,14 @@ } } +#ifdef SOLARIS + /* For Solaris, drop privileges for security. */ + if ((rv = drop_privs())) { + LogError("drop_privs failed: %s", strerror(errno)); + return (rv); + } +#endif /* SOLARIS */ + LogInfo("%s: TCSD up and running.", PACKAGE_STRING); sigemptyset(&sigmask); # Add ability to connect to UNIX socket and make it the default. # Patch suitable for upstream use. # This change was implemented in-house. # --- src/tspi/rpc/tcstp/rpc.c 2014-04-24 11:05:44.000000000 -0700 +++ src/tspi/rpc/tcstp/rpc.c 2016-04-22 15:08:53.058153900 -0700 @@ -477,6 +477,37 @@ goto exit; } + if ((port_str == NULL) || (strlen(port_str) == 0) || + (strcmp(port_str, "0") == 0)) { /* use UNIX socket (default) */ + struct sockaddr_un sock_addr; + + *sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (*sd == -1) { + LogError("socket(PF_UNIX): %s", strerror(errno)); + result = TSPERR(TSS_E_COMM_FAILURE); + return (result); + } + + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sun_family = AF_UNIX; + strncpy(sock_addr.sun_path, TCSD_DEFAULT_SOCKET, + sizeof(sock_addr.sun_path)); + + LogDebug("Connecting to UNIX Domain socket %s", + TCSD_DEFAULT_SOCKET); + + if (connect(*sd, (struct sockaddr *) &sock_addr, + sizeof (sock_addr))) { + LogError("connect: %s", strerror(errno)); + result = TSPERR(TSS_E_COMM_FAILURE); + return (result); + } + + return (TSS_SUCCESS); + } + + /* Use TCP/IP socket */ + LogDebug("Retrieving address information from host: %s", (char *)hte->hostname); rv = getaddrinfo((char *)hte->hostname, port_str, &hints, &res);