在看ldd3的时候,发现了书上说的user mode linux,故实践了一把
主要步骤为
编译内核为um版本
创建rootfs的ext4镜像
启动内核
设置网络环境
在ubuntu机器里面直接拉取对应的内核源码包 linux-source-5.13.0 对应国内清华源地址如下
https://mirrors.tuna.tsinghua.edu.cn/ubuntu/pool/main/l/linux/
对应的deb为
linux-source-5.13.0_5.13.0-37.42_all.deb
直接安装后,可以得到
/usr/src/linux-source-5.13.0/linux-source-5.13.0.tar.bz2
解压
tar xvjf linux-source-5.13.0.tar.bz2
编译
make ARCH=um defconfig make ARCH=um menuconfig make ARCH=um -j8
编译遇到问题,一般是deb包少安装了,根据对应情况安装即可。
编译完成之后,会存在一个二进制
# file linux linux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=d2f9a2cb99247191eaa4e592eeedc6bd2a8c021d, with debug_info, not stripped
可以知道,编译uml只能是x86平台,arm64就不用想了
# find arch/ | grep Makefile.um arch/x86/Makefile.um
dd if=/dev/urandom of=rootfs.img count=1024 mkfs.ext4 rootfs.img resize2fs rootfs.img 500M
下载ubuntu2004的base版本
可以得到 focal-base-amd64.tar.gz
mkdir rootfs mount rootfs.img rootfs tar xvzf focal-base-amd64.tar.gz -C rootfs chroot rootfs adduser kylin umount rootfs e2fsck -fy rootfs.img
至此就得到了最基本的系统环境。
启动内核就是给linux二进制传参数
./linux --help 可以看到对应的介绍
这里我的启动命令如下
./linux ubd0=rootfs.img rw mem=1024m eth0=tuntap,tap3,72:d4:bc:87:80:c9,192.168.0.100 init=/sbin/init
ubd0是uml默认挂载的root,这里指定我们制作的ubuntu-base
rw同bootargs一样,指明读写挂载
mem指明可用内存为1G
eth0=***指明网卡设备使用的信息
init指明内核第一个运行的程序为systemd
启动之后,终端会出现如下log
[ OK ] Reached target Graphical Interface. Starting Update UTMP about System Runlevel Changes... [ OK ] Finished Update UTMP about System Runlevel Changes.
此时,登录系统可以通过screen命令,因为uml默认使用/dev/pts/4作为tty1来login。
直接输入
screen /dev/pts/4
即可看到login程序,输入正确的账户密码即可登录
此时启动的linux系统,无法正常和外接进行网络连接,所以需要启动网络,这样可以利用sshd来进行登录
在实体机上:
ip tuntap add tap3 mode tap group tangfeng chown root:tangfeng /dev/net/tun ip addr add 192.168.0.100/24 dev tap3 ip link set dev tap3 up echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/conf/tap3/proxy_arp iptables -t nat -I POSTROUTING -o enp2s0 -j MASQUERADE iptables -I FORWARD -i tap3 -j ACCEPT iptables -I FORWARD -o tap3 -j ACCEPT
这里tap3是通过tun创建的虚拟网卡,默认ip为任意网段的ip即可。用于和虚拟机内的linux系统进行通信
设置好之后如下
# ifconfig tap3 tap3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.0.100 netmask 255.255.255.0 broadcast 0.0.0.0 inet6 fe80::70d4:bcff:fe87:80c9 prefixlen 64 scopeid 0x20<link> ether 72:d4:bc:87:80:c9 txqueuelen 1000 (以太网) RX packets 1945 bytes 177904 (177.9 KB) RX errors 0 dropped 147 overruns 0 frame 0 TX packets 2991 bytes 3683367 (3.6 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
在虚拟机上:
ip link set dev eth0 up ip addr add 192.168.0.200/24 dev eth0 ip route add default via 192.168.0.100 chmod 777 /tmp
设置好之后,如下
~# ifconfig eth0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.0.200 netmask 255.255.255.0 broadcast 0.0.0.0 ether 72:d4:bc:87:80:c9 txqueuelen 1000 (Ethernet) RX packets 8 bytes 636 (636.0 B) RX errors 0 dropped 6 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 5
在虚拟机内还需要指明dns,这样才能够正常解析域名
echo 'nameserver 8.8.8.8' > /etc/resolv.conf
大功告成,现在可以使用tap3网卡登录192.168.0.200地址了。这里实验一下
# ssh kylin@192.168.0.200 kylin@192.168.0.200's password: Welcome to Ubuntu 20.04.4 LTS (GNU/Linux 5.13.19 x86_64
接下来就可以为所欲为了
https://wiki.archlinux.org/index.php?title=User-mode_Linux
http://uml.devloop.org.uk/howto.html
https://www.kernel.org/doc/html/v5.9/virt/uml/user_mode_linux.html
https://www.kernel.org/doc/html/v5.13/virt/uml/user_mode_linux_howto_v2.html?highlight=uml
sysrq是linux的一种调试手段,经常是因为系统挂死,但内核并没有完全死掉的情况下,通过对内核下发组合按键,从而拿到必要的内核信息。
CONFIG_MAGIC_SYSRQ=y CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
root@ywen233:~# sysctl -a | grep sysrq kernel.sysrq = 176
0 - disable sysrq completely 1 - enable all functions of sysrq >1 - bitmask of allowed sysrq functions (see below for detailed function description): 2 - enable control of console logging level 4 - enable control of keyboard (SAK, unraw) 8 - enable debugging dumps of processes etc. 16 - enable sync command 32 - enable remount read-only 64 - enable signalling of processes (term, kill, oom-kill) 128 - allow reboot/poweroff 256 - allow nicing of all RT tasks
通过alt+sysrq组合按键触发
通过echo /proc/sysrq-trigger触发
可触发类型
0-9 设定终端输出的内核 log 优先级 b 立即重启系统 c 内核live reboot,并输出错误信息 d 显示所有排它锁(显示所有被持有的锁) e 向除 init 外进程发送 SIGTERM 信号,让其自行结束 f 人为触发 OOM Killer (out of memory) g 当进入内核模式时,以 framebuttter 代替输出(kgdb(内核调试器)使用) h 输出帮助 i 向除 init 以外所有进程发送 SIGKILL 信号,强制结束进程 k 安全访问密钥(SAK)杀死当前虚拟控制台上的所有程序 l 显示所有活动cpu的堆栈回溯。 m 内存使用信息(将当前内存信息转储到您的控制台。) n 重置所有进程的 nice(优先级) o 关机 p 输出cpu 寄存器信息 q Display all active high-resolution timers and clock sources. r 把键盘设置为 ASCII 模式,使按键可以穿透 x server 捕捉传递给内核 s 同步缓冲区数据到硬盘 t 输出进程列表(将当前任务及其信息的列表转储到您的控制台。) u 重新挂载所有文件系统为只读模式 v 输出 Voyager SMP 处理信息 w 输出 block(d状态)进程列表
在看LDD3时发现可以通过TIOCLINUX的ioctl控制内核日志输出。其代码可以如下:
#include <stdio.h> #include <fcntl.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <string.h> int main( int argc, char **argv ) { char bytes[ 2 ] = { 11, 0 }; // 11 is the TIOCLINUX command-number if ( argc == 2 ) bytes[1] = atoi( argv[1] ); // console id-number else { fprintf( stderr, "%s: need a single argument\n", argv[0] ); exit(1); } int fd = open( "/dev/console", O_RDWR ); // <--- added if ( fd < 0 ) { perror( "/dev/console" ); exit(1); } // <--- added if ( ioctl( fd, TIOCLINUX, bytes ) < 0 ) // <--- changed { fprintf( stderr, "%s: ioctl( fd, TIOCLINUX ): %s\n", // <--- argv[0], strerror( errno ) ); exit(1); } exit(0); }
通过gcc编译
gcc setconsole.c -o setconsole
查看系统默认console上绑定的tty
cat /sys/devices/virtual/tty/console/active tty0
如果内核日志需要定向到其他tty上,可以如下运行
让内核日志在只在tty3上出现
./setconsole 3 # tty3上会出现内核日志,其他tty不会有内核日志
让内核日志在所有的tty上出现
./setconsole 0 # 所有可关联的tty都会出现内核日志
在装ubuntu的过程中,boot默认设置成了200M,不过200M对存放内核来说是不够用的,所以容易出现更新内核容量不够,更新initrd容量不够等问题
这里说明怎么扩容boot分区。
root@ywen233:~# lsblk sda 8:0 0 111.6G 0 disk ├─sda1 8:1 0 94M 0 part /boot/efi ├─sda2 8:2 0 191M 0 part └─sda3 8:3 0 111.3G 0 part / sdb 8:16 0 931.5G 0 disk ├─sdb1 8:17 0 193.4G 0 part ├─sdb2 8:18 0 403.6G 0 part ├─sdb3 8:19 0 513M 0 part ├─sdb4 8:20 0 2G 0 part /boot └─sdb5 8:21 0 332.1G 0 part
通过fdisk可以创建一个2G的分区
fdisk /dev/sdb n 4 /dev/sdb4 2048 4095999 4093952 2G Linux 文件系统 w
将原boot文件放到新的分区下
mkfs.ext4 /dev/sdb4 mount /dev/sdb4 /mnt cp -rf /boot/ /mnt
修改fstab为新的boot分区
root@ywen233:~# ls -lh /dev/disk/by-uuid/ | grep sdb4 lrwxrwxrwx 1 root root 10 3月 30 14:57 2ba486d2-9605-49dc-a8cf-4f27b1fcbc71 -> ../../sdb4 vim /etc/fstab UUID=2ba486d2-9605-49dc-a8cf-4f27b1fcbc71 /boot ext4 defaults 0 2
然后重启即可。
[name] --共享的名字 comment=this is Linux share directory --说明 path=/home/share --目录路径 public=yes --是否可见,no为看不到 read only=yes --是否只读 create mode=0700 --建立的文件默认的权限掩码 directory mode=0755 --如果有可写权限,建立的目录默认的权限掩码 guest ok = yes --来宾是否可见,和public是差不多的 browseable = yes--指定该共享是否可被浏览 writable=yes --是否允许用户在此目录下可写,no为不可些,如果可写,还需要目录具有w权限 [work] comment=this is Linux share directory path=/root/ public=yes read only=yes create mode=0777 directory mode=0777 guest ok = yes browseable = yes writeable = yes
sudo vim /etc/samba/smb.conf
在配置文件的“[global]”节的最后,加上下面三条设置:
follow symlinks = yes wide links = yes unix extensions = no
然后保存退出,最后重启下samba
sudo /etc/init.d/samba restart
sudo cp /usr/share/samba/smb.conf /etc/samba/
需要增加
security = user map to guest = Bad User
然后用 testparm smb.conf 测试conf是否正常