From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30427 invoked by alias); 12 Jun 2008 20:32:21 -0000 Received: (qmail 30402 invoked by uid 367); 12 Jun 2008 20:32:20 -0000 Date: Thu, 12 Jun 2008 20:32:00 -0000 Message-ID: <20080612203220.30387.qmail@sourceware.org> From: cagney@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: When /proc/PID/exe is invalid throw an exception. X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 531115f2541df6ed1e8a8f16e24c519fb858b209 X-Git-Newrev: e7fe8b0edbf5bc538a3e7fbcd37997bc800d27a5 Mailing-List: contact frysk-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: frysk-cvs-owner@sourceware.org Reply-To: frysk@sourceware.org X-SW-Source: 2008-q2/txt/msg00374.txt.bz2 The branch, master has been updated via e7fe8b0edbf5bc538a3e7fbcd37997bc800d27a5 (commit) from 531115f2541df6ed1e8a8f16e24c519fb858b209 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit e7fe8b0edbf5bc538a3e7fbcd37997bc800d27a5 Author: Andrew Cagney Date: Thu Jun 12 16:31:00 2008 -0400 When /proc/PID/exe is invalid throw an exception. frysk-core/frysk/bindir/ChangeLog 2008-06-12 Andrew Cagney * TestFexe.java (testExeOfDeletedFile()): Enable. Match expected error. * fexe.java: Use Exe.getName. frysk-core/frysk/proc/live/ChangeLog 2008-06-12 Andrew Cagney * LinuxPtraceProc.java (getExe()): Delete. frysk-sys/frysk/sys/ChangeLog 2008-06-12 Andrew Cagney * cni/Errno.cxx (throwUserException): New. * cni/Errno.hxx (throwUserException): New. frysk-sys/frysk/sys/proc/ChangeLog 2008-06-12 Andrew Cagney * Exe.java (getName): Rename get. (openReadOnly): New. * jni/Exe.cxx (Exe::getName): Update. * cni/Exe.cxx (Exe::getName): Update. frysk-sys/jnixx/ChangeLog 2008-06-12 Andrew Cagney * exceptions.cxx (userException): Implement. * exceptions.hxx (userException): Declare. ----------------------------------------------------------------------- Summary of changes: frysk-core/frysk/bindir/ChangeLog | 4 ++ frysk-core/frysk/bindir/TestFexe.java | 4 +-- frysk-core/frysk/bindir/fexe.java | 4 +- frysk-core/frysk/proc/live/ChangeLog | 4 ++ frysk-core/frysk/proc/live/LinuxPtraceProc.java | 33 ++----------------- frysk-sys/frysk/sys/ChangeLog | 3 ++ frysk-sys/frysk/sys/cni/Errno.cxx | 8 +++++ frysk-sys/frysk/sys/cni/Errno.hxx | 4 ++ frysk-sys/frysk/sys/proc/ChangeLog | 7 ++++ frysk-sys/frysk/sys/proc/Exe.java | 9 ++--- frysk-sys/frysk/sys/proc/cni/Exe.cxx | 38 ++++++++++++++++++---- frysk-sys/frysk/sys/proc/jni/Exe.cxx | 29 +++++++++++++++-- frysk-sys/jnixx/ChangeLog | 5 +++ frysk-sys/jnixx/exceptions.cxx | 23 ++++++++++++++ frysk-sys/jnixx/exceptions.hxx | 4 ++ 15 files changed, 129 insertions(+), 50 deletions(-) First 500 lines of diff: diff --git a/frysk-core/frysk/bindir/ChangeLog b/frysk-core/frysk/bindir/ChangeLog index 5f57822..32b6db4 100644 --- a/frysk-core/frysk/bindir/ChangeLog +++ b/frysk-core/frysk/bindir/ChangeLog @@ -1,5 +1,9 @@ 2008-06-12 Andrew Cagney + * TestFexe.java (testExeOfDeletedFile()): Enable. Match expected + error. + * fexe.java: Use Exe.getName. + * TestFexe.java (testExeOfDeletedFile()): New; mark as unresolved 6621. diff --git a/frysk-core/frysk/bindir/TestFexe.java b/frysk-core/frysk/bindir/TestFexe.java index d5aba64..5a37447 100644 --- a/frysk-core/frysk/bindir/TestFexe.java +++ b/frysk-core/frysk/bindir/TestFexe.java @@ -89,8 +89,6 @@ public class TestFexe extends TestLib { } public void testExeOfDeletedFile() { - if (unresolved(6621)) - return; TearDownExpect e = new TearDownExpect(); TearDownFile exe = TearDownFile.create(); // Create a copy of sleep that is executable. @@ -111,6 +109,6 @@ public class TestFexe extends TestLib { assertFalse("file exists", exe.stillExists()); // Try fexe with the executable deleted e.send(Prefix.binFile("fexe").getPath() + " $pid\r"); - e.expect(exe.getName() + " \\(deleted\\)\r\n\\$ "); + e.expect("The link /proc/[0-9]+/exe points to the deleted file .*" + exe.getName() + "\\r\n\\$ "); } } diff --git a/frysk-core/frysk/bindir/fexe.java b/frysk-core/frysk/bindir/fexe.java index 2bcb374..e6a0600 100644 --- a/frysk-core/frysk/bindir/fexe.java +++ b/frysk-core/frysk/bindir/fexe.java @@ -84,11 +84,11 @@ public class fexe if (verbose) { ProcessIdentifier pid = ProcessIdentifierFactory.create(proc.getPid()); - System.out.println( proc.getPid() + System.out.println(proc.getPid() + " " + proc.getExeFile().getFile().getAbsolutePath() + " " - + Exe.get(pid) + + Exe.getName(pid) + " " + sysRootedPath); } else diff --git a/frysk-core/frysk/proc/live/ChangeLog b/frysk-core/frysk/proc/live/ChangeLog index eee24c5..61ffa17 100644 --- a/frysk-core/frysk/proc/live/ChangeLog +++ b/frysk-core/frysk/proc/live/ChangeLog @@ -1,3 +1,7 @@ +2008-06-12 Andrew Cagney + + * LinuxPtraceProc.java (getExe()): Delete. + 2008-06-06 Teresa Thomas * LinuxPtraceTaskState.java: Additional logging messages. diff --git a/frysk-core/frysk/proc/live/LinuxPtraceProc.java b/frysk-core/frysk/proc/live/LinuxPtraceProc.java index e854829..c7e1888 100644 --- a/frysk-core/frysk/proc/live/LinuxPtraceProc.java +++ b/frysk-core/frysk/proc/live/LinuxPtraceProc.java @@ -224,40 +224,15 @@ public class LinuxPtraceProc extends LiveProc { * and a second returning the exe as it should be (but possibly * isn't :-). Better yet have utrace handle it :-) */ - private String exe; - private String getExe() { + private SysRootFile exe; + public SysRootFile getExeFile() { if (exe == null) { - ProcessIdentifier pid - = ProcessIdentifierFactory.create(getPid()); - String exe = Exe.get(pid); - // Linux's /proc/$$/exe can get screwed up in several - // ways. Detect each here and return null. - if (exe.endsWith(" (deleted)")) - // Assume (possibly incorrectly) that a trailing - // "(deleted)" always indicates a deleted file. - return null; - if (exe.indexOf((char)0) >= 0) - // Assume that an EXE that has somehow ended up with - // an embedded NUL character is invalid. This happens - // when the kernel screws up "mv a-really-long-file - // $exe" leaving the updated EXE string with something - // like "$exeally-long-file (deleted)". - return null; - if (!new File(exe).exists()) - // Final sanity check; the above two should have covered - // all possible cases. But one never knows. - return null; - this.exe = exe; + File exeFile = new File(Exe.getName(pid)); + return new SysRootFile(SysRootCache.getSysRoot(exeFile.getName()), exeFile); } return exe; } - public SysRootFile getExeFile() { - String exe = getExe(); - File exeFile = new File(exe); - return new SysRootFile(SysRootCache.getSysRoot(exeFile.getName()), exeFile); - } - /** * If it hasn't already been read, read the stat structure. */ diff --git a/frysk-sys/frysk/sys/ChangeLog b/frysk-sys/frysk/sys/ChangeLog index c6c022a..aec7679 100644 --- a/frysk-sys/frysk/sys/ChangeLog +++ b/frysk-sys/frysk/sys/ChangeLog @@ -1,5 +1,8 @@ 2008-06-12 Andrew Cagney + * cni/Errno.cxx (throwUserException): New. + * cni/Errno.hxx (throwUserException): New. + * Errno.java-sh: Extend ExternalException. * cni/Errno.cxx: Update. diff --git a/frysk-sys/frysk/sys/cni/Errno.cxx b/frysk-sys/frysk/sys/cni/Errno.cxx index 3af0e1b..4ccac23 100644 --- a/frysk-sys/frysk/sys/cni/Errno.cxx +++ b/frysk-sys/frysk/sys/cni/Errno.cxx @@ -163,6 +163,14 @@ throwErrno (int err, const char *prefix) throwErrno (err, ajprintf ("%s: %s", prefix, strerror (err))); } +void throwUserException(const char *format, ...) { + va_list ap; + va_start(ap, format); + jstring message = vajprintf(format, ap); + va_end(ap); + throw new frysk::UserException(message); +} + void throwRuntimeException (const char *message) { diff --git a/frysk-sys/frysk/sys/cni/Errno.hxx b/frysk-sys/frysk/sys/cni/Errno.hxx index 6bcde43..5838b0f 100644 --- a/frysk-sys/frysk/sys/cni/Errno.hxx +++ b/frysk-sys/frysk/sys/cni/Errno.hxx @@ -47,6 +47,10 @@ extern void throwErrno (int err, const char *prefix) extern void throwErrno (int err, const char *prefix, const char *suffix, ...) __attribute__ ((noreturn)) __attribute__((format (printf, 3, 4))); +// <>: <> (<> ...) +extern void throwUserException(const char *format, ...) + __attribute__ ((noreturn)) __attribute__((format (printf, 1, 2))); + // <> extern void throwRuntimeException (const char *message) __attribute__ ((noreturn)); diff --git a/frysk-sys/frysk/sys/proc/ChangeLog b/frysk-sys/frysk/sys/proc/ChangeLog index 84cf92d..79c61d4 100644 --- a/frysk-sys/frysk/sys/proc/ChangeLog +++ b/frysk-sys/frysk/sys/proc/ChangeLog @@ -1,3 +1,10 @@ +2008-06-12 Andrew Cagney + + * Exe.java (getName): Rename get. + (openReadOnly): New. + * jni/Exe.cxx (Exe::getName): Update. + * cni/Exe.cxx (Exe::getName): Update. + 2008-06-04 Andrew Cagney * TestMaps.java (testNative()): New. diff --git a/frysk-sys/frysk/sys/proc/Exe.java b/frysk-sys/frysk/sys/proc/Exe.java index 07c9a05..23e33be 100644 --- a/frysk-sys/frysk/sys/proc/Exe.java +++ b/frysk-sys/frysk/sys/proc/Exe.java @@ -43,14 +43,11 @@ import frysk.sys.ProcessIdentifier; /** * The contents of /proc/PID/exe. - * - * XXX: Should this be more like a builder or like Stat where there's - * a refresh method that detects that the contents actually changed? */ public class Exe { - public static String get(ProcessIdentifier pid) { - return get(pid.intValue()); + public static String getName(ProcessIdentifier pid) { + return getName(pid.intValue()); } - private static native String get (int pid); + private static native String getName(int pid); } diff --git a/frysk-sys/frysk/sys/proc/cni/Exe.cxx b/frysk-sys/frysk/sys/proc/cni/Exe.cxx index 6f258c5..8b583fb 100644 --- a/frysk-sys/frysk/sys/proc/cni/Exe.cxx +++ b/frysk-sys/frysk/sys/proc/cni/Exe.cxx @@ -48,22 +48,46 @@ #include "frysk/sys/proc/Exe.h" jstring -frysk::sys::proc::Exe::get (jint pid) -{ +frysk::sys::proc::Exe::getName(jint pid) { char file[FILENAME_MAX]; if (::snprintf (file, sizeof file, "/proc/%d/exe", (int) pid) >= FILENAME_MAX) - throwRuntimeException ("snprintf: buffer overflow"); + throwRuntimeException("snprintf: buffer overflow"); // /proc/$$/exe contains a soft-link specifying the name of the // executable, possibly with "(deleted)" appended. That link's // upper bound is determined by FILENAME_MAX since that is the - // longest possible allowable file name. - const int maxLen = FILENAME_MAX + sizeof (" (deleted)") + 1; + // longest possible allowable file name. Note that readlink doesn't + // NUL terminate so need to leave space for that. + const char deleted[] = " (deleted)"; + const int maxLen = FILENAME_MAX + sizeof(deleted) + 1; char link[maxLen]; - int len = ::readlink (file, link, sizeof (link)); + int len = ::readlink(file, link, sizeof(link) - 1); if (len < 0 || len >= maxLen) - throwErrno (errno, "readlink"); + throwErrno(errno, "readlink"); + link[len] = '\0'; + + // Linux's /proc/$$/exe can get screwed up in several ways. Detect + // each here and return null. + if ((int) strlen(link) != len) { + // Assume that an EXE that has somehow ended up with an embedded + // NUL character is invalid. This happens when the kernel screws + // up "mv a-really-long-file $exe" leaving the updated EXE string + // with something like "$exeally-long-file (deleted)". + throwUserException("The link %s is corrupt", file); + } + + if (strstr(link, deleted) + strlen(deleted) - link == len) { + // Assume (possibly incorrectly) that a trailing "(deleted)" + // always indicates a deleted file. + link[len - strlen(deleted)] = '\0'; + throwUserException("The link %s points to the deleted file %s", + file, link); + } + + if (access(link, F_OK) != 0) { + throwErrno(errno, "file %s", link); + } // Note that some kernels have a "feature" where the link can become // corrupted. Just retun that, the caller needs to decide if the diff --git a/frysk-sys/frysk/sys/proc/jni/Exe.cxx b/frysk-sys/frysk/sys/proc/jni/Exe.cxx index 12745a8..112f363 100644 --- a/frysk-sys/frysk/sys/proc/jni/Exe.cxx +++ b/frysk-sys/frysk/sys/proc/jni/Exe.cxx @@ -49,7 +49,7 @@ using namespace java::lang; String -frysk::sys::proc::Exe::get(jnixx::env env, jint pid) { +frysk::sys::proc::Exe::getName(jnixx::env env, jint pid) { // Get the name of the EXE in /proc. char file[FILENAME_MAX]; if (::snprintf(file, sizeof file, "/proc/%d/exe", (int) pid) @@ -60,13 +60,36 @@ frysk::sys::proc::Exe::get(jnixx::env env, jint pid) { // executable, possibly with "(deleted)" appended. That link's // upper bound is determined by FILENAME_MAX since that is the // longest possible allowable file name. - const int maxLen = FILENAME_MAX + sizeof (" (deleted)") + 1; + const char deleted[] = " (deleted)"; + const int maxLen = FILENAME_MAX + sizeof(deleted) + 1; char link[maxLen]; - int len = ::readlink (file, link, sizeof (link) - 1); + int len = ::readlink (file, link, sizeof(link) - 1); if (len < 0 || len >= maxLen) errnoException(env, errno, "readlink"); link[len] = '\0'; + // Linux's /proc/$$/exe can get screwed up in several ways. Detect + // each here and return null. + if ((int) strlen(link) != len) { + // Assume that an EXE that has somehow ended up with an embedded + // NUL character is invalid. This happens when the kernel screws + // up "mv a-really-long-file $exe" leaving the updated EXE string + // with something like "$exeally-long-file (deleted)". + userException(env, "The link %s is corrupt", file); + } + + if (strstr(link, deleted) + strlen(deleted) - link == len) { + // Assume (possibly incorrectly) that a trailing "(deleted)" + // always indicates a deleted file. + link[len - strlen(deleted)] = '\0'; + userException(env, "The link %s points to the deleted file %s", + file, link); + } + + if (access(link, F_OK) != 0) { + errnoException(env, errno, "file %s", link); + } + // Note that some kernels have a "feature" where the link can become // corrupted. Just retun that, the caller needs to decide if the // extracted link is valid. diff --git a/frysk-sys/jnixx/ChangeLog b/frysk-sys/jnixx/ChangeLog index 7fdd6ba..8a2673e 100644 --- a/frysk-sys/jnixx/ChangeLog +++ b/frysk-sys/jnixx/ChangeLog @@ -1,3 +1,8 @@ +2008-06-12 Andrew Cagney + + * exceptions.cxx (userException): Implement. + * exceptions.hxx (userException): Declare. + 2008-06-04 Andrew Cagney * elements.cxx (slurp): Don't count the terminating NUL in the diff --git a/frysk-sys/jnixx/exceptions.cxx b/frysk-sys/jnixx/exceptions.cxx index 2f5ce80..928e0fd 100644 --- a/frysk-sys/jnixx/exceptions.cxx +++ b/frysk-sys/jnixx/exceptions.cxx @@ -150,3 +150,26 @@ runtimeException(::jnixx::env& env, const char *fmt, ...) { throw e; } } + + +void +userException(::jnixx::env& env, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + char *message = NULL; + if (::vasprintf(&message, fmt, ap) < 0) { + // If this fails things are pretty much stuffed. + int err = errno; + fprintf(stderr, "warning: vasprintf in runtimeException failed: %s", + ::strerror(err)); + RuntimeException::ThrowNew(env, "vasprintf in runtimeException failed"); + } + va_end(ap); + try { + frysk::UserException::ThrowNew(env, message); + } catch (java::lang::Throwable e) { + // Always executed. + ::free(message); + throw e; + } +} diff --git a/frysk-sys/jnixx/exceptions.hxx b/frysk-sys/jnixx/exceptions.hxx index 877356c..36fde6f 100644 --- a/frysk-sys/jnixx/exceptions.hxx +++ b/frysk-sys/jnixx/exceptions.hxx @@ -52,3 +52,7 @@ extern void errnoException(::jnixx::env& env, int error, const char *prefix, extern void runtimeException(::jnixx::env& env, const char *fmt, ...) __attribute__((noreturn)) __attribute__((format (printf, 2, 3))); + +extern void userException(::jnixx::env& env, const char *fmt, ...) + __attribute__((noreturn)) + __attribute__((format (printf, 2, 3))); hooks/post-receive -- frysk system monitor/debugger