สิ่งที่ทำให้การส่ง init = / path / to / program ไปยังเคอร์เนลไม่ได้เริ่มโปรแกรมในฐานะ init?


13

ฉันพยายามดีบักสคริปต์ init บนระบบ Linux ฉันพยายามที่จะส่งผ่านinit=/bin/shไปยังเคอร์เนลเพื่อให้เริ่มต้นshโดยไม่ต้องเริ่มต้นinitเพื่อให้ฉันสามารถทำงานผ่านลำดับ init ด้วยตนเอง

สิ่งที่ฉันได้พบคือเคอร์เนลเริ่มต้นinitแล้ว ระหว่างการบูทเครื่องข้อความหนึ่งใน printk คือบรรทัดคำสั่งและนั่นแสดงว่าบรรทัดนั้นถูกตั้งค่าอย่างเหมาะสม นอกจากนี้ฉันสามารถส่งผลกระทบต่อสิ่งอื่น ๆ โดยใช้บรรทัดคำสั่งเคอร์เนล ฉันได้ตรวจสอบเพื่อให้แน่ใจว่าเส้นทางนั้นมีอยู่; มันทำ

นี่คือระบบ busybox และ init เป็น symlink ไปยัง busybox; ดังนั้นเพื่อให้แน่ใจว่า busybox ไม่ได้ใช้เวทมนตร์แปลก ๆ เมื่อ PID ของมันคือ 1 ฉันก็ลองใช้โปรแกรมที่ไม่ยุ่งในฐานะ init ที่ไม่ทำงานเช่นกัน ดูเหมือนว่าไม่ว่าฉันจะทำอะไร init ก็จะถูกเรียกใช้

สิ่งที่อาจทำให้เกิดพฤติกรรมนี้


distro พื้นฐานที่ใช้ busybox มีไว้เพื่อinitอะไร พวกเขาอาจละเลยบรรทัดคำสั่ง ... คุณอาจต้องการตรวจสอบ initrdและดูว่าสคริปต์กำลังทำอะไรอยู่
Aaron D. Marasco

ไม่ใช่ distro ใด ๆ - เป็นงานสร้างของฉันเอง นี่คือสาเหตุที่ฉันพยายามดีบักสคริปต์เริ่มต้น
Shawn J. Goff

คำตอบ:


3

ดูที่ลินุกซ์เคอร์เนลซอร์สฉันเห็นว่าถ้าไฟล์ / init มีอยู่เคอร์เนลจะพยายามเรียกใช้บนสมมติฐานที่ว่ามันทำบูท ramdisk อยู่เสมอ ตรวจสอบระบบของคุณเพื่อดูว่า / init มีอยู่ถ้าเป็นเช่นนั้นนั่นอาจเป็นปัญหาของคุณ


ที่จริงมันตรวจสอบexecute_commandก่อนซึ่งมาจากinit=พารามิเตอร์บรรทัดคำสั่งเคอร์เนล หากไม่สามารถดำเนินการได้จะพิมพ์คำเตือนและพยายามเรียกใช้initในตำแหน่งต่างๆ นี้อยู่ในในการทำงานinit/main.c init_post()ฉันตรวจดูข้อความของเคอร์เนล printk และพบคำเตือนในผลลัพธ์ของเคอร์เนลดังนั้นตอนนี้ฉันต้องหาสาเหตุที่มันไม่สามารถเริ่ม / bin / sh หรืออะไรก็ได้ที่ฉันพยายามจะเริ่ม
Shawn J. Goff

รหัสที่ฉันดู (v3.2.2 ฉันคิดว่า) ตรวจสอบการตั้งค่า ramdisk_execute_command หากยังไม่ได้ตั้งค่าจากนั้นลองเรียกใช้ดังนั้นคุณจะต้องไม่เป็นกระแสนั้น แย่มากเพราะฉันไม่เห็นอะไรเลยที่จะอธิบาย
Kyle Jones

คุณต้องใช้rdinitเมื่อทำการบูทจาก ramdisk: unix.stackexchange.com/a/430614/32558
Ciro Santilli 新疆改造中心中心法轮功事件事件

8

มณฑลเสฉวน

หากคุณใช้ initrd หรือ initramfs โปรดคำนึงถึงสิ่งต่อไปนี้:

  • rdinit= ถูกใช้แทน init=

  • ถ้าrdinit=ไม่ได้รับเส้นทางเริ่มต้นความพยายามที่มี: /sbin/init, /etc/init, /bin/initและ/bin/shแต่ไม่/init

    เมื่อไม่ได้ใช้ initrd /initจะมีการลองเส้นทางแรกแล้วตามด้วยเส้นทางอื่น

v4.15 RTFS: ทุกอย่างอยู่ในhttps://github.com/torvalds/linux/blob/v4.15/init/main.cไฟล์

ก่อนอื่นเราเรียนรู้ว่า:

  • execute_comand อะไรก็ตามที่ถูกส่งผ่านไปยัง: init=
  • ramdisk_execute_command อะไรก็ตามที่ถูกส่งผ่านไปยัง: rdinit=

ที่สามารถเห็นได้จาก:

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);

ซึ่ง__setupเป็นวิธีที่วิเศษในการจัดการพารามิเตอร์บรรทัดคำสั่ง

start_kernelเคอร์เนล "จุดเข้าใช้งาน" การโทรrest_initซึ่ง "เรียก" kernel_initบนเธรด:

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

จากนั้นkernel_initทำ:

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_freeableทำ:

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();
    }

สิ่งที่ต้องทำ: sys_accessเข้าใจ

นอกจากนี้โปรดทราบว่ามีความแตกต่างเพิ่มเติมระหว่างหน่วยความจำแรมและหน่วยความจำที่ไม่ใช่หน่วยความจำเช่นการจัดการคอนโซล: ความแตกต่างในการดำเนินการของ init กับการฝังตัวกับการเริ่มต้นภายนอก?


4

บน

https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt

ฉันพบ:

เมื่อทำการดีบั๊กระบบไฟล์รูทปกติก็สามารถบูตได้ด้วย "init = / bin / sh" ค่าเริ่มต้นที่เทียบเท่าคือ "rdinit = / bin / sh" และมันก็มีประโยชน์เหมือนกัน

ดังนั้นอาจลอง ridinit = / bin / sh


0

คุณสามารถปรับแต่งเคอร์เนล Linux ของคุณและทำการคอมไพล์ใหม่ได้ สำหรับเคอร์เนล 4.9 ให้แก้ไขฟังก์ชัน "kernel_init" ใน init / main.c และลองเรียกใช้บรรทัดต่อไปนี้ก่อน:

try_to_run_init_process("/bin/sh")

นอกจากนี้อาจเกิดจากพารามิเตอร์เคอร์เนลที่ส่งผ่านโดย BootLoader

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.