2 पॉइंट द्वारा GN⁺ 2024-09-15 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • FlowTracker एक Java agent है जो ट्रैक करता है कि Java प्रोग्राम डेटा को कैसे पढ़ते, बदलते और लिखते हैं, और दिखाता है कि output किस input, file, network या code constant से आया है
  • यह चल रहे program को observe करके file और network I/O दिखाता है, और खास तौर पर input और output के correspondence को track करके यह समझने में मदद करता है कि Java program का output क्या मायने रखता है और वह क्यों बना
  • Spring PetClinic demo में HTTP response के headers, Thymeleaf template, database values और SQL insert script तक follow करते हुए software stack की कई layers को explore किया जा सकता है
  • अंदरूनी तौर पर यह JVM loading time पर bytecode instrument करता है, और JDK method hooks, data flow analysis, ThreadLocal-based call tracking, ClassOriginTracker को combine करके strings, chars और bytes पर केंद्रित origin mapping बनाए रखता है
  • मौजूदा स्थिति production-ready से ज्यादा proof of concept के करीब है; कुछ example programs में यह अच्छी तरह चला, लेकिन सभी programs के लिए suitable नहीं है और बड़े overhead की वजह से execution speed काफी धीमी हो जाती है

FlowTracker क्या track करता है

  • FlowTracker एक Java agent है जो Java program के अंदर data कैसे पढ़ा, pass, transform और write किया जाता है, इसे track करता है
  • यह सिर्फ files और network I/O दिखाने तक सीमित नहीं है, बल्कि program का output किस input से आया है, यह connect करके दिखाता है
  • इसका उद्देश्य यह समझने में मदद करना है कि Java program का output क्या मायने रखता है, और program ने वह output क्यों लिखा
  • फिलहाल project इस perspective से program behavior देखने पर किस तरह की insights मिल सकती हैं, इसे explore करने वाला proof-of-concept है

Demo: Spring PetClinic में HTTP response की origin tracking

  • FlowTracker PetClinic demo browser में यह देखने देता है कि Spring PetClinic HTTP request को कैसे process करता है और templates व database data के आधार पर HTML page कैसे generate करता है
  • Screen पर PetClinic द्वारा network पर भेजा गया HTTP response दिखता है, और response body के किसी हिस्से पर click करने से नीचे वाले view में देखा जा सकता है कि वह हिस्सा कहां से आया
  • Left tree या mobile में bottom-left button से tracked inputs/origins या outputs/sinks चुने जा सकते हैं
  • HTTP processing layer

    • "HTTP/1.1" या HTTP header पर click करने से दिखता है कि response का यह हिस्सा org.apache.coyote package की Apache Coyote class ने generate किया था
    • FlowTracker दिखाता है कि किस code ने कौन-सा output बनाया
  • Thymeleaf template layer

    • "html" या "head" जैसे HTML tag names पर click करने से दिखता है कि संबंधित HTML हिस्सा layout.html file से आया था
    • layout.html पर click करने के बाद नीचे के color + button को दबाने से उस file से आए सभी हिस्से एक ही color में दिखते हैं
    • नीचे scroll करने पर पता चलता है कि response का कुछ हिस्सा दूसरी file ownerDetails.html से आया है
    • < या > character पर click करने से दिखता है कि वह character Thymeleaf template library द्वारा लिखा गया था
  • Database value की origin

    • HTML page की table में database से आई जानकारी शामिल है
    • Table में George पर click करने से यह सिर्फ इतना नहीं दिखता कि value database से आई है, बल्कि इसे शुरुआत में database में value insert करने वाली SQL script तक track किया जाता है
    • इस demo में SQL script तक tracking इसलिए होती है क्योंकि in-memory database का उपयोग किया गया, जिससे database content JVM के बाहर नहीं गया

MySQL demo और framework independence

  • वही PetClinic demo MySQL database के साथ चलाने पर values database connection point तक track होती हैं
  • इस case में पहले value बनाने के लिए भेजी गई SQL query और MySQL JDBC driver database से कैसे communicate करता है, उसकी details देखी जा सकती हैं
  • FlowTracker PetClinic mysql demo यह भी दिखाता है कि FlowTracker database SSL connection के जरिए भेजे गए decrypted content को intercept करता है
  • Spring PetClinic सिर्फ एक example है; FlowTracker किसी खास framework या library पर निर्भर नहीं है
  • javac demo Java compiler को observe करके यह दिखाता है कि generated class file format और उसके अंदर के bytecode को समझने में FlowTracker कैसे मदद करता है

उपयोग का तरीका और सावधानियां

  • अभी FlowTracker production-ready होने की बजाय proof-of-concept के ज्यादा करीब है
  • कई example programs में यह अच्छी तरह चला, लेकिन हर program में अच्छी तरह चलेगा, इसकी guarantee नहीं है
  • यह काफी overhead जोड़ता है, इसलिए program execution बहुत धीमा हो जाता है
  • इस्तेमाल की प्रक्रिया:
    • Github releases pages से flowtracker-*.jar agent jar download करें
    • Java command line में -javaagent:path/to/flowtracker.jar जोड़ें
    • FlowTracker में बाधा डालने वाली कुछ JVM optimizations को बंद करने के लिए java -jar flowtracker.jar jvmopts का output भी command line में जोड़ें
    • Default रूप से FlowTracker port 8011 पर web server start करता है, इसलिए browser में http://localhost:8011/ खोलें
  • अधिक detailed configuration options USAGE.md में हैं

अंदरूनी कामकाज: bytecode instrumentation और Tracker model

  • FlowTracker एक instrumentation agent है जो JVM द्वारा classes load करते समय class files, यानी bytecode में code inject करता है
  • Injected code program द्वारा data पढ़ने, pass करने और write करने के दौरान memory में data और उसके origins की mapping बनाए रखता है
  • Tracking का focus String, char, byte[] जैसे text और binary data पर है; numbers, structured data और computed data इसका core focus नहीं हैं
  • इस्तेमाल होने के तरीके:
    • कुछ JDK method calls को FlowTracker version के method calls से replace करता है
    • Input और output track करने के लिए JDK के core locations में code inject करता है
    • Method के अंदर local variables और stack values track करने के लिए data flow analysis और deeper instrumentation करता है
    • Method call से पहले/बाद और called method के start/end पर code add करके ThreadLocal के जरिए arguments और return values track करता है
  • Tracker data model

    • Tracker: tracked object का content और origin information store करता है
    • content: InputStream या OutputStream से गुजरे सभी bytes जैसा data
    • source: content की किसी specific range को किसी दूसरे tracker की specific range से connect करता है
    • TrackerRepository: interesting objects और उनके संबंधित Tracker को connect करने वाला बड़ा global Map<Object, Tracker> रखता है
    • TrackerPoint: tracker के अंदर किसी एक position को point करता है और एक single primitive value, जैसे किसी एक byte की origin, को represent करता है

बेसिक instrumentation: JDK hooks और ASM

  • FlowTracker कुछ खास JDK methods के call होने पर hook method calls insert करके Tracker को up-to-date रखता है
  • सबसे सरल उदाहरण System.arraycopy है
    • java.lang.System.arraycopy call को com.coekie.flowtracker.hook.SystemHook.arraycopy call से replace करता है
    • SystemHook असली arraycopy call करने के बाद, TrackerRepository से source और target arrays के trackers लाता है और target tracker को source की ओर point करने के लिए update करता है
  • इस तरह की instrumentation के लिए ASM bytecode manipulation library का उपयोग किया जाता है
  • अधिकतर hooks caller side पर नहीं, बल्कि JDK method के अंदर callee side पर जोड़े जाते हैं
    • उदाहरण के लिए FileInputStream.read(byte[]) के अंत में FileInputStreamHook.afterReadByteArray call जोड़ा जाता है
    • यह instrumentation ASM के AdviceAdapter का उपयोग करने वाले annotation-based custom micro framework से implement की गई है
  • FlowTracker JDK की I/O-related classes जैसे java.io.FileInputStream, java.io.FileOutputStream, sun.nio.ch.FileChannelImpl, sun.nio.ch.IOUtil, sun.nio.ch.NioSocketImpl में hooks जोड़ता है
  • संबंधित implementation:

primitive values की tracking और method के अंदर data flow analysis

  • byte जैसे primitive values की objects जैसी identity नहीं होती, इसलिए उन्हें TrackerRepository के Map key के रूप में सुरक्षित तरीके से track नहीं किया जा सकता
  • FlowTracker code को फिर से लिखता है ताकि primitive values के source को method के अंदर local variables में अलग से store किया जा सके
  • उदाहरण के लिए byte b = x[1] के बाद ArrayHook.getElementTracker(x, 1) से b का tracker मिलता है, और y[2] = b के समय ArrayHook.setElementTracker(y, 2, bTracker) से target array में source record किया जाता है
  • इसके लिए FlowTracker ASM की analysis capabilities के ऊपर symbolic interpretation करता है
  • method के हर point पर local variables और stack की values कहां से आईं और कहां जाती हैं, इसे model करता है
  • संबंधित implementation:
    • FlowValue और ArrayLoadValue
    • MergedValue: if statement या loop जैसे control flow के कारण value कई positions से आ सकती हो, ऐसी स्थितियों को handle करता है
    • FlowInterpreter: ASM Interpreter extension के रूप में bytecode instructions को interpret करता है और उपयुक्त FlowValue बनाता है
    • Store और ArrayStore
    • FlowTransformer: पूरी analysis और instrumentation प्रक्रिया को drive करता है
  • यह सभी primitive values को track नहीं करता; focus byte और char पर है, और intlong को उनसे ज्यादा limited तरीके से handle किया जाता है

method calls के पार data flow

  • केवल method-internal analysis से उन स्थितियों को handle नहीं किया जा सकता जहां primitive values दूसरे methods के arguments और return values के रूप में flow करती हैं
  • FlowTracker Invocation में arguments और return values के PointTracker store करता है, और method call से ठीक पहले इसे ThreadLocal में डालता है
  • called method के start point पर Invocation.start(...) से ThreadLocal की जानकारी निकालकर primitive arguments के sources का उपयोग किया जा सकता है
  • इस तरीके से out.write(b) की तरह primitive value को method में pass करने पर भी write(byte value) के अंदर value का tracker आगे carry किया जा सकता है
  • संबंधित implementation:

कोड को ही डेटा स्रोत की तरह扱ना

  • FlowTracker जिन मुख्य स्रोतों को ट्रैक करता है, वे I/O और कोड से आने वाली values हैं
  • कोड से आने वाली values में 'a', "abc" जैसे primitive और String constants शामिल हैं
  • ऐसे constants के लिए हर class के हिसाब से ClassOriginTracker बनाया जाता है, और class व constant references को text के रूप में represent करने वाली सामग्री रखी जाती है
  • जब कोई constant reference होता है, तो उस value का tracker इस text representation के भीतर की position की ओर इशारा करता है
  • यह model constants को ऐसे treat करता है जैसे वे code के text representation से पढ़े गए हों, इसलिए यह I/O tracking model जैसा हो जाता है
  • performance की वजह से, constantPoint method हर method execution पर call न हो, इसके लिए ConstantDynamic (JEP 309) का इस्तेमाल किया जाता है
  • संबंधित implementation:

String literal की handling और सीमाएं

  • String literal की एक नई String copy बनाई जाती है, और String.value के भीतर के byte[] को ClassOriginTracker से जोड़ा जाता है
  • String s = "abc"; जैसा statement String s = StringHook.constantString("abc", 1234, 81); के रूप में rewrite किया जाता है
  • यह तरीका JVM द्वारा आम तौर पर दी जाने वाली String interning guarantee को तोड़ देता है
    • मूल रूप से, एक ही String constant की सभी occurrences को उसी instance को reference करना चाहिए
    • instrumentation के बाद, इस guarantee पर निर्भर code टूट सकता है
  • FlowTracker इस समस्या को कम करने के लिए कुछ उपाय रखता है
    • ConstantDynamic का इस्तेमाल करके, एक ही line का वही String literal कई बार execute होने पर भी हर बार वही instance return करता है
    • कुछ stringA == stringB expressions को Objects.equals(stringA, stringB) के रूप में rewrite करता है, ताकि कुछ नजरियों से वे same instance जैसे दिखें
    • java.lang.* जैसे कुछ packages में String literal tracking disable कर देता है
    • यह behavior USAGE.md के breakStringInterning से configure किया जा सकता है
  • संबंधित implementation:

जिन values को track नहीं किया जाता, उनके लिए fallback

  • FlowTracker program की सभी values को track नहीं करता
  • वजहें हैं performance concerns, वे हिस्से जो अभी implement नहीं हुए हैं, कम relevance वाली values, और यह कि कई sources के combination से बनने वाली values को represent करने के लिए अधिक जटिल data model चाहिए
  • जब कोई ऐसी value, जो अब तक track नहीं हो रही थी, ऐसी जगह पहुंचती है जहां tracking शुरू होनी चाहिए, तो उसे constants की तरह ClassOriginTracker से जोड़ा जाता है और उसकी position को "<?>" के रूप में represent किया जाता है
  • उदाहरण के लिए, array length track नहीं होती, इसलिए जब write(array.length) call होता है, तो Invocation को write call site की code position की ओर इशारा करने वाला PointTracker दिया जाता है
  • नतीजतन, binary format के output में भले ही original source न दिखे, आसपास की tracked strings और code position के जरिए कभी-कभी value का अर्थ जल्दी समझा जा सकता है

और गहराई में देखे जा सकने वाले implementation विषय

  • MergedValue branches और loops से गुजरने वाली values की tracking को संभालता है, जिसे data flow analysis के सबसे कठिन हिस्सों में माना जाता है
  • String concatenation को indification (JEP 280) के जरिए StringConcatFactory द्वारा लौटाए गए MethodHandle में hook जोड़कर handle किया जाता है
  • implementation में source code ढूंढना, Vineflower से decompile करना, और bytecode को source lines से जोड़ना भी शामिल है
  • ClassLoader configuration का focus bootclasspath dependencies और application conflicts से बचने, और shading व nested jar के बिना तेज़ development cycle बनाए रखने पर है
  • fields में stored primitive values की tracking भी implementation में शामिल है
  • frontend Jetty और JAX-RS आधारित web server, और Svelte आधारित web UI से बना है

1 टिप्पणियां

 
GN⁺ 2024-09-15
Hacker News की रायें
  • शानदार। इसी दिशा में Clojure के लिए एक टूल FlowStorm बनाया है http://www.flow-storm.org/
    instrumentation के लिए instrumentation agent के बजाय आधिकारिक Clojure compiler का fork इस्तेमाल करता है, और Clojure की उस खूबी का फायदा उठाता है जिससे development के दौरान compiler को आसानी से बदला जा सकता है, ताकि अतिरिक्त bytecode डाला जा सके
    Clojure program execution record में दिलचस्प बात यह है कि ज्यादातर values immutable होती हैं, इसलिए सिर्फ pointers बनाए रखकर snapshots लिए जा सकते हैं
    मूल पोस्ट का demo web app exploration है, इसलिए रुचि रखने वालों के लिए FlowStorm से web app debugging का demo भी छोड़ रहा हूं https://www.youtube.com/watch?v=h8AFpZkAwPo
    • सच में शानदार। जिज्ञासा है कि JavaFX क्यों चुना। JavaFX चुनने के बाद क्या cljfx भी देखा था?
    • अच्छा है। जिज्ञासा है कि value tracking के लिए data structure metadata इस्तेमाल करने का तरीका भी आपको पसंद है क्या
  • वाकई कमाल
    Java/JVM ecosystem के tools इतने अच्छे हैं, यह अच्छी बात है। इस तरह मैं पहले jitwatch देखकर हैरान हुआ था https://github.com/AdoptOpenJDK/jitwatch
    FlowTracker से थोड़ा taint analysis याद आता है, जो untrusted user input या secrets program के अंदर कैसे flow करते हैं, यह track करता है ताकि वे leak न हों या validation के बिना इस्तेमाल न हों
    search keyword “dynamic taint tracking/analysis” है
    https://github.com/gmu-swe/phosphor
    https://github.com/soot-oss/SootUp
    https://github.com/feliam/klee-taint
  • HTML element को उस SQL statement तक वापस trace करने वाला demo प्रभावशाली है, जिसने उसकी value database में जोड़ी थी
    आगे चलकर ऐसे tools bugs track करते समय first line of defense बनें, यह आसानी से कल्पना की जा सकती है
    • धन्यवाद
      FlowTracker develop करते हुए काफी काम किसी खास example program की tracking को काम कराने से निकला
      target result पता था, लेकिन किसी खास example के काम करने के लिए कौन-से low-level mechanisms support करने होंगे, यह predict करना मुश्किल था, और यह अक्सर उन JDK या library internals की implementation details पर निर्भर करता था जिनसे data गुजरता था
      लेकिन HTML element का उस SQL script से जुड़ना, जिसने वह data DB में डाला था, वैसा नहीं था
      यह उम्मीद या इरादे से बनाया गया नहीं था, बस ऐसा हो गया, इसलिए मैं भी काफी हैरान हुआ और इस approach से और क्या किया जा सकता है, इसे लेकर उत्साहित हुआ
    • सोचने पर लगता है कि अगर data की provenance और truthfulness track करने का कोई standard तरीका होता, तो बहुत-सी समस्याएं रोकी जा सकती थीं, और कई business rules भी ज्यादा आसानी से express किए जा सकते थे
      यह track करने का तरीका भी अच्छा होगा कि data temporary है या उसे फिर से लिखा जाना चाहिए
      ऐसी constraints को जितना ज्यादा upfront describe कर सकें, उतना बेहतर
  • पूरी तस्वीर या usage pattern अभी पूरी तरह समझा नहीं है, लेकिन यह Smalltalk environment की याद दिलाता है, जहां सब कुछ inspect किया जा सकता है
    Smalltalk में सब कुछ objects और messages है, इसलिए backtrack कर सकते हैं और interact कर सकते हैं
  • बहुत बढ़िया। demo video भी अच्छा है, और किसी अनजान codebase में गहराई से जाने पर यह निश्चित रूप से उपयोगी लगता है
  • कुछ साल पहले मैंने मिलता-जुलता concept experiment किया था[1]. JavaScript source maps जैसा कुछ HTML पर लागू करना चाहता था
    इसे और expand करने का समय नहीं निकाल पाया, लेकिन web development tools को इस तरह की full-stack attribution tracking से बड़ा फायदा मिल सकता है
    हालांकि ऐसे solution को existing frameworks में integrate करना बड़ी challenge लगता है
    [1] HTML Source Maps - https://github.com/connorjclark/html-source-maps https://docs.google.com/document/d/19XYWiPL9h9vA6QcOrGV9Nfkr...
  • अच्छे अर्थ में, Eve-lang demo याद आता है जिसमें program debug करते समय बस “यह यहां क्यों नहीं है?” पूछा जाता था। बेहतरीन काम
    https://www.youtube.com/watch?v=TWAMr72VaaU&t=164s और https://witheve.com/
  • अगर याद सही है, तो Java programs में SQL injection dynamically खोजने वाले मिलते-जुलते tool पर कोई paper था। क्या यह वही tool है?
    • नहीं, शायद वह कोई और tool रहा होगा
      FlowTracker जो करता है उसे extend करें तो SQL या अन्य injection vulnerabilities भी खोजी जा सकती हैं। इसलिए संभव है कि आपके याद किए tool ने similar approach इस्तेमाल किया हो
  • कभी internet के पार data track करने की कल्पना की थी। जैसे कोई image कहां से आई, किस CDN पर थी, वगैरह
    या “यह string बनने के क्षण से मेरी screen तक पहुंचने तक क्या-क्या देख चुकी है” जैसे सवाल
    यह उस दिशा में एक कदम लगता है
  • इस tool को VSCode में, उस project के साथ चलाने की कोशिश कर रहा हूं जिसे समझना चाहता हूं
    अभी थोड़ी देर के लिए रोकना होगा, लेकिन इसे चलाकर इससे छेड़छाड़ करने का इंतजार है