I just fixed a bug which allowed people to cheat in worm(6). This bug was found out by deraadt@ when peer reviewing the mail thread in tech@ 'Fwd: worm.c removing unused variables'.
To reproduce the bug simply hold spacebar and your worm won't move. Highlights: * Use the unused time variables to record how long has been since the last valid key press; * Changed the process() function to return whether the key pressed was valid or not; * Use clock_gettime(CLOCK_UPTIME) instead of gettimeofday() to provide reliable clock source even on suspend/wake up; ok? Index: worm.c =================================================================== RCS file: /cvs/src/games/worm/worm.c,v retrieving revision 1.30 diff -u -p -r1.30 worm.c --- worm.c 22 Aug 2015 14:47:41 -0000 1.30 +++ worm.c 23 Aug 2015 20:42:42 -0000 @@ -78,7 +78,7 @@ void leave(int); void life(void); void newpos(struct body *); struct body *newlink(void); -void process(int); +int process(int); void prize(void); int rnd(int); void setup(void); @@ -88,10 +88,11 @@ int main(int argc, char **argv) { int retval; - struct timeval t, tod; - struct timezone tz; struct pollfd pfd[1]; const char *errstr; + struct timespec t, tn, tdiff; + + memset(&t, 0, sizeof(t)); setbuf(stdout, outbuf); signal(SIGINT, leave); @@ -154,18 +155,34 @@ main(int argc, char **argv) running--; process(lastch); } else { - /* fflush(stdout); */ - /* Delay could be a command line option */ - t.tv_sec = 1; - t.tv_usec = 0; - (void)gettimeofday(&tod, &tz); + /* Check for user input timeout. */ + clock_gettime(CLOCK_UPTIME, &tn); + if (timespeccmp(&t, &tn, <=)) { + t = tn; + t.tv_sec += 1; + + process(lastch); + continue; + } + + /* Prepare next read */ pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; - retval = poll(pfd, 1, t.tv_sec * 1000 + t.tv_usec / 1000); - if (retval > 0) - process(getch()); - else - process(lastch); + timespecsub(&t, &tn, &tdiff); + retval = poll(pfd, 1, (tdiff.tv_sec * 1000) + + (tdiff.tv_nsec / 1000000)); + + /* Nothing to do if timed out or signal. */ + if (retval <= 0) + continue; + + /* Only update timer if valid key was pressed. */ + if (process(getch()) == 0) + continue; + + /* Update using clock_gettime(), tn is too old now. */ + clock_gettime(CLOCK_UPTIME, &t); + t.tv_sec += 1; } } } @@ -245,7 +262,7 @@ prize(void) wrefresh(tv); } -void +int process(int ch) { int x,y; @@ -300,21 +317,21 @@ process(int ch) break; case '\f': setup(); - return; + return (0); case CNTRL('Z'): suspend(0); - return; + return (0); case CNTRL('C'): crash(); - return; + return (0); case CNTRL('D'): crash(); - return; + return (0); case ERR: leave(0); - return; + return (0); default: - return; + return (0); } lastch = ch; if (growing == 0) { @@ -352,6 +369,7 @@ process(int ch) wmove(tv, head->y, head->x); wrefresh(tv); } + return (1); } struct body *