Правильный способ выхода из init в Linux режиме пользователя - PullRequest
1 голос
/ 20 апреля 2020

Я скомпилировал Linux ядро ​​5.6 в режиме пользователя с моим пользовательским initrd, созданным с помощью следующего метода:

mkdir initrd
cd initrd
mkdir bin dev etc home mnt proc sys usr
mknod dev/console c 5 1

с initrd/init.c файлом инициализации

#include <stdio.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("init\n");

    mount("none", "/proc", "proc", MS_MGC_VAL, "");
    mount("none", "/sys", "sysfs", MS_MGC_VAL, "");
    mount("none", "/dev", "devtmpfs", MS_MGC_VAL, "");

    if (access("/dev/ubda", F_OK) != -1) {
        printf("/dev/ubda exists\n");
    } else {
        printf("/dev/ubda not exists\n");
    }

    return EXIT_SUCCESS;
}

Эта программа проверяет для диска, переданного параметром ubd0=....

Скомпилировано с gcc -static -o init init.c.

После всего, что я скомпилировал ядро ​​

make mrproper
make mrproper ARCH=um
make defconfig ARCH=um
make menuconfig ARCH=um
make linux ARCH=um

Я изменил следующие параметры в файле .config (используя menuconfig)

CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE="initrd"
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y

После всего, что я пытался запустить ./linux mem=32M, и все выглядит нормально, кроме выхода

$ ./linux mem=32M
Core dump limits :
    soft - NONE
    hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking environment variables for a tempdir...none found
Checking if /dev/shm is on tmpfs...OK
Checking PROT_EXEC mmap in /dev/shm...OK
Adding 15400960 bytes to physical memory to account for exec-shield gap
Linux version 5.6.0 (root@d97bfdd0b529) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #1 Mon Apr 20 14:47:21 UTC 2020
Built 1 zonelists, mobility grouping on.  Total pages: 11788
Kernel command line: mem=32M root=98:0
Dentry cache hash table entries: 8192 (order: 4, 65536 bytes, linear)
Inode-cache hash table entries: 4096 (order: 3, 32768 bytes, linear)
mem auto-init: stack:off, heap alloc:off, heap free:off
Memory: 26524K/47808K available (2998K kernel code, 1137K rwdata, 956K rodata, 142K init, 167K bss, 21284K reserved, 0K cma-reserved)
NR_IRQS: 16
clocksource: timer: mask: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibrating delay loop... 6966.47 BogoMIPS (lpj=34832384)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512 (order: 0, 4096 bytes, linear)
Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes, linear)
Checking that host ptys support output SIGIO...Yes
Checking that host ptys support SIGIO on close...No, enabling workaround
devtmpfs: initialized
random: get_random_u32 called from bucket_table_alloc+0x118/0x141 with crng_init=0
umid_file_name : buffer too short
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 256 (order: 0, 6144 bytes, linear)
NET: Registered protocol family 16
clocksource: Switched to clocksource timer
VFS: Disk quotas dquot_6.6.0
VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
NET: Registered protocol family 2
tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes, linear)
TCP established hash table entries: 512 (order: 0, 4096 bytes, linear)
TCP bind hash table entries: 512 (order: 0, 4096 bytes, linear)
TCP: Hash tables configured (established 512 bind 512)
UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
NET: Registered protocol family 1
printk: console [stderr0] disabled
mconsole (version 2) initialized on /root/.uml/BolhBq/mconsole
Checking host MADV_REMOVE support...OK
workingset: timestamp_bits=62 max_order=13 bucket_order=0
io scheduler mq-deadline registered
io scheduler kyber registered
NET: Registered protocol family 17
9pnet: Installing 9P2000 support
Initialized stdio console driver
Console initialized on /dev/tty0
printk: console [tty0] enabled
Initializing software serial port version 1
printk: console [mc-1] enabled
Failed to initialize ubd device 0 :Couldn't determine size of device's file
epollctl add err fd 0, Operation not permitted
This architecture does not have kernel memory protection.
Run /init as init process
init
/dev/ubda not exists
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
CPU: 0 PID: 1 Comm: init Not tainted 5.6.0 #1
Stack:
 6282bcb0 602f95fa 62826000 6038c6db
 6006cd66 6001e201 6282bcc0 602f963f
 6282bde0 6003c7ee 00412000 62a8bec0
Call Trace:
 [<6006cd66>] ? printk+0x0/0x94
 [<6003d5a8>] ? exit_mm+0x0/0x223
 [<600214a8>] show_stack+0x13b/0x155
 [<602f95fa>] ? dump_stack_print_info+0xe2/0xeb
 [<6006cd66>] ? printk+0x0/0x94
 [<602f963f>] dump_stack+0x2a/0x2c
 [<6003c7ee>] panic+0x18c/0x3be
 [<6003c662>] ? panic+0x0/0x3be
 [<6008bbf6>] ? acct_collect+0x0/0x1df
 [<60022177>] ? flush_tlb_page+0x12e/0x1f5
 [<600672f2>] ? up_read+0x10/0x12
 [<60067388>] ? __percpu_up_read+0x1a/0x1c
 [<600455fd>] ? cgroup_threadgroup_change_end.isra.29+0x2e/0x30
 [<6003d5a8>] ? exit_mm+0x0/0x223
 [<6003de69>] do_exit+0x220/0x914
 [<6003f33b>] sys_exit_group+0x0/0x16
 [<6003f351>] __wake_up_parent+0x0/0x25
 [<6002345b>] handle_syscall+0x79/0xa7
 [<60036012>] userspace+0x483/0x510
 [<600201fa>] new_thread_handler+0xb0/0xb2

Как правильно выйти?

1 Ответ

4 голосов
/ 20 апреля 2020

Процесс init никогда не должен завершаться. Правильный способ выхода из init - это shutdown.

#include <linux/reboot.h>

int main(int argc, char *argv[]) {
  // ...
  // return EXIT_SUCCESS;

  sync();
  reboot(LINUX_REBOOT_MAGIC1, 
     LINUX_REBOOT_MAGIC2, 
     LINUX_REBOOT_CMD_POWER_OFF, 0);
}

Под glib c и большинством альтернативных lib c (включая uclib c, dietlib c, musl и некоторыми другими) некоторые из задействованных констант получили символьные c имена RB_ *, а библиотечный вызов представляет собой оболочку с 1 аргументом для системного вызова:

#include <sys/reboot.h>

int main(int argc, char *argv[]) {
  // ...
  // return EXIT_SUCCESS;

  sync();
  reboot(RB_POWER_OFF);
}

Для значений cmd, которые останавливают или перезапускают система, успешный вызов reboot() не возвращает.

...