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 *