So why did this attacker choose such an obvious 'typo' rather than a subtle flaw in a large patch set?
So why did this attacker choose such an obvious 'typo' rather than a subtle flaw in a large patch set?
And if you look at the "Scoring and Extra Points" section of http://underhanded-c.org/_page_id_5.html you will notice that it checks most of the boxes.
It is short, errors based on human perception (here = vs ==) are good enough, it is innocent looking under syntax highlighting, is is not platform dependent, and it even passes the "irony" check. It is just the plausible deniability that is not great, but it is still defensible with a lot of bad faith.
if ((fd = open(...)) != -1) {
/* do something with fd */
} else {
perror("open");
}
The compiler outputs a warning when you have something like "if (a = b)". If that's what you mean (it sometimes is), you have to write it "if ((a = b))" to silence the warning. int fd; /* fd must be declared in order to be assigned */
if ((fd = open(...)) != -1) {
/* do something with fd */
} else {
perror("open");
}
which would be better written as: int fd = open(...);
if (fd != -1) /* etc */
It would be nice for scoping reasons to be able to write something like: if ((int fd = open(...)) != -1) /* etc */
but if ((int fd == open(...)) != -1) /* etc */
isn't valid code.Anyways, I am a bit torn about the second option. I like the idea of putting the call inside the if clause as it makes for a very explicit error handling but the uninitialized declaration is ugly. What I do in practice tends to depend on the situation but it is rarely satisfying.
Your last suggestion would be ideal, but as you said, it is invalid code unfortunately.
Maybe this
for (int fd = open(...); fd != -1; fd = -1) {
/* do stuff */
}
Just kidding, don't do that. > for (int fd = open(...); fd != -1; fd = -1) {
that doesn't correctly (or rather at all) handle the failure case. You should do (IIRC): #define LET(...) for(__VA_ARGS__,_tmp[0],*_once=_tmp; _once ;_once=0)
/* ^^^ goes in a header file */
LET(int fd = open())
{
if(fd == -1) { /* handle error, return or break */ }
/* do stuff */
} char *strcpy(char *d, char *s) {
char *r = d;
while (*d++ = *s++);
return r;
}
(If you don't need the return value, this becomes even nicer.)while((i = getchar()) != EOF) putchar(i);
This type of thing seems to be "encouraged"...
Including a red herring to invite extra scrutiny doesn't seem wise if you're trying to hide something.