Điều gì có thể làm cho việc truyền init = / path / to / chương trình vào kernel không khởi động chương trình như init?


13

Tôi đang cố gắng gỡ lỗi một tập lệnh init trên hệ thống Linux; Tôi đang cố gắng chuyển init=/bin/shđến kernel để làm cho nó bắt đầu shmà không bắt đầu initđể tôi có thể chạy qua chuỗi init theo cách thủ công.

Những gì tôi đã tìm thấy là kernel đang bắt đầu init. Trong quá trình khởi động, một trong các thông báo printk là dòng lệnh và điều đó cho thấy rằng dòng đang được đặt đúng; Ngoài ra, tôi có thể ảnh hưởng đến những thứ khác bằng cách sử dụng dòng lệnh kernel. Tôi đã kiểm tra để đảm bảo đường dẫn tồn tại; nó làm

Đây là một hệ thống busybox và init là một symlink đến busybox; Vì vậy, để đảm bảo busybox không thực hiện phép thuật lạ khi PID của nó là 1, tôi cũng đã thử chạy chương trình non-busybox dưới dạng init; điều đó cũng không hiệu quả. Dường như bất kể tôi làm gì, init đều chạy.

Điều gì có thể gây ra hành vi này?


Bản phân phối cơ sở đang sử dụng busybox để làm initgì? Họ có thể chỉ đơn giản là bỏ qua dòng lệnh ... bạn có thể muốn kiểm tra initrd và xem các tập lệnh đang thực sự làm gì.
Aaron D. Marasco

Đó không phải là bất kỳ bản phân phối nào - đó là bản dựng của riêng tôi; đó là lý do tại sao tôi đang cố gắng gỡ lỗi các tập lệnh init.
Shawn J. Goff

Câu trả lời:


3

Nhìn vào nguồn nhân Linux, tôi thấy rằng nếu tệp / init tồn tại, kernel sẽ luôn cố gắng chạy nó với giả định rằng nó đang thực hiện khởi động ramdisk. Kiểm tra hệ thống của bạn để xem nếu / init tồn tại, nếu có, thì đó có lẽ là vấn đề của bạn.


Trên thực tế, nó kiểm tra execute_commandđầu tiên, xuất phát từ init=tham số dòng lệnh kernel . Nếu nó không thể thực thi nó, nó sẽ in một cảnh báo và cố gắng chạy initở nhiều vị trí khác nhau. Đây là trong init/main.cchức năng init_post(). Tôi đã xem qua các thông điệp printk kernel và tìm thấy cảnh báo trong đầu ra của kernel, vì vậy bây giờ tôi phải tìm ra lý do tại sao nó không thể bắt đầu / bin / sh hoặc bất cứ điều gì khác mà tôi cố gắng bắt đầu.
Shawn J. Goff

Mã tôi đã xem (v3.2.2 tôi nghĩ) đã kiểm tra bộ ramdisk_execute_command nếu nó không được đặt và sau đó thử chạy nó, vì vậy bạn không được như vậy. Quá tệ, vì tôi đã không thấy bất cứ điều gì khác sẽ giải thích nó.
Kyle Jones

Bạn phải sử dụng rdinitkhi khởi động từ đĩa RAM rõ ràng: unix.stackexchange.com/a/430614/32558
Ciro Santilli新疆改造中心法轮功六四事件

8

shenanigans initrd

Nếu bạn đang sử dụng initrd hoặc initramfs, hãy ghi nhớ những điều sau:

  • rdinit= được sử dụng thay vì init=

  • nếu rdinit=không được đưa ra, các đường dẫn mặc định cố gắng là: /sbin/init, /etc/init, /bin/init/bin/shnhưng không/init

    Khi không sử dụng initrd, /initlà đường dẫn đầu tiên được thử, tiếp theo là các đường dẫn khác.

v4.15 RTFS: mọi thứ được chứa trong tệp https://github.com/torvalds/linux/blob/v4.15/init/main.c .

Đầu tiên chúng ta học được rằng:

  • execute_comand là bất cứ điều gì được truyền đến: init=
  • ramdisk_execute_command là bất cứ điều gì được truyền đến: rdinit=

như có thể thấy từ:

static int __init init_setup(char *str)
{
    unsigned int i;

    execute_command = str;
    /*
    * In case LILO is going to boot us with default command line,
    * it prepends "auto" before the whole cmdline which makes
    * the shell think it should execute a script with such name.
    * So we ignore all arguments entered _before_ init=... [MJ]
    */
    for (i = 1; i < MAX_INIT_ARGS; i++)
        argv_init[i] = NULL;
    return 1;
}
__setup("init=", init_setup);

static int __init rdinit_setup(char *str)
{
    unsigned int i;

    ramdisk_execute_command = str;
    /* See "auto" comment in init_setup */
    for (i = 1; i < MAX_INIT_ARGS; i++)
        argv_init[i] = NULL;
    return 1;
}
__setup("rdinit=", rdinit_setup);

đâu __setuplà một cách kỳ diệu để xử lý các tham số dòng lệnh.

start_kernel, kernel "entry point", gọi rest_init, mà "gọi" kernel_inittrên một luồng:

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

Sau đó, kernel_initkhông:

static int __ref kernel_init(void *unused)
{
    int ret;

    kernel_init_freeable();

    [...]

    if (ramdisk_execute_command) {
        ret = run_init_process(ramdisk_execute_command);
        if (!ret)
            return 0;
        pr_err("Failed to execute %s (error %d)\n",
            ramdisk_execute_command, ret);
    }

    [...]

    if (execute_command) {
        ret = run_init_process(execute_command);
        if (!ret)
            return 0;
        panic("Requested init %s failed (error %d).",
            execute_command, ret);
    }
    if (!try_to_run_init_process("/sbin/init") ||
        !try_to_run_init_process("/etc/init") ||
        !try_to_run_init_process("/bin/init") ||
        !try_to_run_init_process("/bin/sh"))
        return 0;

    panic("No working init found.  Try passing init= option to kernel. "
        "See Linux Documentation/admin-guide/init.rst for guidance.");
}

kernel_init_freeablekhông:

static noinline void __init kernel_init_freeable(void)
{

    [...]

    if (!ramdisk_execute_command)
        ramdisk_execute_command = "/init";

    if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
        ramdisk_execute_command = NULL;
        prepare_namespace();
    }

TODO: hiểu sys_access.

Cũng lưu ý rằng có sự khác biệt hơn nữa giữa ram inits và non-ram inits, ví dụ như xử lý giao diện điều khiển: Sự khác biệt trong việc thực thi init với nhúng initramfs bên ngoài?



0

Bạn có thể tùy chỉnh nhân Linux của mình và biên dịch lại nó. Đối với kernel 4.9, Chỉnh sửa chức năng "kernel_init" trong init / main.c và thử chạy dòng sau:

try_to_run_init_process("/bin/sh")

Ngoài ra, nó có thể được gây ra bởi các tham số kernel được truyền bởi BootLoader.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.