distr1 / distri

a Linux distribution to research fast package management
https://distr1.org
Other
536 stars 26 forks source link

dracut generates non-booting initrd when run on distri #8

Closed stapelberg closed 4 years ago

stapelberg commented 5 years ago

The initrd generated by distri pack works fine, but when I try to create a new one, that results in a non-booting system. Deserves a closer look.

stapelberg commented 5 years ago

This might be almost certainly is due to commit 37a067378ed4f7ae85a07e4a13b615d7e0ca9312, after which our dracut patch is no longer effective.

stapelberg commented 5 years ago

Also, commit 19f342071283f4d78353bdbac8d6849809927f93 might result in the /init binary in the initrd not being able to locate shared libraries anymore. Perhaps we should build systemd with a full rpath as an exception.

stapelberg commented 5 years ago

This is confirmed fixed as of git commit 64e935dabc767cc06a15cc14d5002692f78d5227

stapelberg commented 4 years ago

Running into this again, this time with the Linux 5.4.6 initramfs, which is not bootable when generated on my laptop running distri.

stapelberg commented 4 years ago

Looks like the issue is that systemd requested /ro/glibc-amd64-2.27-3/out/lib/ld-linux-x86-64.so.2 as interpreter, but dracut only copied glibc-amd64-2.27-1’s ld-linux file.

This is a non-issue when using distri pack as there is only one version of glibc in the environment.

I think we need to patch dracut to explicitly read the interpreter ELF section and copy that file instead of using ldd, which doesn’t print what we want here:

% ldd init | grep ld-linux
    /ro/glibc-amd64-2.27-3/out/lib/ld-linux-x86-64.so.2 => /ro/glibc-amd64-2.27-1/out/lib/ld-linux-x86-64.so.2 (0x00007f1c2a17e000)
stapelberg commented 4 years ago

Proof-of-concept for reading the ELF interpreter programmatically:

char *read_elf_interp(const char *filename) {
  char *res = NULL;
  int fd = open(filename, O_RDONLY, 0);
  if (fd < 0) {
    err(EXIT_FAILURE, "open %s", filename);
  }
  Elf *e = elf_begin(fd, ELF_C_READ, NULL);
  if (e == NULL) {
    errx(EXIT_FAILURE, "elf_begin: %s", elf_errmsg(-1));
  }
  if (elf_kind(e) != ELF_K_ELF) {
    goto out;
  }

  GElf_Ehdr ehdr;
  if (gelf_getehdr(e, &ehdr) == NULL) {
    goto out;
  }

  for (int i = 0; i < ehdr.e_phnum; i++) {
    GElf_Phdr mem;
    GElf_Phdr *phdr = gelf_getphdr(e, i, &mem);
    if (phdr->p_type != PT_INTERP) {
      continue;
    }
    size_t maxsize;
    char *filedata = elf_rawfile(e, &maxsize);
    if (filedata == NULL || phdr->p_offset >= maxsize) {
      continue;
    }
    res = strdup(filedata + phdr->p_offset);
    break;
  }

 out:
  elf_end(e);
  close(fd);
  return res;
}