Thứ Tự Tìm Kiếm Của LoadLibrary
Trong quá trình lập trình hôm nay, tôi gặp phải một vấn đề khá khó hiểu. Tôi đã phát triển một thư viện mở rộng C tên là “console” cho Lua, nhưng không hiểu sao nó luôn thất bại khi tải. Sau nhiều giờ vật lộn, cuối cùng tôi phát hiện ra nguyên nhân: Bộ thông dịch Lua thực tế đang tìm thấy một file DLL cùng tên trong thư mục Windows/System32. Hóa ra hệ thống đã tồn tại một file console.dll rồi!
Tôi nhớ rằng trước đây không có vấn đề này. Tra cứu tài liệu MSDN, tôi mới hiểu ra vấn đề. Hóa ra từ Windows XP SP2 trở đi, Microsoft đã thay đổi thứ tự tìm kiếm thư viện liên kết động (DLL) mặc định. Trong Windows XP và Windows 2000 SP4 trở về sau, hệ điều hành thêm một thiết lập trong registry tại:
HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
Thiết lập này nhằm tăng cường bảo mật khi tải DLL. Ban đầu, tùy chọn này mặc định bị tắt. Tuy nhiên từ phiên bản XP SP2, Microsoft đã quyết định bật nó theo mặc định (tôi cho rằng rất ít người chủ động thay đổi thiết lập này trong registry, nên việc tắt/mở thiết lập này trước đây gần như không có khác biệt).
Với thiết lập này, thư mục hiện hành sẽ bị đẩy xuống vị trí ưu tiên thấp nhất trong thứ tự tìm kiếm. Do đó, chỉ cần vô tình trùng tên với DLL hệ thống, lệnh require của Lua sẽ không thể tìm thấy file DLL trong thư mục hiện tại. Thậm chí khi bạn cố ý chỉ định đường dẫn “.\console.dll” thì vẫn không hiệu quả (hệ thống require của Lua hoạt động như vậy), vì độ ưu tiên của đường dẫn tương đối từ thư mục hiện hành luôn ở mức thấp nhất.
Giải pháp tối ưu nhất là sửa đổi mã nguồn Lua, thay đổi dòng 128 trong file loadlib.c từ:
HINSTANCE lib = LoadLibrary(path);
thành sử dụng LoadLibraryEx:
HINSTANCE lib = LoadLibraryEx(path,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
Bổ sung: Qua trao đổi thêm, tôi nhận ra quyết định điều chỉnh thứ tự tìm kiếm DLL của Microsoft là hoàn toàn có lý. Thư mục đường dẫn hiện hành vốn là nơi tiềm ẩn nhiều rủi ro bảo mật. Thậm chí việc mở một hộp thoại chọn file cũng có thể làm thay đổi nó. Việc tải mã thực thi từ đây thực sự là một hành động mạo hiểm.
Tôi đề xuất Lua nên thay đổi toàn bộ các vị trí phụ thuộc vào đường dẫn tương đối hiện hành thành phụ thuộc vào đường dẫn tuyệt đối lúc khởi động ứng dụng. Vấn đề này không chỉ ảnh hưởng đến DLL, mà liên quan đến mọi thành phần mã thực thi trong hệ thống.