LINUX.ORG.RU

По какой причине clang собирает pie executable вместо shared object ?

 ,


3

4

Вот мой код:

$ cat library.h 
#ifndef __LIBRARY_H__
#define __LIBRARY_H__

int hello_world();

#endif // __LIBRARY_H__

$ cat library.c 
#include "library.h"

int hello_world()
{
	return 42;
}

$ cat main.c 
#include 
#include "library.h"

int main(int argc, char** argv)
{
	int res = hello_world();
	printf ("%d\n", res);
	return 0;
}

Собираю командами:

$ cat build.sh 
#!/bin/bash

clang -shared -nostdlib library.c -o library.so
clang -L ./ library.so main.c

Запускаю
LD_LIBRARY_PATH=. ./a.out

проблема в том, что
$ file library.so
library.so: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped

а должен быть не pie executable

Ответ на: комментарий от Einstok_Fair

Кстати, офигей:

$ file /lib/libc-2.28.so 
/lib/libc-2.28.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=d8324f2e2fa5d960605b0e767d016739dc56b776, for GNU/Linux 3.2.0, not stripped, too many notes (256)

$ /lib/libc-2.28.so 
GNU C Library (GNU libc) stable release version 2.28.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 8.2.1 20181011 (Red Hat 8.2.1-4).
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

Deleted
()
Ответ на: комментарий от Deleted

т.е. в ней есть функция _start и при этом утилита file показывает её как «shared object» ?

Я тоже так хочу! (хотя бы вторую часть)

Einstok_Fair ★★☆
() автор топика
Ответ на: комментарий от Deleted

не вижу других путей

другие пути могут быть не в этой функции, а выше по стеку вызовов. Так, например, для библиотек могла бы вообще другая какая-нибудь функция вызываться.

Но я допускаю, что другой такой функции отдельно для библиотек нет.

Einstok_Fair ★★☆
() автор топика

Эххх ... Если на конкретной платформе генерация so по-умолчанию выключена то с вероятностью 99% она на этой платформе сломана. Смени платформу или задачу. Ну еще, как вариант, можешь использовать кросс-компилятор для создания so для других платформ. У них проблем не будет.

cvv ★★★★★
()
Ответ на: комментарий от cvv

Эххх ... Если на конкретной платформе генерация so по-умолчанию выключена то с вероятностью 99% она на этой платформе сломана. Смени платформу или задачу. Ну еще, как вариант, можешь использовать кросс-компилятор для создания so для других платформ. У них проблем не будет.

Почитай тему. У нас тут сломаны какие-то эвристики внутри утилиты file. И мы пытаемся угадать как правильно скомпилировать бинарник так, чтобы поломанный file распознал в нём разделяемую библиотеку.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Einstok_Fair

(хотя бы вторую часть)

Нашёл:

$ gcc -shared library.c -o library.so

$ file library.so 
library.so: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=3cca802ef4e1d7c8e3b70065ea08c2b2f9322764, not stripped

$ gcc -shared -Wl,-z,now library.c -o library.so

$ file library.so 
library.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=d291cddabb595c8d27aeef4d4d4d2a303bcedfea, not stripped
Источник магии найден и теперь мы можем спать спокойно.

Но, повторюсь, дело тут не в gcc или clang или ld или любой другой части тулчейна. Дело в том, как утилита file пытается угадать тип ELF-файла. При том, что на уровне формата чёткого разделения между «исполнимый файл» и «разделяемая библиотека» просто не предусмотрено.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

man ld

-z keyword
The recognized keywords are:
now
When generating an executable or shared library, mark it to tell the dynamic linker to resolve all symbols when the program is started, or when the shared library is linked to using dlopen, instead of deferring function call resolution to the point when the function is first called.

Слова эти много где встречаются
BIND_NOW
https://wiki.debian.org/Hardening#DEB_BUILD_HARDENING_BINDNOW_.28ld_-z_now.29
https://wiki.gentoo.org/wiki/Hardened/Toolchain#Default_full_binding_at_load-...
https://eklitzke.org/all-about-linkers
https://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-sha...
https://cardaci.xyz/blog/2018/03/01/overriding-shared-libraries-in-immediatel...
https://nostarch.com/download/PracticalBinary_Ch5.pdf
https://blog.quarkslab.com/have-fun-with-lief-and-executable-formats.html

Но не очень понятно, при чём тут утилита file. Наверное ты смотрел её исходный код.
$ which file
/usr/bin/file
$ qfile /usr/bin/file
sys-apps/file (/usr/bin/file)

HOMEPAGE="https://www.darwinsys.com/file/"
EGIT_REPO_URI="https://github.com/glensc/file.git"
https://github.com/file/file/blob/master/src/readelf.h#L486

дальше мысль не идёт

Einstok_Fair ★★☆
() автор топика
Последнее исправление: Einstok_Fair (всего исправлений: 3)
Ответ на: комментарий от Einstok_Fair

https://github.com/file/file/blob/master/magic/Magdir/elf#L51

>16 leshort 3 ${x?pie executable:shared object},

Совершенно непонятные символы, что такое 3, что такое leshort, зачем >16...

выше уже предлагали флаг «+x» в качестве магии, но потом выяснилось, что дело не в нём. Может быть и с этим BIND_NOW так же.

Einstok_Fair ★★☆
() автор топика
Последнее исправление: Einstok_Fair (всего исправлений: 3)
Ответ на: комментарий от sf

https://linux.die.net/man/5/magic описывает формат.

за исключением того, что не упоминает про x в описании выводимых строк.

вычисляет «${» конструкции.

Из этого кода понятно, что кроме одиночной буквы x там ничего другого быть не может.

Вместо x подставляется одна из двух строк в зависимости от значения ms->mode

ms->mode задается здесь

Мне непонятно, это работает
ms->mode = b.st.st_mode;

похоже, что в читаются байты в буфер, а эта конструкция означает какое-то конкретное поле.

struct buffer
struct stat
mode_t st_mode mode of file (see below)

ну и там флаги - +x или нет.

Т.е. конкретно этот правило проверяет - помечен ли файл как исполняемый
if (ms->mode & 0111)
восьмеричное переводим в двоичное - получается 0b01001001

Но это не та проверка, которую хочется найти. Должна быть ещё одна.

Einstok_Fair ★★☆
() автор топика
Ответ на: комментарий от Deleted

Источник магии найден и теперь мы можем спать спокойно.

мне не ясно, как это работает

$ gcc -shared -Wl,-z,now library.c -o library.so

В этой команде используется gcc, а не clang
и отсутствует опция -fPIC

Хотя странным образом оно работает...
$ clang -shared -fPIC -Wl,-z,now library.c -o library.so
$ file library.so
library.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped

Einstok_Fair ★★☆
() автор топика
Последнее исправление: Einstok_Fair (всего исправлений: 2)

Боже мой, шла вторая страница, человеку не могут сказать что у него не так.

$ clang -shared -nostdlib library.c -o liblibrary.so
$ clang -L. -llibrary main.c 
$ LD_LIBRARY_PATH=. ldd ./a.out 
        linux-vdso.so.1 (0x00007ffed27cf000)
        liblibrary.so => ./liblibrary.so (0x00007f0041523000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f004115b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0041724000)
$ LD_LIBRARY_PATH=. ./a.out 
42

Префикс lib* добавь. Флаг -lfoo означает что надо искать libfoo.so или libfoo.a

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 4)
Ответ на: комментарий от Deleted

Внутри утилиты file никаких эвристик не существует. Она тупо парсит хэдэр файла и пишет то что распарсила. Правильный ответ - на этой платформе скорее всего - никак.

cvv ★★★★★
()
Ответ на: комментарий от cvv

В file минимум 2 эврисити упомянутые в этом треде:

- исполняемый бит файла (${x?...}) - наличие (или отсутствие!) необязательного DF_I_PIE бита в DT_FLAGS_1.

Обе эвристики потому что не дают точного ответа.

anonymous
()
Ответ на: комментарий от anonymous

Исолняемый бит файла для обьектников не анализируется. Если DF_I_PIE влияет на распознавание файла как исполняемого то это баг в базе сигнатур file. Исправьте и отошлите патч. Утилита file простая как гладинльная доска. В ней нет места никаким эвристикам.

cvv ★★★★★
()
Ответ на: комментарий от Einstok_Fair

В общем, для ответа про поведение file по-прежнему было достаточно grep ;-)


$ cd /tmp
$ git clone https://github.com/file/file.git
$ cd file/src
$ grep -nrC2 — '->mode'
softmagic.c-498- switch (*ptr) {
softmagic.c-499- case 'x':
softmagic.c:500: if (ms->mode & 0111) {
softmagic.c-501- ptr = t;
softmagic.c-502- l = et - t;
--
readelf.c-1094- case DT_FLAGS_1:
readelf.c-1095- if (xdh_val == DF_1_PIE)
readelf.c:1096: ms->mode |= 0111;
readelf.c-1097- else
readelf.c:1098: ms->mode &= ~0111;
readelf.c-1099- break;
readelf.c-1100- default:
--
funcs.c-214-
funcs.c-215- buffer_init(&b, fd, buf, nb);
funcs.c:216: ms->mode = b.st.st_mode;
funcs.c-217-
funcs.c-218- if (nb == 0) {

bormant ★★★★★
()
Ответ на: комментарий от pon4ik

Ты ж сейчас про другое говоришь. Про -pie по умолчанию я знаю. И, емнип, это отличается от -fpic

Deleted
()
Ответ на: комментарий от Einstok_Fair

Именно. Суть в том что ld-linux.so запускается как «интерпретатор» динамически линкованных бинарников.

Кстати, с помощью него можно починить chmod без права запуска.

KennyMinigun ★★★★★
()
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от cvv

Внутри утилиты file никаких эвристик не существует. Она тупо парсит хэдэр файла и пишет то что распарсила.

В хедере файла тупо не написано кто он - executable или shared library. file пытается угадать по косвенным признакам. Из-за этого там периодически вылезают баги. Плюсом: непонятно как определять граничные случаи типа libc.so, которые одновременно и shared library и executable.

Правильный ответ - на этой платформе скорее всего - никак.

Да успокойся ты, мы уже поняли, что разделяемых библиотек под x86 на линуксе не бывает. Редко используемая проприетарная платформа, шоб её...

Тут в соседних темах на топик-стартера наезжают за тупые вопросы. И при этом половина ЛОРа - чёртовы наркоманы =/.

Deleted
()
Ответ на: комментарий от Deleted

В хедере файла тупо не написано кто он - executable или shared library.

Вы видели хэдер своими собственными глазами? А спеки читали?

поле хэдера со смещением 0x10, два байта, с именем e_type определяет тип файла. Список допустимых значений:

...
ET_EXEC	2	Исполняемый файл
ET_DYN	3	Разделяемый объектный файл
ET_CORE	4	Core file
...

все версии file с которыми я имел дело тупо аналищировали два вот этих байта.

cvv ★★★★★
()
Последнее исправление: cvv (всего исправлений: 2)
Ответ на: комментарий от cvv

уже разобрали исходные тексты утилиты file построчно выше в топике.

Einstok_Fair ★★☆
() автор топика
Последнее исправление: Einstok_Fair (всего исправлений: 2)
Ответ на: комментарий от cvv

Исолняемый бит файла для обьектников не анализируется.

Прочитайте тред ещё раз.

anonymous
()
Ответ на: комментарий от cvv

Это вопрос не к комитетам, а к разработчикам компилятора.

Если разработчики решили нарушить стандарт, они должны обосновать своё решение.

Einstok_Fair ★★☆
() автор топика
Ответ на: комментарий от Einstok_Fair

Здесь нет прямых нарушений. Появление PIE сделало часть стандартов морально устаревшими и неадекватными. И никто не подсуетился о сохранении консистентности.

cvv ★★★★★
()
Ответ на: комментарий от Bass

Класс. Надо будет взять во внимание :-)

cvv ★★★★★
()
Ответ на: комментарий от Einstok_Fair

Dyn/exec решение принимает линекер, не компилятор.

Не думаю, что стандарт оговаривает что либо по поводу Dyn vs. exec.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.