Files
s390-tools/zconf/zcrypt/chzcrypt.c
Harald Freudenberger 6b8b336cf0 lszcrypt: Fix core dump caused by stack overwrite.
There was a too tight buffer allocated on the stack
which was overwritten by just one byte caused to
dump the application on function exit's stack check.
Reviewed all the buffer sizes and adapted them
to the need of the functions.

Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2017-09-06 13:03:31 +02:00

422 lines
11 KiB
C

/*
* chzcrypt - Tool to modify zcrypt configuration
*
* Copyright IBM Corp. 2008, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <argz.h>
#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_opt.h"
#include "lib/util_panic.h"
#include "lib/util_path.h"
#include "lib/util_prg.h"
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
#include "misc.h"
/*
* Private data
*/
struct chzcrypt_l {
int verbose;
} l;
struct chzcrypt_l *chzcrypt_l = &l;
/*
* Program configuration
*/
const struct util_prg prg = {
.desc = "Modify zcrypt configuration.",
.args = "[DEVICE_IDS]",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2008,
.pub_last = 2017,
},
UTIL_PRG_COPYRIGHT_END
}
};
/*
* Configuration of command line options
*/
static struct util_opt opt_vec[] = {
{
.option = { "enable", no_argument, NULL, 'e'},
.argument = "DEVICE_IDS",
.desc = "Set the given cryptographic device(s) online"
},
{
.option = { "disable", no_argument, NULL, 'd'},
.argument = "DEVICE_IDS",
.desc = "Set the given cryptographic device(s) offline",
},
{
.option = { "all", no_argument, NULL, 'a'},
.desc = "Set all available cryptographic device(s) "
"online/offline, must be used in conjunction "
"with the enable or disable option",
},
{
.option = { "poll-thread-enable", no_argument, NULL, 'p'},
.desc = "Enable zcrypt's poll thread",
},
{
.option = { "poll-thread-disable", no_argument, NULL, 'n'},
.desc = "Disable zcrypt's poll thread",
},
{
.option = { "config-time", required_argument, NULL, 'c'},
.argument = "TIMEOUT",
.desc = "Set configuration timer for re-scanning the AP bus "
"to TIMEOUT seconds",
},
{
.option = { "poll-timeout", required_argument, NULL, 't'},
.argument = "TIMEOUT",
.desc = "Set poll timer to run poll tasklet all TIMEOUT "
"nanoseconds after a request has been queued",
},
{
.option = { "default-domain", required_argument, NULL, 'q'},
.argument = "DOMAIN",
.desc = "Set new default domain to DOMAIN",
},
{
.option = { "verbose", no_argument, NULL, 'V'},
.desc = "Print verbose messages",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
/*
* Print if verbose is set
*/
#define verbose(x...) \
do { \
if (!l.verbose) \
break; \
printf(x); \
} while (0)
/*
* Set poll settings
*/
static void poll_thread_set(const char *mode_str)
{
long mode, mode_read = -1;
char *attr;
sscanf(mode_str, "%ld", &mode);
if (mode == 1)
verbose("Enabling poll thread.\n");
else
verbose("Disabling poll thread.\n");
attr = util_path_sysfs("bus/ap/poll_thread");
if (!util_path_is_writable(attr))
errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions"
" or wrong tools version.", attr);
util_file_write_l(mode, 10, attr);
util_file_read_l(&mode_read, 10, attr);
if (mode != mode_read)
errx(EXIT_FAILURE, "Error - unable to change poll thread setting.");
free(attr);
}
/*
* Set timer
*/
static void config_time_set(const char *timeout_str)
{
long timeout, timeout_read;
char *attr;
if (sscanf(timeout_str, "%ld", &timeout) != 1) {
errx(EXIT_FAILURE, "Error - invalid configuration timeout '%s'.", timeout_str);
}
attr = util_path_sysfs("bus/ap/config_time");
verbose("Setting configuration timer to %ld seconds.\n", timeout);
if (!util_path_is_writable(attr))
errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions"
" or wrong tools version.", attr);
util_file_write_l(timeout, 10, attr);
util_file_read_l(&timeout_read, 10, attr);
if (timeout != timeout_read)
errx(EXIT_FAILURE, "Error - unable to change configuration timer setting.");
free(attr);
}
/*
* Set poll timeout
*/
static void poll_timeout_set(const char *poll_timeout_str)
{
long poll_timeout, poll_timeout_read;
char *attr;
if (sscanf(poll_timeout_str, "%ld", &poll_timeout) != 1)
errx(EXIT_FAILURE, "Error - invalid poll timeout '%s'.", poll_timeout_str);
attr = util_path_sysfs("bus/ap/poll_timeout");
verbose("Setting poll timeout to %ld seconds.\n", poll_timeout);
if (!util_path_is_writable(attr))
errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions"
" or wrong tools version.", attr);
util_file_write_l(poll_timeout, 10, attr);
util_file_read_l(&poll_timeout_read, 10, attr);
if (poll_timeout != poll_timeout_read)
errx(EXIT_FAILURE, "Error - unable to change poll timeout setting.");
free(attr);
}
/*
* Set default domain
*/
static void default_domain_set(const char *default_domain_str)
{
long max_dom, default_domain, default_domain_read;
char *attr, *ap_max_domain_id;
sscanf(default_domain_str, "%li", &default_domain);
ap_max_domain_id = util_path_sysfs("bus/ap/ap_max_domain_id");
util_file_read_l(&max_dom, 10, ap_max_domain_id);
if (default_domain < 0 || default_domain > max_dom)
errx(EXIT_FAILURE, "Error - invalid default domain '%s'.", default_domain_str);
attr = util_path_sysfs("bus/ap/ap_domain");
if (!util_path_is_writable(attr))
errx(EXIT_FAILURE, "Error - can't write to %s.\n Wrong permissions"
" or wrong tools version.", attr);
verbose("Setting default domain to %ld.\n", default_domain);
util_file_write_l(default_domain, 10, attr);
util_file_read_l(&default_domain_read, 10, attr);
if (default_domain != default_domain_read)
errx(EXIT_FAILURE, "Error - unable to change default domain.");
free(ap_max_domain_id);
free(attr);
}
/*
* Print invalid commandline error message and then exit with error code
*/
#define invalid_cmdline_exit(x...) \
do { \
fprintf(stderr, "%s: ", program_invocation_short_name); \
fprintf(stderr, x); \
util_prg_print_parse_error(); \
exit(EXIT_FAILURE); \
} while (0)
/*
* Get device list from sysfs
*/
static void dev_list_all(char **argz, size_t *len)
{
struct dirent **de_vec;
int count, i;
char *path;
path = util_path_sysfs("bus/ap/devices/");
count = util_scandir(&de_vec, NULL, path, "card.*");
if (count < 0)
errx(EXIT_FAILURE, "Error - Could not read directory %s.", path);
*argz = NULL;
*len = 0;
for (i = 0; i < count; i++)
util_assert(argz_add(argz, len, de_vec[i]->d_name) == 0,
"Out of memory\n");
util_scandir_free(de_vec, count);
free(path);
}
/*
* Get device list from commandline
*/
static void dev_list_argv(char **argz, size_t *len, char * const argv[])
{
if (argv[0] == NULL)
errx(EXIT_FAILURE, "Need to specify at least one device ID.");
util_assert(argz_create(argv, argz, len) == 0, "Out of memory\n");
}
/*
* Describe adapter ids
*/
void print_adapter_id_help(void)
{
printf("\n");
printf("DEVICE_IDS\n");
printf(" List of cryptographic device ids separated by blanks which will be set\n");
printf(" online/offline. Must be used in conjunction with the enable or disable option.\n");
printf(" DEVICE_ID could either be card device id ('<card-id>') or queue device id\n");
printf(" '<card-id>.<domain-id>').\n");
printf(" \n");
printf("EXAMPLE:\n");
printf(" Disable the cryptographic device with card id '02' (inclusive all queues).\n");
printf(" #>chzcrypt -d 02\n");
printf(" \n");
printf(" Enable the cryptographic devices with card id '03' and domain id '0005'.\n");
printf(" #>chzcrypt -e 03.0005\n");
printf(" \n");
}
/*
* Parse options and execute the command
*/
int main(int argc, char *argv[])
{
const char *online, *online_text = NULL, *poll_thread, *config_time;
const char *poll_timeout, *default_domain;
char *path, *dev_path, *dev, *dev_list, device[256], online_read[32];
bool all = false, actionset = false;
size_t len;
int id, dom, c, i, j;
for (i=0; i < argc; i++)
for (j=2; j < (int) strlen(argv[i]); j++)
if (argv[i][j] == '_')
argv[i][j] = '-';
online = poll_thread = config_time = poll_timeout = default_domain = NULL;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
while (1) {
c = util_opt_getopt_long(argc, argv);
if (c == -1)
break;
switch (c) {
case 'e':
actionset = true;
online = "1";
online_text = "online";
break;
case 'd':
actionset = true;
online = "0";
online_text = "offline";
break;
case 'a':
all = true;
break;
case 'p':
actionset = true;
poll_thread = "1";
break;
case 'n':
actionset = true;
poll_thread = "0";
break;
case 'c':
actionset = true;
config_time = optarg;
break;
case 't':
actionset = true;
poll_timeout = optarg;
break;
case 'q':
actionset = true;
default_domain = optarg;
break;
case 'V':
l.verbose = true;
break;
case 'h':
util_prg_print_help();
util_opt_print_help();
print_adapter_id_help();
return EXIT_SUCCESS;
case 'v':
util_prg_print_version();
return EXIT_SUCCESS;
default:
util_opt_print_parse_error(c, argv);
return EXIT_FAILURE;
}
}
if (!actionset)
invalid_cmdline_exit("Error - missing argument.\n");
path = util_path_sysfs("bus/ap");
if (!util_path_is_dir(path))
errx(EXIT_FAILURE, "Crypto device driver not available.");
free(path);
if (poll_thread) {
poll_thread_set(poll_thread);
return EXIT_SUCCESS;
}
if (config_time) {
config_time_set(config_time);
return EXIT_SUCCESS;
}
if (poll_timeout) {
poll_timeout_set(poll_timeout);
return EXIT_SUCCESS;
}
if (default_domain) {
default_domain_set(default_domain);
return EXIT_SUCCESS;
}
if (all)
dev_list_all(&dev_list, &len);
else
dev_list_argv(&dev_list, &len, &argv[optind]);
if (online && len == 0)
errx(EXIT_FAILURE, "Error - missing cryptographic device id(s).");
for (dev = dev_list; dev != NULL; dev = argz_next(dev_list, len, dev)) {
if (strncmp(dev, "card", 4) == 0) {
/* dev == "card2" */
sscanf(dev, "card%02x", &id);
sprintf(device, "card%02x", id);
} else if (strncmp(dev, "0x", 2) == 0) {
/* dev == "0x.." */
sscanf(dev, "0x%02x", &id);
sprintf(device, "card%02x", id);
} else if (misc_regex_match(dev, "^[0-9a-fA-F]+$")) {
/* dev == "2" */
sscanf(dev, "%02x", &id);
sprintf(device, "card%02x", id);
} else {
/* Form: 01.0003 ? */
if (sscanf(dev, "%02x.%04x", &id, &dom) != 2)
errx(EXIT_FAILURE, "Error - cryptographic device %s malformed.", dev);
sprintf(device, "card%02x/%02x.%04x", id, id, dom);
}
dev_path = util_path_sysfs("bus/ap/devices/%s", device);
if (!util_path_is_dir(dev_path))
errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device);
if (!util_path_is_writable("%s/online", dev_path))
errx(EXIT_FAILURE, "Error - can't write to %s/online.\n Wrong permissions"
" or wrong tools version.", dev_path);
verbose("Setting cryptographic device %s %s\n", device, online_text);
util_file_write_s(online, "%s/online", dev_path);
util_file_read_line(online_read, sizeof(online_read), "%s/online", dev_path);
if (strcmp(online, online_read) != 0)
errx(EXIT_FAILURE, "Error - unable to set cryptographic device %s %s.",
device, online_text);
free(dev_path);
}
free(dev_list);
return EXIT_SUCCESS;
}