NULL pointer dereference in `git_worktree_lookup` on a repository without a git directory

Đang mở Phù hợp với người mới
#7,462 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
78/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c, git

Hướng nghiên cứu

Đọc src/libgit2/worktree.c tại git_worktree_lookup và so sánh cách git_worktree_list() xử lý một repository không có thư mục chung. Bắt đầu bằng cách kiểm tra các bài kiểm thử worktree hiện có để tìm các hàm trợ giúp thiết lập repository, sau đó thêm một trường hợp hồi quy chỉ sử dụng cơ sở dữ liệu đối tượng. Hoàn thành khi thao tác tra cứu trả về GIT_ENOTFOUND mà không bị crash.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả


First of all, thank you so much for maintaining libgit2; while applying our testing tool across multiple Rust crates during its evaluation, we encountered an issue in libgit2 (reached through the Rust binding git2) that I would like to bring to your attention.

git_worktree_lookup() passes a NULL repo->commondir to strlen when the repository has no git directory, for example one created with git_repository_wrap_odb().

I notice the following code may have a problem: https://github.com/libgit2/libgit2/blob/42a89d7cc9374a19e72fa57011e5fe3a99c7b3bf/src/libgit2/worktree.c#L189

Describe the bug

int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
{
    ...
    GIT_ASSERT_ARG(repo);
    GIT_ASSERT_ARG(name);

    *out = NULL;

    if ((error = git_str_join3(&path, '/', repo->commondir, "worktrees", name)) < 0)
        goto out;

A repository made by git_repository_wrap_odb() has no git directory, so repo->commondir is NULL. git_str_join3() calls strlen() on each of its three strings (src/util/str.c#L816) and reads from address 0.

git_worktree_list() uses git_str_joinpath() on the same field instead, which accepts NULL, so it does not crash in this case.

Tested on libgit2 1.9.7, the latest release (as bundled by libgit2-sys 0.18.8+1.9.7, used by git2 0.21.0). Current main (42a89d7) has the same code.

To Reproduce

  1. Create a repository without a git directory with git_odb_new + git_repository_wrap_odb.
  2. Call git_worktree_lookup(&wt, repo, "a").

Through the safe Rust binding git2 0.21.0:

fn main() {
    // a repository with an object database only, no git directory
    let repo = git2::Repository::from_odb(git2::Odb::new().unwrap()).unwrap();

    let _ = repo.find_worktree("a");
}

Expected behavior

The lookup should return "not found" (GIT_ENOTFOUND), since such a repository has no worktrees, not crash the process.

output (AddressSanitizer, libgit2 built with -fsanitize=address):

==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000
==The signal is caused by a READ memory access.
    #1 strlen
    #2 git_str_join3
    #3 git_worktree_lookup
    #4 git2::repo::Repository::find_worktree

Without AddressSanitizer the process is killed by SIGSEGV.

Suggested fix

Return "not found" when there is no common directory (src/libgit2/worktree.c, git_worktree_lookup):

*out = NULL;

/* a repository without a git directory (git_repository_wrap_odb) has no worktrees */
if (repo->commondir == NULL) {
    git_error_set(GIT_ERROR_WORKTREE, "worktree '%s' not found", name);
    return GIT_ENOTFOUND;
}

if ((error = git_str_join3(&path, '/', repo->commondir, "worktrees", name)) < 0)
    goto out;

I applied this to the libgit2 1.9.7 sources bundled in libgit2-sys. The reproducer then gets GIT_ENOTFOUND (worktree 'a' not found) with no crash.

Thank you for your time.

Ngôn ngữ chính
C
Star
10.6k
Fork
2.7k
Merge trung bình
1 ngày 5 giờ
Pull request đã merge (30 ngày)
5

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của libgit2/libgit2

Tất cả issue của libgit2/libgit2

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.