Files
Deshab-OS/CODE/linux/initramfs/bin/utsm_bindmount.c
T

279 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Static mount(2) helper. Guest vdb util-linux/mount is unreadable
* (runtime ext4 checksum) and persist ld.so hits SHSTK (fault at 0).
* Built the same way as utsm_exec_daemon, which already runs in-guest.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <string.h>
#include <sys/mount.h>
#include <time.h>
#include <unistd.h>
static void wstr(const char *s)
{
(void)write(2, s, strlen(s));
}
static int do_mount(const char *src, const char *tgt,
const char *fstype, unsigned long flags, const void *data)
{
if (mount(src, tgt, fstype, flags, data) == 0)
return 0;
wstr("utsm_bindmount errno=");
if (errno >= 10) {
char d[2];
d[0] = (char)('0' + (errno / 10));
d[1] = (char)('0' + (errno % 10));
(void)write(2, d, 2);
} else {
char d = (char)('0' + errno);
(void)write(2, &d, 1);
}
wstr("\n");
return 1;
}
int main(int argc, char **argv)
{
if (argc < 3) {
wstr("usage: utsm_bindmount bind|rbind|slave|fstype|msleep|yield|setinterp|umount|nsexec ...\n");
return 2;
}
if (strcmp(argv[1], "bind") == 0 && argc >= 4)
return do_mount(argv[2], argv[3], NULL, MS_BIND, NULL);
if (strcmp(argv[1], "rbind") == 0 && argc >= 4)
return do_mount(argv[2], argv[3], NULL, MS_BIND | MS_REC, NULL);
if (strcmp(argv[1], "slave") == 0 && argc >= 3)
return do_mount(NULL, argv[2], NULL, MS_SLAVE, NULL);
if (strcmp(argv[1], "fstype") == 0 && argc >= 5)
return do_mount(argv[3], argv[4], argv[2], 0,
(argc >= 6) ? argv[5] : NULL);
if (strcmp(argv[1], "yield") == 0) {
sched_yield();
return 0;
}
if (strcmp(argv[1], "tail") == 0 && argc >= 3) {
int fd, maxlines = 40, lines = 0, i;
off_t sz, start;
static char buf[16384];
ssize_t n;
if (argc >= 4) {
const char *p = argv[3];
maxlines = 0;
while (*p >= '0' && *p <= '9') {
maxlines = maxlines * 10 + (*p - '0');
p++;
}
if (maxlines < 1)
maxlines = 40;
}
fd = open(argv[2], O_RDONLY);
if (fd < 0)
return 1;
sz = lseek(fd, 0, SEEK_END);
if (sz < 0)
sz = 0;
start = (sz > (off_t)sizeof(buf)) ? sz - (off_t)sizeof(buf) : 0;
if (lseek(fd, start, SEEK_SET) < 0)
start = 0;
n = read(fd, buf, sizeof(buf));
close(fd);
if (n <= 0)
return 1;
for (i = (int)n - 1; i >= 0; i--) {
if (buf[i] == '\n')
lines++;
if (lines > maxlines) {
i++;
break;
}
}
if (i < 0)
i = 0;
(void)write(1, buf + i, (size_t)(n - i));
return 0;
}
if (strcmp(argv[1], "msleep") == 0 && argc >= 3) {
unsigned long ms = 0;
const char *p = argv[2];
struct timespec ts;
while (*p >= '0' && *p <= '9') {
ms = ms * 10ul + (unsigned long)(*p - '0');
p++;
}
ts.tv_sec = (time_t)(ms / 1000ul);
ts.tv_nsec = (long)(ms % 1000ul) * 1000000L;
(void)nanosleep(&ts, 0);
return 0;
}
if (strcmp(argv[1], "chroot") == 0 && argc >= 4) {
int kfd;
if (chroot(argv[2]) != 0) {
wstr("utsm_bindmount: chroot failed\n");
return 1;
}
if (chdir("/") != 0) {
wstr("utsm_bindmount: chdir / failed\n");
return 1;
}
kfd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (kfd >= 0) {
const char *m = "[utsm_bindmount] inside chroot, exec next\n";
(void)write(kfd, m, strlen(m));
close(kfd);
}
execv(argv[3], argv + 3);
wstr("utsm_bindmount: exec after chroot failed path=");
wstr(argv[3]);
wstr(" errno=");
if (errno >= 10) {
char d[2];
d[0] = (char)('0' + (errno / 10));
d[1] = (char)('0' + (errno % 10));
(void)write(2, d, 2);
} else {
char d = (char)('0' + errno);
(void)write(2, &d, 1);
}
wstr("\n");
return 127;
}
if (strcmp(argv[1], "nsexec") == 0 && argc >= 3) {
int kfd;
int u1, u2, u3, pr;
kfd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
if (unshare(CLONE_NEWNS) != 0) {
wstr("nsexec: unshare failed\n");
if (kfd >= 0) {
const char *m = "[nsexec] unshare failed\n";
(void)write(kfd, m, strlen(m));
close(kfd);
}
return 1;
}
pr = mount((const char *)0, "/", (const char *)0,
MS_REC | MS_PRIVATE, (const void *)0);
if (pr != 0) {
pr = mount((const char *)0, "/", (const char *)0,
MS_REC | MS_SLAVE, (const void *)0);
}
/* BUG-XORG-SEGV 根修(2026-09-20):此处 umount 会把 chroot 里的
* vdb ld.so bind 拆掉,Xorg 落回 persist ld.so —— 其 0x15ded 处
* NULL+8 segfault(Xorg/dbus 均复现)。12:18 好运行中这些 bind
* 全部保持激活(shell umount 均 EBUSY),Xorg 用 vdb ld.so 存活。
* 恢复该行为:nsexec 不再卸载 ld.so bind。 */
u1 = -1;
u2 = -1;
u3 = -1;
if (kfd >= 0) {
const char *m = "[nsexec] umount done, exec Xorg\n";
(void)write(kfd, m, strlen(m));
if (u1 == 0)
m = "[nsexec] umount lib64 ld.so ok\n";
else
m = "[nsexec] umount lib64 ld.so FAIL\n";
(void)write(kfd, m, strlen(m));
if (u2 == 0)
m = "[nsexec] umount usr/lib ld.so ok\n";
else
m = "[nsexec] umount usr/lib ld.so FAIL\n";
(void)write(kfd, m, strlen(m));
(void)pr;
(void)u3;
close(kfd);
}
execv(argv[2], argv + 2);
wstr("nsexec: exec failed\n");
return 127;
}
if (strcmp(argv[1], "umount") == 0 && argc >= 3) {
if (umount(argv[2]) == 0)
return 0;
wstr("umount errno=");
if (errno >= 10) {
char d[2];
d[0] = (char)('0' + (errno / 10));
d[1] = (char)('0' + (errno % 10));
(void)write(2, d, 2);
} else {
char d = (char)('0' + errno);
(void)write(2, &d, 1);
}
wstr("\n");
return 1;
}
if (strcmp(argv[1], "setinterp") == 0 && argc >= 4) {
int fd;
unsigned char eh[64];
unsigned long phoff = 0, nlen;
unsigned short phentsize = 0, phnum = 0, i;
const char *ni = argv[3];
nlen = strlen(ni) + 1;
fd = open(argv[2], O_RDWR);
if (fd < 0) {
wstr("setinterp: open failed\n");
return 1;
}
if (read(fd, eh, 64) != 64 || eh[0] != 0x7f || eh[4] != 2) {
wstr("setinterp: not elf64\n");
close(fd);
return 1;
}
memcpy(&phoff, eh + 32, 8);
memcpy(&phentsize, eh + 54, 2);
memcpy(&phnum, eh + 56, 2);
for (i = 0; i < phnum; i++) {
unsigned char ph[56];
unsigned int type = 0;
unsigned long off = 0, filesz = 0;
if (lseek(fd, (off_t)(phoff + (unsigned long)i * phentsize),
SEEK_SET) < 0)
break;
if (read(fd, ph, 56) != 56)
break;
memcpy(&type, ph, 4);
if (type != 3)
continue;
memcpy(&off, ph + 8, 8);
memcpy(&filesz, ph + 32, 8);
if (nlen > filesz) {
wstr("setinterp: path too long\n");
close(fd);
return 1;
}
if (lseek(fd, (off_t)off, SEEK_SET) < 0) {
close(fd);
return 1;
}
if (write(fd, ni, nlen) != (ssize_t)nlen) {
close(fd);
return 1;
}
if (filesz > nlen) {
unsigned char z[32];
unsigned long pad = filesz - nlen;
memset(z, 0, sizeof z);
while (pad) {
unsigned long c = pad > sizeof z ? sizeof z : pad;
if (write(fd, z, c) != (ssize_t)c) {
close(fd);
return 1;
}
pad -= c;
}
}
close(fd);
wstr("setinterp: ok\n");
return 0;
}
wstr("setinterp: no PT_INTERP\n");
close(fd);
return 1;
}
wstr("utsm_bindmount: bad args\n");
return 2;
}