1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/os/bsd/vm/attachListener_bsd.cpp Sun Sep 25 16:03:29 2011 -0700 1.3 @@ -0,0 +1,520 @@ 1.4 +/* 1.5 + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "runtime/interfaceSupport.hpp" 1.30 +#include "runtime/os.hpp" 1.31 +#include "services/attachListener.hpp" 1.32 +#include "services/dtraceAttacher.hpp" 1.33 + 1.34 +#include <unistd.h> 1.35 +#include <signal.h> 1.36 +#include <sys/types.h> 1.37 +#include <sys/socket.h> 1.38 +#include <sys/un.h> 1.39 +#include <sys/stat.h> 1.40 + 1.41 +#ifndef UNIX_PATH_MAX 1.42 +#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path) 1.43 +#endif 1.44 + 1.45 +// The attach mechanism on Bsd uses a UNIX domain socket. An attach listener 1.46 +// thread is created at startup or is created on-demand via a signal from 1.47 +// the client tool. The attach listener creates a socket and binds it to a file 1.48 +// in the filesystem. The attach listener then acts as a simple (single- 1.49 +// threaded) server - it waits for a client to connect, reads the request, 1.50 +// executes it, and returns the response to the client via the socket 1.51 +// connection. 1.52 +// 1.53 +// As the socket is a UNIX domain socket it means that only clients on the 1.54 +// local machine can connect. In addition there are two other aspects to 1.55 +// the security: 1.56 +// 1. The well known file that the socket is bound to has permission 400 1.57 +// 2. When a client connect, the SO_PEERCRED socket option is used to 1.58 +// obtain the credentials of client. We check that the effective uid 1.59 +// of the client matches this process. 1.60 + 1.61 +// forward reference 1.62 +class BsdAttachOperation; 1.63 + 1.64 +class BsdAttachListener: AllStatic { 1.65 + private: 1.66 + // the path to which we bind the UNIX domain socket 1.67 + static char _path[UNIX_PATH_MAX]; 1.68 + static bool _has_path; 1.69 + 1.70 + // the file descriptor for the listening socket 1.71 + static int _listener; 1.72 + 1.73 + static void set_path(char* path) { 1.74 + if (path == NULL) { 1.75 + _has_path = false; 1.76 + } else { 1.77 + strncpy(_path, path, UNIX_PATH_MAX); 1.78 + _path[UNIX_PATH_MAX-1] = '\0'; 1.79 + _has_path = true; 1.80 + } 1.81 + } 1.82 + 1.83 + static void set_listener(int s) { _listener = s; } 1.84 + 1.85 + // reads a request from the given connected socket 1.86 + static BsdAttachOperation* read_request(int s); 1.87 + 1.88 + public: 1.89 + enum { 1.90 + ATTACH_PROTOCOL_VER = 1 // protocol version 1.91 + }; 1.92 + enum { 1.93 + ATTACH_ERROR_BADVERSION = 101 // error codes 1.94 + }; 1.95 + 1.96 + // initialize the listener, returns 0 if okay 1.97 + static int init(); 1.98 + 1.99 + static char* path() { return _path; } 1.100 + static bool has_path() { return _has_path; } 1.101 + static int listener() { return _listener; } 1.102 + 1.103 + // write the given buffer to a socket 1.104 + static int write_fully(int s, char* buf, int len); 1.105 + 1.106 + static BsdAttachOperation* dequeue(); 1.107 +}; 1.108 + 1.109 +class BsdAttachOperation: public AttachOperation { 1.110 + private: 1.111 + // the connection to the client 1.112 + int _socket; 1.113 + 1.114 + public: 1.115 + void complete(jint res, bufferedStream* st); 1.116 + 1.117 + void set_socket(int s) { _socket = s; } 1.118 + int socket() const { return _socket; } 1.119 + 1.120 + BsdAttachOperation(char* name) : AttachOperation(name) { 1.121 + set_socket(-1); 1.122 + } 1.123 +}; 1.124 + 1.125 +// statics 1.126 +char BsdAttachListener::_path[UNIX_PATH_MAX]; 1.127 +bool BsdAttachListener::_has_path; 1.128 +int BsdAttachListener::_listener = -1; 1.129 + 1.130 +// Supporting class to help split a buffer into individual components 1.131 +class ArgumentIterator : public StackObj { 1.132 + private: 1.133 + char* _pos; 1.134 + char* _end; 1.135 + public: 1.136 + ArgumentIterator(char* arg_buffer, size_t arg_size) { 1.137 + _pos = arg_buffer; 1.138 + _end = _pos + arg_size - 1; 1.139 + } 1.140 + char* next() { 1.141 + if (*_pos == '\0') { 1.142 + return NULL; 1.143 + } 1.144 + char* res = _pos; 1.145 + char* next_pos = strchr(_pos, '\0'); 1.146 + if (next_pos < _end) { 1.147 + next_pos++; 1.148 + } 1.149 + _pos = next_pos; 1.150 + return res; 1.151 + } 1.152 +}; 1.153 + 1.154 + 1.155 +// atexit hook to stop listener and unlink the file that it is 1.156 +// bound too. 1.157 +extern "C" { 1.158 + static void listener_cleanup() { 1.159 + static int cleanup_done; 1.160 + if (!cleanup_done) { 1.161 + cleanup_done = 1; 1.162 + int s = BsdAttachListener::listener(); 1.163 + if (s != -1) { 1.164 + ::close(s); 1.165 + } 1.166 + if (BsdAttachListener::has_path()) { 1.167 + ::unlink(BsdAttachListener::path()); 1.168 + } 1.169 + } 1.170 + } 1.171 +} 1.172 + 1.173 +// Initialization - create a listener socket and bind it to a file 1.174 + 1.175 +int BsdAttachListener::init() { 1.176 + char path[UNIX_PATH_MAX]; // socket file 1.177 + char initial_path[UNIX_PATH_MAX]; // socket file during setup 1.178 + int listener; // listener socket (file descriptor) 1.179 + 1.180 + // register function to cleanup 1.181 + ::atexit(listener_cleanup); 1.182 + 1.183 + int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", 1.184 + os::get_temp_directory(), os::current_process_id()); 1.185 + if (n < (int)UNIX_PATH_MAX) { 1.186 + n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); 1.187 + } 1.188 + if (n >= (int)UNIX_PATH_MAX) { 1.189 + return -1; 1.190 + } 1.191 + 1.192 + // create the listener socket 1.193 + listener = ::socket(PF_UNIX, SOCK_STREAM, 0); 1.194 + if (listener == -1) { 1.195 + return -1; 1.196 + } 1.197 + 1.198 + // bind socket 1.199 + struct sockaddr_un addr; 1.200 + addr.sun_family = AF_UNIX; 1.201 + strcpy(addr.sun_path, initial_path); 1.202 + ::unlink(initial_path); 1.203 + int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); 1.204 + if (res == -1) { 1.205 + RESTARTABLE(::close(listener), res); 1.206 + return -1; 1.207 + } 1.208 + 1.209 + // put in listen mode, set permissions, and rename into place 1.210 + res = ::listen(listener, 5); 1.211 + if (res == 0) { 1.212 + RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res); 1.213 + if (res == 0) { 1.214 + res = ::rename(initial_path, path); 1.215 + } 1.216 + } 1.217 + if (res == -1) { 1.218 + RESTARTABLE(::close(listener), res); 1.219 + ::unlink(initial_path); 1.220 + return -1; 1.221 + } 1.222 + set_path(path); 1.223 + set_listener(listener); 1.224 + 1.225 + return 0; 1.226 +} 1.227 + 1.228 +// Given a socket that is connected to a peer we read the request and 1.229 +// create an AttachOperation. As the socket is blocking there is potential 1.230 +// for a denial-of-service if the peer does not response. However this happens 1.231 +// after the peer credentials have been checked and in the worst case it just 1.232 +// means that the attach listener thread is blocked. 1.233 +// 1.234 +BsdAttachOperation* BsdAttachListener::read_request(int s) { 1.235 + char ver_str[8]; 1.236 + sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER); 1.237 + 1.238 + // The request is a sequence of strings so we first figure out the 1.239 + // expected count and the maximum possible length of the request. 1.240 + // The request is: 1.241 + // <ver>0<cmd>0<arg>0<arg>0<arg>0 1.242 + // where <ver> is the protocol version (1), <cmd> is the command 1.243 + // name ("load", "datadump", ...), and <arg> is an argument 1.244 + int expected_str_count = 2 + AttachOperation::arg_count_max; 1.245 + const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) + 1.246 + AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1); 1.247 + 1.248 + char buf[max_len]; 1.249 + int str_count = 0; 1.250 + 1.251 + // Read until all (expected) strings have been read, the buffer is 1.252 + // full, or EOF. 1.253 + 1.254 + int off = 0; 1.255 + int left = max_len; 1.256 + 1.257 + do { 1.258 + int n; 1.259 + RESTARTABLE(read(s, buf+off, left), n); 1.260 + if (n == -1) { 1.261 + return NULL; // reset by peer or other error 1.262 + } 1.263 + if (n == 0) { 1.264 + break; 1.265 + } 1.266 + for (int i=0; i<n; i++) { 1.267 + if (buf[off+i] == 0) { 1.268 + // EOS found 1.269 + str_count++; 1.270 + 1.271 + // The first string is <ver> so check it now to 1.272 + // check for protocol mis-match 1.273 + if (str_count == 1) { 1.274 + if ((strlen(buf) != strlen(ver_str)) || 1.275 + (atoi(buf) != ATTACH_PROTOCOL_VER)) { 1.276 + char msg[32]; 1.277 + sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION); 1.278 + write_fully(s, msg, strlen(msg)); 1.279 + return NULL; 1.280 + } 1.281 + } 1.282 + } 1.283 + } 1.284 + off += n; 1.285 + left -= n; 1.286 + } while (left > 0 && str_count < expected_str_count); 1.287 + 1.288 + if (str_count != expected_str_count) { 1.289 + return NULL; // incomplete request 1.290 + } 1.291 + 1.292 + // parse request 1.293 + 1.294 + ArgumentIterator args(buf, (max_len)-left); 1.295 + 1.296 + // version already checked 1.297 + char* v = args.next(); 1.298 + 1.299 + char* name = args.next(); 1.300 + if (name == NULL || strlen(name) > AttachOperation::name_length_max) { 1.301 + return NULL; 1.302 + } 1.303 + 1.304 + BsdAttachOperation* op = new BsdAttachOperation(name); 1.305 + 1.306 + for (int i=0; i<AttachOperation::arg_count_max; i++) { 1.307 + char* arg = args.next(); 1.308 + if (arg == NULL) { 1.309 + op->set_arg(i, NULL); 1.310 + } else { 1.311 + if (strlen(arg) > AttachOperation::arg_length_max) { 1.312 + delete op; 1.313 + return NULL; 1.314 + } 1.315 + op->set_arg(i, arg); 1.316 + } 1.317 + } 1.318 + 1.319 + op->set_socket(s); 1.320 + return op; 1.321 +} 1.322 + 1.323 + 1.324 +// Dequeue an operation 1.325 +// 1.326 +// In the Bsd implementation there is only a single operation and clients 1.327 +// cannot queue commands (except at the socket level). 1.328 +// 1.329 +BsdAttachOperation* BsdAttachListener::dequeue() { 1.330 + for (;;) { 1.331 + int s; 1.332 + 1.333 + // wait for client to connect 1.334 + struct sockaddr addr; 1.335 + socklen_t len = sizeof(addr); 1.336 + RESTARTABLE(::accept(listener(), &addr, &len), s); 1.337 + if (s == -1) { 1.338 + return NULL; // log a warning? 1.339 + } 1.340 + 1.341 + // get the credentials of the peer and check the effective uid/guid 1.342 + // - check with jeff on this. 1.343 +#ifdef _ALLBSD_SOURCE 1.344 + uid_t puid; 1.345 + gid_t pgid; 1.346 + if (::getpeereid(s, &puid, &pgid) != 0) { 1.347 + int res; 1.348 + RESTARTABLE(::close(s), res); 1.349 + continue; 1.350 + } 1.351 +#else 1.352 + struct ucred cred_info; 1.353 + socklen_t optlen = sizeof(cred_info); 1.354 + if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) { 1.355 + int res; 1.356 + RESTARTABLE(::close(s), res); 1.357 + continue; 1.358 + } 1.359 + uid_t puid = cred_info.uid; 1.360 + gid_t pgid = cred_info.gid; 1.361 +#endif 1.362 + uid_t euid = geteuid(); 1.363 + gid_t egid = getegid(); 1.364 + 1.365 + if (puid != euid || pgid != egid) { 1.366 + int res; 1.367 + RESTARTABLE(::close(s), res); 1.368 + continue; 1.369 + } 1.370 + 1.371 + // peer credential look okay so we read the request 1.372 + BsdAttachOperation* op = read_request(s); 1.373 + if (op == NULL) { 1.374 + int res; 1.375 + RESTARTABLE(::close(s), res); 1.376 + continue; 1.377 + } else { 1.378 + return op; 1.379 + } 1.380 + } 1.381 +} 1.382 + 1.383 +// write the given buffer to the socket 1.384 +int BsdAttachListener::write_fully(int s, char* buf, int len) { 1.385 + do { 1.386 + int n = ::write(s, buf, len); 1.387 + if (n == -1) { 1.388 + if (errno != EINTR) return -1; 1.389 + } else { 1.390 + buf += n; 1.391 + len -= n; 1.392 + } 1.393 + } 1.394 + while (len > 0); 1.395 + return 0; 1.396 +} 1.397 + 1.398 +// Complete an operation by sending the operation result and any result 1.399 +// output to the client. At this time the socket is in blocking mode so 1.400 +// potentially we can block if there is a lot of data and the client is 1.401 +// non-responsive. For most operations this is a non-issue because the 1.402 +// default send buffer is sufficient to buffer everything. In the future 1.403 +// if there are operations that involves a very big reply then it the 1.404 +// socket could be made non-blocking and a timeout could be used. 1.405 + 1.406 +void BsdAttachOperation::complete(jint result, bufferedStream* st) { 1.407 + JavaThread* thread = JavaThread::current(); 1.408 + ThreadBlockInVM tbivm(thread); 1.409 + 1.410 + thread->set_suspend_equivalent(); 1.411 + // cleared by handle_special_suspend_equivalent_condition() or 1.412 + // java_suspend_self() via check_and_wait_while_suspended() 1.413 + 1.414 + // write operation result 1.415 + char msg[32]; 1.416 + sprintf(msg, "%d\n", result); 1.417 + int rc = BsdAttachListener::write_fully(this->socket(), msg, strlen(msg)); 1.418 + 1.419 + // write any result data 1.420 + if (rc == 0) { 1.421 + BsdAttachListener::write_fully(this->socket(), (char*) st->base(), st->size()); 1.422 + ::shutdown(this->socket(), 2); 1.423 + } 1.424 + 1.425 + // done 1.426 + RESTARTABLE(::close(this->socket()), rc); 1.427 + 1.428 + // were we externally suspended while we were waiting? 1.429 + thread->check_and_wait_while_suspended(); 1.430 + 1.431 + delete this; 1.432 +} 1.433 + 1.434 + 1.435 +// AttachListener functions 1.436 + 1.437 +AttachOperation* AttachListener::dequeue() { 1.438 + JavaThread* thread = JavaThread::current(); 1.439 + ThreadBlockInVM tbivm(thread); 1.440 + 1.441 + thread->set_suspend_equivalent(); 1.442 + // cleared by handle_special_suspend_equivalent_condition() or 1.443 + // java_suspend_self() via check_and_wait_while_suspended() 1.444 + 1.445 + AttachOperation* op = BsdAttachListener::dequeue(); 1.446 + 1.447 + // were we externally suspended while we were waiting? 1.448 + thread->check_and_wait_while_suspended(); 1.449 + 1.450 + return op; 1.451 +} 1.452 + 1.453 +int AttachListener::pd_init() { 1.454 + JavaThread* thread = JavaThread::current(); 1.455 + ThreadBlockInVM tbivm(thread); 1.456 + 1.457 + thread->set_suspend_equivalent(); 1.458 + // cleared by handle_special_suspend_equivalent_condition() or 1.459 + // java_suspend_self() via check_and_wait_while_suspended() 1.460 + 1.461 + int ret_code = BsdAttachListener::init(); 1.462 + 1.463 + // were we externally suspended while we were waiting? 1.464 + thread->check_and_wait_while_suspended(); 1.465 + 1.466 + return ret_code; 1.467 +} 1.468 + 1.469 +// Attach Listener is started lazily except in the case when 1.470 +// +ReduseSignalUsage is used 1.471 +bool AttachListener::init_at_startup() { 1.472 + if (ReduceSignalUsage) { 1.473 + return true; 1.474 + } else { 1.475 + return false; 1.476 + } 1.477 +} 1.478 + 1.479 +// If the file .attach_pid<pid> exists in the working directory 1.480 +// or /tmp then this is the trigger to start the attach mechanism 1.481 +bool AttachListener::is_init_trigger() { 1.482 + if (init_at_startup() || is_initialized()) { 1.483 + return false; // initialized at startup or already initialized 1.484 + } 1.485 + char path[PATH_MAX + 1]; 1.486 + int ret; 1.487 + struct stat st; 1.488 + 1.489 + snprintf(path, PATH_MAX + 1, "%s/.attach_pid%d", 1.490 + os::get_temp_directory(), os::current_process_id()); 1.491 + RESTARTABLE(::stat(path, &st), ret); 1.492 + if (ret == 0) { 1.493 + // simple check to avoid starting the attach mechanism when 1.494 + // a bogus user creates the file 1.495 + if (st.st_uid == geteuid()) { 1.496 + init(); 1.497 + return true; 1.498 + } 1.499 + } 1.500 + return false; 1.501 +} 1.502 + 1.503 +// if VM aborts then remove listener 1.504 +void AttachListener::abort() { 1.505 + listener_cleanup(); 1.506 +} 1.507 + 1.508 +void AttachListener::pd_data_dump() { 1.509 + os::signal_notify(SIGQUIT); 1.510 +} 1.511 + 1.512 +AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) { 1.513 + return NULL; 1.514 +} 1.515 + 1.516 +jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { 1.517 + out->print_cr("flag '%s' cannot be changed", op->arg(0)); 1.518 + return JNI_ERR; 1.519 +} 1.520 + 1.521 +void AttachListener::pd_detachall() { 1.522 + // do nothing for now 1.523 +}