summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjirka-h <hladky.jiri@gmail.com>2020-12-20 03:07:40 +0100
committerGitHub <noreply@github.com>2020-12-20 03:07:40 +0100
commita806aa1c2d639296be7be537d825d116f3ba6e34 (patch)
treea72c781d56eeb5005f0ba1d1ee6eb13759047dc1
parentUpdate README (diff)
parentFix error handling as well as add new command (diff)
downloadhaveged-a806aa1c2d639296be7be537d825d116f3ba6e34.tar.xz
haveged-a806aa1c2d639296be7be537d825d116f3ba6e34.zip
Merge pull request #52 from bitstreamout/boo1178738
Fix error handling as well as add new command
-rw-r--r--man/haveged.86
-rw-r--r--src/havegecmd.c200
-rw-r--r--src/havegecmd.h17
-rw-r--r--src/haveged.c82
-rw-r--r--src/haveged.h5
5 files changed, 226 insertions, 84 deletions
diff --git a/man/haveged.8 b/man/haveged.8
index 75bc5a2..edbc611 100644
--- a/man/haveged.8
+++ b/man/haveged.8
@@ -34,7 +34,11 @@ Set collection buffer size to nnn KW. Default is 128KW (or 512KB).
-c cmd, --command=cmd
Switch to command mode and send a command to an already running
.B haveged
-process or daemon. Currently the only knows command is
+process or daemon. Currently the only known commands are
+.I close
+to close the current communication socket of the running
+.B haveged
+process as well as
.IR root = <new_root>
where
.I <new_root>
diff --git a/src/havegecmd.c b/src/havegecmd.c
index 18ff322..0a324ed 100644
--- a/src/havegecmd.c
+++ b/src/havegecmd.c
@@ -26,6 +26,7 @@
#ifndef NO_COMMAND_MODE
#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
@@ -35,6 +36,7 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
@@ -49,45 +51,60 @@ struct ucred
#include "havegecmd.h"
+int first_byte;
int socket_fd;
+static char errmsg[1024];
-static void new_root( /* RETURN: nothing */
+static int new_root( /* RETURN: status */
const char *root, /* IN: path of the new root file system */
const volatile char *path, /* IN: path of the haveged executable */
char *const argv[], /* IN: arguments for the haveged process */
struct pparams *params) /* IN: input params */
{
int ret;
+ struct stat st;
+ const char *realtive = (const char*)&path[0];
- fprintf(stderr, "%s: restart in new root: %s\n", params->daemon, root);
ret = chdir(root);
if (ret < 0) {
- if (errno != ENOENT)
- error_exit("can't change to working directory : %s", root);
- else
- fprintf(stderr, "%s: can't change to working directory : %s\n", params->daemon, root);
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't change to working directory %s: %s\n",
+ root, strerror(errno));
+ goto err;
+ }
+ if (path[0] == '/')
+ realtive++;
+ ret = fstatat(AT_FDCWD, realtive, &st, 0);
+ if (ret < 0) {
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't restart %s: %s\n",
+ path, strerror(errno));
+ goto err;
}
ret = chroot(".");
if (ret < 0) {
- if (errno != ENOENT)
- error_exit("can't change root directory");
- else
- fprintf(stderr, "%s: can't change root directory\n", params->daemon);
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't change root directory %s\n",
+ strerror(errno));
+ goto err;
}
ret = chdir("/");
if (ret < 0) {
- if (errno != ENOENT)
- error_exit("can't change to working directory /");
- else
- fprintf(stderr, "%s: can't change to working directory /\n", params->daemon);
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't change to working directory / : %s\n",
+ strerror(errno));
+ goto err;
}
ret = execv((const char *)path, argv);
if (ret < 0) {
- if (errno != ENOENT)
- error_exit("can't restart %s", path);
- else
- fprintf(stderr, "%s: can't restart %s\n", params->daemon, path);
- }
+ snprintf(&errmsg[0], sizeof(errmsg)-1,
+ "can't restart %s: %s\n",
+ path, strerror(errno));
+ }
+err:
+ if (ret < 0)
+ print_msg("%s", errmsg);
+ return ret;
}
/**
@@ -105,7 +122,7 @@ int cmd_listen( /* RETURN: UNIX socket file descriptor */
fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
- fprintf(stderr, "%s: can not open UNIX socket\n", params->daemon);
+ print_msg("%s: can not open UNIX socket\n", params->daemon);
goto err;
}
@@ -113,7 +130,7 @@ int cmd_listen( /* RETURN: UNIX socket file descriptor */
if (ret < 0) {
close(fd);
fd = -1;
- fprintf(stderr, "%s: can not set option for UNIX socket\n", params->daemon);
+ print_msg("%s: can not set option for UNIX socket\n", params->daemon);
goto err;
}
@@ -122,7 +139,7 @@ int cmd_listen( /* RETURN: UNIX socket file descriptor */
close(fd);
fd = -1;
if (errno != EADDRINUSE)
- fprintf(stderr, "%s: can not bind a name to UNIX socket\n", params->daemon);
+ print_msg("%s: can not bind a name to UNIX socket\n", params->daemon);
else
fd = -2;
goto err;
@@ -132,7 +149,7 @@ int cmd_listen( /* RETURN: UNIX socket file descriptor */
if (ret < 0) {
close(fd);
fd = -1;
- fprintf(stderr, "%s: can not listen on UNIX socket\n", params->daemon);
+ print_msg("%s: can not listen on UNIX socket\n", params->daemon);
goto err;
}
err:
@@ -154,13 +171,13 @@ int cmd_connect( /* RETURN: UNIX socket file descriptor */
fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
- fprintf(stderr, "%s: can not open UNIX socket\n", params->daemon);
+ print_msg("%s: can not open UNIX socket\n", params->daemon);
goto err;
}
ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, (socklen_t)sizeof(one));
if (ret < 0) {
- fprintf(stderr, "%s: can not set option for UNIX socket\n", params->daemon);
+ print_msg("%s: can not set option for UNIX socket\n", params->daemon);
close(fd);
fd = -1;
goto err;
@@ -169,7 +186,7 @@ int cmd_connect( /* RETURN: UNIX socket file descriptor */
ret = connect(fd, (struct sockaddr *)&su, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1));
if (ret < 0) {
if (errno != ECONNREFUSED)
- fprintf(stderr, "%s: can not connect on UNIX socket\n", params->daemon);
+ print_msg("%s: can not connect on UNIX socket\n", params->daemon);
close(fd);
fd = -1;
goto err;
@@ -191,6 +208,7 @@ int getcmd( /* RETURN: success or error */
const char* opt;
} cmds[] = {
{ "root=", MAGIC_CHROOT, 1, NULL }, /* New root */
+ { "close", MAGIC_CLOSE, 0, NULL }, /* Close socket */
{0}
}, *cmd = cmds;
int ret = -1;
@@ -235,39 +253,52 @@ int socket_handler( /* RETURN: closed file descriptor */
int ret = -1, len;
if (fd < 0) {
- fprintf(stderr, "%s: no connection jet\n", params->daemon);
+ print_msg("%s: no connection jet\n", params->daemon);
}
ptr = &magic[0];
len = sizeof(magic);
ret = safein(fd, ptr, len);
+ if (ret < 0) {
+ print_msg("%s: can not read from UNIX socket\n", params->daemon);
+ goto out;
+ }
- if (magic[1] == '\002') { /* read argument provided */
- unsigned char alen;
+ if (magic[1] == '\002') { /* ASCII start of text: read argument provided */
+ uint32_t alen;
- ret = safein(fd, &alen, sizeof(unsigned char));
+ ret = receive_uinteger(fd, &alen);
+ if (ret < 0) {
+ print_msg("%s: can not read from UNIX socket\n", params->daemon);
+ goto out;
+ }
optarg = calloc(alen, sizeof(char));
- if (!optarg)
- error_exit("can not allocate memory for message from UNIX socket");
-
+ if (!optarg) {
+ print_msg("can not allocate memory for message from UNIX socket");
+ goto out;
+ }
ptr = (unsigned char*)optarg;
- len = alen;
- ret = safein(fd, ptr, len);
+
+ ret = safein(fd, ptr, alen);
+ if (ret < 0) {
+ print_msg("%s: can not read from UNIX socket\n", params->daemon);
+ goto out;
+ }
}
clen = sizeof(struct ucred);
ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &clen);
if (ret < 0) {
- fprintf(stderr, "%s: can not get credentials from UNIX socket part1\n", params->daemon);
+ print_msg("%s: can not get credentials from UNIX socket part1\n", params->daemon);
goto out;
}
if (clen != sizeof(struct ucred)) {
- fprintf(stderr, "%s: can not get credentials from UNIX socket part2\n", params->daemon);
+ print_msg("%s: can not get credentials from UNIX socket part2\n", params->daemon);
goto out;
}
if (cred.uid != 0) {
- enqry = "\x15";
+ enqry = ASCII_NAK;
ptr = (unsigned char *)enqry;
len = (int)strlen(enqry)+1;
@@ -276,19 +307,39 @@ int socket_handler( /* RETURN: closed file descriptor */
switch (magic[0]) {
case MAGIC_CHROOT:
- enqry = "\x6";
+ enqry = ASCII_ACK;
+
+ ret = new_root(optarg, path, argv, params);
+ if (ret < 0) {
+ uint32_t size = strlen(errmsg);
+ safeout(fd, ASCII_STX, strlen(ASCII_STX));
+ send_uinteger(fd, size);
+ safeout(fd, errmsg, size+1);
+ break;
+ }
+
+ ptr = (unsigned char *)enqry;
+ len = (int)strlen(enqry);
+ safeout(fd, ptr, len);
+
+ break;
+ case MAGIC_CLOSE:
+ enqry = ASCII_ACK;
+
+ close(socket_fd);
+ socket_fd = -1;
ptr = (unsigned char *)enqry;
- len = (int)strlen(enqry)+1;
+ len = (int)strlen(enqry);
safeout(fd, ptr, len);
+ argv[0][0] = first_byte;
- new_root(optarg, path, argv, params);
break;
default:
- enqry = "\x15";
+ enqry = ASCII_NAK;
ptr = (unsigned char *)enqry;
- len = (int)strlen(enqry)+1;
+ len = (int)strlen(enqry);
safeout(fd, ptr, len);
break;
}
@@ -308,31 +359,30 @@ out:
ssize_t safein( /* RETURN: read bytes */
int fd, /* IN: file descriptor */
void *ptr, /* OUT: pointer to buffer */
- size_t sz) /* IN: size of buffer */
+ size_t len) /* IN: size of buffer */
{
- int saveerr = errno, t;
+ int saveerr = errno, avail;
ssize_t ret = 0;
- size_t len;
- if (sz > SSIZE_MAX)
- sz = SSIZE_MAX;
+ if (len > SSIZE_MAX)
+ len = SSIZE_MAX;
- t = 0;
- if ((ioctl(fd, FIONREAD, &t) < 0) || (t <= 0))
+ ret = ioctl(fd, FIONREAD, &avail);
+ if (ret < 0 || avail <=0)
goto out;
- len = (size_t)t;
- if (len > sz)
- len = sz;
+ if (len > avail)
+ len = avail;
do {
- ssize_t p = recv(fd, ptr, len, MSG_DONTWAIT);
+ errno = saveerr;
+ ssize_t p = recv(fd, ptr, len, 0 /* MSG_DONTWAIT */);
if (p < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
- error_exit("Unable to read from socket: %d", socket_fd);
+ print_msg("Unable to read from socket %d: %s", socket_fd, strerror(errno));
}
ptr = (char *) ptr + p;
ret += p;
@@ -340,7 +390,6 @@ ssize_t safein( /* RETURN: read bytes */
}
while (len > 0);
out:
- errno = saveerr;
return ret;
}
@@ -361,7 +410,7 @@ void safeout( /* RETURN: nothing */
continue;
if (errno == EPIPE || errno == EAGAIN || errno == EWOULDBLOCK)
break;
- error_exit("Unable to write to socket: %d", fd);
+ print_msg("Unable to write to socket %d: %s", fd, strerror(errno));
}
ptr = (char *) ptr + p;
len -= p;
@@ -371,4 +420,41 @@ void safeout( /* RETURN: nothing */
errno = saveerr;
}
+/**
+ * Send outgoing unsigned integer to socket
+ */
+void send_uinteger( /* RETURN: nothing */
+ int fd, /* IN: file descriptor */
+ uint32_t value) /* IN: 32 bit unsigned integer */
+{
+ uint8_t buffer[4];
+
+ buffer[0] = (uint8_t)((value >> 24) & 0xFF);
+ buffer[1] = (uint8_t)((value >> 16) & 0xFF);
+ buffer[2] = (uint8_t)((value >> 8) & 0xFF);
+ buffer[3] = (uint8_t)((value >> 0) & 0xFF);
+
+ safeout(fd, buffer, 4 * sizeof(uint8_t));
+}
+
+/**
+ * Receive incomming unsigned integer from socket
+ */
+int receive_uinteger( /* RETURN: status */
+ int fd, /* IN: file descriptor */
+ uint32_t *value) /* OUT: 32 bit unsigned integer */
+{
+ uint8_t buffer[4];
+
+ if (safein(fd, buffer, 4 * sizeof(uint8_t)) < 0)
+ return -1;
+
+ *value = (((uint32_t)buffer[0]) << 24) |
+ (((uint32_t)buffer[1]) << 16) |
+ (((uint32_t)buffer[2]) << 8) |
+ (((uint32_t)buffer[3]) << 0);
+
+ return 0;
+}
+
#endif
diff --git a/src/havegecmd.h b/src/havegecmd.h
index 997c5d1..a9f2b9a 100644
--- a/src/havegecmd.h
+++ b/src/havegecmd.h
@@ -34,6 +34,12 @@ extern "C" {
#define HAVEGED_SOCKET_PATH "\0/sys/entropy/haveged"
#define MAGIC_CHROOT 'R'
+#define MAGIC_CLOSE 'X'
+#define MAGIC_PATH 'P'
+
+#define ASCII_ACK "\x6" /* ASCII acknowledge */
+#define ASCII_NAK "\x15" /* ASCII negative acknowledge */
+#define ASCII_STX "\x2" /* ASCII start of text */
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
@@ -74,10 +80,21 @@ ssize_t safein(int, void *, size_t);
void safeout(int, const void *, size_t);
/**
+ * Send outgoing unsigned integer to socket
+ */
+void send_uinteger(int, uint32_t);
+
+/**
+ * Receive incomming unsigned integer from socket
+ */
+int receive_uinteger(int, uint32_t *);
+
+/**
* Socket file descriptor used for communication
*/
extern int socket_fd;
+extern int first_byte;
#ifdef __cplusplus
}
diff --git a/src/haveged.c b/src/haveged.c
index 733d0da..4440a45 100644
--- a/src/haveged.c
+++ b/src/haveged.c
@@ -19,6 +19,7 @@
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
+#include <sys/auxv.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
@@ -118,7 +119,6 @@ static void set_watermark(int level);
static void anchor_info(H_PTR h);
static int get_runsize(unsigned int *bufct, unsigned int *bufrem, char *bp);
static char *ppSize(char *buffer, double sz);
-static void print_msg(const char *format, ...);
static void run_app(H_PTR handle, H_UINT bufct, H_UINT bufres);
static void show_meterInfo(H_UINT id, H_UINT event);
@@ -135,6 +135,8 @@ int main(int argc, char **argv)
{
volatile char *path = strdup(argv[0]);
volatile char *arg0 = argv[0];
+ if (path[0] != '/')
+ path = (char*)getauxval(AT_EXECFN);
static const char* cmds[] = {
"b", "buffer", "1", SETTINGR("Buffer size [KW], default: ",COLLECT_BUFSIZE),
"d", "data", "1", SETTINGR("Data cache size [KB], with fallback to: ", GENERIC_DCACHE ),
@@ -188,6 +190,7 @@ int main(int argc, char **argv)
params->setup |= MULTI_CORE;
#endif
+ first_byte = arg0[0];
if (access("/etc/initrd-release", F_OK) >= 0) {
arg0[0] = '@';
path[0] = '/';
@@ -339,8 +342,10 @@ int main(int argc, char **argv)
#ifndef NO_COMMAND_MODE
if (params->setup & CMD_MODE) {
int ret = 0, len;
- char *ptr, message[PATH_MAX+5], answer[2], cmd[2];
+ uint32_t size;
+ char *ptr, answer[6], cmd[2];
fd_set read_fd;
+ sigset_t block;
socket_fd = cmd_connect(params);
if (socket_fd < 0) {
@@ -357,14 +362,15 @@ int main(int argc, char **argv)
char *root;
case MAGIC_CHROOT:
root = optarg;
- len = (int)strlen(root);
- ret = snprintf(message, sizeof(message), "%c\002%c%s%n", cmd[0], (int)(strlen(root) + 1), root, &len);
- if (ret < 0 || (unsigned) ret >= sizeof(message)) {
- fprintf(stderr, "%s: can not store message\n", params->daemon);
- break;
- }
- ptr = &message[0];
- len += 1;
+ size = (uint32_t)strlen(root)+1;
+ cmd[1] = '\002';
+ safeout(socket_fd, &cmd[0], 2);
+ send_uinteger(socket_fd, size);
+ safeout(socket_fd, root, size);
+ break;
+ case MAGIC_CLOSE:
+ ptr = &cmd[0];
+ len = (int)strlen(cmd)+1;
safeout(socket_fd, ptr, len);
break;
case '?':
@@ -374,13 +380,15 @@ int main(int argc, char **argv)
}
answer[0] = '\0';
ptr = &answer[0];
- len = sizeof(answer);
+
+ sigemptyset(&block);
+ sigaddset(&block, SIGPIPE);
FD_ZERO(&read_fd);
FD_SET(socket_fd, &read_fd);
do {
- struct timeval two = {2, 0};
+ struct timeval two = {6, 0};
ret = select(socket_fd+1, &read_fd, NULL, NULL, &two);
if (ret >= 0) break;
if (errno != EINTR)
@@ -388,15 +396,37 @@ int main(int argc, char **argv)
}
while (1);
- ret = safein(socket_fd, ptr, len);
- close(socket_fd);
+ ret = safein(socket_fd, ptr, 1);
if (ret < 0)
goto err;
- if (answer[0] != '\x6')
- ret = -1;
- else
- ret = 0;
+ switch (answer[0]) {
+ case '\002': {
+ char *msg;
+ ret = receive_uinteger(socket_fd, &size);
+ if (ret < 0)
+ goto err;
+ msg = calloc(size, sizeof(char));
+ if (!msg)
+ error_exit("can not allocate memory for message from UNIX socket: %s",
+ strerror(errno));
+ ret = safein(socket_fd, msg, size);
+ if (ret < 0)
+ goto err;
+ fprintf(stderr, "%s: %s", params->daemon, msg);
+ free(msg);
+ ret = -1;
+ }
+ break;
+ case '\x6':
+ ret = 0;
+ break;
+ case '\x15':
+ default:
+ ret = -1;
+ break;
+ }
err:
+ close(socket_fd);
return ret;
}
else {
@@ -404,13 +434,13 @@ int main(int argc, char **argv)
if (socket_fd >= 0)
fprintf(stderr, "%s: command socket is listening at fd %d\n", params->daemon, socket_fd);
else {
- if (socket_fd == -2) {
- fprintf(stderr, "%s: command socket already in use\n", params->daemon);
- fprintf(stderr, "%s: please check if there is another instance of haveged running\n", params->daemon);
- fprintf(stderr, "%s: disabling command mode for this instance\n", params->daemon);
- } else {
- fprintf(stderr, "%s: can not initialize command socket: %s\n", params->daemon, strerror(errno));
- }
+ if (socket_fd == -2) {
+ fprintf(stderr, "%s: command socket already in use\n", params->daemon);
+ error_exit("%s: please check if there is another instance of haveged running\n", params->daemon);
+ } else {
+ fprintf(stderr, "%s: can not initialize command socket: %s\n", params->daemon, strerror(errno));
+ fprintf(stderr, "%s: disabling command mode for this instance\n", params->daemon);
+ }
}
}
#endif
@@ -834,7 +864,7 @@ static char *ppSize( /* RETURN: the formatted size */
/**
* Execution notices - to stderr or syslog
*/
-static void print_msg( /* RETURN: nothing */
+void print_msg( /* RETURN: nothing */
const char *format, /* IN: format string */
...) /* IN: args */
{
diff --git a/src/haveged.h b/src/haveged.h
index 9b1efaf..40e07a0 100644
--- a/src/haveged.h
+++ b/src/haveged.h
@@ -92,4 +92,9 @@ typedef struct {
*/
void error_exit(const char *, ...);
+/**
+ * Execution notices - to stderr or syslog
+ */
+void print_msg(const char *, ...);
+
#endif