summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/nvmutil/nvmutil.c266
1 files changed, 137 insertions, 129 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 2aa47d19..c92744ac 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -22,7 +22,7 @@
* Make most of nvmutil a *library* for re-use
*
* TODO: gettimeofday not posible - use portable functions.
- * TODO: uint32_t fallback: modify the program instead
+ * TODO: ux fallback: modify the program instead
* to run on 16-bit systems: smaller buffers, and do
* operations byte-based instead of word-based.
*
@@ -135,11 +135,12 @@ CFLAGS += -fstack-protector-strong
CFLAGS += -fno-common
CFLAGS += -D_FORTIFY_SOURCE=2
CFLAGS += -fPIE
-*/
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 500
-#endif
+also consider:
+-fstack-clash-protection
+-Wl,-z,relro
+-Wl,-z,now
+*/
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
@@ -156,32 +157,23 @@ CFLAGS += -fPIE
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
-#if defined(__has_include)
-#if __has_include(<stdint.h>)
-#include <stdint.h>
-#else
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-#endif
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-#include <stdint.h>
-#else
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
+typedef unsigned char u8;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+
/* type asserts */
typedef char static_assert_char_is_8_bits[(CHAR_BIT == 8) ? 1 : -1];
-typedef char static_assert_uint8_is_1[(sizeof(uint8_t) == 1) ? 1 : -1];
-typedef char static_assert_uint16_is_2[(sizeof(uint16_t) == 2) ? 1 : -1];
-typedef char static_assert_uint32_is_4[(sizeof(uint32_t) == 4) ? 1 : -1];
+typedef char static_assert_char_is_1[(sizeof(char) == 1) ? 1 : -1];
+typedef char static_assert_uint8_is_1[(sizeof(u8) == 1) ? 1 : -1];
+typedef char static_assert_uint16_is_2[(sizeof(ushort) >= 2) ? 1 : -1];
+typedef char static_assert_short_is_2[(sizeof(short) >= 2) ? 1 : -1];
+typedef char static_assert_uint32_is_4[(sizeof(uint) >= 4) ? 1 : -1];
typedef char static_assert_int_ge_32[(sizeof(int) >= 4) ? 1 : -1];
typedef char static_assert_twos_complement[
((-1 & 3) == 3) ? 1 : -1
@@ -226,8 +218,8 @@ typedef char static_assert_off_t_is_32[(sizeof(off_t) >= 4) ? 1 : -1];
#define O_BINARY 0
#endif
-#ifndef O_NONBLOCK
-#define O_NONBLOCK 0
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
#endif
/*
@@ -253,6 +245,7 @@ static int xstrxcmp(const char *a, const char *b, size_t maxlen);
*/
static void open_dev_urandom(void);
static void open_gbe_file(void);
+static void lock_gbe_file(void);
static void xopen(int *fd, const char *path, int flags, struct stat *st);
/*
@@ -271,7 +264,7 @@ static int good_checksum(size_t partnum);
*/
static void run_cmd(size_t c);
static void check_command_num(size_t c);
-static uint8_t valid_command(size_t c);
+static u8 valid_command(size_t c);
/*
* Helper functions for command: setmac
@@ -282,9 +275,9 @@ static size_t xstrxlen(const char *scmp, size_t maxlen);
static void set_mac_byte(size_t mac_byte_pos);
static void set_mac_nib(size_t mac_str_pos,
size_t mac_byte_pos, size_t mac_nib_pos);
-static uint16_t hextonum(char ch_s);
-static uint16_t rhex(void);
-static uint16_t fallback_rand(void);
+static ushort hextonum(char ch_s);
+static ushort rhex(void);
+static ushort fallback_rand(void);
static unsigned long entropy_jitter(void);
static void write_mac_part(size_t partnum);
@@ -300,7 +293,7 @@ static void hexdump(size_t partnum);
* cat, cat16 and cat128
*/
static void cmd_helper_cat(void);
-static void gbe_cat_buf(uint8_t *b);
+static void gbe_cat_buf(u8 *b);
/*
* After command processing, write
@@ -312,14 +305,14 @@ static void gbe_cat_buf(uint8_t *b);
static void write_gbe_file(void);
static void override_part_modified(void);
static void set_checksum(size_t part);
-static uint16_t calculated_checksum(size_t p);
+static ushort calculated_checksum(size_t p);
/*
* Helper functions for accessing
* the NVM area during operation.
*/
-static uint16_t nvm_word(size_t pos16, size_t part);
-static void set_nvm_word(size_t pos16, size_t part, uint16_t val16);
+static ushort nvm_word(size_t pos16, size_t part);
+static void set_nvm_word(size_t pos16, size_t part, ushort val16);
static void set_part_modified(size_t p);
static void check_nvm_bound(size_t pos16, size_t part);
static void check_bin(size_t a, const char *a_name);
@@ -330,16 +323,14 @@ static void check_bin(size_t a, const char *a_name);
*/
static void rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str);
-static uint8_t *gbe_mem_offset(size_t part, const char *f_op);
+static u8 *gbe_mem_offset(size_t part, const char *f_op);
static off_t gbe_file_offset(size_t part, const char *f_op);
static off_t gbe_x_offset(size_t part, const char *f_op,
const char *d_type, off_t nsize, off_t ncmp);
-static ssize_t rw_file_exact(int fd, uint8_t *mem, size_t len,
+static ssize_t rw_file_exact(int fd, u8 *mem, size_t len,
off_t off, int rw_type);
-static ssize_t rw_file_once(int fd, uint8_t *mem, size_t len,
+static ssize_t rw_file_once(int fd, u8 *mem, size_t len,
off_t off, int rw_type, size_t rc);
-static ssize_t do_rw(int fd,
- uint8_t *mem, size_t len, off_t off, int rw_type);
static ssize_t prw(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
static off_t lseek_eintr(int fd, off_t off, int whence);
@@ -352,7 +343,7 @@ static int io_args(int fd, void *mem, size_t nrw,
static void err(int nvm_errval, const char *msg, ...);
static void close_files(void);
static const char *getnvmprogname(void);
-static void usage(uint8_t usage_exit);
+static void usage(u8 usage_exit);
/*
* Sizes in bytes:
@@ -383,6 +374,7 @@ static void usage(uint8_t usage_exit);
#define NVM_CHECKSUM_WORD (NVM_WORDS - 1)
#define NUM_RANDOM_BYTES 12
+static u8 rnum[NUM_RANDOM_BYTES];
/*
* Portable macro based on BSD nitems.
@@ -402,17 +394,17 @@ static const char *rname = NULL;
*
* The code will handle this properly.
*/
-static uint8_t buf[GBE_FILE_SIZE];
-static uint8_t pad[GBE_PART_SIZE]; /* the file that wouldn't die */
+static u8 buf[GBE_FILE_SIZE];
+static u8 pad[GBE_PART_SIZE]; /* the file that wouldn't die */
-static uint16_t mac_buf[3];
+static ushort mac_buf[3];
static off_t gbe_file_size;
static int urandom_fd = -1;
static int gbe_fd = -1;
static size_t part;
-static uint8_t part_modified[2];
-static uint8_t part_valid[2];
+static u8 part_modified[2];
+static u8 part_valid[2];
static const char rmac[] = "xx:xx:xx:xx:xx:xx";
static const char *mac_str;
@@ -489,11 +481,11 @@ struct commands {
const char *str;
void (*run)(void);
int argc;
- uint8_t invert;
- uint8_t set_modified;
- uint8_t arg_part;
- uint8_t chksum_read;
- uint8_t chksum_write;
+ u8 invert;
+ u8 set_modified;
+ u8 arg_part;
+ u8 chksum_read;
+ u8 chksum_write;
size_t rw_size; /* within the 4KB GbE part */
int flags; /* e.g. O_RDWR or O_RDONLY */
};
@@ -652,6 +644,7 @@ main(int argc, char *argv[])
open_dev_urandom();
open_gbe_file();
+ lock_gbe_file();
#ifdef NVMUTIL_PLEDGE
if (pledge("stdio", NULL) == -1)
@@ -694,7 +687,7 @@ sanitize_command_list(void)
static void
sanitize_command_index(size_t c)
{
- uint8_t mod_type;
+ u8 mod_type;
size_t gbe_rw_size;
check_command_num(c);
@@ -775,7 +768,7 @@ set_cmd(int argc, char *argv[])
static void
set_cmd_args(int argc, char *argv[])
{
- uint8_t arg_part;
+ u8 arg_part;
if (!valid_command(cmd_index) || argc < 3)
usage(1);
@@ -865,7 +858,8 @@ open_gbe_file(void)
{
struct stat gbe_st;
- xopen(&gbe_fd, fname, command[cmd_index].flags | O_BINARY, &gbe_st);
+ xopen(&gbe_fd, fname,
+ command[cmd_index].flags | O_BINARY | O_NOFOLLOW, &gbe_st);
gbe_file_size = gbe_st.st_size;
@@ -880,6 +874,24 @@ open_gbe_file(void)
}
static void
+lock_gbe_file(void)
+{
+ struct flock fl;
+
+ memset(&fl, 0, sizeof(fl));
+
+ if (command[cmd_index].flags == O_RDONLY)
+ fl.l_type = F_RDLCK;
+ else
+ fl.l_type = F_WRLCK;
+
+ fl.l_whence = SEEK_SET;
+
+ if (fcntl(gbe_fd, F_SETLK, &fl) == -1)
+ err(errno, "file is locked by another process");
+}
+
+static void
xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
{
if ((*fd_ptr = open(path, flags)) == -1)
@@ -896,7 +908,7 @@ static void
read_gbe_file(void)
{
size_t p;
- uint8_t do_read[2] = {1, 1};
+ u8 do_read[2] = {1, 1};
/*
* Commands specifying a partnum only
@@ -916,10 +928,10 @@ read_checksums(void)
{
size_t p;
size_t skip_part;
- uint8_t invert;
- uint8_t arg_part;
- uint8_t num_invalid;
- uint8_t max_invalid;
+ u8 invert;
+ u8 arg_part;
+ u8 num_invalid;
+ u8 max_invalid;
part_valid[0] = 0;
part_valid[1] = 0;
@@ -965,8 +977,8 @@ read_checksums(void)
static int
good_checksum(size_t partnum)
{
- uint16_t expected_checksum = calculated_checksum(partnum);
- uint16_t current_checksum = nvm_word(NVM_CHECKSUM_WORD, partnum);
+ ushort expected_checksum = calculated_checksum(partnum);
+ ushort current_checksum = nvm_word(NVM_CHECKSUM_WORD, partnum);
if (current_checksum == expected_checksum)
return 1;
@@ -990,7 +1002,7 @@ check_command_num(size_t c)
(unsigned long)c);
}
-static uint8_t
+static u8
valid_command(size_t c)
{
if (c >= N_COMMANDS)
@@ -1084,7 +1096,7 @@ set_mac_nib(size_t mac_str_pos,
size_t mac_byte_pos, size_t mac_nib_pos)
{
char mac_ch;
- uint16_t hex_num;
+ ushort hex_num;
mac_ch = mac_str[mac_str_pos + mac_nib_pos];
@@ -1109,7 +1121,7 @@ set_mac_nib(size_t mac_str_pos,
| ((mac_nib_pos ^ 1) << 2)); /* left or right nib? */
}
-static uint16_t
+static ushort
hextonum(char ch_s)
{
unsigned char ch = (unsigned char)ch_s;
@@ -1128,11 +1140,10 @@ hextonum(char ch_s)
return 16; /* invalid character */
}
-static uint16_t
+static ushort
rhex(void)
{
static size_t n = 0;
- static uint8_t rnum[NUM_RANDOM_BYTES];
if (use_prng)
return fallback_rand();
@@ -1143,10 +1154,10 @@ rhex(void)
err(errno, "Randomisation failed");
}
- return (uint16_t)(rnum[--n] & 0xf);
+ return (ushort)(rnum[--n] & 0xf);
}
-static uint16_t
+static ushort
fallback_rand(void)
{
struct timeval tv;
@@ -1170,7 +1181,7 @@ fallback_rand(void)
mix ^= (unsigned long)&tv;
mix ^= (unsigned long)&counter;
- return (uint16_t)(mix & 0xf);
+ return (ushort)(mix & 0xf);
}
static unsigned long
@@ -1245,7 +1256,7 @@ static void
print_mac_from_nvm(size_t partnum)
{
size_t c;
- uint16_t val16;
+ ushort val16;
for (c = 0; c < 3; c++) {
val16 = nvm_word(c, partnum);
@@ -1264,7 +1275,7 @@ hexdump(size_t partnum)
{
size_t c;
size_t row;
- uint16_t val16;
+ ushort val16;
for (row = 0; row < 8; row++) {
printf("%08lx ", (unsigned long)((size_t)row << 4));
@@ -1305,7 +1316,7 @@ cmd_helper_cat(void)
}
static void
-gbe_cat_buf(uint8_t *b)
+gbe_cat_buf(u8 *b)
{
ssize_t rval;
@@ -1332,9 +1343,11 @@ gbe_cat_buf(uint8_t *b)
static void
write_gbe_file(void)
{
+ struct stat gbe_st;
+
size_t p;
size_t partnum;
- uint8_t update_checksum;
+ u8 update_checksum;
if (command[cmd_index].flags == O_RDONLY)
return;
@@ -1342,6 +1355,15 @@ write_gbe_file(void)
update_checksum = command[cmd_index].chksum_write;
override_part_modified();
+
+ if (fstat(gbe_fd, &gbe_st) == -1)
+ err(errno, "%s: re-check", fname);
+
+ if (gbe_st.st_size != gbe_file_size)
+ err(errno, "%s: file size changed before write", fname);
+
+ if (!S_ISREG(gbe_st.st_mode))
+ err(errno, "%s: file type changed before write", fname);
for (p = 0; p < 2; p++) {
partnum = p ^ command[cmd_index].invert;
@@ -1359,7 +1381,7 @@ write_gbe_file(void)
static void
override_part_modified(void)
{
- uint8_t mod_type = command[cmd_index].set_modified;
+ u8 mod_type = command[cmd_index].set_modified;
switch (mod_type) {
case SET_MOD_0:
@@ -1390,16 +1412,16 @@ set_checksum(size_t p)
set_nvm_word(NVM_CHECKSUM_WORD, p, calculated_checksum(p));
}
-static uint16_t
+static ushort
calculated_checksum(size_t p)
{
size_t c;
- uint32_t val16 = 0;
+ uint val16 = 0;
for (c = 0; c < NVM_CHECKSUM_WORD; c++)
- val16 += (uint32_t)nvm_word(c, p);
+ val16 += (uint)nvm_word(c, p);
- return (uint16_t)((NVM_CHECKSUM - val16) & 0xffff);
+ return (ushort)((NVM_CHECKSUM - val16) & 0xffff);
}
/*
@@ -1410,7 +1432,7 @@ calculated_checksum(size_t p)
* file, but we assume otherwise and adapt accordingly.
*/
-static uint16_t
+static ushort
nvm_word(size_t pos16, size_t p)
{
size_t pos;
@@ -1418,20 +1440,20 @@ nvm_word(size_t pos16, size_t p)
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
- return (uint16_t)buf[pos] |
- ((uint16_t)buf[pos + 1] << 8);
+ return (ushort)buf[pos] |
+ ((ushort)buf[pos + 1] << 8);
}
static void
-set_nvm_word(size_t pos16, size_t p, uint16_t val16)
+set_nvm_word(size_t pos16, size_t p, ushort val16)
{
size_t pos;
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
- buf[pos] = (uint8_t)(val16 & 0xff);
- buf[pos + 1] = (uint8_t)(val16 >> 8);
+ buf[pos] = (u8)(val16 & 0xff);
+ buf[pos + 1] = (u8)(val16 >> 8);
set_part_modified(p);
}
@@ -1472,9 +1494,9 @@ rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str)
{
size_t gbe_rw_size = command[cmd_index].rw_size;
- uint8_t invert = command[cmd_index].invert;
+ u8 invert = command[cmd_index].invert;
- uint8_t *mem_offset;
+ u8 *mem_offset;
if (rw_type < IO_PREAD || rw_type > IO_PWRITE)
err(errno, "%s: %s: part %lu: invalid rw_type, %d",
@@ -1501,13 +1523,13 @@ rw_gbe_file_part(size_t p, int rw_type,
* but used to check Gbe bounds in memory,
* and it is *also* used during file I/O.
*/
-static uint8_t *
+static u8 *
gbe_mem_offset(size_t p, const char *f_op)
{
off_t gbe_off = gbe_x_offset(p, f_op, "mem",
GBE_PART_SIZE, GBE_FILE_SIZE);
- return (uint8_t *)(buf + gbe_off);
+ return (u8 *)(buf + gbe_off);
}
/*
@@ -1565,17 +1587,12 @@ gbe_x_offset(size_t p, const char *f_op, const char *d_type,
* means that EOF is also considered fatal.
*/
static ssize_t
-rw_file_exact(int fd, uint8_t *mem, size_t nrw,
+rw_file_exact(int fd, u8 *mem, size_t nrw,
off_t off, int rw_type)
{
ssize_t rv;
size_t rc;
- if (io_args(fd, mem, nrw, off, rw_type) == -1) {
- errno = EIO;
- return -1;
- }
-
for (rc = 0, rv = 0; rc < nrw; ) {
if ((rv = rw_file_once(fd, mem, nrw, off, rw_type, rc)) <= 0)
return -1;
@@ -1591,18 +1608,15 @@ rw_file_exact(int fd, uint8_t *mem, size_t nrw,
* Use rw_file_exact for guaranteed length.
*/
static ssize_t
-rw_file_once(int fd, uint8_t *mem, size_t nrw,
+rw_file_once(int fd, u8 *mem, size_t nrw,
off_t off, int rw_type, size_t rc)
{
ssize_t rv;
size_t retries_on_zero = 0;
size_t max_retries = 10;
- if (io_args(fd, mem, nrw, off, rw_type) == -1)
- goto err_rw_file_once;
-
read_again:
- rv = do_rw(fd, mem + rc, nrw - rc, off + rc, rw_type);
+ rv = prw(fd, mem + rc, nrw - rc, off + rc, rw_type);
if (rv < 0 && errno == EINTR)
goto read_again;
@@ -1625,27 +1639,6 @@ err_rw_file_once:
return -1;
}
-static ssize_t
-do_rw(int fd, uint8_t *mem,
- size_t nrw, off_t off, int rw_type)
-{
- if (io_args(fd, mem, nrw, off, rw_type) == -1)
- goto err_do_rw;
-
- if (rw_type == IO_READ)
- return read(fd, mem, nrw);
-
- if (rw_type == IO_WRITE)
- return write(fd, mem, nrw);
-
- if (rw_type == IO_PREAD || rw_type == IO_PWRITE)
- return prw(fd, mem, nrw, off, rw_type);
-
-err_do_rw:
- errno = EIO;
- return -1;
-}
-
/*
* This implements a portable analog of pwrite()
* and pread() - note that this version is not
@@ -1654,6 +1647,10 @@ err_do_rw:
*
* This limitation is acceptable, since nvmutil is
* single-threaded. Portability is the main goal.
+ *
+ * A fallback is provided for regular read/write.
+ * rw_type can be IO_READ, IO_WRITE, IO_PREAD
+ * or IO_PWRITE
*/
static ssize_t
prw(int fd, void *mem, size_t nrw,
@@ -1662,16 +1659,16 @@ prw(int fd, void *mem, size_t nrw,
off_t off_orig;
ssize_t r;
int saved_errno;
- int prw_type;
int flags;
if (io_args(fd, mem, nrw, off, rw_type) == -1)
goto err_prw;
- prw_type = rw_type ^ IO_PREAD;
+ if (rw_type == IO_WRITE)
+ return write(fd, mem, nrw);
- if ((unsigned int)prw_type > IO_WRITE)
- goto err_prw;
+ if (rw_type == IO_READ)
+ return read(fd, mem, nrw);
flags = fcntl(fd, F_GETFL);
if (flags == -1)
@@ -1693,7 +1690,10 @@ prw(int fd, void *mem, size_t nrw,
return -1;
do {
- r = do_rw(fd, mem, nrw, off, prw_type);
+ if (rw_type == IO_PREAD)
+ r = read(fd, mem, nrw);
+ else if (rw_type == IO_PWRITE)
+ r = write(fd, mem, nrw);
} while (r < 0 && errno == EINTR);
saved_errno = errno;
@@ -1716,13 +1716,21 @@ static int
io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type)
{
- if (off > 0
- && off != GBE_PART_SIZE)
+ if (mem == NULL)
+ goto err_io_args;
+
+ if (mem != (void *)pad
+ && mem != (void *)rnum
+ && (mem < (void *)buf || mem >= (void *)(buf + GBE_FILE_SIZE)))
+ goto err_io_args;
+
+ if (off < 0 || off >= gbe_file_size)
+ goto err_io_args;
+
+ if (nrw > (size_t)(gbe_file_size - off))
goto err_io_args;
- if (nrw != GBE_PART_SIZE &&
- nrw != NVM_SIZE &&
- nrw != NUM_RANDOM_BYTES)
+ if (nrw > GBE_PART_SIZE)
goto err_io_args;
if (fd < 0
@@ -1807,7 +1815,7 @@ getnvmprogname(void)
}
static void
-usage(uint8_t usage_exit)
+usage(u8 usage_exit)
{
const char *util = getnvmprogname();