WIP: hardened mktemp

i'm pretty much nearly there. still no dir support,
only files.

i won't keep amending now - will do more, then
squash later.

Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-20 04:02:51 +00:00
parent f50ffd6bb1
commit 6838db4647
10 changed files with 2244 additions and 696 deletions

View File

@@ -35,11 +35,20 @@
int fchmod(int fd, mode_t mode);
/* analog of SSIZE_MAX
/* if 1: on operations that
* check ownership, always
* permit root to access even
* if not the file/dir owner
*/
#ifndef ALLOW_ROOT_OVERRIDE
#define ALLOW_ROOT_OVERRIDE 0
#endif
/*
*/
#ifndef X_LONG_MAX
#define X_LONG_MAX ((long)(~((long)1 << (sizeof(long)*CHAR_BIT-1))))
#ifndef SSIZE_MAX
#define SSIZE_MAX ((ssize_t)(~((ssize_t)1 << (sizeof(ssize_t)*CHAR_BIT-1))))
#endif
@@ -60,6 +69,13 @@ int fchmod(int fd, mode_t mode);
#define OFF_RESET 1
#endif
/* by default: allow use
of openat in hardened mkstemp
*/
#ifndef DISABLE_OPENAT
#define DISABLE_OPENAT 0 /* change to 1 if you don't have openat (old unix) */
#endif
#ifndef S_ISVTX
#define S_ISVTX 01000
#endif
@@ -72,8 +88,8 @@ int fchmod(int fd, mode_t mode);
#define MAX_ZERO_RW_RETRY 5
#endif
#ifndef HAVE_REAL_PREAD_PWRITE
#define HAVE_REAL_PREAD_PWRITE 0
#ifndef REAL_POS_IO
#define REAL_POS_IO 0
#endif
#ifndef LOOP_EAGAIN
@@ -95,6 +111,10 @@ int fchmod(int fd, mode_t mode);
#define EXIT_SUCCESS 0
#endif
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
@@ -208,14 +228,14 @@ int fchmod(int fd, mode_t mode);
*/
struct commands {
unsigned long chk;
size_t chk;
char *str;
void (*run)(void);
int argc;
unsigned char arg_part;
unsigned char chksum_read;
unsigned char chksum_write;
unsigned long rw_size; /* within the 4KB GbE part */
size_t rw_size; /* within the 4KB GbE part */
int flags; /* e.g. O_RDWR or O_RDONLY */
};
@@ -254,7 +274,7 @@ struct xfile {
off_t gbe_file_size;
off_t gbe_tmp_size;
unsigned long part;
size_t part;
unsigned char part_modified[2];
unsigned char part_valid[2];
@@ -278,7 +298,7 @@ struct xstate {
char *argv0;
unsigned long i; /* index to cmd[] for current command */
size_t i; /* index to cmd[] for current command */
int no_cmd;
/* Cat commands set this.
@@ -286,28 +306,33 @@ struct xstate {
int cat;
};
struct path_split {
int dirfd;
char *buf;
const char *base;
};
struct xstate *xstatus(int argc, char *argv[]);
struct xstate *xstart(int argc, char *argv[]);
struct xstate *xstatus(void);
/* Sanitize command tables.
*/
void sanitize_command_list(void);
void sanitize_command_index(unsigned long c);
void sanitize_command_index(size_t c);
/* Argument handling (user input)
*/
void set_cmd(int argc, char *argv[]);
void set_cmd_args(int argc, char *argv[]);
unsigned long conv_argv_part_num(const char *part_str);
int xstrxcmp(const char *a, const char *b, unsigned long maxlen);
size_t conv_argv_part_num(const char *part_str);
/* Prep files for reading
*/
void open_gbe_file(void);
int is_owner(struct stat *st);
int lock_file(int fd, int flags);
int same_file(int fd, struct stat *st_old, int check_size);
void xopen(int *fd, const char *path, int flags, struct stat *st);
@@ -318,25 +343,37 @@ void xopen(int *fd, const char *path, int flags, struct stat *st);
void copy_gbe(void);
void read_file(void);
void read_checksums(void);
int good_checksum(unsigned long partnum);
int good_checksum(size_t partnum);
/* validate commands
*/
void check_command_num(unsigned long c);
unsigned char valid_command(unsigned long c);
void check_command_num(size_t c);
unsigned char valid_command(size_t c);
/* Helper functions for command: setmac
*/
void cmd_helper_setmac(void);
void parse_mac_string(void);
unsigned long xstrxlen(const char *scmp, unsigned long maxlen);
void set_mac_byte(unsigned long mac_byte_pos);
void set_mac_nib(unsigned long mac_str_pos,
unsigned long mac_byte_pos, unsigned long mac_nib_pos);
void set_mac_byte(size_t mac_byte_pos);
void set_mac_nib(size_t mac_str_pos,
size_t mac_byte_pos, size_t mac_nib_pos);
void write_mac_part(size_t partnum);
/* string functions
*/
int slen(const char *scmp, size_t maxlen,
size_t *rval);
int scmp(const char *a, const char *b,
size_t maxlen, int *rval);
/* numerical functions
*/
unsigned short hextonum(char ch_s);
unsigned long rlong(void);
size_t rlong(void);
#if !(defined(FALLBACK_RAND_1989) && \
((FALLBACK_RAND_1989) > 0))
#if defined(__linux__)
@@ -346,17 +383,16 @@ int fallback_rand_getrandom(void *buf, size_t len);
#endif
#endif
#else
unsigned long fallback_rand_1989(void);
unsigned long entropy_jitter(void);
size_t fallback_rand_1989(void);
size_t entropy_jitter(void);
#endif
void write_mac_part(unsigned long partnum);
/* Helper functions for command: dump
*/
void cmd_helper_dump(void);
void print_mac_from_nvm(unsigned long partnum);
void hexdump(unsigned long partnum);
void print_mac_from_nvm(size_t partnum);
void hexdump(size_t partnum);
/* Helper functions for command: swap
*/
@@ -375,7 +411,7 @@ void cmd_helper_copy(void);
void cmd_helper_cat(void);
void cmd_helper_cat16(void);
void cmd_helper_cat128(void);
void cat(unsigned long nff);
void cat(size_t nff);
void cat_buf(unsigned char *b);
/* Command verification/control
@@ -388,51 +424,51 @@ void cmd_helper_err(void);
*/
void write_gbe_file(void);
void set_checksum(unsigned long part);
unsigned short calculated_checksum(unsigned long p);
void set_checksum(size_t part);
unsigned short calculated_checksum(size_t p);
/* NVM read/write
*/
unsigned short nvm_word(unsigned long pos16, unsigned long part);
void set_nvm_word(unsigned long pos16,
unsigned long part, unsigned short val16);
void set_part_modified(unsigned long p);
void check_nvm_bound(unsigned long pos16, unsigned long part);
void check_bin(unsigned long a, const char *a_name);
unsigned short nvm_word(size_t pos16, size_t part);
void set_nvm_word(size_t pos16,
size_t part, unsigned short val16);
void set_part_modified(size_t p);
void check_nvm_bound(size_t pos16, size_t part);
void check_bin(size_t a, const char *a_name);
/* GbE file read/write
*/
void rw_gbe_file_part(unsigned long p, int rw_type,
void rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str);
void write_to_gbe_bin(void);
int gbe_mv(void);
void check_written_part(unsigned long p);
void check_written_part(size_t p);
void report_io_err_rw(void);
unsigned char *gbe_mem_offset(unsigned long part, const char *f_op);
off_t gbe_file_offset(unsigned long part, const char *f_op);
off_t gbe_x_offset(unsigned long part, const char *f_op,
unsigned char *gbe_mem_offset(size_t part, const char *f_op);
off_t gbe_file_offset(size_t part, const char *f_op);
off_t gbe_x_offset(size_t part, const char *f_op,
const char *d_type, off_t nsize, off_t ncmp);
long rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
ssize_t rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
off_t off, int rw_type);
/* Generic read/write
*/
int fsync_dir(const char *path);
long rw_file_exact(int fd, unsigned char *mem, unsigned long len,
ssize_t rw_file_exact(int fd, unsigned char *mem, size_t len,
off_t off, int rw_type, int loop_eagain, int loop_eintr,
unsigned long max_retries, int off_reset);
long prw(int fd, void *mem, unsigned long nrw,
size_t max_retries, int off_reset);
ssize_t prw(int fd, void *mem, size_t nrw,
off_t off, int rw_type, int loop_eagain, int loop_eintr,
int off_reset);
int io_args(int fd, void *mem, unsigned long nrw,
int io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
int check_file(int fd, struct stat *st);
long rw_over_nrw(long r, unsigned long nrw);
#if !defined(HAVE_REAL_PREAD_PWRITE) || \
HAVE_REAL_PREAD_PWRITE < 1
ssize_t rw_over_nrw(ssize_t r, size_t nrw);
#if !defined(REAL_POS_IO) || \
REAL_POS_IO < 1
off_t lseek_on_eintr(int fd, off_t off,
int whence, int loop_eagain, int loop_eintr);
#endif
@@ -442,16 +478,40 @@ int try_err(int loop_err, int errval);
*/
void usage(void);
void err_no_cleanup(int nvm_errval, const char *msg, ...);
void err(int nvm_errval, const char *msg, ...);
int exit_cleanup(void);
const char *getnvmprogname(void);
/* Portable libc functions
/* libc hardening
*/
char *new_tmpfile(int *fd, int local, const char *path);
int mkstemp_n(char *template);
char *get_tmpdir(void);
char *new_tmplate(int *fd, int local, const char *path);
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
int mkhtemp(int *fd, struct stat *st,
char *template, int dirfd, const char *fname,
struct stat *st_dir_initial);
#else
int mkhtemp(int *fd, struct stat *st,
char *template);
#endif
int world_writeable_and_sticky(const char *s,
int sticky_allowed, int always_sticky);
int same_dir(const char *a, const char *b);
int tmpdir_policy(const char *path,
int *allow_noworld_unsticky);
char *env_tmpdir(int always_sticky);
int split_path(const char *path,
struct path_split *ps);
int open_verified_dir(const char *path);
int check_dirfd(int dirfd, const char *path);
int secure_file(int *fd, struct stat *st,
int bad_flags, int check_seek,
int do_lock, mode_t mode);
int close_on_eintr(int fd);
int fsync_on_eintr(int fd);
@@ -467,16 +527,16 @@ typedef char static_assert_unsigned_short_is_2[
typedef char static_assert_short_is_2[(sizeof(short) >= 2) ? 1 : -1];
typedef char static_assert_unsigned_int_is_4[
(sizeof(unsigned int) >= 4) ? 1 : -1];
typedef char static_assert_unsigned_long_is_4[
(sizeof(unsigned long) >= 4) ? 1 : -1];
typedef char static_assert_long_ulong[
(sizeof(unsigned long) == sizeof(long)) ? 1 : -1];
typedef char static_assert_unsigned_ssize_t_is_4[
(sizeof(size_t) >= 4) ? 1 : -1];
typedef char static_assert_ssize_t_ussize_t[
(sizeof(size_t) == sizeof(ssize_t)) ? 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
];
typedef char assert_unsigned_long_ptr[
(sizeof(unsigned long) >= sizeof(void *)) ? 1 : -1
typedef char assert_unsigned_ssize_t_ptr[
(sizeof(size_t) >= sizeof(void *)) ? 1 : -1
];
/*

View File

@@ -17,12 +17,12 @@
void
read_checksums(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
unsigned long _p;
unsigned long _skip_part;
size_t _p;
size_t _skip_part;
unsigned char _num_invalid;
unsigned char _max_invalid;
@@ -60,7 +60,7 @@ read_checksums(void)
if (_max_invalid == 1)
err(ECANCELED, "%s: part %lu has a bad checksum",
f->fname, (unsigned long)f->part);
f->fname, (size_t)f->part);
err(ECANCELED, "%s: No valid checksum found in file",
f->fname);
@@ -68,7 +68,7 @@ read_checksums(void)
}
int
good_checksum(unsigned long partnum)
good_checksum(size_t partnum)
{
unsigned short expected_checksum;
unsigned short actual_checksum;
@@ -87,16 +87,16 @@ good_checksum(unsigned long partnum)
}
void
set_checksum(unsigned long p)
set_checksum(size_t p)
{
check_bin(p, "part number");
set_nvm_word(NVM_CHECKSUM_WORD, p, calculated_checksum(p));
}
unsigned short
calculated_checksum(unsigned long p)
calculated_checksum(size_t p)
{
unsigned long c;
size_t c;
unsigned int val16;
val16 = 0;

View File

@@ -21,10 +21,10 @@
void
sanitize_command_list(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
unsigned long c;
unsigned long num_commands;
size_t c;
size_t num_commands;
num_commands = items(x->cmd);
@@ -33,37 +33,41 @@ sanitize_command_list(void)
}
void
sanitize_command_index(unsigned long c)
sanitize_command_index(size_t c)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[c];
int _flag;
unsigned long gbe_rw_size;
size_t gbe_rw_size;
size_t rval;
check_command_num(c);
if (cmd->argc < 3)
err(EINVAL, "cmd index %lu: argc below 3, %d",
(unsigned long)c, cmd->argc);
(size_t)c, cmd->argc);
if (cmd->str == NULL)
err(EINVAL, "cmd index %lu: NULL str",
(unsigned long)c);
(size_t)c);
if (*cmd->str == '\0')
err(EINVAL, "cmd index %lu: empty str",
(unsigned long)c);
(size_t)c);
if (xstrxlen(cmd->str, MAX_CMD_LEN + 1) >
MAX_CMD_LEN) {
if (slen(cmd->str, MAX_CMD_LEN +1, &rval) < 0)
err(errno, "Could not get command length");
if (rval > MAX_CMD_LEN) {
err(EINVAL, "cmd index %lu: str too long: %s",
(unsigned long)c, cmd->str);
(size_t)c, cmd->str);
}
if (cmd->run == NULL)
err(EINVAL, "cmd index %lu: cmd ptr null",
(unsigned long)c);
(size_t)c);
check_bin(cmd->arg_part, "cmd.arg_part");
check_bin(cmd->chksum_read, "cmd.chksum_read");
@@ -77,12 +81,12 @@ sanitize_command_index(unsigned long c)
break;
default:
err(EINVAL, "Unsupported rw_size: %lu",
(unsigned long)gbe_rw_size);
(size_t)gbe_rw_size);
}
if (gbe_rw_size > GBE_PART_SIZE)
err(EINVAL, "rw_size larger than GbE part: %lu",
(unsigned long)gbe_rw_size);
(size_t)gbe_rw_size);
_flag = (cmd->flags & O_ACCMODE);
@@ -94,18 +98,22 @@ sanitize_command_index(unsigned long c)
void
set_cmd(int argc, char *argv[])
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
const char *cmd;
unsigned long c;
int rval;
size_t c;
for (c = 0; c < items(x->cmd); c++) {
cmd = x->cmd[c].str;
/* not the right command */
if (xstrxcmp(argv[2], cmd, MAX_CMD_LEN) != 0)
continue;
if (scmp(argv[2], cmd, MAX_CMD_LEN, &rval) < 0)
err_no_cleanup(EINVAL,
"could not compare command strings");
if (rval != 0)
continue; /* not the right command */
/* valid command found */
if (argc >= x->cmd[c].argc) {
@@ -115,7 +123,7 @@ set_cmd(int argc, char *argv[])
return;
}
err(EINVAL,
err_no_cleanup(EINVAL,
"Too few args on command '%s'", cmd);
}
@@ -125,8 +133,8 @@ set_cmd(int argc, char *argv[])
void
set_cmd_args(int argc, char *argv[])
{
struct xstate *x = xstatus(0, NULL);
unsigned long i = x->i;
struct xstate *x = xstatus();
size_t i = x->i;
struct commands *cmd = &x->cmd[i];
struct xfile *f = &x->f;
@@ -159,7 +167,7 @@ set_cmd_args(int argc, char *argv[])
}
}
unsigned long
size_t
conv_argv_part_num(const char *part_str)
{
unsigned char ch;
@@ -173,21 +181,21 @@ conv_argv_part_num(const char *part_str)
if (ch < '0' || ch > '1')
err(EINVAL, "Bad part number (%c)", ch);
return (unsigned long)(ch - '0');
return (size_t)(ch - '0');
}
void
check_command_num(unsigned long c)
check_command_num(size_t c)
{
if (!valid_command(c))
err(EINVAL, "Invalid run_cmd arg: %lu",
(unsigned long)c);
(size_t)c);
}
unsigned char
valid_command(unsigned long c)
valid_command(size_t c)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd;
if (c >= items(x->cmd))
@@ -206,10 +214,10 @@ valid_command(unsigned long c)
void
cmd_helper_setmac(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
unsigned long partnum;
size_t partnum;
check_cmd(cmd_helper_setmac, "setmac");
@@ -223,12 +231,17 @@ cmd_helper_setmac(void)
void
parse_mac_string(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
unsigned long mac_byte;
size_t mac_byte;
if (xstrxlen(x->mac.str, 18) != 17)
size_t rval;
if (slen(x->mac.str, 18, &rval) < 0)
err(EINVAL, "Could not determine MAC length");
if (rval != 17)
err(EINVAL, "MAC address is the wrong length");
memset(mac->mac_buf, 0, sizeof(mac->mac_buf));
@@ -244,15 +257,15 @@ parse_mac_string(void)
}
void
set_mac_byte(unsigned long mac_byte_pos)
set_mac_byte(size_t mac_byte_pos)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
char separator;
unsigned long mac_str_pos;
unsigned long mac_nib_pos;
size_t mac_str_pos;
size_t mac_nib_pos;
mac_str_pos = mac_byte_pos * 3;
@@ -267,10 +280,10 @@ set_mac_byte(unsigned long mac_byte_pos)
}
void
set_mac_nib(unsigned long mac_str_pos,
unsigned long mac_byte_pos, unsigned long mac_nib_pos)
set_mac_nib(size_t mac_str_pos,
size_t mac_byte_pos, size_t mac_nib_pos)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct macaddr *mac = &x->mac;
char mac_ch;
@@ -278,9 +291,13 @@ set_mac_nib(unsigned long mac_str_pos,
mac_ch = mac->str[mac_str_pos + mac_nib_pos];
if ((hex_num = hextonum(mac_ch)) > 15)
err(EINVAL, "Invalid character '%c'",
mac->str[mac_str_pos + mac_nib_pos]);
if ((hex_num = hextonum(mac_ch)) > 15) {
if (hex_num >= 17)
err(EIO, "Randomisation failure");
else
err(EINVAL, "Invalid character '%c'",
mac->str[mac_str_pos + mac_nib_pos]);
}
/* If random, ensure that local/unicast bits are set.
*/
@@ -298,13 +315,13 @@ set_mac_nib(unsigned long mac_str_pos,
}
void
write_mac_part(unsigned long partnum)
write_mac_part(size_t partnum)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
struct macaddr *mac = &x->mac;
unsigned long w;
size_t w;
check_bin(partnum, "part number");
if (!f->part_valid[partnum])
@@ -314,17 +331,17 @@ write_mac_part(unsigned long partnum)
set_nvm_word(w, partnum, mac->mac_buf[w]);
printf("Wrote MAC address to part %lu: ",
(unsigned long)partnum);
(size_t)partnum);
print_mac_from_nvm(partnum);
}
void
cmd_helper_dump(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
unsigned long p;
size_t p;
check_cmd(cmd_helper_dump, "dump");
@@ -338,12 +355,12 @@ cmd_helper_dump(void)
fprintf(stderr,
"BAD checksum %04x in part %lu (expected %04x)\n",
nvm_word(NVM_CHECKSUM_WORD, p),
(unsigned long)p,
(size_t)p,
calculated_checksum(p));
}
printf("MAC (part %lu): ",
(unsigned long)p);
(size_t)p);
print_mac_from_nvm(p);
@@ -352,9 +369,9 @@ cmd_helper_dump(void)
}
void
print_mac_from_nvm(unsigned long partnum)
print_mac_from_nvm(size_t partnum)
{
unsigned long c;
size_t c;
unsigned short val16;
for (c = 0; c < 3; c++) {
@@ -373,16 +390,16 @@ print_mac_from_nvm(unsigned long partnum)
}
void
hexdump(unsigned long partnum)
hexdump(size_t partnum)
{
unsigned long c;
unsigned long row;
size_t c;
size_t row;
unsigned short val16;
for (row = 0; row < 8; row++) {
printf("%08lx ",
(unsigned long)((unsigned long)row << 4));
(size_t)((size_t)row << 4));
for (c = 0; c < 8; c++) {
@@ -404,24 +421,24 @@ hexdump(unsigned long partnum)
void
cmd_helper_swap(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
check_cmd(cmd_helper_swap, "swap");
memcpy(
f->buf + (unsigned long)GBE_WORK_SIZE,
f->buf + (size_t)GBE_WORK_SIZE,
f->buf,
GBE_PART_SIZE);
memcpy(
f->buf,
f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (size_t)GBE_PART_SIZE,
GBE_PART_SIZE);
memcpy(
f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (unsigned long)GBE_WORK_SIZE,
f->buf + (size_t)GBE_PART_SIZE,
f->buf + (size_t)GBE_WORK_SIZE,
GBE_PART_SIZE);
set_part_modified(0);
@@ -431,14 +448,14 @@ cmd_helper_swap(void)
void
cmd_helper_copy(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
check_cmd(cmd_helper_copy, "copy");
memcpy(
f->buf + (unsigned long)((f->part ^ 1) * GBE_PART_SIZE),
f->buf + (unsigned long)(f->part * GBE_PART_SIZE),
f->buf + (size_t)((f->part ^ 1) * GBE_PART_SIZE),
f->buf + (size_t)(f->part * GBE_PART_SIZE),
GBE_PART_SIZE);
set_part_modified(f->part ^ 1);
@@ -447,7 +464,7 @@ cmd_helper_copy(void)
void
cmd_helper_cat(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
check_cmd(cmd_helper_cat, "cat");
@@ -458,7 +475,7 @@ cmd_helper_cat(void)
void
cmd_helper_cat16(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
check_cmd(cmd_helper_cat16, "cat16");
@@ -469,7 +486,7 @@ cmd_helper_cat16(void)
void
cmd_helper_cat128(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
check_cmd(cmd_helper_cat128, "cat128");
@@ -478,18 +495,18 @@ cmd_helper_cat128(void)
}
void
cat(unsigned long nff)
cat(size_t nff)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
unsigned long p;
unsigned long ff;
size_t p;
size_t ff;
p = 0;
ff = 0;
if ((unsigned long)x->cat != nff) {
if ((size_t)x->cat != nff) {
err(ECANCELED, "erroneous call to cat");
}
@@ -501,7 +518,7 @@ cat(unsigned long nff)
for (p = 0; p < 2; p++) {
cat_buf(f->bufcmp +
(unsigned long)(p * (f->gbe_file_size >> 1)));
(size_t)(p * (f->gbe_file_size >> 1)));
for (ff = 0; ff < nff; ff++) {
@@ -525,8 +542,8 @@ void
check_cmd(void (*fn)(void),
const char *name)
{
struct xstate *x = xstatus(0, NULL);
unsigned long i = x->i;
struct xstate *x = xstatus();
size_t i = x->i;
if (x->cmd[i].run != fn)
err(ECANCELED, "Running %s, but cmd %s is set",

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@
void
open_gbe_file(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
@@ -29,12 +29,12 @@ open_gbe_file(void)
xopen(&f->gbe_fd, f->fname,
cmd->flags | O_BINARY |
O_NOFOLLOW | O_CLOEXEC, &f->gbe_st);
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, &f->gbe_st);
if (f->gbe_st.st_nlink > 1)
err(EINVAL,
"%s: warning: file has multiple (%lu) hard links\n",
f->fname, (unsigned long)f->gbe_st.st_nlink);
f->fname, (size_t)f->gbe_st.st_nlink);
if (f->gbe_st.st_nlink == 0)
err(EIO, "%s: file unlinked while open", f->fname);
@@ -69,7 +69,7 @@ open_gbe_file(void)
void
copy_gbe(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
read_file();
@@ -77,19 +77,19 @@ copy_gbe(void)
if (f->gbe_file_size == SIZE_8KB)
return;
memcpy(f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (unsigned long)(f->gbe_file_size >> 1),
(unsigned long)GBE_PART_SIZE);
memcpy(f->buf + (size_t)GBE_PART_SIZE,
f->buf + (size_t)(f->gbe_file_size >> 1),
(size_t)GBE_PART_SIZE);
}
void
read_file(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
struct stat _st;
long _r;
ssize_t _r;
/* read main file
*/
@@ -141,11 +141,11 @@ read_file(void)
void
write_gbe_file(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
unsigned long p;
size_t p;
unsigned char update_checksum;
if ((cmd->flags & O_ACCMODE) == O_RDONLY)
@@ -171,25 +171,25 @@ write_gbe_file(void)
}
void
rw_gbe_file_part(unsigned long p, int rw_type,
rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
long rval;
ssize_t rval;
off_t file_offset;
unsigned long gbe_rw_size;
size_t gbe_rw_size;
unsigned char *mem_offset;
gbe_rw_size = cmd->rw_size;
if (rw_type < IO_PREAD || rw_type > IO_PWRITE)
err(errno, "%s: %s: part %lu: invalid rw_type, %d",
f->fname, rw_type_str, (unsigned long)p, rw_type);
f->fname, rw_type_str, (size_t)p, rw_type);
mem_offset = gbe_mem_offset(p, rw_type_str);
file_offset = (off_t)gbe_file_offset(p, rw_type_str);
@@ -199,17 +199,17 @@ rw_gbe_file_part(unsigned long p, int rw_type,
if (rval == -1)
err(errno, "%s: %s: part %lu",
f->fname, rw_type_str, (unsigned long)p);
f->fname, rw_type_str, (size_t)p);
if ((unsigned long)rval != gbe_rw_size)
if ((size_t)rval != gbe_rw_size)
err(EIO, "%s: partial %s: part %lu",
f->fname, rw_type_str, (unsigned long)p);
f->fname, rw_type_str, (size_t)p);
}
void
write_to_gbe_bin(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
@@ -240,14 +240,20 @@ write_to_gbe_bin(void)
saved_errno = errno;
if (close_on_eintr(f->tmp_fd) == -1) {
f->tmp_fd = -1;
fprintf(stderr, "FAIL: %s: close\n", f->tname);
f->io_err_gbe_bin = 1;
}
f->tmp_fd = -1;
if (close_on_eintr(f->gbe_fd) == -1) {
f->gbe_fd = -1;
fprintf(stderr, "FAIL: %s: close\n", f->fname);
f->io_err_gbe_bin = 1;
}
f->gbe_fd = -1;
errno = saved_errno;
@@ -274,8 +280,10 @@ write_to_gbe_bin(void)
/* removed by rename
*/
if (f->tname != NULL)
if (f->tname != NULL) {
free(f->tname);
f->tname = NULL;
}
f->tname = NULL;
}
@@ -292,15 +300,15 @@ write_to_gbe_bin(void)
}
void
check_written_part(unsigned long p)
check_written_part(size_t p)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
long rval;
ssize_t rval;
unsigned long gbe_rw_size;
size_t gbe_rw_size;
off_t file_offset;
unsigned char *mem_offset;
@@ -328,7 +336,7 @@ check_written_part(unsigned long p)
if (rval == -1)
f->rw_check_err_read[p] = f->io_err_gbe = 1;
else if ((unsigned long)rval != gbe_rw_size)
else if ((size_t)rval != gbe_rw_size)
f->rw_check_partial_read[p] = f->io_err_gbe = 1;
else if (memcmp(mem_offset, f->pad, gbe_rw_size) != 0)
f->rw_check_bad_part[p] = f->io_err_gbe = 1;
@@ -359,10 +367,10 @@ check_written_part(unsigned long p)
void
report_io_err_rw(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
unsigned long p;
size_t p;
if (!f->io_err_gbe)
return;
@@ -374,22 +382,22 @@ report_io_err_rw(void)
if (f->rw_check_err_read[p])
fprintf(stderr,
"%s: pread: p%lu (post-verification)\n",
f->fname, (unsigned long)p);
f->fname, (size_t)p);
if (f->rw_check_partial_read[p])
fprintf(stderr,
"%s: partial pread: p%lu (post-verification)\n",
f->fname, (unsigned long)p);
f->fname, (size_t)p);
if (f->rw_check_bad_part[p])
fprintf(stderr,
"%s: pwrite: corrupt write on p%lu\n",
f->fname, (unsigned long)p);
f->fname, (size_t)p);
if (f->rw_check_err_read[p] ||
f->rw_check_partial_read[p]) {
fprintf(stderr,
"%s: p%lu: skipped checksum verification "
"(because read failed)\n",
f->fname, (unsigned long)p);
f->fname, (size_t)p);
continue;
}
@@ -402,7 +410,7 @@ report_io_err_rw(void)
fprintf(stderr, "BAD");
fprintf(stderr, " checksum in p%lu on-disk.\n",
(unsigned long)p);
(size_t)p);
if (f->post_rw_checksum[p]) {
fprintf(stderr,
@@ -415,7 +423,7 @@ report_io_err_rw(void)
int
gbe_mv(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
int rval;
@@ -490,8 +498,11 @@ gbe_mv(void)
if (fsync_on_eintr(dest_fd) == -1)
goto ret_gbe_mv;
if (close_on_eintr(dest_fd) == -1)
if (close_on_eintr(dest_fd) == -1) {
dest_fd = -1;
goto ret_gbe_mv;
}
dest_fd = -1;
if (rename(dest_tmp, f->fname) == -1)
goto ret_gbe_mv;
@@ -501,25 +512,37 @@ gbe_mv(void)
goto ret_gbe_mv;
}
free(dest_tmp);
if (dest_tmp != NULL) {
free(dest_tmp);
dest_tmp = NULL;
}
dest_tmp = NULL;
ret_gbe_mv:
/* TODO: this whole section is bloat.
it can be generalised
*/
if (f->gbe_fd > -1) {
if (close_on_eintr(f->gbe_fd) < 0)
if (close_on_eintr(f->gbe_fd) < 0) {
f->gbe_fd = -1;
rval = -1;
}
f->gbe_fd = -1;
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
rval = -1;
}
f->gbe_fd = -1;
}
if (f->tmp_fd > -1) {
if (close_on_eintr(f->tmp_fd) < 0)
if (close_on_eintr(f->tmp_fd) < 0) {
f->tmp_fd = -1;
rval = -1;
}
f->tmp_fd = -1;
}
@@ -552,9 +575,9 @@ ret_gbe_mv:
* and it is *also* used during file I/O.
*/
unsigned char *
gbe_mem_offset(unsigned long p, const char *f_op)
gbe_mem_offset(size_t p, const char *f_op)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
off_t gbe_off;
@@ -563,7 +586,7 @@ gbe_mem_offset(unsigned long p, const char *f_op)
GBE_PART_SIZE, GBE_WORK_SIZE);
return (unsigned char *)
(f->buf + (unsigned long)gbe_off);
(f->buf + (size_t)gbe_off);
}
/* I/O operations filtered here. These operations must
@@ -571,9 +594,9 @@ gbe_mem_offset(unsigned long p, const char *f_op)
* within the GbE file, and write 4KB of data.
*/
off_t
gbe_file_offset(unsigned long p, const char *f_op)
gbe_file_offset(size_t p, const char *f_op)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
off_t gbe_file_half_size;
@@ -585,10 +608,10 @@ gbe_file_offset(unsigned long p, const char *f_op)
}
off_t
gbe_x_offset(unsigned long p, const char *f_op, const char *d_type,
gbe_x_offset(size_t p, const char *f_op, const char *d_type,
off_t nsize, off_t ncmp)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
off_t off;
@@ -608,14 +631,14 @@ gbe_x_offset(unsigned long p, const char *f_op, const char *d_type,
return off;
}
long
rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
ssize_t
rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
off_t off, int rw_type)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
long r;
ssize_t r;
if (io_args(fd, mem, nrw, off, rw_type) == -1)
return -1;
@@ -624,17 +647,17 @@ rw_gbe_file_exact(int fd, unsigned char *mem, unsigned long nrw,
if (mem < f->buf)
goto err_rw_gbe_file_exact;
if ((unsigned long)(mem - f->buf) >= GBE_WORK_SIZE)
if ((size_t)(mem - f->buf) >= GBE_WORK_SIZE)
goto err_rw_gbe_file_exact;
}
if (off < 0 || off >= f->gbe_file_size)
goto err_rw_gbe_file_exact;
if (nrw > (unsigned long)(f->gbe_file_size - off))
if (nrw > (size_t)(f->gbe_file_size - off))
goto err_rw_gbe_file_exact;
if (nrw > (unsigned long)GBE_PART_SIZE)
if (nrw > (size_t)GBE_PART_SIZE)
goto err_rw_gbe_file_exact;
r = rw_file_exact(fd, mem, nrw, off, rw_type,

View File

@@ -4,6 +4,10 @@
* Numerical functions.
*/
/*
TODO: properly handle errno in this file
*/
#ifdef __OpenBSD__
#include <sys/param.h>
#endif
@@ -30,31 +34,108 @@
#include "../include/common.h"
/* TODO:
* make this and errno handling more
* flexible
in particular:
hextonum could be modified to
write into a buffer instead,
with the converted numbers,
of an arbitrary length
*/
unsigned short
hextonum(char ch_s)
{
int saved_errno = errno;
/* rlong() can return error,
but preserves errno if no
error. we need to detect
this because it handles
/dev/urandom sometimes
therefore, if it's zero
at start, we know if there
was an err at the end, by
return value zero, if errno
was set; this is technically
valid, since zero is also
a valid random number!
it's an edge case that i had
to fix. i'll rewrite the code
better later. for now, it
should be ok.
*/
errno = 0;
unsigned char ch;
size_t rval;
ch = (unsigned char)ch_s;
if ((unsigned int)(ch - '0') <= 9)
return ch - '0';
if ((unsigned int)(ch - '0') <= 9) {
rval = ch - '0';
goto hextonum_success;
}
ch |= 0x20;
if ((unsigned int)(ch - 'a') <= 5)
return ch - 'a' + 10;
if ((unsigned int)(ch - 'a') <= 5) {
if (ch == '?' || ch == 'x')
return (unsigned short)rlong() & 0xf;
rval = ch - 'a' + 10;
goto hextonum_success;
}
if (ch == '?' || ch == 'x') {
rval = rlong();
if (errno > 0)
goto err_hextonum;
goto hextonum_success;
}
goto err_hextonum;
hextonum_success:
errno = saved_errno;
return (unsigned short)rval & 0xf;
err_hextonum:
if (errno == saved_errno)
errno = EINVAL;
else
return 17; /* 17 indicates getrandom/urandom fail */
return 16; /* invalid character */
/* caller just checks >15. */
}
/* Random numbers
*/
unsigned long
/* when calling this: save errno
* first, then set errno to zero.
* on error, this function will
* set errno and possibly return
*
* rlong also preserves errno
* and leaves it unchanged on
* success, so if you do it
* right, you can detect error.
* this is because it uses
* /dev/urandom which can err.
* ditto getrandom (EINTR),
* theoretically.
*/
size_t
rlong(void)
{
#if !(defined(FALLBACK_RAND_1989) && \
@@ -63,14 +144,17 @@ rlong(void)
defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__APPLE__)
unsigned long rval;
arc4random_buf(&rval, sizeof(unsigned long));
int saved_errno = errno;
size_t rval;
arc4random_buf(&rval, sizeof(size_t));
errno = saved_errno;
return rval;
#else
static int fd = -1;
static long nr = -1;
static unsigned long off = 0;
static ssize_t nr = -1;
static size_t off = 0;
#if defined (BUFSIZ)
static char rbuf[BUFSIZ];
#else
@@ -82,12 +166,14 @@ rlong(void)
static char rbuf[4096]; /* typical 32-bit BUFSIZ */
#endif
#endif
unsigned long rval;
long new_nr;
size_t rval;
ssize_t new_nr;
int retries = 0;
int max_retries = 100;
int saved_errno = errno;
#if defined(__linux__)
#if defined(HAVE_GETRANDOM) || \
defined(HAVE_GETRANDOM_SYSCALL)
@@ -98,17 +184,12 @@ rlong(void)
* modern linux, but not on
* every libc. better use the
* official linux function
*
* similar benefits to arc4random
* e.g. works in chroot, blocks
* until it has enough entropy,
* and works even when /dev/urandom
* is available (doesn't use it);
* it's generally more reliable
*/
if (fallback_rand_getrandom(&rval, sizeof(rval)) == 0)
if (fallback_rand_getrandom(&rval, sizeof(rval)) == 0) {
errno = saved_errno;
return rval;
}
/*
* now fall back to urandom if getrandom failed:
@@ -131,15 +212,15 @@ rlong(void)
retry_urandom_read:
if (++retries > max_retries)
goto rlong_next;
goto err_rlong;
if (nr < 0 || nr < (long)sizeof(unsigned long)) {
if (nr < 0 || nr < (ssize_t)sizeof(size_t)) {
if (fd < 0) {
fd = open("/dev/urandom",
O_RDONLY | O_BINARY | O_NOFOLLOW |
O_CLOEXEC);
O_CLOEXEC | O_NOCTTY);
#ifdef USE_OLD_DEV_RANDOM
#if (USE_OLD_DEV_RANDOM) > 0
@@ -155,7 +236,7 @@ retry_urandom_read:
if (fd < 0)
fd = open("/dev/random",
O_RDONLY | O_BINARY | O_NOFOLLOW |
O_CLOEXEC);
O_CLOEXEC | O_NOCTTY);
#endif
#endif
@@ -169,7 +250,7 @@ retry_urandom_read:
sizeof(rbuf), 0, IO_READ, LOOP_EAGAIN,
LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
if (new_nr < 0 || new_nr < (long)sizeof(rbuf))
if (new_nr < 0 || new_nr < (ssize_t)sizeof(rbuf))
goto retry_urandom_read;
/* only reset buffer after successful refill */
@@ -187,37 +268,37 @@ retry_urandom_read:
fd = -1;
retries = 0;
memcpy(&rval, rbuf + off, sizeof(unsigned long));
memcpy(&rval, rbuf + off, sizeof(size_t));
nr -= (long)sizeof(unsigned long);
off += sizeof(unsigned long);
nr -= (ssize_t)sizeof(size_t);
off += sizeof(size_t);
errno = saved_errno;
return rval;
rlong_next:
err_rlong:
fd = -1;
off = 0;
nr = -1;
if (errno == saved_errno)
errno = EIO;
err(EIO, "Can't read from /dev/[ua]random");
return 0;
#endif
#else /* FALLBACK_RAND_1989 */
/* your computer is from a museum
*/
unsigned long mix = 0;
int nr;
size_t mix = 0;
int nr = 0;
int saved_errno = errno;
/* 100 times, for entropy
*/
for (nr = 0; nr < 100; nr++)
mix ^= fallback_rand_1989();
/* 101 times ;)
*/
return fallback_rand_1989();
errno = saved_errno;
return mix;
#endif
}
@@ -226,17 +307,22 @@ rlong_next:
#if defined(__linux__)
#if defined(HAVE_GETRANDOM) || \
defined(HAVE_GETRANDOM_SYSCALL)
int
fallback_rand_getrandom(void *buf, unsigned long len)
int /* yes, linux is a fallback */
fallback_rand_getrandom(void *buf, size_t len)
{
unsigned long off = 0;
long rval = -1;
size_t off = 0;
ssize_t rval = -1;
int saved_errno = errno;
if (!len)
if (!len) {
errno = EINVAL;
return -1;
}
if (buf == NULL)
if (buf == NULL) {
errno = EFAULT;
return -1;
}
#if defined(HAVE_GETRANDOM) || \
defined(HAVE_GETRANDOM_SYSCALL)
@@ -244,51 +330,60 @@ fallback_rand_getrandom(void *buf, unsigned long len)
while (off < len) {
#if defined(HAVE_GETRANDOM)
rval = (long)getrandom((char *)buf + off, len - off, 0);
rval = (ssize_t)getrandom((char *)buf + off, len - off, 0);
#elif defined(HAVE_GETRANDOM_SYSCALL)
rval = (long)syscall(SYS_getrandom,
rval = (ssize_t)syscall(SYS_getrandom,
(char *)buf + off, len - off, 0);
#endif
if (rval < 0) {
if (errno == EINTR)
if (errno == EINTR || errno == EAGAIN)
continue;
errno = EIO;
return -1; /* unsupported by kernel */
}
off += (unsigned long)rval;
if (rval == 0) {
errno = EIO;
return -1;
}
off += (size_t)rval;
}
errno = saved_errno;
return 0;
#else
(void)buf;
(void)len;
errno = EIO;
return -1;
#endif
}
#endif
#endif
#else
/* nobody should use this
* (not crypto-safe)
*/
unsigned long
size_t
fallback_rand_1989(void)
{
static unsigned long mix = 0;
static unsigned long counter = 0;
static size_t mix = 0;
static size_t counter = 0;
struct timeval tv;
/* nobody should use this
* (not crypto-safe)
*/
gettimeofday(&tv, NULL);
mix ^= (unsigned long)tv.tv_sec
^ (unsigned long)tv.tv_usec
^ (unsigned long)getpid()
^ (unsigned long)&mix
mix ^= (size_t)tv.tv_sec
^ (size_t)tv.tv_usec
^ (size_t)getpid()
^ (size_t)&mix
^ counter++
^ entropy_jitter();
@@ -296,20 +391,20 @@ fallback_rand_1989(void)
* Stack addresses can vary between
* calls, thus increasing entropy.
*/
mix ^= (unsigned long)&mix;
mix ^= (unsigned long)&tv;
mix ^= (unsigned long)&counter;
mix ^= (size_t)&mix;
mix ^= (size_t)&tv;
mix ^= (size_t)&counter;
return mix;
}
unsigned long
size_t
entropy_jitter(void)
{
unsigned long mix;
size_t mix;
struct timeval a, b;
long mix_diff;
ssize_t mix_diff;
int c;
@@ -326,13 +421,13 @@ entropy_jitter(void)
* prevent negative numbers to prevent overflow,
* which would bias rand to large numbers
*/
mix_diff = (long)(b.tv_usec - a.tv_usec);
mix_diff = (ssize_t)(b.tv_usec - a.tv_usec);
if (mix_diff < 0)
mix_diff = -mix_diff;
mix ^= (unsigned long)(mix_diff);
mix ^= (size_t)(mix_diff);
mix ^= (unsigned long)&mix;
mix ^= (size_t)&mix;
}
@@ -341,9 +436,9 @@ entropy_jitter(void)
#endif
void
check_bin(unsigned long a, const char *a_name)
check_bin(size_t a, const char *a_name)
{
if (a > 1)
err(EINVAL, "%s must be 0 or 1, but is %lu",
a_name, (unsigned long)a);
a_name, (size_t)a);
}

View File

@@ -23,8 +23,11 @@
#include "../include/common.h"
struct xstate *
xstatus(int argc, char *argv[])
xstart(int argc, char *argv[])
{
static int first_run = 1;
static int pre_init = 0;
static struct xstate us = {
/* DO NOT MESS THIS UP, OR THERE WILL BE DEMONS */
{
@@ -86,92 +89,52 @@ xstatus(int argc, char *argv[])
};
static int first_run = 1;
struct xstate *x = &us;
if (!first_run) {
if (pre_init)
err_no_cleanup(ECANCELED,
"Outside access to state during init");
first_run = 0;
if (!first_run)
return &us;
}
if (argc < 3)
err_no_cleanup(EINVAL, "xstart: Too few arguments");
if (argv == NULL)
err_no_cleanup(EINVAL, "xstart: NULL argv");
first_run = 0;
pre_init = 1;
us.f.buf = us.f.real_buf;
first_run = 0;
us.argv0 = argv[0];
if (argc > 1)
us.f.fname = argv[1];
if (argc < 3)
usage();
/* https://man.openbsd.org/pledge.2
https://man.openbsd.org/unveil.2 */
#if defined(__OpenBSD__) && defined(OpenBSD)
#if (OpenBSD) >= 604
if (pledge("stdio flock rpath wpath cpath unveil", NULL) == -1)
err(errno, "pledge plus unveil");
#elif (OpenBSD) >= 509
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
err(errno, "pledge");
#endif
#endif
#ifndef S_ISREG
err(ECANCELED, "Can't determine file types (S_ISREG undefined)");
#endif
#ifndef CHAR_BIT
err(ECANCELED, "Unknown char size");
#else
if (CHAR_BIT != 8)
err(EINVAL, "Unsupported char size");
#endif
us.f.fname = argv[1];
#if defined(__OpenBSD__) && defined(OpenBSD) && \
(OpenBSD) >= 604
/* can only use local tmp on openbsd, due to unveil */
us.f.tname = new_tmpfile(&us.f.tmp_fd, 1, NULL);
#else
us.f.tname = new_tmpfile(&us.f.tmp_fd, 0, NULL);
// TODO: new_tmplate (do for above too)
us.f.tname = new_tmpfile(&us.f.tmp_fd, 0, NULL); // TODO: NULL BAD!
#endif
if (us.f.tname == NULL)
err(errno, "Can't create tmpfile");
if (*us.f.tname == '\0')
err(errno, "tmp dir is an empty string");
#if defined(__OpenBSD__) && defined(OpenBSD) && \
OpenBSD >= 604
if (unveil(us.f.tname, "rwc") == -1)
err(errno, "unveil rwc: %s", us.f.tname);
#endif
if (fstat(us.f.tmp_fd, &us.f.tmp_st) < 0)
err(errno, "%s: stat", us.f.tname);
sanitize_command_list();
/* parse user command */
// TODO: CHECK ACCESSES VIA xstatus()
set_cmd(argc, argv);
set_cmd_args(argc, argv);
#if defined(__OpenBSD__) && defined(OpenBSD) && \
(OpenBSD) >= 604
if ((us.cmd[i].flags & O_ACCMODE) == O_RDONLY) {
if (unveil(us.f.fname, "r") == -1)
err(errno, "%s: unveil r", us.f.fname);
} else {
if (unveil(us.f.fname, "rwc") == -1)
err(errno, "%s: unveil rw", us.f.fname);
}
if (us.f.tname == NULL)
err_no_cleanup(errno, "x->f.tname null");
if (*us.f.tname == '\0')
err_no_cleanup(errno, "x->f.tname empty");
if (unveil(us.f.tname, "rwc") == -1)
err(errno, "%s: unveil rwc", us.f.tname);
if (unveil(NULL, NULL) == -1)
err(errno, "unveil block (rw)");
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
err(errno, "pledge (kill unveil)");
#endif
open_gbe_file();
if (fstat(us.f.tmp_fd, &us.f.tmp_st) < 0)
err_no_cleanup(errno, "%s: stat", us.f.tname);
memset(us.f.real_buf, 0, sizeof(us.f.real_buf));
memset(us.f.bufcmp, 0, sizeof(us.f.bufcmp));
@@ -179,16 +142,55 @@ xstatus(int argc, char *argv[])
/* for good measure */
memset(us.f.pad, 0, sizeof(us.f.pad));
copy_gbe();
read_checksums();
pre_init = 0;
return &us;
}
struct xstate *
xstatus(void)
{
struct xstate *x = xstart(0, NULL);
if (x == NULL)
err_no_cleanup(EACCES, "NULL pointer to xstate");
sanitize_command_list();
return x;
}
/* early init functions that
should not access state
WARNING:
does not do cleanup. only
call this during pre-init
*/
void
err_no_cleanup(int nvm_errval, const char *msg, ...)
{
va_list args;
if (errno == 0)
errno = nvm_errval;
if (!errno)
errno = ECANCELED;
fprintf(stderr, "nvmutil: ");
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, ": %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
void
err(int nvm_errval, const char *msg, ...)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
va_list args;
@@ -214,7 +216,7 @@ err(int nvm_errval, const char *msg, ...)
const char *
getnvmprogname(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
const char *p;
static char fallback[] = "nvmutil";
@@ -239,7 +241,7 @@ getnvmprogname(void)
int
exit_cleanup(void)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f;
int close_err;
@@ -252,14 +254,19 @@ exit_cleanup(void)
f = &x->f;
if (f->gbe_fd > -1) {
if (close_on_eintr(f->gbe_fd) == -1)
if (close_on_eintr(f->gbe_fd) == -1) {
f->gbe_fd = -1;
close_err = 1;
}
f->gbe_fd = -1;
}
if (f->tmp_fd > -1) {
if (close_on_eintr(f->tmp_fd) == -1)
if (close_on_eintr(f->tmp_fd) == -1) {
f->tmp_fd = -1;
close_err = 1;
}
f->tmp_fd = -1;
}
if (f->tname != NULL) {

View File

@@ -9,67 +9,106 @@
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include "../include/common.h"
/* Portable strncmp() that blocks
* NULL/empty/unterminated strings
/* scmp() - strict string comparison
*
* strict string comparison
* similar to strncmp, but null and
* unterminated inputs do not produce
* a return value; on error, errno is
* set and -1 is returned.
*
* the real return value is stored in
* the 4th argument by pointer.
*
* the value at rval pointer is set,
* only upon success. callers should
* check the return value accordingly.
*/
int
xstrxcmp(const char *a, const char *b, unsigned long maxlen)
scmp(const char *a,
const char *b,
size_t maxlen,
int *rval)
{
unsigned long i;
size_t ch;
unsigned char ac;
unsigned char bc;
if (a == NULL || b == NULL)
err(EINVAL, "NULL input to xstrxcmp");
if (a == NULL ||
b == NULL ||
rval == NULL) {
if (*a == '\0' || *b == '\0')
err(EINVAL, "Empty string in xstrxcmp");
for (i = 0; i < maxlen; i++) {
unsigned char ac = (unsigned char)a[i];
unsigned char bc = (unsigned char)b[i];
if (ac == '\0' || bc == '\0') {
if (ac == bc)
return 0;
return ac - bc;
}
if (ac != bc)
return ac - bc;
errno = EFAULT;
return -1;
}
err(EINVAL, "Unterminated string in xstrxcmp");
for (ch = 0; ch < maxlen; ch++) {
errno = EINVAL;
ac = (unsigned char)a[ch];
bc = (unsigned char)b[ch];
if (ac != bc) {
*rval = ac - bc;
return 0;
}
if (ac == '\0') {
*rval = 0;
return 0;
}
}
/* block unterminated strings */
errno = EFAULT;
return -1;
}
/* Portable strncmp() that blocks
* NULL/empty/unterminated strings
/* slen() - strict strict length
*
* strict string length calculation
* similar to strnlen, but null and
* unterminated inputs do not produce
* a return value; on error, errno is
* set and -1 is returned.
*
* the real return value is stored in
* the 3rd argument by pointer.
*
* the value at rval pointer is set,
* only upon success. callers should
* check the return value accordingly.
*/
unsigned long
xstrxlen(const char *scmp, unsigned long maxlen)
int
slen(const char *s,
size_t maxlen,
size_t *rval)
{
unsigned long xstr_index;
size_t ch;
if (scmp == NULL)
err(EINVAL, "NULL input to xstrxlen");
if (s == NULL ||
rval == NULL) {
if (*scmp == '\0')
err(EINVAL, "Empty string in xstrxlen");
errno = EFAULT;
return -1;
}
for (xstr_index = 0;
xstr_index < maxlen && scmp[xstr_index] != '\0';
xstr_index++);
for (ch = 0;
ch < maxlen && s[ch] != '\0';
ch++);
if (xstr_index == maxlen)
err(EINVAL, "Unterminated string in xstrxlen");
if (ch == maxlen) {
/* unterminated */
errno = EFAULT;
return -1;
}
return xstr_index;
*rval = ch;
return 0;
}

View File

@@ -13,12 +13,12 @@
#include "../include/common.h"
unsigned short
nvm_word(unsigned long pos16, unsigned long p)
nvm_word(size_t pos16, size_t p)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
unsigned long pos;
size_t pos;
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
@@ -28,12 +28,12 @@ nvm_word(unsigned long pos16, unsigned long p)
}
void
set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
set_nvm_word(size_t pos16, size_t p, unsigned short val16)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
unsigned long pos;
size_t pos;
check_nvm_bound(pos16, p);
pos = (pos16 << 1) + (p * GBE_PART_SIZE);
@@ -45,9 +45,9 @@ set_nvm_word(unsigned long pos16, unsigned long p, unsigned short val16)
}
void
set_part_modified(unsigned long p)
set_part_modified(size_t p)
{
struct xstate *x = xstatus(0, NULL);
struct xstate *x = xstatus();
struct xfile *f = &x->f;
check_bin(p, "part number");
@@ -55,7 +55,7 @@ set_part_modified(unsigned long p)
}
void
check_nvm_bound(unsigned long c, unsigned long p)
check_nvm_bound(size_t c, size_t p)
{
/* Block out of bound NVM access
*/
@@ -64,5 +64,5 @@ check_nvm_bound(unsigned long c, unsigned long p)
if (c >= NVM_WORDS)
err(ECANCELED, "check_nvm_bound: out of bounds %lu",
(unsigned long)c);
(size_t)c);
}

View File

@@ -6,6 +6,12 @@
* These images configure your Intel Gigabit Ethernet adapter.
*/
#ifdef __OpenBSD__
/* for pledge/unveil test:
*/
#include <sys/param.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
@@ -13,22 +19,88 @@
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "include/common.h"
int
main(int argc, char *argv[])
{
struct xstate *x = xstatus(argc, argv);
struct commands *cmd = &x->cmd[x->i];
struct xfile *f = &x->f;
struct xstate *x;
unsigned long c;
struct commands *cmd;
struct xfile *f;
size_t c;
/* https://man.openbsd.org/pledge.2
https://man.openbsd.org/unveil.2 */
#if defined(__OpenBSD__) && defined(OpenBSD)
#if (OpenBSD) >= 604
if (pledge("stdio flock rpath wpath cpath unveil", NULL) == -1)
err_no_cleanup(errno, "pledge plus unveil, main");
if (unveil("/dev/null", "r") == -1)
err_no_cleanup(errno, "unveil r: /dev/null");
#elif (OpenBSD) >= 509
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
err_no_cleanup(errno, "pledge, main");
#endif
#endif
#ifndef S_ISREG
err_no_cleanup(ECANCELED,
"Can't determine file types (S_ISREG undefined)");
#endif
#if ((CHAR_BIT) != 8)
err_no_cleanup(ECANCELED, "Unsupported char size");
#endif
x = xstart(argc, argv);
if (x == NULL)
err_no_cleanup(ECANCELED, "NULL state on init");
cmd = &x->cmd[x->i];
f = &x->f;
/* https://man.openbsd.org/pledge.2
https://man.openbsd.org/unveil.2 */
#if defined(__OpenBSD__) && defined(OpenBSD)
#if (OpenBSD) >= 604
if ((us.cmd[i].flags & O_ACCMODE) == O_RDONLY) {
if (unveil(us.f.fname, "r") == -1)
err(errno, "%s: unveil r", us.f.fname);
} else {
if (unveil(us.f.fname, "rwc") == -1)
err(errno, "%s: unveil rw", us.f.fname);
}
if (unveil(us.f.tname, "rwc") == -1)
err(errno, "unveil rwc: %s", us.f.tname);
if (unveil(NULL, NULL) == -1)
err(errno, "unveil block (rw)");
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
err(errno, "pledge (kill unveil)");
#elif (OpenBSD) >= 509
if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
err(errno, "pledge");
#endif
#endif
if (cmd->run == NULL)
err(errno, "Command not set");
open_gbe_file();
copy_gbe();
read_checksums();
cmd->run();
for (c = 0; c < items(x->cmd); c++)
@@ -43,8 +115,10 @@ main(int argc, char *argv[])
if (f->io_err_gbe_bin)
err(EIO, "%s: error writing final file");
if (f->tname != NULL)
if (f->tname != NULL) {
free(f->tname);
f->tname = NULL;
}
return EXIT_SUCCESS;
}