Hệ điều hành · 03/10/2026

coredumpctl thực chiến: Điều tra process crash trên Linux

Một dịch vụ Linux vừa thoát với SIGSEGV, systemd khởi động lại nó và vài giây sau mọi thứ có vẻ bình thường. Log chỉ cho biết tiến trình đã “dumped core” — vậy làm sao xác định thread nào lỗi, call stack ở đâu và binary nào thực sự đã chạy? Đây là lúc systemd-coredump, coredumpctl và GDB biến một sự cố thoáng qua thành bằng chứng có thể phân tích sau đó.

coredumpctl thực chiến: Điều tra process crash trên Linux

Một dịch vụ Linux vừa thoát với SIGSEGV, systemd khởi động lại nó và vài giây sau mọi thứ có vẻ bình thường. Log chỉ cho biết tiến trình đã “dumped core” — vậy làm sao xác định thread nào lỗi, call stack ở đâu và binary nào thực sự đã chạy? Đây là lúc systemd-coredump, coredumpctl và GDB biến một sự cố thoáng qua thành bằng chứng có thể phân tích sau đó.

Bài này trình bày quy trình điều tra an toàn trên production: tìm đúng lần crash, đọc metadata trước, xuất core dump có kiểm soát, ghép đúng binary và debug symbols, lấy backtrace đa luồng, xử lý tình huống container và thiết kế chính sách lưu trữ. Hành vi được đối chiếu với coredumpctl, tài liệu systemd-coredump upstream, Linux kernel core_pattern và tài liệu backtrace của GDB.

1. Core dump là gì — và không phải là gì?

Core dump là ảnh chụp trạng thái tiến trình tại thời điểm nó kết thúc bởi một tín hiệu có hành vi tạo core, thường gặp như SIGSEGV, SIGABRT, SIGBUS hoặc SIGFPE. Nó có thể chứa thanh ghi CPU, stack của các thread và nhiều vùng nhớ của tiến trình. Trình gỡ lỗi dùng core cùng executable để dựng lại vị trí chương trình đã dừng.

Core dump không phải log ứng dụng đầy đủ, không phát lại toàn bộ lịch sử trước sự cố và cũng không tự chứng minh nguyên nhân gốc. Nó cho biết trạng thái tại một thời điểm. Muốn kết luận, ta vẫn phải ghép nó với release, cấu hình, request trace, journal và thay đổi hạ tầng quanh thời điểm crash.

Core dump có thể chứa bí mật. Token, mật khẩu, dữ liệu khách hàng, khóa mã hóa hoặc nội dung request có thể đang nằm trong bộ nhớ. Hãy xem core như bằng chứng nhạy cảm, không phải file log được phép gửi tự do.

2. systemd-coredump nằm ở đâu trong luồng?

Trên hệ thống dùng systemd, kernel.core_pattern thường được cấu hình để pipe core dump vào handler của systemd. Handler ngắn hạn chuyển dữ liệu qua socket cho service xử lý, thu thập metadata, tạo backtrace khi có thể và lưu core ra file ngoài — mặc định thường ở /var/lib/systemd/coredump/ — hoặc vào journal tùy cấu hình.

sysctl kernel.core_pattern
systemctl status systemd-coredump.socket
systemd-analyze cat-config systemd/coredump.conf

Nếu core_pattern trỏ sang Apport, ABRT, một agent khác hoặc một script nội bộ, coredumpctl có thể không có dữ liệu. Đừng thay đổi handler ngay giữa sự cố; trước hết hãy xác định thành phần nào đang sở hữu pipeline và nơi nó lưu bằng chứng.

Khi core_pattern bắt đầu bằng ký tự |, kernel gửi core vào stdin của chương trình userspace. Trong cơ chế pipe này, RLIMIT_CORE không được kernel áp dụng theo cách của core file truyền thống. Vì vậy ulimit -c không phải phép kiểm tra duy nhất; với service systemd còn phải xem LimitCORE=, chính sách handler và coredump.conf.

3. Triage trong 5 phút đầu

Đừng bắt đầu bằng cách mở “core gần nhất” nếu máy có nhiều dịch vụ. Ghi lại hostname, thời gian, deployment/release, boot ID, tên unit và múi giờ trước khi dữ liệu bị xoay vòng.

date --iso-8601=seconds
cat /proc/sys/kernel/random/boot_id
systemctl status payments-api.service --no-pager

sudo coredumpctl list --since "2026-10-03 09:00:00"
sudo coredumpctl list /opt/payments/bin/payments-api
sudo coredumpctl info 18427

Bảng list cho biết thời gian, PID, UID/GID, signal, executable và trạng thái core. Các trạng thái quan trọng:

Trạng tháiÝ nghĩa vận hành
presentCore ngoài journal còn tồn tại và người hiện tại có quyền truy cập.
journalCore được giữ trong journal.
truncatedDữ liệu vượt giới hạn; backtrace có thể thiếu vùng nhớ hoặc thread quan trọng.
missingMetadata còn trong journal nhưng file core ngoài đã bị dọn.
noneSự kiện có metadata nhưng core không được lưu.
errorKhông thể truy cập core, thường cần kiểm tra quyền hoặc lỗi lưu trữ.

PID có thể được tái sử dụng. Khi có nhiều kết quả, lọc thêm executable, thời gian, boot ID hoặc journal fields như COREDUMP_EXE= thay vì chọn chỉ theo PID.

sudo coredumpctl info \
  COREDUMP_EXE=/opt/payments/bin/payments-api \
  _BOOT_ID=8f4c2c6c0d2d4de2b56cfc9d48d2a317

4. Đọc metadata trước khi xuất dữ liệu

coredumpctl info thường cho biết signal, command line, executable, UID/GID, timestamp, boot ID, cgroup, unit, hostname, kiến trúc và kích thước core. Chỉ riêng metadata đã đủ loại bỏ nhiều giả thuyết:

  • SIGABRT có thể là ứng dụng chủ động gọi abort() sau assertion, không nhất thiết là truy cập bộ nhớ sai.
  • Executable path hoặc build ID khác kỳ vọng cho thấy rollout không đồng nhất.
  • Cgroup/unit khác cho thấy crash thuộc worker hoặc job phụ, không phải service đang bị nghi ngờ.
  • Nhiều core cùng executable trong vài giây là dấu hiệu crash loop; cần ưu tiên giảm tác động trước khi phân tích sâu.

Đồng thời lấy journal trong cùng cửa sổ thời gian:

sudo journalctl -u payments-api.service \
  --since "2026-10-03 09:12:00" \
  --until "2026-10-03 09:17:00" \
  --output=short-iso-precise

Không nên chỉ lọc journal bằng _PID trong khoảng dài vì PID tái sử dụng được. Ghép _BOOT_ID, unit và một cửa sổ thời gian hẹp sẽ đáng tin cậy hơn.

5. Bảo toàn bằng chứng và xuất core an toàn

Nếu chính sách cho phép phân tích ngoài máy production, xuất đúng bản ghi vào thư mục hạn chế quyền. Tránh ghi core vào thư mục dùng chung hoặc đưa thẳng lên ticket.

sudo install -d -m 0700 /var/tmp/incident-20261003
sudo coredumpctl dump 18427 \
  --output=/var/tmp/incident-20261003/payments-api.18427.core
sudo chmod 0600 /var/tmp/incident-20261003/payments-api.18427.core
sha256sum /var/tmp/incident-20261003/payments-api.18427.core

Lưu kèm output của coredumpctl info, hash, thời gian xuất, release ID, package version và người xử lý. Nếu phải chuyển file, dùng kênh được mã hóa, kiểm soát truy cập và retention ngắn. Không dùng dịch vụ chia sẻ công cộng.

Trước khi xóa hoặc dọn core, hãy xác nhận nhóm điều tra đã có bản sao hợp lệ. Dữ liệu missing không thể được phục hồi chỉ từ metadata journal.

6. Binary khớp chính xác quan trọng hơn việc “có GDB”

Core chứa bộ nhớ nhưng GDB vẫn cần executable và shared libraries phù hợp để giải mã địa chỉ. Debug symbols bổ sung tên hàm, file nguồn, số dòng và biến. Binary “cùng phiên bản” nhưng khác cờ compiler, dependency hoặc build ID có thể tạo backtrace sai.

file /opt/payments/bin/payments-api
readelf -n /opt/payments/bin/payments-api | grep -A1 'Build ID'
ldd /opt/payments/bin/payments-api

Một pipeline release tốt nên lưu theo release ID:

  • binary chưa strip hoặc separate debug symbols;
  • build ID và checksum;
  • source commit, compiler và build flags;
  • manifest shared libraries hoặc container image digest;
  • SBOM và cấu hình triển khai cần thiết để tái tạo môi trường phân tích.

Thông báo <optimized out> không đồng nghĩa core hỏng. Compiler có thể đã loại hoặc di chuyển biến. Symbols giúp nhiều nhưng không đảo ngược hoàn toàn tối ưu hóa.

7. Phân tích nhanh bằng coredumpctl và GDB

Nếu máy điều tra có đúng binary/symbols và quyền phù hợp, có thể mở trực tiếp core cuối cùng khớp điều kiện:

sudo coredumpctl debug 18427

Trong GDB, bắt đầu từ tín hiệu và mọi thread, sau đó mới đi sâu vào frame đáng ngờ:

(gdb) info threads
(gdb) thread apply all bt
(gdb) thread apply all bt full
(gdb) frame 0
(gdb) info args
(gdb) info locals
(gdb) info registers

bt cho chuỗi lời gọi của thread hiện tại; thread apply all bt rất quan trọng với server đa luồng vì thread nhận signal có thể đang phản ánh hậu quả, còn lock hoặc trạng thái gây lỗi nằm ở thread khác. Dùng bt full có chọn lọc: nó in local variables và có thể làm lộ bí mật trong terminal, transcript hoặc ticket.

Khi phân tích core đã xuất trên máy cô lập:

gdb /srv/symbols/payments-api \
  /srv/incidents/payments-api.18427.core

Nếu shared libraries nằm trong một root filesystem riêng, cấu hình set sysroot và set solib-search-path tới đúng snapshot. Không trỏ bừa vào thư viện hiện tại của máy phân tích.

8. Đọc backtrace mà không kết luận quá sớm

Frame 0 là vị trí CPU dừng, chưa chắc là nơi bug bắt đầu. Ví dụ crash trong memcpy, allocator hoặc libc thường do con trỏ/kích thước đã bị làm hỏng ở lớp gọi phía trên. Quy trình đọc nên là:

  1. Xác nhận signal và thread nhận signal.
  2. Tìm frame đầu tiên thuộc mã ứng dụng.
  3. Kiểm tra arguments, locals và invariants tại frame đó.
  4. So sánh các thread: deadlock, use-after-free và shutdown race thường cần nhìn toàn cục.
  5. Đối chiếu timestamp với request trace, deploy, health check và áp lực tài nguyên.
  6. Tạo giả thuyết có thể kiểm chứng; tái hiện bằng ASan/UBSan, test tải hoặc fault injection trong môi trường an toàn.

Một stack bị hỏng, nhiều địa chỉ ?? hoặc backtrace dừng sớm có thể do thiếu symbols, binary không khớp, core bị truncate hoặc memory corruption thật sự. Hãy phân biệt bốn trường hợp này trước khi sửa mã.

9. Container và Kubernetes: core thường thuộc về host

Container dùng kernel của host, còn handler từ core_pattern chạy theo cấu hình host. Vì thế core có thể được systemd-coredump trên node thu thập, trong khi executable và thư viện chỉ tồn tại trong image/container đã biến mất. PID nhìn từ host cũng có thể khác PID trong namespace.

Playbook phù hợp là lưu node name, pod UID, container ID, image digest, release và thời điểm crash; sau đó lấy metadata/core từ node theo chính sách của nền tảng. Dùng đúng image digest để dựng root filesystem phân tích. Với cluster managed, kiểm tra trước quyền truy cập node và cơ chế coredump của runtime — đừng giả định mọi node đều bật systemd-coredump.

Core dump không nên được ghi vào writable layer không giới hạn của container. Thiết kế quota, đường dẫn lưu trên host và quy trình chuyển bằng chứng rõ ràng trước khi sự cố xảy ra.

10. Thiết kế coredump.conf cho production

Đặt override cục bộ trong drop-in thay vì sửa file của package:

# /etc/systemd/coredump.conf.d/60-local.conf
[Coredump]
Storage=external
Compress=yes
ProcessSizeMax=2G
ExternalSizeMax=2G
MaxUse=20G
KeepFree=10G

Các số trên chỉ là ví dụ. Chọn giới hạn theo RAM tiến trình, dung lượng node, số crash đồng thời, mục tiêu điều tra và yêu cầu dữ liệu. ProcessSizeMax giới hạn lượng core được xử lý; ExternalSizeMax giới hạn core lưu ngoài; MaxUse và KeepFree bảo vệ filesystem.

Thời gian lưu file ngoài còn chịu chính sách systemd-tmpfiles. Vì journal và file core có vòng đời khác nhau, coredumpctl list vẫn có thể hiển thị metadata sau khi core thành missing. Hãy kiểm tra cả cấu hình tmpfiles, journal retention và dung lượng thực tế.

Nếu tổ chức quyết định không thu core vì rủi ro dữ liệu, tài liệu systemd hướng dẫn kết hợp:

[Coredump]
Storage=none
ProcessSizeMax=0

Đây là quyết định policy, không nên thực hiện tùy hứng trong lúc incident. Nếu tắt core, cần bù bằng crash reporting, symbols, structured logs và telemetry đủ mạnh.

11. Các lỗi điều tra thường gặp

Hiện tượngKiểm traHướng xử lý
No coredumps foundcore_pattern, quyền journal, unit LimitCORE, handler khácTìm đúng pipeline; không vội bật lại trên production.
missingtmpfiles cleanup, disk pressure, retentionDùng metadata còn lại và sửa retention cho lần sau.
truncatedProcessSizeMax/ExternalSizeMax, kích thước processĐiều chỉnh có tính toán; không tăng vô hạn.
Nhiều frame ??build ID, symbols, shared librariesLấy đúng artifact của release đã crash.
Core liên tụcrestart policy, cùng signal/executable/buildChặn crash loop, rollback/cô lập trước rồi điều tra.
Không thấy core trong containernode handler, namespace, image digestĐiều tra từ host và tái dựng đúng rootfs.

12. Runbook chuẩn hóa cho đội vận hành

  1. Giảm tác động: rollback, cô lập traffic hoặc giới hạn restart nếu crash loop gây sự cố.
  2. Định danh: ghi thời gian, host/node, boot ID, unit/pod, executable, PID, release và image digest.
  3. Khoanh đúng core: dùng list rồi info; xác nhận signal, executable, trạng thái và build.
  4. Bảo toàn: xuất core vào vùng 0700, đặt file 0600, hash và ghi chain of custody tối thiểu.
  5. Ghép artifact: lấy exact binary, symbols, libraries và source commit.
  6. Phân tích: lấy backtrace mọi thread, sau đó kiểm tra frame, arguments và locals có chọn lọc.
  7. Tương quan: ghép journal, trace, deploy, resource pressure và sự kiện hạ tầng.
  8. Kiểm chứng: tái hiện ở môi trường cô lập với sanitizer/test phù hợp.
  9. Khắc phục: sửa mã hoặc vận hành, thêm regression test và theo dõi crash theo executable/signal/build.
  10. Kết thúc an toàn: xóa bản sao theo retention, thu hồi quyền tạm và ghi lại bài học.

Kết luận

coredumpctl không chỉ là lệnh mở GDB. Giá trị thật của nó nằm ở chuỗi bằng chứng: chọn đúng sự kiện, hiểu trạng thái lưu trữ, giữ core an toàn, ghép chính xác artifact và đọc backtrace trong bối cảnh vận hành. Khi đội ngũ chuẩn bị symbols, release metadata, quota và runbook trước sự cố, một dòng “dumped core” có thể trở thành chẩn đoán có căn cứ thay vì một lần phỏng đoán trên production.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.