From: Matthew Mondor Date: Fri, 4 Aug 2023 21:23:44 +0000 (+0000) Subject: util/noidle.c: audit and update, improve security. X-Git-Url: http://git.pulsar-zone.net/?a=commitdiff_plain;h=0845bd045e14c8da9e84f88ec7c536c43bd24d12;p=mmondor.git util/noidle.c: audit and update, improve security. --- diff --git a/mmsoftware/util/hdnoidle.c b/mmsoftware/util/hdnoidle.c index be6576c..abbc33c 100644 --- a/mmsoftware/util/hdnoidle.c +++ b/mmsoftware/util/hdnoidle.c @@ -116,6 +116,9 @@ int disk_getsize(int, off_t *); ssize_t disk_getblocksize(int); +uint8_t *membuf = NULL; + + /* * Splits columns of a string delimited by spaces and/or tabs, and fills * char **argv with pointers to each column. Returns the number of columns @@ -149,8 +152,8 @@ straspl(char **argv, char *str, int maxcols) void conf_read(noidledisk_t **disks, int *dn) { + noidledisk_t *dmem = NULL; FILE *fh; - noidledisk_t *d = NULL; int n = 0, i; char *cols[3] = { NULL, NULL, NULL }; char line[CONFIG_LZ + 1]; @@ -168,82 +171,87 @@ conf_read(noidledisk_t **disks, int *dn) (void)fclose(fh); /* Allocate structs */ - if ((d = malloc(sizeof(noidledisk_t) * n)) == NULL) + if ((dmem = malloc(sizeof(noidledisk_t) * n)) == NULL) err(EXIT_FAILURE, "malloc()"); - /* Reopen and fill structs */ + /* + * Reopen and fill structs. There's a possible race condition between + * the above and this, but we ensure not to configure more than . + * If there are more lines than expected, we ignore them. If there + * are less, we adjust . + */ if ((fh = fopen(CONFIG, "r")) == NULL) err(EXIT_FAILURE, "fopen(%s)", CONFIG); - i = 0; - while (fgets(line, CONFIG_LZ, fh) != NULL) { + for (i = 0; i < n && fgets(line, CONFIG_LZ, fh) != NULL; ) { line[CONFIG_LZ] = '\0'; - if (*line != '#') { - if (straspl(cols, line, 2) == 2) { - if ((d[i].dev = strdup(cols[0])) == NULL) - err(EXIT_FAILURE, "strdup()"); - if ((d[i].delay = atoi(cols[1])) < 1) - err(EXIT_FAILURE, "atoi(delay) < 1"); - i++; - } + if (*line == '#') + continue; + if (straspl(cols, line, 2) == 2) { + noidledisk_t *d = &dmem[i]; + + if ((d->dev = strdup(cols[0])) == NULL) + err(EXIT_FAILURE, "strdup()"); + if ((d->delay = atoi(cols[1])) < 1) + err(EXIT_FAILURE, "atoi(delay) < 1"); + i++; } } (void)fclose(fh); + if (i < 1) + err(EXIT_FAILURE, "hdnoidle: Quitting, no disk configured."); - if (i != n) - err(EXIT_FAILURE, "conf_read() - i != n"); - - *disks = d; - *dn = n; + *disks = dmem; + *dn = i; } void -conf_setup(noidledisk_t *d, int nd) +conf_setup(noidledisk_t *disks, int nd) { int i; + /* + * Large buffer in which we'll custom-align smaller regions that can + * overlap and will only be used one at a time then discarded. + */ + if ((membuf = malloc(65536)) == NULL) + err(EXIT_FAILURE, "malloc(65536)"); + for (i = 0; i < nd; i++) { - uint8_t *membuf; int pad; + noidledisk_t *d = &disks[i]; /* * O_DIRECT has no effect when already using a raw device but * Linux now lacks real raw devices and apparently relies on * this to hopefully offer similar behavior. */ - if ((d[i].fd = open(d[i].dev, O_RDONLY | O_DIRECT)) == -1) - err(EXIT_FAILURE, "open(%s)", d[i].dev); - if (disk_getsize(d[i].fd, &(d[i].size)) == -1) - err(EXIT_FAILURE, "disk_getsize(%s)", d[i].dev); - if ((d[i].bsize = disk_getblocksize(d[i].fd)) == -1) - err(EXIT_FAILURE, "disk_getblocksize(%s)", d[i].dev); + if ((d->fd = open(d->dev, O_RDONLY | O_DIRECT)) == -1) + err(EXIT_FAILURE, "open(%s)", d->dev); + if (disk_getsize(d->fd, &(d->size)) == -1) + err(EXIT_FAILURE, "disk_getsize(%s)", d->dev); + if ((d->bsize = disk_getblocksize(d->fd)) == -1) + err(EXIT_FAILURE, "disk_getblocksize(%s)", d->dev); - d[i].t = d[i].delay; - d[i].offset = 0; + d->t = d->delay; + d->offset = 0; /* * We need memory to also be block-aligned. Since malloc(3) * will only guarantee 32-bit or 64-bit aligned memory, let's - * allocate a larger buffer and use an aligned sub-buffer. + * assign them an aligned sub-buffer in membuf. */ - if ((membuf = malloc(65536)) == NULL) - err(EXIT_FAILURE, "malloc(65536)"); - d[i].sbuf = membuf; - - if ((d[i].sbuf = malloc(d[i].bsize)) == NULL) - err(EXIT_FAILURE, "malloc(%lu)", - (unsigned long)d[i].bsize); - if ((pad = (uintptr_t)d[i].sbuf % d->bsize) > 0) + d->sbuf = membuf; + if ((pad = (uintptr_t)d->sbuf % d->bsize) > 0) pad = d->bsize - pad; - d[i].sbuf += pad; - if (d[i].sbuf + d->bsize > &membuf[65536]) + d->sbuf += pad; + if (&d->sbuf[d->bsize] > &membuf[65535]) err(EXIT_FAILURE, "Device block size for %s larger than expected!", - d[i].dev); + d->dev); (void)printf("hdnoidle: device=%s, size=%" PRIu64 ", " "blocksize=%lu, delay=%u\n", - d[i].dev, d[i].size, (unsigned long)d[i].bsize, - d[i].delay); + d->dev, d->size, (unsigned long)d->bsize, d->delay); } } @@ -305,19 +313,28 @@ main(void) if (--d->t < 1) { off_t pad; + ssize_t rz; + /* Reset timer */ d->t = d->delay; + + /* Seek to current offset */ if (lseek(d->fd, d->offset, SEEK_SET) == -1) { warn("seek(%s, %" PRIu64 ")", d->dev, d->offset); continue; } - if (read(d->fd, d->sbuf, d->bsize) == -1) + + /* Read and discard by zeroing. */ + if ((rz = read(d->fd, d->sbuf, d->bsize)) + == -1) warn("read(dev=%s (fd=%d), buf=%p, " "sz=%lu) off=%" PRIu64, d->dev, d->fd, d->sbuf, (unsigned long)d->bsize, d->offset); + (void)memset(d->sbuf, '\0', rz); + /* * Skip forward somewhat arbitrarily hoping to * hit a non-cached block and to defeat