From: David Smith Date: Wed, 28 May 2014 15:54:57 +0000 (-0500) Subject: Fixed PR16991 by avoiding an inifinte loop in task_dentry_path(). X-Git-Tag: release-2.6~107^2~32 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=979929ed22092e90e33ca43fb8726e0248a082ad;p=systemtap.git Fixed PR16991 by avoiding an inifinte loop in task_dentry_path(). * tapset/linux/dentry.stp (task_dentry_path): Return "UNKNOWN" for unmounted synthetic filesystems. * testsuite/systemtap.base/task_dentry_path.exp: New file. * testsuite/systemtap.base/task_dentry_path.sh: Ditto. * testsuite/systemtap.base/task_dentry_path.stp: Ditto. --- diff --git a/tapset/linux/dentry.stp b/tapset/linux/dentry.stp index 0a564058c..db3eba038 100644 --- a/tapset/linux/dentry.stp +++ b/tapset/linux/dentry.stp @@ -170,6 +170,26 @@ function real_mount:long(vfsmnt:long) */ function task_dentry_path:string(task:long,dentry:long,vfsmnt:long) { + /* + * There are various synthetic filesystems that never get + * mounted. Filesystems needing to implement special "root + * names" do so with dentry->d_op->d_dname(). Unfortunately, + * it isn't really safe for us to call + * dentry->d_op->d_dname(). We can't really validate the + * function pointer or know that it can be called safely in + * the current context. + * + * Some pseudo inodes are mountable. When they are mounted, + * dentry == vfsmnt->mnt_root. In that case, we'll just go + * ahead and handle them normally. + */ + if (@defined(@cast(0, "dentry")->d_op->d_dname) + && @cast(dentry, "dentry")->d_op + && @cast(dentry, "dentry")->d_op->d_dname + && (!__dentry_IS_ROOT(dentry) + || dentry != @cast(vfsmnt, "vfsmount")->mnt_root)) + return "UNKNOWN" + root = & @cast(task, "task_struct")->fs->root while (1) { diff --git a/testsuite/systemtap.base/task_dentry_path.exp b/testsuite/systemtap.base/task_dentry_path.exp new file mode 100644 index 000000000..6e8d95084 --- /dev/null +++ b/testsuite/systemtap.base/task_dentry_path.exp @@ -0,0 +1,16 @@ +# This testcase tests the fix for PR16991 - infinite loop in +# task_dentry_path. When task_dentry_path hit a dentry from an +# unmounted synthentic filesystem, it would go into an infinite loop +# (until killed by MAXACTION). + +set test "task_dentry_path" +spawn stap $srcdir/$subdir/$test.stp -c "sh $srcdir/$subdir/$test.sh" +set ok 0 +expect { + -timeout 150 + -re {ERROR.*MAXACTION} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} +catch {close}; catch {wait} +if {$ok == 1} { fail "$test ($ok)" } { pass "$test ($ok)" } diff --git a/testsuite/systemtap.base/task_dentry_path.sh b/testsuite/systemtap.base/task_dentry_path.sh new file mode 100644 index 000000000..398600cb6 --- /dev/null +++ b/testsuite/systemtap.base/task_dentry_path.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cd /tmp +BASE="$(cd $(dirname ".")/../..; pwd -P)" +echo $BASE diff --git a/testsuite/systemtap.base/task_dentry_path.stp b/testsuite/systemtap.base/task_dentry_path.stp new file mode 100644 index 000000000..7aeaec2ee --- /dev/null +++ b/testsuite/systemtap.base/task_dentry_path.stp @@ -0,0 +1,18 @@ +global FSNOTIFY_EVENT_PATH = 1 + +probe kernel.function("fsnotify") ? +{ + if (!target_set_pid(pid())) { + next + } + if ($data_is == FSNOTIFY_EVENT_PATH) { + path = task_dentry_path(task_current(), @cast($data, "path")->dentry, + @cast($data, "path")->mnt); + println(path); + } +} + +probe begin +{ + printf("begin\n") +}