Projects
New Ticket     Wiki     Browse Source     Timeline     Roadmap     Bug Reports     Search

root/trunk/base/src/port1.0/porttrace.tcl

Revision 44791, 8.8 KB (checked in by raimue@…, 5 days ago)

port1.0/porttrace.tcl:
Add $CCACHE_DIR and $HOME/.ccache to whitelist for trace mode, see #12218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1# et:ts=4
2# porttrace.tcl
3#
4# $Id$
5#
6# Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions are
11# met:
12#
13# 1. Redistributions of source code must retain the above copyright
14#    notice, this list of conditions and the following disclaimer.
15# 2. Redistributions in binary form must reproduce the above copyright
16#    notice, this list of conditions and the following disclaimer in the
17#    documentation and/or other materials provided with the distribution.
18# 3. Neither the name of Apple Computer, Inc. nor the names of its
19#    contributors may be used to endorse or promote products derived from
20#    this software without specific prior written permission.
21#
22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#
34
35package provide porttrace 1.0
36package require Pextlib 1.0
37
38proc trace_start {workpath} {
39        global os.platform
40        if {${os.platform} == "darwin"} {
41                if {[catch {package require Thread} error]} {
42                        ui_warn "trace requires Tcl Thread package ($error)"
43                } else {
44                        global env trace_fifo trace_sandboxbounds portpath
45                        # Create a fifo.
46                        # path in unix socket limited to 109 chars
47                        # # set trace_fifo "$workpath/trace_fifo"
48                        set trace_fifo "/tmp/macports/[pid]_[expr {int(rand()*1000)}]" 
49                        file mkdir "/tmp/macports"
50                        file delete -force $trace_fifo
51                       
52                        # Create the thread/process.
53                        create_slave $workpath $trace_fifo
54                                       
55                        # Launch darwintrace.dylib.
56                       
57                        set tracelib_path [file join ${portutil::autoconf::prefix} share macports Tcl darwintrace1.0 darwintrace.dylib]
58
59                        if {[info exists env(DYLD_INSERT_LIBRARIES)] && [string length "$env(DYLD_INSERT_LIBRARIES)"] > 0} {
60                                set env(DYLD_INSERT_LIBRARIES) "${env(DYLD_INSERT_LIBRARIES)}:${tracelib_path}"
61                        } else {
62                                set env(DYLD_INSERT_LIBRARIES) ${tracelib_path}
63                        }
64                        set env(DYLD_FORCE_FLAT_NAMESPACE) 1
65                        set env(DARWINTRACE_LOG) "$trace_fifo"
66                        # The sandbox is limited to:
67                        # workpath
68                        # /tmp
69                        # /private/tmp
70                        # /var/tmp
71                        # /private/var/tmp
72                        # $TMPDIR
73                        # /dev/null
74                        # /dev/tty
75                        # /Library/Caches/com.apple.Xcode
76                        # $CCACHE_DIR
77                        # $HOMEDIR/.ccache
78                        set trace_sandboxbounds "/tmp:/private/tmp:/var/tmp:/private/var/tmp:/dev/:/etc/passwd:/etc/groups:/etc/localtime:/Library/Caches/com.apple.Xcode:$env(HOME)/.ccache:${workpath}:$portpath"
79                        if {[info exists env(TMPDIR)]} {
80                                set trace_sandboxbounds "${trace_sandboxbounds}:$env(TMPDIR)"
81                        }
82                        if {[info exists env(CCACHE_DIR)]} {
83                                set trace_sandboxbounds "${trace_sandboxbounds}:$env(CCACHE_DIR)"
84                        }
85                        tracelib setsandbox $trace_sandboxbounds
86                }
87        }
88}
89
90# Enable the fence.
91# Only done for targets that should only happen in the sandbox.
92proc trace_enable_fence {} {
93        global env trace_sandboxbounds
94        set env(DARWINTRACE_SANDBOX_BOUNDS) $trace_sandboxbounds
95        tracelib enablefence
96}
97
98# Disable the fence.
99# Unused yet.
100proc trace_disable_fence {} {
101        global env
102        if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
103                unset env(DARWINTRACE_SANDBOX_BOUNDS)
104        }
105}
106
107# Check the list of ports.
108# Output a warning for every port the trace revealed a dependency on
109# that isn't included in portslist
110# This method must be called after trace_start
111proc trace_check_deps {target portslist} {
112        # Get the list of ports.
113        set ports [slave_send slave_get_ports]
114       
115        # Compare with portslist
116        set portslist [lsort $portslist]
117        foreach port $ports {
118                if {[lsearch -sorted -exact $portslist $port] == -1} {
119                        ui_warn "Target $target has an undeclared dependency on $port"
120                }
121        }
122        foreach port $portslist {
123                if {[lsearch -sorted -exact $ports $port] == -1} {
124                        ui_debug "Target $target has no traceable dependency on $port"
125                }
126        }       
127}
128
129# Check that no violation happened.
130# Output a warning for every sandbox violation the trace revealed.
131# This method must be called after trace_start
132proc trace_check_violations {} {
133        # Get the list of violations.
134        set violations [slave_send slave_get_sandbox_violations]
135       
136        foreach violation [lsort $violations] {
137                ui_warn "An activity was attempted outside sandbox: $violation"
138        }
139}
140
141# Stop the trace and return the list of ports the port depends on.
142# This method must be called after trace_start
143proc trace_stop {} {
144        global os.platform
145        if {${os.platform} == "darwin"} {
146                global env trace_fifo
147                unset env(DYLD_INSERT_LIBRARIES)
148                unset env(DYLD_FORCE_FLAT_NAMESPACE)
149                unset env(DARWINTRACE_LOG)
150                if [info exists env(DARWINTRACE_SANDBOX_BOUNDS)] {
151                        unset env(DARWINTRACE_SANDBOX_BOUNDS)
152                }
153               
154                #kill socket
155                tracelib clean
156
157                # Clean up.
158                slave_send slave_stop
159
160                # Delete the slave.
161                delete_slave
162
163                file delete -force $trace_fifo
164        }
165}
166
167# Private
168# Create the slave thread.
169proc create_slave {workpath trace_fifo} {
170        global trace_thread
171        # Create the thread.
172        set trace_thread [macports_create_thread]
173       
174        # The slave thread requires the registry package.
175        thread::send -async $trace_thread "package require registry 1.0"
176        # and this file as well.
177        thread::send -async $trace_thread "package require porttrace 1.0"
178
179        # Start the slave work.
180        thread::send -async $trace_thread "slave_start $trace_fifo $workpath"
181}
182
183# Private
184# Send a command to the thread without waiting for the result.
185proc slave_send_async {command} {
186        global trace_thread
187
188        thread::send -async $trace_thread "$command"
189}
190
191# Private
192# Send a command to the thread.
193proc slave_send {command} {
194        global trace_thread
195
196        # ui_warn "slave send $command ?"
197
198        thread::send $trace_thread "$command" result
199        return $result
200}
201
202# Private
203# Destroy the thread.
204proc delete_slave {} {
205        global trace_thread
206
207        # Destroy the thread.
208        thread::release $trace_thread
209}
210
211# Private.
212# Slave method to read a line from the trace.
213proc slave_read_line {chan} {
214        global ports_list trace_filemap sandbox_violation_list workpath
215        global env
216
217        while 1 {
218                # We should never get EOF, actually.
219                if {[eof $chan]} {
220                        break
221                }
222               
223                # The line is of the form: verb\tpath
224                # Get the path by chopping it.
225                set theline [gets $chan]
226               
227                if {[fblocked $chan]} {
228                        # Exit the loop.
229                        break
230                }
231
232                set line_length [string length $theline]
233               
234                # Skip empty lines.
235                if {$line_length > 0} {
236                        set path_start [expr [string first "\t" $theline] + 1]
237                        set op [string range $theline 0 [expr $path_start - 2]]
238                        set path [string range $theline $path_start [expr $line_length - 1]]
239                       
240                        # open/execve
241                        if {$op == "open" || $op == "execve"} {
242                                # Only work on files.
243                                if {[file isfile $path]} {
244                                        # Did we process the file yet?
245                                        if {![filemap exists trace_filemap $path]} {
246                                                # Obtain information about this file.
247                                                set port [registry::file_registered $path]
248                                                if { $port != 0 } {
249                                                        # Add the port to the list.
250                                                        if {[lsearch -sorted -exact $ports_list $port] == -1} {
251                                                                lappend ports_list $port
252                                                                set ports_list [lsort $ports_list]
253                                                                # Maybe fill trace_filemap for efficiency?
254                                                        }
255                                                }
256                       
257                                                # Add the file to the tree with port information.
258                                                # Ignore errors. Errors can occur if a directory was
259                                                # created where a file once lived.
260                                                # This doesn't affect existing ports and we just
261                                                # add this information to speed up port detection.
262                                                catch {filemap set trace_filemap $path $port}
263                                        }
264                                }
265                        } elseif {$op == "sandbox_violation"} {
266                                lappend sandbox_violation_list $path
267                        }
268                }
269        }
270}
271
272# Private.
273# Slave init method.
274proc slave_start {fifo p_workpath} {
275        global ports_list trace_filemap sandbox_violation_list
276        # Save the workpath.
277        set workpath $p_workpath
278        # Create a virtual filemap.
279        filemap create trace_filemap
280        set ports_list {}
281        set sandbox_violation_list {}
282        tracelib setname $fifo
283        tracelib run
284}
285
286# Private.
287# Slave cleanup method.
288proc slave_stop {} {
289        global trace_filemap trace_fifo_r_chan trace_fifo_w_chan
290        # Close the virtual filemap.
291        filemap close trace_filemap
292        # Close the pipe (both ends).
293}
294
295# Private.
296# Slave ports export method.
297proc slave_get_ports {} {
298        global ports_list
299        return $ports_list
300}
301
302# Private.
303# Slave sandbox violations export method.
304proc slave_get_sandbox_violations {} {
305        global sandbox_violation_list
306        return $sandbox_violation_list
307}
308
309proc slave_add_sandbox_violation {path} {
310        global sandbox_violation_list
311        lappend sandbox_violation_list $path
312}
Note: See TracBrowser for help on using the browser.