diff options
| -rw-r--r-- | util/nvmutil/nvmutil.c | 119 | 
1 files changed, 35 insertions, 84 deletions
| diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index f51bafeb..12aabe4d 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -25,9 +25,9 @@ uint8_t hextonum(char chs), rhex(void);  #define COMMAND argv[2]  #define MAC_ADDRESS argv[3]  #define PARTN argv[3] -#define NVM_CHECKSUM 0xBABA /* checksum value */ -#define NVM_CHECKSUM_WORD 0x3F /* checksum word position */ -#define NVM_SIZE 128 /* Area containing NVM words */ +#define NVM_CHECKSUM 0xBABA +#define NVM_CHECKSUM_WORD 0x3F +#define NVM_SIZE 128  #define SIZE_4KB 0x1000  #define SIZE_8KB 0x2000 @@ -42,7 +42,6 @@ int flags, rfd, fd, part;  const char *strMac = NULL, *strRMac = "??:??:??:??:??:??", *filename = NULL; -/* available commands, set a pointer based on user command */  typedef struct op {  	char *str;  	void (*cmd)(void); @@ -58,15 +57,12 @@ op_t op[] = {  };  void (*cmd)(void) = NULL; -/* wrappers for BSD-style err() function (error handling) */  #define ERR() errno = errno ? errno : ECANCELED  #define err_if(x) if (x) err(ERR(), "%s", filename) -/* Macro for opening a file with errors properly handled */  #define xopen(f,l,p) if ((f = open(l, p)) == -1) err(ERR(), "%s", l); \      if (fstat(f, &st) == -1) err(ERR(), "%s", l) -/* Macros for reading/writing the GbE file in memory */  #define word(pos16, partnum) ((uint16_t *) gbe[partnum])[pos16]  #define setWord(pos16, p, val16) if (word(pos16, p) != val16) \      nvmPartChanged[p] = 1 | (word(pos16, p) = val16) @@ -75,11 +71,10 @@ int  main(int argc, char *argv[])  {  #ifdef __OpenBSD__ -	/* OpenBSD pledge (sandboxing): https://man.openbsd.org/pledge.2 */  	err_if(pledge("stdio rpath wpath unveil", NULL) == -1);  #endif -	if (argc < 2) { /* TODO: manpage! */ +	if (argc < 2) {  #ifdef __OpenBSD__  		err_if(pledge("stdio", NULL) == -1);  #endif @@ -102,38 +97,32 @@ main(int argc, char *argv[])  	if (argc > 2) {  		if (strcmp(COMMAND, "dump") == 0) { -			flags = O_RDONLY; /* write not needed for dump cmd */ +			flags = O_RDONLY;  #ifdef __OpenBSD__ -			/* writes not needed for the dump command */  			err_if(pledge("stdio rpath unveil", NULL) == -1);  #endif  		}  	} -	/* check for dir first, to prevent unveil from -	   permitting directory access on OpenBSD */  	checkdir("/dev/urandom"); -	checkdir(filename); /* Must be a file, not a directory */ +	checkdir(filename);  #ifdef __OpenBSD__ -	/* OpenBSD unveil: https://man.openbsd.org/unveil.2 */  	err_if(unveil("/dev/urandom", "r") == -1); -	/* Only allow access to /dev/urandom and the gbe file */ -	if (flags == O_RDONLY) { /* dump command */ -		err_if(unveil(filename, "r") == -1); /* write not needed */ -		err_if(unveil(NULL, NULL) == -1); /* lock unveil */ -		err_if(pledge("stdio rpath", NULL) == -1); /* lock unveil */ -	} else { /* other commands need read-write */ +	if (flags == O_RDONLY) { +		err_if(unveil(filename, "r") == -1); +		err_if(unveil(NULL, NULL) == -1); +		err_if(pledge("stdio rpath", NULL) == -1); +	} else {  		err_if(unveil(filename, "rw") == -1); -		err_if(unveil(NULL, NULL) == -1); /* lock unveil */ -		err_if(pledge("stdio rpath wpath", NULL) == -1); /* no unveil */ +		err_if(unveil(NULL, NULL) == -1); +		err_if(pledge("stdio rpath wpath", NULL) == -1);  	}  #endif -	openFiles(filename); /* open files first, to allow harder pledge: */ +	openFiles(filename);  #ifdef __OpenBSD__ -	/* OpenBSD sandboxing: https://man.openbsd.org/pledge.2 */  	err_if(pledge("stdio", NULL) == -1);  #endif @@ -157,29 +146,22 @@ main(int argc, char *argv[])  		cmd = cmd_setmac;  	} else if (cmd == cmd_setmac) { /* nvm gbe setmac [MAC] */  		strMac = strRMac; /* random MAC */ -		if (argc > 3) /* user-supplied MAC (can be random) */ +		if (argc > 3)  			strMac = MAC_ADDRESS;  	} else if ((cmd != NULL) && (argc > 3)) { /* user-supplied partnum */  		err_if((errno = (!((part = PARTN[0] - '0') == 0 || part == 1))  		    || PARTN[1] ? EINVAL : errno)); /* only allow '0' or '1' */  	} -	err_if((errno = (cmd == NULL) ? EINVAL : errno)); /* bad user arg */ - -	readGbe(); /* read gbe file into memory */ +	err_if((errno = (cmd == NULL) ? EINVAL : errno)); -	(*cmd)(); /* operate on gbe file in memory */ +	readGbe(); +	(*cmd)(); +	writeGbe(); -	writeGbe(); /* write changes back to file */ - -	err_if((errno != 0) && (cmd != cmd_dump)); /* don't err on dump */ -	return errno; /* errno can be set by the dump command */ +	err_if((errno != 0) && (cmd != cmd_dump)); +	return errno;  } -/* - * check whether urandom/file is a directory, and err if so, - * to prevent later unveil calls from permitting directory access - * on OpenBSD - */  void  checkdir(const char *path)  { @@ -190,13 +172,12 @@ checkdir(const char *path)  	err_if(errno);  } -/* open gbe file and /dev/urandom, setting permissions */  void  openFiles(const char *path)  {  	struct stat st; -	xopen(fd, path, flags); /* gbe file */ +	xopen(fd, path, flags);  	switch(st.st_size) {  	case SIZE_8KB: @@ -209,40 +190,32 @@ openFiles(const char *path)  		break;  	} -	/* the MAC address randomiser relies on reading urandom */  	xopen(rfd, "/dev/urandom", O_RDONLY);  } -/* read gbe file into memory buffer */  void  readGbe(void)  {  	if ((cmd == cmd_swap) || (cmd == cmd_copy)) -		nf = SIZE_4KB; /* read/write the entire block */ -			/* only need to do 4KB even on larger gbe files */ +		nf = SIZE_4KB;  	else -		nf = NVM_SIZE; /* only read/write the nvm part of the block */ +		nf = NVM_SIZE;  	if ((cmd == cmd_copy) || (cmd == cmd_setchecksum) || (cmd == cmd_brick)) -		do_read[part ^ 1] = 0; /* only read the user-specified part */ +		do_read[part ^ 1] = 0; -	/* AND do_read[*] to avoid wasteful malloc */ -	/* cmd_copy also relies on this */  	char *buf = malloc(nf << (do_read[0] & do_read[1]));  	if (buf == NULL)  		err(errno, NULL); -	/* we pread per-part, so each part has its own pointer: */ -	/* if a do_read is 0, both pointers are the same; this accomplishes -	   the desired result for cmd_copy (see cmd_copy function) */  	gbe[0] = (size_t) buf;  	gbe[1] = gbe[0] + (nf * (do_read[0] & do_read[1])); -	ssize_t tnr = 0; /* total bytes read */ +	ssize_t tnr = 0;  	for (int p = 0; p < 2; p++) {  		if (!do_read[p]) -			continue; /* avoid unnecessary reads */ +			continue;  		ssize_t nr = pread(fd, (uint8_t *) gbe[p], nf, p * partsize);  		err_if(nr == -1); @@ -252,14 +225,12 @@ readGbe(void)  			    nr, filename, nf);  		tnr += nr; -  		swap(p); /* handle big-endian host CPU */  	}  	printf("%ld bytes read from file '%s'\n", tnr, filename);  } -/* set MAC address and checksum on nvm part */  void  cmd_setmac(void)  { @@ -272,21 +243,20 @@ cmd_setmac(void)  		if (!goodChecksum(part = partnum))  			continue; -		for (int w = 0; w < 3; w++) /* write MAC to gbe part */ +		for (int w = 0; w < 3; w++)  			setWord(w, partnum, mac[w]);  		printf("Wrote MAC address to part %d: ", partnum);  		macf(partnum); -		cmd_setchecksum(); /* MAC updated; need valid checksum */ +		cmd_setchecksum();  		mac_updated = 1;  	}  	if (mac_updated) -		errno = 0; /* reset in case one of the checksums failed */ +		errno = 0;  } -/* parse MAC string, write to char buffer */  void  parseMacString(const char *strMac, uint16_t *mac)  { @@ -303,14 +273,12 @@ parseMacString(const char *strMac, uint16_t *mac)  		int byte = i / 3; -		/* Update MAC buffer per-nibble from a given string */  		for (int nib = 0; nib < 2; nib++, total += h) {  			if ((h = hextonum(strMac[i + nib])) > 15)  				err(errno = EINVAL, "Invalid character '%c'",  				    strMac[i + nib]); -			/* if random: ensure local-only, unicast MAC */ -			if ((byte == 0) && (nib == 1)) /* unicast/local nib */ +			if ((byte == 0) && (nib == 1))  				if (strMac[i + nib] == '?') /* ?=random */  					h = (h & 0xE) | 2; /* local, unicast */ @@ -325,7 +293,6 @@ parseMacString(const char *strMac, uint16_t *mac)  		err(errno = EINVAL, "Invalid MAC (multicast bit set)");  } -/* convert hex char to char value (0-15) */  uint8_t  hextonum(char ch)  { @@ -335,10 +302,9 @@ hextonum(char ch)  		return ch - 'A' + 10;  	else if ((ch >= 'a') && (ch <= 'f'))  		return ch - 'a' + 10; -	return (ch == '?') ? rhex() : 16; /* 16 for error (invalid char) */ +	return (ch == '?') ? rhex() : 16;  } -/* random number generator */  uint8_t  rhex(void)  { @@ -348,7 +314,6 @@ rhex(void)  	return rnum[n--] & 0xf;  } -/* print mac address and hexdump of parts */  void  cmd_dump(void)  { @@ -369,7 +334,6 @@ cmd_dump(void)  	}  } -/* print mac address of part */  void  macf(int partnum)  { @@ -383,7 +347,6 @@ macf(int partnum)  	}  } -/* print hexdump of nvm part */  void  hexdump(int partnum)  { @@ -399,7 +362,6 @@ hexdump(int partnum)  	}  } -/* correct the checksum on part */  void  cmd_setchecksum(void)  { @@ -407,11 +369,9 @@ cmd_setchecksum(void)  	for (int c = 0; c < NVM_CHECKSUM_WORD; c++)  		val16 += word(c, part); -	/* correct the checksum */  	setWord(NVM_CHECKSUM_WORD, part, NVM_CHECKSUM - val16);  } -/* intentionally set wrong checksum on part */  void  cmd_brick(void)  { @@ -420,23 +380,17 @@ cmd_brick(void)  		    ((word(NVM_CHECKSUM_WORD, part)) ^ 0xFF));  } -/* overwrite the contents of one part with the other */  void  cmd_copy(void)  {  	nvmPartChanged[part ^ 1] = goodChecksum(part); - -	/* no need to actually copy because gbe[] pointers are both the same */ -	/* we simply set the right nvm part as changed, and write the file */  } -/* swap contents between the two parts */  void  cmd_swap(void) {  	err_if(!(goodChecksum(0) || goodChecksum(1)));  	errno = 0; -	/* speedhack: swap pointers, not words. (xor swap) */  	gbe[0] ^= gbe[1];  	gbe[1] ^= gbe[0];  	gbe[0] ^= gbe[1]; @@ -444,7 +398,6 @@ cmd_swap(void) {  	nvmPartChanged[0] = nvmPartChanged[1] = 1;  } -/* verify nvm part checksum (return 1 if valid) */  int  goodChecksum(int partnum)  { @@ -460,11 +413,10 @@ goodChecksum(int partnum)  	return 0;  } -/* write the nvm parts back to the file */  void  writeGbe(void)  { -	ssize_t tnw = 0; /* total bytes written */ +	ssize_t tnw = 0;  	for (int p = 0; p < 2; p++) {  		if ((!nvmPartChanged[p]) || (flags == O_RDONLY)) @@ -498,10 +450,9 @@ writeGbe(void)  	err_if(close(fd) == -1);  } -/* swap byte order on big-endian CPUs. swap skipped on little endian */  void -swap(int partnum) /* swaps bytes in words, not pointers. */ -{		/* not to be confused with cmd_swap */ +swap(int partnum) +{  	size_t w, x;  	uint8_t *n = (uint8_t *) gbe[partnum];  	int e = 1; | 
