1 /*
   2  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include <door.h>
  26 #include <errno.h>
  27 #include <fcntl.h>
  28 #include <limits.h>
  29 #include <poll.h>
  30 #include <signal.h>
  31 #include <stdarg.h>
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <sys/types.h>
  36 #include <sys/stat.h>
  37 #include <thread.h>
  38 #include <unistd.h>
  39 #include "jvm_dtrace.h"
  40 
  41 // NOTE: These constants are used in JVM code as well.
  42 // KEEP JVM CODE IN SYNC if you are going to change these...
  43 
  44 #define DTRACE_ALLOC_PROBES   0x1
  45 #define DTRACE_METHOD_PROBES  0x2
  46 #define DTRACE_MONITOR_PROBES 0x4
  47 #define DTRACE_ALL_PROBES     -1
  48 
  49 // generic error messages
  50 #define JVM_ERR_OUT_OF_MEMORY            "out of memory (native heap)"
  51 #define JVM_ERR_INVALID_PARAM            "invalid input parameter(s)"
  52 #define JVM_ERR_NULL_PARAM               "input paramater is NULL"
  53 
  54 // error messages for attach
  55 #define JVM_ERR_CANT_OPEN_DOOR           "cannot open door file"
  56 #define JVM_ERR_CANT_CREATE_ATTACH_FILE  "cannot create attach file"
  57 #define JVM_ERR_DOOR_FILE_PERMISSION     "door file is not secure"
  58 #define JVM_ERR_CANT_SIGNAL              "cannot send SIGQUIT to target"
  59 
  60 // error messages for enable probe
  61 #define JVM_ERR_DOOR_CMD_SEND            "door command send failed"
  62 #define JVM_ERR_DOOR_CANT_READ_STATUS    "cannot read door command status"
  63 #define JVM_ERR_DOOR_CMD_STATUS          "door command error status"
  64 
  65 // error message for detach
  66 #define JVM_ERR_CANT_CLOSE_DOOR          "cannot close door file"
  67 
  68 #define RESTARTABLE(_cmd, _result) do { \
  69     do { \
  70         _result = _cmd; \
  71     } while((_result == -1) && (errno == EINTR)); \
  72 } while(0)
  73 
  74 struct _jvm_t {
  75     pid_t pid;
  76     int door_fd;
  77 };
  78 
  79 static int libjvm_dtrace_debug;
  80 static void print_debug(const char* fmt,...) {
  81     if (libjvm_dtrace_debug) {
  82         va_list alist;
  83         va_start(alist, fmt);
  84         fputs("libjvm_dtrace DEBUG: ", stderr);
  85         vfprintf(stderr, fmt, alist);
  86         va_end(alist);
  87     }
  88 }
  89 
  90 /* Key for thread local error message */
  91 static thread_key_t jvm_error_key;
  92 
  93 /* init function for this library */
  94 static void init_jvm_dtrace() {
  95     /* check for env. var for debug mode */
  96     libjvm_dtrace_debug = getenv("LIBJVM_DTRACE_DEBUG") != NULL;
  97     /* create key for thread local error message */
  98     if (thr_keycreate(&jvm_error_key, NULL) != 0) {
  99         print_debug("can't create thread_key_t for jvm error key\n");
 100         // exit(1); ?
 101     }
 102 }
 103 
 104 #pragma init(init_jvm_dtrace)
 105 
 106 /* set thread local error message */
 107 static void set_jvm_error(const char* msg) {
 108     thr_setspecific(jvm_error_key, (void*)msg);
 109 }
 110 
 111 /* clear thread local error message */
 112 static void clear_jvm_error() {
 113     thr_setspecific(jvm_error_key, NULL);
 114 }
 115 
 116 /* file handling functions that can handle interrupt */
 117 
 118 static int file_open(const char* path, int flag) {
 119     int ret;
 120     RESTARTABLE(open(path, flag), ret);
 121     return ret;
 122 }
 123 
 124 static int file_close(int fd) {
 125     int ret;
 126     RESTARTABLE(close(fd), ret);
 127     return ret;
 128 }
 129 
 130 static int file_read(int fd, char* buf, int len) {
 131     int ret;
 132     RESTARTABLE(read(fd, buf, len), ret);
 133     return ret;
 134 }
 135 
 136 /* send SIGQUIT signal to given process */
 137 static int send_sigquit(pid_t pid) {
 138     int ret;
 139     RESTARTABLE(kill(pid, SIGQUIT), ret);
 140     return ret;
 141 }
 142 
 143 /* called to check permissions on attach file */
 144 static int check_permission(const char* path) {
 145     struct stat64 sb;
 146     uid_t uid, gid;
 147     int res;
 148 
 149     /*
 150      * Check that the path is owned by the effective uid/gid of this
 151      * process. Also check that group/other access is not allowed.
 152      */
 153     uid = geteuid();
 154     gid = getegid();
 155 
 156     res = stat64(path, &sb);
 157     if (res != 0) {
 158         print_debug("stat failed for %s\n", path);
 159         return -1;
 160     }
 161 
 162     if ((sb.st_uid != uid) || (sb.st_gid != gid) ||
 163         ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0)) {
 164         print_debug("well-known file %s is not secure\n", path);
 165         return -1;
 166     }
 167     return 0;
 168 }
 169 
 170 #define ATTACH_FILE_PATTERN "/tmp/.attach_pid%d"
 171 
 172 /* fill-in the name of attach file name in given buffer */
 173 static void fill_attach_file_name(char* path, int len, pid_t pid) {
 174     memset(path, 0, len);
 175     sprintf(path, ATTACH_FILE_PATTERN, pid);
 176 }
 177 
 178 #define DOOR_FILE_PATTERN "/tmp/.java_pid%d"
 179 
 180 /* open door file for the given JVM */
 181 static int open_door(pid_t pid) {
 182     char path[PATH_MAX + 1];
 183     int fd;
 184 
 185     sprintf(path, DOOR_FILE_PATTERN, pid);
 186     fd = file_open(path, O_RDONLY);
 187     if (fd < 0) {
 188         set_jvm_error(JVM_ERR_CANT_OPEN_DOOR);
 189         print_debug("cannot open door file %s\n", path);
 190         return -1;
 191     }
 192     print_debug("opened door file %s\n", path);
 193     if (check_permission(path) != 0) {
 194         set_jvm_error(JVM_ERR_DOOR_FILE_PERMISSION);
 195         print_debug("check permission failed for %s\n", path);
 196         file_close(fd);
 197         fd = -1;
 198     }
 199     return fd;
 200 }
 201 
 202 /* create attach file for given process */
 203 static int create_attach_file(pid_t pid) {
 204     char path[PATH_MAX + 1];
 205     int fd;
 206     fill_attach_file_name(path, sizeof(path), pid);
 207     fd = file_open(path, O_CREAT | O_RDWR);
 208     if (fd < 0) {
 209         set_jvm_error(JVM_ERR_CANT_CREATE_ATTACH_FILE);
 210         print_debug("cannot create file %s\n", path);
 211     } else {
 212         print_debug("created attach file %s\n", path);
 213     }
 214     return fd;
 215 }
 216 
 217 /* delete attach file for given process */
 218 static void delete_attach_file(pid_t pid) {
 219     char path[PATH_MAX + 1];
 220     fill_attach_file_name(path, sizeof(path), pid);
 221     int res = unlink(path);
 222     if (res) {
 223         print_debug("cannot delete attach file %s\n", path);
 224     } else {
 225         print_debug("deleted attach file %s\n", path);
 226     }
 227 }
 228 
 229 /* attach to given JVM */
 230 jvm_t* jvm_attach(pid_t pid) {
 231     jvm_t* jvm;
 232     int door_fd, attach_fd, i;
 233 
 234     jvm = (jvm_t*) calloc(1, sizeof(jvm_t));
 235     if (jvm == NULL) {
 236         set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
 237         print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__);
 238         return NULL;
 239     }
 240     jvm->pid = pid;
 241     attach_fd = -1;
 242 
 243     door_fd = open_door(pid);
 244     if (door_fd < 0) {
 245         print_debug("trying to create attach file\n");
 246         if ((attach_fd = create_attach_file(pid)) < 0) {
 247             goto quit;
 248         }
 249 
 250         /* send QUIT signal to the target so that it will
 251          * check for the attach file.
 252          */
 253         if (send_sigquit(pid) != 0) {
 254             set_jvm_error(JVM_ERR_CANT_SIGNAL);
 255             print_debug("sending SIGQUIT failed\n");
 256             goto quit;
 257         }
 258 
 259         /* give the target VM time to start the attach mechanism */
 260         do {
 261             int res;
 262             RESTARTABLE(poll(0, 0, 200), res);
 263             door_fd = open_door(pid);
 264             i++;
 265         } while (i <= 50 && door_fd == -1);
 266         if (door_fd < 0) {
 267             print_debug("Unable to open door to process %d\n", pid);
 268             goto quit;
 269         }
 270     }
 271 
 272 quit:
 273     if (attach_fd >= 0) {
 274         file_close(attach_fd);
 275         delete_attach_file(jvm->pid);
 276     }
 277     if (door_fd >= 0) {
 278         jvm->door_fd = door_fd;
 279         clear_jvm_error();
 280     } else {
 281         free(jvm);
 282         jvm = NULL;
 283     }
 284     return jvm;
 285 }
 286 
 287 /* return the last thread local error message */
 288 const char* jvm_get_last_error() {
 289     const char* res = NULL;
 290     thr_getspecific(jvm_error_key, (void**)&res);
 291     return res;
 292 }
 293 
 294 /* detach the givenb JVM */
 295 int jvm_detach(jvm_t* jvm) {
 296     if (jvm) {
 297         int res;
 298         if (jvm->door_fd != -1) {
 299             if (file_close(jvm->door_fd) != 0) {
 300                 set_jvm_error(JVM_ERR_CANT_CLOSE_DOOR);
 301                 res = -1;
 302             } else {
 303                 clear_jvm_error();
 304                 res = 0;
 305             }
 306         }
 307         free(jvm);
 308         return res;
 309     } else {
 310         set_jvm_error(JVM_ERR_NULL_PARAM);
 311         print_debug("jvm_t* is NULL\n");
 312         return -1;
 313     }
 314 }
 315 
 316 /*
 317  * A simple table to translate some known errors into reasonable
 318  * error messages
 319  */
 320 static struct {
 321     int err;
 322     const char* msg;
 323 } const error_messages[] = {
 324     { 100,      "Bad request" },
 325     { 101,      "Protocol mismatch" },
 326     { 102,      "Resource failure" },
 327     { 103,      "Internal error" },
 328     { 104,      "Permission denied" },
 329 };
 330 
 331 /*
 332  * Lookup the given error code and return the appropriate
 333  * message. If not found return NULL.
 334  */
 335 static const char* translate_error(int err) {
 336     int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
 337     int i;
 338 
 339     for (i=0; i<table_size; i++) {
 340         if (err == error_messages[i].err) {
 341             return error_messages[i].msg;
 342         }
 343     }
 344     return NULL;
 345 }
 346 
 347 /*
 348  * Current protocol version
 349  */
 350 static const char* PROTOCOL_VERSION = "1";
 351 
 352 #define RES_BUF_SIZE 128
 353 
 354 /*
 355  * Enqueue attach-on-demand command to the given JVM
 356  */
 357 static
 358 int enqueue_command(jvm_t* jvm, const char* cstr, int arg_count, const char** args) {
 359     size_t size;
 360     door_arg_t door_args;
 361     char res_buffer[RES_BUF_SIZE];
 362     int rc, i;
 363     char* buf = NULL;
 364     int result = -1;
 365 
 366     /*
 367      * First we get the command string and create the start of the
 368      * argument string to send to the target VM:
 369      * <ver>\0<cmd>\0
 370      */
 371     if (cstr == NULL) {
 372         print_debug("command name is NULL\n");
 373         goto quit;
 374     }
 375     size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
 376     buf = (char*)malloc(size);
 377     if (buf != NULL) {
 378         char* pos = buf;
 379         strcpy(buf, PROTOCOL_VERSION);
 380         pos += strlen(PROTOCOL_VERSION)+1;
 381         strcpy(pos, cstr);
 382     } else {
 383         set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
 384         print_debug("malloc failed at %d in %s\n", __LINE__, __FILE__);
 385         goto quit;
 386     }
 387 
 388     /*
 389      * Next we iterate over the arguments and extend the buffer
 390      * to include them.
 391      */
 392     for (i=0; i<arg_count; i++) {
 393         cstr = args[i];
 394         if (cstr != NULL) {
 395             size_t len = strlen(cstr);
 396             char* newbuf = (char*)realloc(buf, size+len+1);
 397             if (newbuf == NULL) {
 398                 set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
 399                 print_debug("realloc failed in %s at %d\n", __FILE__, __LINE__);
 400                 goto quit;
 401             }
 402             buf = newbuf;
 403             strcpy(buf+size, cstr);
 404             size += len+1;
 405         }
 406     }
 407 
 408     /*
 409      * The arguments to the door function are in 'buf' so we now
 410      * do the door call
 411      */
 412     door_args.data_ptr = buf;
 413     door_args.data_size = size;
 414     door_args.desc_ptr = NULL;
 415     door_args.desc_num = 0;
 416     door_args.rbuf = (char*)&res_buffer;
 417     door_args.rsize = sizeof(res_buffer);
 418 
 419     RESTARTABLE(door_call(jvm->door_fd, &door_args), rc);
 420 
 421     /*
 422      * door_call failed
 423      */
 424     if (rc == -1) {
 425         print_debug("door_call failed\n");
 426     } else {
 427         /*
 428          * door_call succeeded but the call didn't return the the expected jint.
 429          */
 430         if (door_args.data_size < sizeof(int)) {
 431             print_debug("Enqueue error - reason unknown as result is truncated!");
 432         } else {
 433             int* res = (int*)(door_args.data_ptr);
 434             if (*res != 0) {
 435                 const char* msg = translate_error(*res);
 436                 if (msg == NULL) {
 437                     print_debug("Unable to enqueue command to target VM: %d\n", *res);
 438                 } else {
 439                     print_debug("Unable to enqueue command to target VM: %s\n", msg);
 440                 }
 441             } else {
 442                 /*
 443                  * The door call should return a file descriptor to one end of
 444                  * a socket pair
 445                  */
 446                 if ((door_args.desc_ptr != NULL) &&
 447                     (door_args.desc_num == 1) &&
 448                     (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
 449                     result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
 450                 } else {
 451                     print_debug("Reply from enqueue missing descriptor!\n");
 452                 }
 453             }
 454         }
 455     }
 456 
 457 quit:
 458     if (buf) free(buf);
 459     return result;
 460 }
 461 
 462 /* read status code for a door command */
 463 static int read_status(int fd) {
 464     char ch, buf[16];
 465     int index = 0;
 466 
 467     while (1) {
 468         if (file_read(fd, &ch, sizeof(ch)) != sizeof(ch)) {
 469             set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
 470             print_debug("door cmd status: read status failed\n");
 471             return -1;
 472         }
 473         buf[index++] = ch;
 474         if (ch == '\n') {
 475             buf[index - 1] = '\0';
 476             return atoi(buf);
 477         }
 478         if (index == sizeof(buf)) {
 479             set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
 480             print_debug("door cmd status: read status overflow\n");
 481             return -1;
 482         }
 483     }
 484 }
 485 
 486 static const char* ENABLE_DPROBES_CMD = "enabledprobes";
 487 
 488 /* enable one or more DTrace probes for a given JVM */
 489 int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types) {
 490     int fd, status = 0;
 491     char ch;
 492     const char* args[1];
 493     char buf[16];
 494     int probe_type = 0, index;
 495     int count = 0;
 496 
 497     if (jvm == NULL) {
 498         set_jvm_error(JVM_ERR_NULL_PARAM);
 499         print_debug("jvm_t* is NULL\n");
 500         return -1;
 501     }
 502 
 503     if (num_probe_types == 0 || probe_types == NULL ||
 504         probe_types[0] == NULL) {
 505         set_jvm_error(JVM_ERR_INVALID_PARAM);
 506         print_debug("invalid probe type argument(s)\n");
 507         return -1;
 508     }
 509 
 510     for (index = 0; index < num_probe_types; index++) {
 511         const char* p = probe_types[index];
 512         if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) {
 513             probe_type |= DTRACE_ALLOC_PROBES;
 514             count++;
 515         } else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 ||
 516                    strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) {
 517             probe_type |= DTRACE_METHOD_PROBES;
 518             count++;
 519         } else if (strcmp(p, JVM_DTPROBE_MONITOR_ENTER) == 0   ||
 520                    strcmp(p, JVM_DTPROBE_MONITOR_ENTERED) == 0 ||
 521                    strcmp(p, JVM_DTPROBE_MONITOR_EXIT) == 0    ||
 522                    strcmp(p, JVM_DTPROBE_MONITOR_WAIT) == 0    ||
 523                    strcmp(p, JVM_DTPROBE_MONITOR_WAITED) == 0  ||
 524                    strcmp(p, JVM_DTPROBE_MONITOR_NOTIFY) == 0  ||
 525                    strcmp(p, JVM_DTPROBE_MONITOR_NOTIFYALL) == 0) {
 526             probe_type |= DTRACE_MONITOR_PROBES;
 527             count++;
 528         } else if (strcmp(p, JVM_DTPROBE_ALL) == 0) {
 529             probe_type |= DTRACE_ALL_PROBES;
 530             count++;
 531         }
 532     }
 533 
 534     if (count == 0) {
 535         return count;
 536     }
 537     sprintf(buf, "%d", probe_type);
 538     args[0] = buf;
 539 
 540     fd = enqueue_command(jvm, ENABLE_DPROBES_CMD, 1, args);
 541     if (fd < 0) {
 542         set_jvm_error(JVM_ERR_DOOR_CMD_SEND);
 543         return -1;
 544     }
 545 
 546     status = read_status(fd);
 547     // non-zero status is error
 548     if (status) {
 549         set_jvm_error(JVM_ERR_DOOR_CMD_STATUS);
 550         print_debug("%s command failed (status: %d) in target JVM\n",
 551                     ENABLE_DPROBES_CMD, status);
 552         file_close(fd);
 553         return -1;
 554     }
 555     // read from stream until EOF
 556     while (file_read(fd, &ch, sizeof(ch)) == sizeof(ch)) {
 557         if (libjvm_dtrace_debug) {
 558             printf("%c", ch);
 559         }
 560     }
 561 
 562     file_close(fd);
 563     clear_jvm_error();
 564     return count;
 565 }