1 /*
   2  * Copyright (c) 2006, 2015, 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     return close(fd);
 126 }
 127 
 128 static int file_read(int fd, char* buf, int len) {
 129     int ret;
 130     RESTARTABLE(read(fd, buf, len), ret);
 131     return ret;
 132 }
 133 
 134 /* send SIGQUIT signal to given process */
 135 static int send_sigquit(pid_t pid) {
 136     int ret;
 137     RESTARTABLE(kill(pid, SIGQUIT), ret);
 138     return ret;
 139 }
 140 
 141 /* called to check permissions on attach file */
 142 static int check_permission(const char* path) {
 143     struct stat64 sb;
 144     uid_t uid, gid;
 145     int res;
 146 
 147     /*
 148      * Check that the path is owned by the effective uid/gid of this
 149      * process. Also check that group/other access is not allowed.
 150      */
 151     uid = geteuid();
 152     gid = getegid();
 153 
 154     res = stat64(path, &sb);
 155     if (res != 0) {
 156         print_debug("stat failed for %s\n", path);
 157         return -1;
 158     }
 159 
 160     if ((sb.st_uid != uid) || (sb.st_gid != gid) ||
 161         ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0)) {
 162         print_debug("well-known file %s is not secure\n", path);
 163         return -1;
 164     }
 165     return 0;
 166 }
 167 
 168 #define ATTACH_FILE_PATTERN "/tmp/.attach_pid%d"
 169 
 170 /* fill-in the name of attach file name in given buffer */
 171 static void fill_attach_file_name(char* path, int len, pid_t pid) {
 172     memset(path, 0, len);
 173     sprintf(path, ATTACH_FILE_PATTERN, pid);
 174 }
 175 
 176 #define DOOR_FILE_PATTERN "/tmp/.java_pid%d"
 177 
 178 /* open door file for the given JVM */
 179 static int open_door(pid_t pid) {
 180     char path[PATH_MAX + 1];
 181     int fd;
 182 
 183     sprintf(path, DOOR_FILE_PATTERN, pid);
 184     fd = file_open(path, O_RDONLY);
 185     if (fd < 0) {
 186         set_jvm_error(JVM_ERR_CANT_OPEN_DOOR);
 187         print_debug("cannot open door file %s\n", path);
 188         return -1;
 189     }
 190     print_debug("opened door file %s\n", path);
 191     if (check_permission(path) != 0) {
 192         set_jvm_error(JVM_ERR_DOOR_FILE_PERMISSION);
 193         print_debug("check permission failed for %s\n", path);
 194         file_close(fd);
 195         fd = -1;
 196     }
 197     return fd;
 198 }
 199 
 200 /* create attach file for given process */
 201 static int create_attach_file(pid_t pid) {
 202     char path[PATH_MAX + 1];
 203     int fd;
 204     fill_attach_file_name(path, sizeof(path), pid);
 205     fd = file_open(path, O_CREAT | O_RDWR);
 206     if (fd < 0) {
 207         set_jvm_error(JVM_ERR_CANT_CREATE_ATTACH_FILE);
 208         print_debug("cannot create file %s\n", path);
 209     } else {
 210         print_debug("created attach file %s\n", path);
 211     }
 212     return fd;
 213 }
 214 
 215 /* delete attach file for given process */
 216 static void delete_attach_file(pid_t pid) {
 217     char path[PATH_MAX + 1];
 218     fill_attach_file_name(path, sizeof(path), pid);
 219     int res = unlink(path);
 220     if (res) {
 221         print_debug("cannot delete attach file %s\n", path);
 222     } else {
 223         print_debug("deleted attach file %s\n", path);
 224     }
 225 }
 226 
 227 /* attach to given JVM */
 228 jvm_t* jvm_attach(pid_t pid) {
 229     jvm_t* jvm;
 230     int door_fd, attach_fd, i = 0;
 231 
 232     jvm = (jvm_t*) calloc(1, sizeof(jvm_t));
 233     if (jvm == NULL) {
 234         set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
 235         print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__);
 236         return NULL;
 237     }
 238     jvm->pid = pid;
 239     attach_fd = -1;
 240 
 241     door_fd = open_door(pid);
 242     if (door_fd < 0) {
 243         print_debug("trying to create attach file\n");
 244         if ((attach_fd = create_attach_file(pid)) < 0) {
 245             goto quit;
 246         }
 247 
 248         /* send QUIT signal to the target so that it will
 249          * check for the attach file.
 250          */
 251         if (send_sigquit(pid) != 0) {
 252             set_jvm_error(JVM_ERR_CANT_SIGNAL);
 253             print_debug("sending SIGQUIT failed\n");
 254             goto quit;
 255         }
 256 
 257         /* give the target VM time to start the attach mechanism */
 258         do {
 259             int res;
 260             RESTARTABLE(poll(0, 0, 200), res);
 261             door_fd = open_door(pid);
 262             i++;
 263         } while (i <= 50 && door_fd == -1);
 264         if (door_fd < 0) {
 265             print_debug("Unable to open door to process %d\n", pid);
 266             goto quit;
 267         }
 268     }
 269 
 270 quit:
 271     if (attach_fd >= 0) {
 272         file_close(attach_fd);
 273         delete_attach_file(jvm->pid);
 274     }
 275     if (door_fd >= 0) {
 276         jvm->door_fd = door_fd;
 277         clear_jvm_error();
 278     } else {
 279         free(jvm);
 280         jvm = NULL;
 281     }
 282     return jvm;
 283 }
 284 
 285 /* return the last thread local error message */
 286 const char* jvm_get_last_error() {
 287     const char* res = NULL;
 288     thr_getspecific(jvm_error_key, (void**)&res);
 289     return res;
 290 }
 291 
 292 /* detach the givenb JVM */
 293 int jvm_detach(jvm_t* jvm) {
 294     if (jvm) {
 295         int res = 0;
 296         if (jvm->door_fd != -1) {
 297             if (file_close(jvm->door_fd) != 0) {
 298                 set_jvm_error(JVM_ERR_CANT_CLOSE_DOOR);
 299                 res = -1;
 300             } else {
 301                 clear_jvm_error();
 302             }
 303         }
 304         free(jvm);
 305         return res;
 306     } else {
 307         set_jvm_error(JVM_ERR_NULL_PARAM);
 308         print_debug("jvm_t* is NULL\n");
 309         return -1;
 310     }
 311 }
 312 
 313 /*
 314  * A simple table to translate some known errors into reasonable
 315  * error messages
 316  */
 317 static struct {
 318     int err;
 319     const char* msg;
 320 } const error_messages[] = {
 321     { 100,      "Bad request" },
 322     { 101,      "Protocol mismatch" },
 323     { 102,      "Resource failure" },
 324     { 103,      "Internal error" },
 325     { 104,      "Permission denied" },
 326 };
 327 
 328 /*
 329  * Lookup the given error code and return the appropriate
 330  * message. If not found return NULL.
 331  */
 332 static const char* translate_error(int err) {
 333     int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
 334     int i;
 335 
 336     for (i=0; i<table_size; i++) {
 337         if (err == error_messages[i].err) {
 338             return error_messages[i].msg;
 339         }
 340     }
 341     return NULL;
 342 }
 343 
 344 /*
 345  * Current protocol version
 346  */
 347 static const char* PROTOCOL_VERSION = "1";
 348 
 349 #define RES_BUF_SIZE 128
 350 
 351 /*
 352  * Enqueue attach-on-demand command to the given JVM
 353  */
 354 static
 355 int enqueue_command(jvm_t* jvm, const char* cstr, int arg_count, const char** args) {
 356     size_t size;
 357     door_arg_t door_args;
 358     char res_buffer[RES_BUF_SIZE];
 359     int rc, i;
 360     char* buf = NULL;
 361     int result = -1;
 362 
 363     /*
 364      * First we get the command string and create the start of the
 365      * argument string to send to the target VM:
 366      * <ver>\0<cmd>\0
 367      */
 368     if (cstr == NULL) {
 369         print_debug("command name is NULL\n");
 370         goto quit;
 371     }
 372     size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
 373     buf = (char*)malloc(size);
 374     if (buf != NULL) {
 375         char* pos = buf;
 376         strcpy(buf, PROTOCOL_VERSION);
 377         pos += strlen(PROTOCOL_VERSION)+1;
 378         strcpy(pos, cstr);
 379     } else {
 380         set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
 381         print_debug("malloc failed at %d in %s\n", __LINE__, __FILE__);
 382         goto quit;
 383     }
 384 
 385     /*
 386      * Next we iterate over the arguments and extend the buffer
 387      * to include them.
 388      */
 389     for (i=0; i<arg_count; i++) {
 390         cstr = args[i];
 391         if (cstr != NULL) {
 392             size_t len = strlen(cstr);
 393             char* newbuf = (char*)realloc(buf, size+len+1);
 394             if (newbuf == NULL) {
 395                 set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
 396                 print_debug("realloc failed in %s at %d\n", __FILE__, __LINE__);
 397                 goto quit;
 398             }
 399             buf = newbuf;
 400             strcpy(buf+size, cstr);
 401             size += len+1;
 402         }
 403     }
 404 
 405     /*
 406      * The arguments to the door function are in 'buf' so we now
 407      * do the door call
 408      */
 409     door_args.data_ptr = buf;
 410     door_args.data_size = size;
 411     door_args.desc_ptr = NULL;
 412     door_args.desc_num = 0;
 413     door_args.rbuf = (char*)&res_buffer;
 414     door_args.rsize = sizeof(res_buffer);
 415 
 416     RESTARTABLE(door_call(jvm->door_fd, &door_args), rc);
 417 
 418     /*
 419      * door_call failed
 420      */
 421     if (rc == -1) {
 422         print_debug("door_call failed\n");
 423     } else {
 424         /*
 425          * door_call succeeded but the call didn't return the the expected jint.
 426          */
 427         if (door_args.data_size < sizeof(int)) {
 428             print_debug("Enqueue error - reason unknown as result is truncated!");
 429         } else {
 430             int* res = (int*)(door_args.data_ptr);
 431             if (*res != 0) {
 432                 const char* msg = translate_error(*res);
 433                 if (msg == NULL) {
 434                     print_debug("Unable to enqueue command to target VM: %d\n", *res);
 435                 } else {
 436                     print_debug("Unable to enqueue command to target VM: %s\n", msg);
 437                 }
 438             } else {
 439                 /*
 440                  * The door call should return a file descriptor to one end of
 441                  * a socket pair
 442                  */
 443                 if ((door_args.desc_ptr != NULL) &&
 444                     (door_args.desc_num == 1) &&
 445                     (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
 446                     result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
 447                 } else {
 448                     print_debug("Reply from enqueue missing descriptor!\n");
 449                 }
 450             }
 451         }
 452     }
 453 
 454 quit:
 455     if (buf) free(buf);
 456     return result;
 457 }
 458 
 459 /* read status code for a door command */
 460 static int read_status(int fd) {
 461     char ch, buf[16];
 462     int index = 0;
 463 
 464     while (1) {
 465         if (file_read(fd, &ch, sizeof(ch)) != sizeof(ch)) {
 466             set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
 467             print_debug("door cmd status: read status failed\n");
 468             return -1;
 469         }
 470         buf[index++] = ch;
 471         if (ch == '\n') {
 472             buf[index - 1] = '\0';
 473             return atoi(buf);
 474         }
 475         if (index == sizeof(buf)) {
 476             set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
 477             print_debug("door cmd status: read status overflow\n");
 478             return -1;
 479         }
 480     }
 481 }
 482 
 483 static const char* ENABLE_DPROBES_CMD = "enabledprobes";
 484 
 485 /* enable one or more DTrace probes for a given JVM */
 486 int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types) {
 487     int fd, status = 0;
 488     char ch;
 489     const char* args[1];
 490     char buf[16];
 491     int probe_type = 0, index;
 492     int count = 0;
 493 
 494     if (jvm == NULL) {
 495         set_jvm_error(JVM_ERR_NULL_PARAM);
 496         print_debug("jvm_t* is NULL\n");
 497         return -1;
 498     }
 499 
 500     if (num_probe_types == 0 || probe_types == NULL ||
 501         probe_types[0] == NULL) {
 502         set_jvm_error(JVM_ERR_INVALID_PARAM);
 503         print_debug("invalid probe type argument(s)\n");
 504         return -1;
 505     }
 506 
 507     for (index = 0; index < num_probe_types; index++) {
 508         const char* p = probe_types[index];
 509         if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) {
 510             probe_type |= DTRACE_ALLOC_PROBES;
 511             count++;
 512         } else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 ||
 513                    strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) {
 514             probe_type |= DTRACE_METHOD_PROBES;
 515             count++;
 516         } else if (strcmp(p, JVM_DTPROBE_MONITOR_ENTER) == 0   ||
 517                    strcmp(p, JVM_DTPROBE_MONITOR_ENTERED) == 0 ||
 518                    strcmp(p, JVM_DTPROBE_MONITOR_EXIT) == 0    ||
 519                    strcmp(p, JVM_DTPROBE_MONITOR_WAIT) == 0    ||
 520                    strcmp(p, JVM_DTPROBE_MONITOR_WAITED) == 0  ||
 521                    strcmp(p, JVM_DTPROBE_MONITOR_NOTIFY) == 0  ||
 522                    strcmp(p, JVM_DTPROBE_MONITOR_NOTIFYALL) == 0) {
 523             probe_type |= DTRACE_MONITOR_PROBES;
 524             count++;
 525         } else if (strcmp(p, JVM_DTPROBE_ALL) == 0) {
 526             probe_type |= DTRACE_ALL_PROBES;
 527             count++;
 528         }
 529     }
 530 
 531     if (count == 0) {
 532         return count;
 533     }
 534     sprintf(buf, "%d", probe_type);
 535     args[0] = buf;
 536 
 537     fd = enqueue_command(jvm, ENABLE_DPROBES_CMD, 1, args);
 538     if (fd < 0) {
 539         set_jvm_error(JVM_ERR_DOOR_CMD_SEND);
 540         return -1;
 541     }
 542 
 543     status = read_status(fd);
 544     // non-zero status is error
 545     if (status) {
 546         set_jvm_error(JVM_ERR_DOOR_CMD_STATUS);
 547         print_debug("%s command failed (status: %d) in target JVM\n",
 548                     ENABLE_DPROBES_CMD, status);
 549         file_close(fd);
 550         return -1;
 551     }
 552     // read from stream until EOF
 553     while (file_read(fd, &ch, sizeof(ch)) == sizeof(ch)) {
 554         if (libjvm_dtrace_debug) {
 555             printf("%c", ch);
 556         }
 557     }
 558 
 559     file_close(fd);
 560     clear_jvm_error();
 561     return count;
 562 }