| File: | jdk/src/hotspot/os/linux/attachListener_linux.cpp |
| Warning: | line 314, column 9 Value stored to 'v' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright (c) 2005, 2021, 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 "precompiled.hpp" |
| 26 | #include "logging/log.hpp" |
| 27 | #include "memory/allocation.inline.hpp" |
| 28 | #include "runtime/interfaceSupport.inline.hpp" |
| 29 | #include "runtime/os.inline.hpp" |
| 30 | #include "services/attachListener.hpp" |
| 31 | #include "services/dtraceAttacher.hpp" |
| 32 | |
| 33 | #include <unistd.h> |
| 34 | #include <signal.h> |
| 35 | #include <sys/types.h> |
| 36 | #include <sys/socket.h> |
| 37 | #include <sys/un.h> |
| 38 | #include <sys/stat.h> |
| 39 | |
| 40 | #ifndef UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path) |
| 41 | #define UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path) sizeof(((struct sockaddr_un *)0)->sun_path) |
| 42 | #endif |
| 43 | |
| 44 | // The attach mechanism on Linux uses a UNIX domain socket. An attach listener |
| 45 | // thread is created at startup or is created on-demand via a signal from |
| 46 | // the client tool. The attach listener creates a socket and binds it to a file |
| 47 | // in the filesystem. The attach listener then acts as a simple (single- |
| 48 | // threaded) server - it waits for a client to connect, reads the request, |
| 49 | // executes it, and returns the response to the client via the socket |
| 50 | // connection. |
| 51 | // |
| 52 | // As the socket is a UNIX domain socket it means that only clients on the |
| 53 | // local machine can connect. In addition there are two other aspects to |
| 54 | // the security: |
| 55 | // 1. The well known file that the socket is bound to has permission 400 |
| 56 | // 2. When a client connect, the SO_PEERCRED socket option is used to |
| 57 | // obtain the credentials of client. We check that the effective uid |
| 58 | // of the client matches this process. |
| 59 | |
| 60 | // forward reference |
| 61 | class LinuxAttachOperation; |
| 62 | |
| 63 | class LinuxAttachListener: AllStatic { |
| 64 | private: |
| 65 | // the path to which we bind the UNIX domain socket |
| 66 | static char _path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; |
| 67 | static bool _has_path; |
| 68 | |
| 69 | // the file descriptor for the listening socket |
| 70 | static volatile int _listener; |
| 71 | |
| 72 | static bool _atexit_registered; |
| 73 | |
| 74 | // reads a request from the given connected socket |
| 75 | static LinuxAttachOperation* read_request(int s); |
| 76 | |
| 77 | public: |
| 78 | enum { |
| 79 | ATTACH_PROTOCOL_VER = 1 // protocol version |
| 80 | }; |
| 81 | enum { |
| 82 | ATTACH_ERROR_BADVERSION = 101 // error codes |
| 83 | }; |
| 84 | |
| 85 | static void set_path(char* path) { |
| 86 | if (path == NULL__null) { |
| 87 | _path[0] = '\0'; |
| 88 | _has_path = false; |
| 89 | } else { |
| 90 | strncpy(_path, path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)); |
| 91 | _path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)-1] = '\0'; |
| 92 | _has_path = true; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | static void set_listener(int s) { _listener = s; } |
| 97 | |
| 98 | // initialize the listener, returns 0 if okay |
| 99 | static int init(); |
| 100 | |
| 101 | static char* path() { return _path; } |
| 102 | static bool has_path() { return _has_path; } |
| 103 | static int listener() { return _listener; } |
| 104 | |
| 105 | // write the given buffer to a socket |
| 106 | static int write_fully(int s, char* buf, int len); |
| 107 | |
| 108 | static LinuxAttachOperation* dequeue(); |
| 109 | }; |
| 110 | |
| 111 | class LinuxAttachOperation: public AttachOperation { |
| 112 | private: |
| 113 | // the connection to the client |
| 114 | int _socket; |
| 115 | |
| 116 | public: |
| 117 | void complete(jint res, bufferedStream* st); |
| 118 | |
| 119 | void set_socket(int s) { _socket = s; } |
| 120 | int socket() const { return _socket; } |
| 121 | |
| 122 | LinuxAttachOperation(char* name) : AttachOperation(name) { |
| 123 | set_socket(-1); |
| 124 | } |
| 125 | }; |
| 126 | |
| 127 | // statics |
| 128 | char LinuxAttachListener::_path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; |
| 129 | bool LinuxAttachListener::_has_path; |
| 130 | volatile int LinuxAttachListener::_listener = -1; |
| 131 | bool LinuxAttachListener::_atexit_registered = false; |
| 132 | |
| 133 | // Supporting class to help split a buffer into individual components |
| 134 | class ArgumentIterator : public StackObj { |
| 135 | private: |
| 136 | char* _pos; |
| 137 | char* _end; |
| 138 | public: |
| 139 | ArgumentIterator(char* arg_buffer, size_t arg_size) { |
| 140 | _pos = arg_buffer; |
| 141 | _end = _pos + arg_size - 1; |
| 142 | } |
| 143 | char* next() { |
| 144 | if (*_pos == '\0') { |
| 145 | // advance the iterator if possible (null arguments) |
| 146 | if (_pos < _end) { |
| 147 | _pos += 1; |
| 148 | } |
| 149 | return NULL__null; |
| 150 | } |
| 151 | char* res = _pos; |
| 152 | char* next_pos = strchr(_pos, '\0'); |
| 153 | if (next_pos < _end) { |
| 154 | next_pos++; |
| 155 | } |
| 156 | _pos = next_pos; |
| 157 | return res; |
| 158 | } |
| 159 | }; |
| 160 | |
| 161 | |
| 162 | // atexit hook to stop listener and unlink the file that it is |
| 163 | // bound too. |
| 164 | extern "C" { |
| 165 | static void listener_cleanup() { |
| 166 | int s = LinuxAttachListener::listener(); |
| 167 | if (s != -1) { |
| 168 | LinuxAttachListener::set_listener(-1); |
| 169 | ::shutdown(s, SHUT_RDWRSHUT_RDWR); |
| 170 | ::close(s); |
| 171 | } |
| 172 | if (LinuxAttachListener::has_path()) { |
| 173 | ::unlink(LinuxAttachListener::path()); |
| 174 | LinuxAttachListener::set_path(NULL__null); |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | // Initialization - create a listener socket and bind it to a file |
| 180 | |
| 181 | int LinuxAttachListener::init() { |
| 182 | char path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; // socket file |
| 183 | char initial_path[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; // socket file during setup |
| 184 | int listener; // listener socket (file descriptor) |
| 185 | |
| 186 | // register function to cleanup |
| 187 | if (!_atexit_registered) { |
| 188 | _atexit_registered = true; |
| 189 | ::atexit(listener_cleanup); |
| 190 | } |
| 191 | |
| 192 | int n = snprintf(path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s/.java_pid%d", |
| 193 | os::get_temp_directory(), os::current_process_id()); |
| 194 | if (n < (int)UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)) { |
| 195 | n = snprintf(initial_path, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s.tmp", path); |
| 196 | } |
| 197 | if (n >= (int)UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)) { |
| 198 | return -1; |
| 199 | } |
| 200 | |
| 201 | // create the listener socket |
| 202 | listener = ::socket(PF_UNIX1, SOCK_STREAMSOCK_STREAM, 0); |
| 203 | if (listener == -1) { |
| 204 | return -1; |
| 205 | } |
| 206 | |
| 207 | // bind socket |
| 208 | struct sockaddr_un addr; |
| 209 | memset((void *)&addr, 0, sizeof(addr)); |
| 210 | addr.sun_family = AF_UNIX1; |
| 211 | strcpy(addr.sun_path, initial_path); |
| 212 | ::unlink(initial_path); |
| 213 | int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); |
| 214 | if (res == -1) { |
| 215 | ::close(listener); |
| 216 | return -1; |
| 217 | } |
| 218 | |
| 219 | // put in listen mode, set permissions, and rename into place |
| 220 | res = ::listen(listener, 5); |
| 221 | if (res == 0) { |
| 222 | RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res)do { res = ::chmod(initial_path, 0400|0200); } while(((int)res == OS_ERR) && ((*__errno_location ()) == 4)); |
| 223 | if (res == 0) { |
| 224 | // make sure the file is owned by the effective user and effective group |
| 225 | // e.g. the group could be inherited from the directory in case the s bit is set |
| 226 | RESTARTABLE(::chown(initial_path, geteuid(), getegid()), res)do { res = ::chown(initial_path, geteuid(), getegid()); } while (((int)res == OS_ERR) && ((*__errno_location ()) == 4 )); |
| 227 | if (res == 0) { |
| 228 | res = ::rename(initial_path, path); |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | if (res == -1) { |
| 233 | ::close(listener); |
| 234 | ::unlink(initial_path); |
| 235 | return -1; |
| 236 | } |
| 237 | set_path(path); |
| 238 | set_listener(listener); |
| 239 | |
| 240 | return 0; |
| 241 | } |
| 242 | |
| 243 | // Given a socket that is connected to a peer we read the request and |
| 244 | // create an AttachOperation. As the socket is blocking there is potential |
| 245 | // for a denial-of-service if the peer does not response. However this happens |
| 246 | // after the peer credentials have been checked and in the worst case it just |
| 247 | // means that the attach listener thread is blocked. |
| 248 | // |
| 249 | LinuxAttachOperation* LinuxAttachListener::read_request(int s) { |
| 250 | char ver_str[8]; |
| 251 | sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER); |
| 252 | |
| 253 | // The request is a sequence of strings so we first figure out the |
| 254 | // expected count and the maximum possible length of the request. |
| 255 | // The request is: |
| 256 | // <ver>0<cmd>0<arg>0<arg>0<arg>0 |
| 257 | // where <ver> is the protocol version (1), <cmd> is the command |
| 258 | // name ("load", "datadump", ...), and <arg> is an argument |
| 259 | int expected_str_count = 2 + AttachOperation::arg_count_max; |
| 260 | const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) + |
| 261 | AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1); |
| 262 | |
| 263 | char buf[max_len]; |
| 264 | int str_count = 0; |
| 265 | |
| 266 | // Read until all (expected) strings have been read, the buffer is |
| 267 | // full, or EOF. |
| 268 | |
| 269 | int off = 0; |
| 270 | int left = max_len; |
| 271 | |
| 272 | do { |
| 273 | int n; |
| 274 | RESTARTABLE(read(s, buf+off, left), n)do { n = read(s, buf+off, left); } while(((int)n == OS_ERR) && ((*__errno_location ()) == 4)); |
| 275 | assert(n <= left, "buffer was too small, impossible!")do { if (!(n <= left)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/os/linux/attachListener_linux.cpp" , 275, "assert(" "n <= left" ") failed", "buffer was too small, impossible!" ); ::breakpoint(); } } while (0); |
| 276 | buf[max_len - 1] = '\0'; |
| 277 | if (n == -1) { |
| 278 | return NULL__null; // reset by peer or other error |
| 279 | } |
| 280 | if (n == 0) { |
| 281 | break; |
| 282 | } |
| 283 | for (int i=0; i<n; i++) { |
| 284 | if (buf[off+i] == 0) { |
| 285 | // EOS found |
| 286 | str_count++; |
| 287 | |
| 288 | // The first string is <ver> so check it now to |
| 289 | // check for protocol mis-match |
| 290 | if (str_count == 1) { |
| 291 | if ((strlen(buf) != strlen(ver_str)) || |
| 292 | (atoi(buf) != ATTACH_PROTOCOL_VER)) { |
| 293 | char msg[32]; |
| 294 | sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION); |
| 295 | write_fully(s, msg, strlen(msg)); |
| 296 | return NULL__null; |
| 297 | } |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | off += n; |
| 302 | left -= n; |
| 303 | } while (left > 0 && str_count < expected_str_count); |
| 304 | |
| 305 | if (str_count != expected_str_count) { |
| 306 | return NULL__null; // incomplete request |
| 307 | } |
| 308 | |
| 309 | // parse request |
| 310 | |
| 311 | ArgumentIterator args(buf, (max_len)-left); |
| 312 | |
| 313 | // version already checked |
| 314 | char* v = args.next(); |
Value stored to 'v' during its initialization is never read | |
| 315 | |
| 316 | char* name = args.next(); |
| 317 | if (name == NULL__null || strlen(name) > AttachOperation::name_length_max) { |
| 318 | return NULL__null; |
| 319 | } |
| 320 | |
| 321 | LinuxAttachOperation* op = new LinuxAttachOperation(name); |
| 322 | |
| 323 | for (int i=0; i<AttachOperation::arg_count_max; i++) { |
| 324 | char* arg = args.next(); |
| 325 | if (arg == NULL__null) { |
| 326 | op->set_arg(i, NULL__null); |
| 327 | } else { |
| 328 | if (strlen(arg) > AttachOperation::arg_length_max) { |
| 329 | delete op; |
| 330 | return NULL__null; |
| 331 | } |
| 332 | op->set_arg(i, arg); |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | op->set_socket(s); |
| 337 | return op; |
| 338 | } |
| 339 | |
| 340 | |
| 341 | // Dequeue an operation |
| 342 | // |
| 343 | // In the Linux implementation there is only a single operation and clients |
| 344 | // cannot queue commands (except at the socket level). |
| 345 | // |
| 346 | LinuxAttachOperation* LinuxAttachListener::dequeue() { |
| 347 | for (;;) { |
| 348 | int s; |
| 349 | |
| 350 | // wait for client to connect |
| 351 | struct sockaddr addr; |
| 352 | socklen_t len = sizeof(addr); |
| 353 | RESTARTABLE(::accept(listener(), &addr, &len), s)do { s = ::accept(listener(), &addr, &len); } while(( (int)s == OS_ERR) && ((*__errno_location ()) == 4)); |
| 354 | if (s == -1) { |
| 355 | return NULL__null; // log a warning? |
| 356 | } |
| 357 | |
| 358 | // get the credentials of the peer and check the effective uid/guid |
| 359 | struct ucred cred_info; |
| 360 | socklen_t optlen = sizeof(cred_info); |
| 361 | if (::getsockopt(s, SOL_SOCKET1, SO_PEERCRED17, (void*)&cred_info, &optlen) == -1) { |
| 362 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Failed to get socket option SO_PEERCRED"); |
| 363 | ::close(s); |
| 364 | continue; |
| 365 | } |
| 366 | |
| 367 | if (!os::Posix::matches_effective_uid_and_gid_or_root(cred_info.uid, cred_info.gid)) { |
| 368 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("euid/egid check failed (%d/%d vs %d/%d)", |
| 369 | cred_info.uid, cred_info.gid, geteuid(), getegid()); |
| 370 | ::close(s); |
| 371 | continue; |
| 372 | } |
| 373 | |
| 374 | // peer credential look okay so we read the request |
| 375 | LinuxAttachOperation* op = read_request(s); |
| 376 | if (op == NULL__null) { |
| 377 | ::close(s); |
| 378 | continue; |
| 379 | } else { |
| 380 | return op; |
| 381 | } |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | // write the given buffer to the socket |
| 386 | int LinuxAttachListener::write_fully(int s, char* buf, int len) { |
| 387 | do { |
| 388 | int n = ::write(s, buf, len); |
| 389 | if (n == -1) { |
| 390 | if (errno(*__errno_location ()) != EINTR4) return -1; |
| 391 | } else { |
| 392 | buf += n; |
| 393 | len -= n; |
| 394 | } |
| 395 | } |
| 396 | while (len > 0); |
| 397 | return 0; |
| 398 | } |
| 399 | |
| 400 | // Complete an operation by sending the operation result and any result |
| 401 | // output to the client. At this time the socket is in blocking mode so |
| 402 | // potentially we can block if there is a lot of data and the client is |
| 403 | // non-responsive. For most operations this is a non-issue because the |
| 404 | // default send buffer is sufficient to buffer everything. In the future |
| 405 | // if there are operations that involves a very big reply then it the |
| 406 | // socket could be made non-blocking and a timeout could be used. |
| 407 | |
| 408 | void LinuxAttachOperation::complete(jint result, bufferedStream* st) { |
| 409 | JavaThread* thread = JavaThread::current(); |
| 410 | ThreadBlockInVM tbivm(thread); |
| 411 | |
| 412 | // write operation result |
| 413 | char msg[32]; |
| 414 | sprintf(msg, "%d\n", result); |
| 415 | int rc = LinuxAttachListener::write_fully(this->socket(), msg, strlen(msg)); |
| 416 | |
| 417 | // write any result data |
| 418 | if (rc == 0) { |
| 419 | LinuxAttachListener::write_fully(this->socket(), (char*) st->base(), st->size()); |
| 420 | ::shutdown(this->socket(), 2); |
| 421 | } |
| 422 | |
| 423 | // done |
| 424 | ::close(this->socket()); |
| 425 | |
| 426 | delete this; |
| 427 | } |
| 428 | |
| 429 | |
| 430 | // AttachListener functions |
| 431 | |
| 432 | AttachOperation* AttachListener::dequeue() { |
| 433 | JavaThread* thread = JavaThread::current(); |
| 434 | ThreadBlockInVM tbivm(thread); |
| 435 | |
| 436 | AttachOperation* op = LinuxAttachListener::dequeue(); |
| 437 | |
| 438 | return op; |
| 439 | } |
| 440 | |
| 441 | // Performs initialization at vm startup |
| 442 | // For Linux we remove any stale .java_pid file which could cause |
| 443 | // an attaching process to think we are ready to receive on the |
| 444 | // domain socket before we are properly initialized |
| 445 | |
| 446 | void AttachListener::vm_start() { |
| 447 | char fn[UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path)]; |
| 448 | struct stat64 st; |
| 449 | int ret; |
| 450 | |
| 451 | int n = snprintf(fn, UNIX_PATH_MAXsizeof(((struct sockaddr_un *)0)->sun_path), "%s/.java_pid%d", |
| 452 | os::get_temp_directory(), os::current_process_id()); |
| 453 | assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow")do { if (!(n < (int)sizeof(((struct sockaddr_un *)0)->sun_path ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/os/linux/attachListener_linux.cpp" , 453, "assert(" "n < (int)sizeof(((struct sockaddr_un *)0)->sun_path)" ") failed", "java_pid file name buffer overflow"); ::breakpoint (); } } while (0); |
| 454 | |
| 455 | RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR ) && ((*__errno_location ()) == 4)); |
| 456 | if (ret == 0) { |
| 457 | ret = ::unlink(fn); |
| 458 | if (ret == -1) { |
| 459 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Failed to remove stale attach pid file at %s", fn); |
| 460 | } |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | int AttachListener::pd_init() { |
| 465 | JavaThread* thread = JavaThread::current(); |
| 466 | ThreadBlockInVM tbivm(thread); |
| 467 | |
| 468 | int ret_code = LinuxAttachListener::init(); |
| 469 | |
| 470 | return ret_code; |
| 471 | } |
| 472 | |
| 473 | bool AttachListener::check_socket_file() { |
| 474 | int ret; |
| 475 | struct stat64 st; |
| 476 | ret = stat64(LinuxAttachListener::path(), &st); |
| 477 | if (ret == -1) { // need to restart attach listener. |
| 478 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Socket file %s does not exist - Restart Attach Listener", |
| 479 | LinuxAttachListener::path()); |
| 480 | |
| 481 | listener_cleanup(); |
| 482 | |
| 483 | // wait to terminate current attach listener instance... |
| 484 | { |
| 485 | // avoid deadlock if AttachListener thread is blocked at safepoint |
| 486 | ThreadBlockInVM tbivm(JavaThread::current()); |
| 487 | while (AttachListener::transit_state(AL_INITIALIZING, |
| 488 | AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) { |
| 489 | os::naked_yield(); |
| 490 | } |
| 491 | } |
| 492 | return is_init_trigger(); |
| 493 | } |
| 494 | return false; |
| 495 | } |
| 496 | |
| 497 | // Attach Listener is started lazily except in the case when |
| 498 | // +ReduseSignalUsage is used |
| 499 | bool AttachListener::init_at_startup() { |
| 500 | if (ReduceSignalUsage) { |
| 501 | return true; |
| 502 | } else { |
| 503 | return false; |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | // If the file .attach_pid<pid> exists in the working directory |
| 508 | // or /tmp then this is the trigger to start the attach mechanism |
| 509 | bool AttachListener::is_init_trigger() { |
| 510 | if (init_at_startup() || is_initialized()) { |
| 511 | return false; // initialized at startup or already initialized |
| 512 | } |
| 513 | char fn[PATH_MAX4096 + 1]; |
| 514 | int ret; |
| 515 | struct stat64 st; |
| 516 | sprintf(fn, ".attach_pid%d", os::current_process_id()); |
| 517 | RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR ) && ((*__errno_location ()) == 4)); |
| 518 | if (ret == -1) { |
| 519 | log_trace(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Trace>("Failed to find attach file: %s, trying alternate", fn); |
| 520 | snprintf(fn, sizeof(fn), "%s/.attach_pid%d", |
| 521 | os::get_temp_directory(), os::current_process_id()); |
| 522 | RESTARTABLE(::stat64(fn, &st), ret)do { ret = ::stat64(fn, &st); } while(((int)ret == OS_ERR ) && ((*__errno_location ()) == 4)); |
| 523 | if (ret == -1) { |
| 524 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("Failed to find attach file: %s", fn); |
| 525 | } |
| 526 | } |
| 527 | if (ret == 0) { |
| 528 | // simple check to avoid starting the attach mechanism when |
| 529 | // a bogus non-root user creates the file |
| 530 | if (os::Posix::matches_effective_uid_or_root(st.st_uid)) { |
| 531 | init(); |
| 532 | log_trace(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Trace>("Attach triggered by %s", fn); |
| 533 | return true; |
| 534 | } else { |
| 535 | log_debug(attach)(!(LogImpl<(LogTag::_attach), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_attach), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Debug>("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid()); |
| 536 | } |
| 537 | } |
| 538 | return false; |
| 539 | } |
| 540 | |
| 541 | // if VM aborts then remove listener |
| 542 | void AttachListener::abort() { |
| 543 | listener_cleanup(); |
| 544 | } |
| 545 | |
| 546 | void AttachListener::pd_data_dump() { |
| 547 | os::signal_notify(SIGQUIT3); |
| 548 | } |
| 549 | |
| 550 | AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) { |
| 551 | return NULL__null; |
| 552 | } |
| 553 | |
| 554 | jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { |
| 555 | out->print_cr("flag '%s' cannot be changed", op->arg(0)); |
| 556 | return JNI_ERR(-1); |
| 557 | } |
| 558 | |
| 559 | void AttachListener::pd_detachall() { |
| 560 | // do nothing for now |
| 561 | } |