3 điểm bởi GN⁺ 2024-06-10 | 2 bình luận | Chia sẻ qua WhatsApp
  • libtree là công cụ chuyển đầu ra của ldd thành dạng cây, đồng thời giải thích thư viện dùng chung được tìm thấy như thế nào hoặc vì sao không thể tìm thấy
  • Ở đầu ra mặc định, công cụ ẩn một số phụ thuộc tiêu chuẩn; có thể dùng -v, -vv, -vvv để lần lượt xem các thư viện bị ẩn và cả phụ thuộc của những thư viện đã gặp
  • --path hoặc -p hiển thị đường dẫn thay vì soname, và có thể giới hạn độ sâu tìm kiếm đệ quy bằng --max-depth
  • Có thể cài đặt qua binary dựng sẵn v3.1.1, Fedora/RHEL/CentOS, Ubuntu 22.04+ và GNU Guix
  • Khi build từ mã nguồn, cần trình biên dịch C hiểu C99; khi dùng make, khuyến nghị dùng LDFLAGS=-static

libtree làm gì

  • libtree là công cụ chuyển ldd sang dạng cây
  • Giải thích thư viện dùng chung được tìm thấy như thế nào, hoặc vì sao không thể xác định vị trí của chúng
  • README có kèm ảnh chụp màn hình doc/screenshot.png

Tùy chọn đầu ra

  • Ở đầu ra mặc định, một số phụ thuộc tiêu chuẩn sẽ không được hiển thị
  • Đầu ra chi tiết hơn được điều khiển bằng các tùy chọn verbosity
    • libtree -v: hiển thị các thư viện bị bỏ qua theo mặc định
    • libtree -vv: cũng hiển thị phụ thuộc của các thư viện bị bỏ qua theo mặc định
    • libtree -vvv: cũng hiển thị phụ thuộc của các thư viện đã gặp trước đó
  • Cờ --path hoặc -p hiển thị đường dẫn thay vì soname
    • Ví dụ: libtree -p $(which tar)
  • --max-depth giới hạn độ sâu đệ quy

Cách cài đặt

Build từ mã nguồn

  • libtree cần trình biên dịch C hiểu C99
  • Quy trình build cơ bản là clone repository rồi chạy make
  • Khi dùng make, khuyến nghị dùng LDFLAGS=-static
  • README cũng cung cấp riêng trong một mục gập lệnh unsafe quick install để tải libtree.c bằng curl rồi biên dịch

2 bình luận

 
GN⁺ 2024-06-10
Ý kiến trên Hacker News
  • Công cụ này có lặp lại đúng hành vi ngoài dự kiến của ldd, tức là thực sự chạy một phần thư viện đang được kiểm tra không?
    https://catonmat.net/ldd-arbitrary-code-execution

    • Gần đây, các phiên bản ldd khoảng hơn 5 năm tuổi trở lại đây không chạy binary đích
      Tham khảo: https://manpages.debian.org/unstable/manpages/ldd.1.en.html#...
    • Lướt nhanh mã nguồn trên điện thoại thì có vẻ nó không làm vậy
      Trên thực tế, có vẻ nó tự parse trực tiếp file ELF, rồi cũng parse đệ quy các dependency, nên khá ấn tượng
    • Tôi từng làm một thứ na ná vậy cho Python, nhưng rốt cuộc vẫn không thể né được vấn đề này https://github.com/google/importlab/issues/69
    • Dùng objdump thì nó sẽ in ra dữ liệu đúng như được mã hóa trong file ELF
      Bao gồm cả danh sách thư viện mà vdso sẽ tìm kiếm
  • Có một công cụ tương tự là lddtree
    https://github.com/gentoo/pax-utils/tree/master

  • Việc phải lần theo đệ quy lặp đi lặp lại các dependency bị thiếu bằng ldd khá là chán
    Nên cái này trông như một cải tiến tốt, và lần tới nếu gặp một lỗi not found mơ hồ thì tôi sẽ thử dùng

  • Về cơ bản nó giống phiên bản Linux CLI của depends.exe

    • Công cụ cụ thể đó giờ không còn hoạt động tốt trên các bản Windows mới nữa
      Thay vào đó nên dùng https://github.com/lucasg/Dependencies. Dù nó cũng không hoàn toàn cập nhật nhất...
      Nếu bạn đã cài Visual Studio và chọn x64/x86 build tools (latest) trong trình cài đặt, thì chạy dumpbin /dependents trong VS Developer Command Prompt vẫn là lựa chọn đáng tin cậy nhất
    • Đúng vậy, tôi cũng nghĩ ngay đến nó
      [1] https://www.dependencywalker.com/
  • Ghi chú cho ai thắc mắc màu sắc có ý nghĩa gì, vì tôi không tìm thấy trong manpage/README
    Màu tím hồng: nằm trong danh sách loại trừ, chỉ hiển thị với -v[v[v]]
    Màu xanh dương: mục đã thấy trước đó, nên có thể tìm ra các dependency xuất hiện nhiều lần

  • “Giải thích lý do thư viện được tìm thấy hoặc không được tìm thấy” nghĩa là gì? Chẳng phải chỉ là có nằm trong LD_LIBRARY_PATH hay không thôi sao?
    Chỉ nhìn ảnh chụp màn hình thì tôi không rõ nó đang ám chỉ điều gì

    • Tôi không biết chính xác trong ngữ cảnh của công cụ này, nhưng quá trình tìm kiếm thư viện phức tạp hơn nhiều so với một biến môi trường đơn lẻ
      Có nhiều cơ chế tìm thư mục khác nhau như đường dẫn tìm kiếm của hệ thống, runpath, rpath, LD_LIBRARY_PATH, v.v.
      Thư viện thường được liên kết bằng tên ngắn như foo.so, nhưng cũng có thể được liên kết động bằng đường dẫn đầy đủ của thư viện
      Nói thêm thì thông thường nên tránh cấu hình LD_LIBRARY_PATH nếu có thể. Không phải lúc nào cũng làm được, nhưng nếu đặt nó thì nó sẽ nhảy lên đầu thứ tự ưu tiên tìm kiếm cho mọi lần thực thi. Kể cả khi thứ gì đó được liên kết động bằng đường dẫn đầy đủ tới thư viện thì LD_LIBRARY_PATH vẫn được ưu tiên, làm phẳng hoàn toàn cơ chế tìm kiếm
    • Thư viện không nhất thiết phải nằm trong LD_LIBRARY_PATH mới được tìm thấy
      Ý chính của tiêu đề là libtree giúp dễ dàng lần ra đường đi từ file thực thi tới toàn bộ dependency trực tiếp và gián tiếp của nó. Một trong những công dụng là hỗ trợ chẩn đoán vấn đề dependency bị thiếu
      Trên thực tế, nếu bạn dùng hệ thống quản lý gói thì dependency thường hiếm khi bị thiếu, nên có lẽ bạn sẽ dùng libtree vì các lý do khác
    • Không chỉ có chuyện có hoặc không có trong LD_LIBRARY_PATH, mà còn có RPATH được đánh giá lúc load cho từng thư viện
      Điểm lớn hơn là các dependency tạo thành một đồ thị, và có thể hiển thị nó dưới dạng cây. Biết được thư viện nào không tìm thấy do một thư viện nào khác cần đến là điều hữu ích
    • Thư viện không chỉ được tìm bằng LD_LIBRARY_PATH. Loader còn xét nhiều nguồn khác để tìm thư viện
      Trong một cấu hình bình thường, đó sẽ là tổ hợp giữa các trường ELF thông dụng của từng binary được tải và các đường dẫn khác mà loader biết
      Trên hệ thống có nhiều phiên bản của cùng một thư viện hoặc nhiều thư viện trùng tên, việc phụ thuộc vào LD_LIBRARY_PATH có thể rất thiển cận. Loader sẽ duyệt các đường dẫn trong LD_LIBRARY_PATH theo thứ tự cho từng binary và chọn thư viện khớp đầu tiên. Nếu bạn không thiết lập đường dẫn ưu tiên cao hơn bằng cách khác thì thư viện đó có thể không phải thứ bạn thực sự muốn, và điều này có thể dẫn tới lỗi bất ngờ lúc runtime
      Cách tốt hơn là thiết lập RPATH trỏ tới nơi chứa thư viện mà binary đó cần
      Nếu cấu hình môi trường và RPATH không nhất quán, bạn thậm chí có thể tải đồng thời nhiều phiên bản của cùng một thư viện. Công cụ này giúp xác định có vấn đề hay không, và vì sao
    • Tối thiểu thì có RPATH, RUNPATH, và LD_LIBRARY_PATH
      Vì công cụ này dựa trên ldd, nên có lẽ nó cũng sẽ diễn giải DYLD_LIBRARY_PATH, DYLD_FALLBACK_FRAMEWORK_PATH, DYLD_FALLBACK_LIBRARY_PATH, @executable_path, @loader_path, @rpath
  • Thật sự hữu ích. Bình thường tôi sẽ dùng readelf để đọc các section hòng tìm ra yêu cầu thực tế là gì

  • LD_DEBUG=libs là chưa đủ sao?

    • Cái đó không hoàn toàn giống nhau vì nó là cờ debug của loader, chứ không phải đánh giá tĩnh về dependency thư viện
  • Không rõ đây có phải bug không, nhưng trong ví dụ với vim thì ldd và libtree hiển thị các thư viện khác nhau
    Ví dụ, linux-vdso.so.1 xuất hiện ở đầu danh sách trong ldd nhưng hoàn toàn không có trong libtree

    • linux-vdso.so.1 không phải là thư viện thực có thể tìm thấy đâu đó trong hệ thống file, và cũng không được tham chiếu bên trong file ELF, nên libtree không thể biết về nó
      Thay vào đó, kernel tự động map nó vào không gian địa chỉ của tiến trình mới khởi chạy. Đây là một tối ưu để tránh overhead của system call cho các hàm như gettimeofday. Tham khảo: https://man7.org/linux/man-pages/man7/vdso.7.html
  • Trên NixOS, tôi từng viết một script nhỏ khá tệ để chạy ldd đệ quy nhằm tìm ra cần đưa vào những gì để chạy được binary đóng nguồn
    Nếu lại phải làm chuyện đó, tôi sẽ thử công cụ này

 
kayws426 2024-06-11

Trông có vẻ hay đấy!!