LINUX.ORG.RU

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

Если скриптовый, то может tcc

То есть переполнение в буфере можно теперь будет устроить прямо в скриптухе?

Psilocybe ★★★★
()

Я тебе скажу. Sh начало. И любые команды шелл все в других. другие шелл это просто Эхо шел

Bootmen ☆☆☆
()

Все языки идут от SH Всем посмотреть. низкоуровненые в топку!

Bootmen ☆☆☆
()
Последнее исправление: Bootmen (всего исправлений: 1)
Ответ на: Бггг... =))) от Moisha_Liberman

Отдохнул.

То что он задумал

Вообще ничего умного и хитрого не задумывал. Тупо хочу *.c.sh заставить работать с tcc через шебанг.

И таки заставил. Волшебный шебанг: #!/usr/bin/env -S /usr/bin/tcc -run -xc -w

Там что-то удивительное и мне не понятное...

$ F1=tcc_test.abc;echo -e '#!/usr/bin/tcc -run -xc -w\nmain() {printf("filename ['$F1'] yes\\n");}' > $F1; chmod +x ./$F1; ./$F1; rm ./$F1
./tcc_test.abc: error: unrecognized file type
не работает.

но в то же время:

$ F1=tcc_test.abc;echo -e '#!/usr/bin/env -S /usr/bin/tcc -run -xc -w\nmain() {printf("filename ['$F1'] yes\\n");}' > $F1; chmod +x ./$F1; ./$F1; rm ./$F1
filename [tcc_test.abc] yes
работает!

Т.е.:
1. Ключ «интерпретировать как Си» всё-таки есть -xc
2. Этот ключ почему-то не работает в прямом шебанге
3. Мало того - в формате #!/usr/bin/tcc он ведёт себя по-разному в зависимости от места: до -run или после -run: или компилируется, но не выполняется; или выполняется, но без явно указанного типа (и поэтому определяет тип по расширению файла).
4. Но ведь -w работает же! Хоть так, хоть эдак. Кажется наврал. И кажется вообще понял что происходит.

Вопрос: А как отловить execve внутри скрипта? Хотел посмотреть, что там на самом деле ядро делает с шебангом - не могу поймать strace'ом как оно параметры передает на самом деле.

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

Не. Сложно это.

То есть переполнение в буфере можно теперь будет устроить прямо в скриптухе?

В tcc есть проверка bounds checker – -b. Помогает обычно. Ну и ненужно отключать предупреждения – -w. Плохая идея, как правило.

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

Эммм...

  1. Ключ «интерпретировать как Си» всё-таки есть -xc

Есть, но я бы на него не сильно надеялся, т.к. семантика этого ключа говорит только о том, какой именно файл мы подсунули на вход – С, если -xc, asm – -xa или ещё что. В принципе, использовать можно, но идея не очень.

На мой взгляд, более «чистый» вариант всё таки настроить binfmt_misc.

  1. Этот ключ почему-то не работает в прямом шебанге

Я бы сказал что он и не должен, т.к. не для того делался.

  1. Мало того - в формате #!/usr/bin/tcc он ведёт себя по-разному в зависимости от места: до -run или после -run: или компилируется, но не выполняется; или выполняется, но без явно указанного типа (и поэтому определяет тип по расширению файла).

В принципе, он должен указываться до -run, а options как в указанном случае – tcc [options...] -run infile [arguments...].

Но вообще, если честно, то tcc это прежде всего компилятор, выполнение скриптухи это так… «приятный бонус».

Вопрос: А как отловить execve внутри скрипта? Хотел посмотреть, что там на самом деле ядро делает с шебангом - не могу поймать strace’ом как оно параметры передает на самом деле.

Just use strace -b execve ./4strace. В 4strace следующее содержимое, для простоты:

#!/usr/bin/tcc -run

#include <unistd.h>

int main(int argc, char **argv) {
	execve("./t.sh", NULL, NULL); /* And this */
	return(0);
}

Опция -b разве что и поддерживает только именно execve.

P.S. С -w всё просто – это отключение предупреждений. Плохая идея, да и не особо эта опция важна в нашем случае.

Moisha_Liberman ★★
()
Последнее исправление: Moisha_Liberman (всего исправлений: 1)
Ответ на: Эммм... от Moisha_Liberman

Спасибо.

strace -b execve

так и пытался делать - не попадает сам вызов tcc туда, только вызов самого скрипта, а не того, что там в шебанге написано.

Ладно.
Зашёл с другой стороны - навтыкал принтов в интересующие места в исходник tcc. C #!env такое:

0: </usr/local/bin/tcc>
1: <-run>
2: <-w>
3: <-xc>
4: <./tcc_test.c>
TCC_OPTION_w is set
TCC_OPTION_x is set on c
Напрямую такое:
0: </usr/local/bin/tcc>
1: <-run -w -xc>
2: <./tcc_test.c>
TCC_OPTION_w is set
TCC_OPTION_x is set on c

Понятно, что argc argv разные. Но всё равно должны были бы работать - опции-то устанавливаются и так, и эдак сначала. Где-то дальше ошибка там в tcc при разборе аргументов - сбрасывает тип файла позже во втором варианте.

Да и ладно. Я там не разберусь. Какой-то очень свой вариант разбора аргументов, слишком мудрёный для меня. Достаточно, что через env работает.

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

Так. Стоп.

так и пытался делать - не попадает сам вызов tcc туда, только вызов самого скрипта, а не того, что там в шебанге написано.

А вот этого я не совсем понял, т.к. из описания execve() следует что в int execve(const char *pathname,...) это самый pathname это может быть и бинарный файл и шелл-скрипт.

У меня в конце выхлопа strace прилетает execve("./t.sh", NULL, NULLstrace: Process 4208 detached. Т.е., в принципе, логично – я запускаю шелл-скрипт. Он и исполняется именно как скрипт.

Перекомпилил в стандартный бинарь, картина ровно та же. Чего-то не понял в томи, что нужно найти?

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

эбаут:

Pike is Extendable - with modules written in C for speed or Pike for brevity. Pike supports multiple inheritance and most other constructs you would demand from a modern programming language.

внезапно, напомнило shell на аде SparForte: github сайт

та же идея: сначала экспериментируем с галимой скриптухой – быстро, грязно, брутально.

затем получаем возможность отконпелировать в Си, в Аду либо заменить Си модулем (исходник которого который совпадает почти буквально с такой вот скриптухой, только конпелируемый)

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

И синтаксис чтоб даже не сишный

Pike

а… нет, паскаль для скриптоты

AdaScript/SparForte

anonymous
()
Ответ на: Так. Стоп. от Moisha_Liberman

что нужно найти?

Аргументы, которые передаются tcc из шебанга думал подсмотреть.

Где-то в Гугле человек говорил, что это невозможно, потому что этот execve происходит внутри другого execve. Спросил у вас - мол, может знаете какой-то хитрый фокус, а человек в Гугле заблуждается.

Раз такого фокуса нет - значит подглядывал argv изнутри tcc.

-------------

Тут вот интересное Pike люди предлагают посмотреть ) Предлагаю считать, что с tcc разобрались ) Pike забавный.

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

А! Ну да!

Где-то в Гугле человек говорил, что это невозможно, потому что этот execve происходит внутри другого execve. Спросил у вас - мол, может знаете какой-то хитрый фокус, а человек в Гугле заблуждается.

Что я сделал. Я взял ./4strace, из неё вызвал абсолютно аналогичную программу ./test, из этой программы вызвал свою глупо хихикающую программу ./t.sh. Код весь выше.

Далее делаю strace -e execve ./4strace. Получаю выхлоп:

execve("./4strace", ["./4strace"], 0x7ffd64ed0a60 /* 49 vars */) = 0
execve("./test", NULL, NULL)            = 0
execve("./t.sh", NULL, NULL)            = 0
hi-hi
+++ exited with 0 +++

Т.е., первый вызов (из tcc) производится точно по такому же вызову execve() с аргументом ./4strace, ну и дальше по коду теми же вызовами и работаем. И ./test и ./t.sh благополучно вызваны, как мы видим.

Не? Не оно?

Тут вот интересное Pike люди предлагают посмотреть ) Предлагаю считать, что с tcc разобрались ) Pike забавный.

А, не, не знаю. У меня к tcc сугубо утилитарный интерес.

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

в общем, метапрог надо было изначально писать на самом себе AdaScript/SparForte

а чо, OpenGL есть.

anonymous
()
Ответ на: А! Ну да! от Moisha_Liberman

Не? Не оно?

Не. Не оно. Есть:

$ cat ./some.c
#!/usr/bin/tcc -run -xc -w
main() {printf("Hello\n");}
Вижу:
$ strace -e execve ./some.c
execve("./some.c", ["./some.c"], 0x7fffd9554490 /* 49 vars */) = 0
Hello
А хотелось видеть внутренности, как:
$ strace -e execve tcc -run -xc -w ./some.c
execve("/usr/bin/tcc", ["tcc", "-run", "-xc", "-w", "./some.c"], 0x7fff15f52320 /* 49 vars */) = 0
Hello
Поэтому:
$ sed 's+/bin+/local/bin+g' ./some.c
и:
$ strace -e execve ./some.c
execve("./some.c", ["./some.c"], 0x7fff11aac8f0 /* 49 vars */) = 0
0: </usr/local/bin/tcc>
1: <-run -xc -w>
2: <./some.c>
TCC_OPTION_x is set on c
TCC_OPTION_w is set
Hello

Где-то в Гугле человек говорил

тут

The interpreter specified in the shebang line is executed by the kernel itself inside the execve call.

-----------

Кстати - тоже слегка удивительно мне: тот tcc, который сейчас утягивается из Git авторов очень сильно отличается от release с тем же номером. В том числе - они ещё и файлы *.h теперь добавили в C_TYPE. А сравнить libtcc.c из гита и из релиза по строкам просто нереально - они совсем разные. Формально версии 0.9.27 и там, и там.

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

Есть (странные) люди, которые go как скриптовый язык используют

Довольно удобно, я пробовал; есть шебанг для этого, JIT-компиляция, то есть компилируется только в первый запуск, а бинарники держит в кеше. То, что нужно для топикстартера, тем более что Go как-никак — Си 21-го века… Но Go всё-таки слишком вербозный для скриптового языка, Haskell оказался удобнее.

https://zignar.net/2021/07/09/why-haskell-became-my-favorite-scripting-language

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

У меня сейчас версия...

Кстати - тоже слегка удивительно мне: тот tcc, который сейчас утягивается из Git авторов очень сильно отличается от release с тем же номером.

Вот только что глянул – dev-lang/tcc-0.9.27_p20211022. Я ставил просто как emerge dev-lang/tcc и даже не парился по данному поводу. Видимо, у них идёт разработка и они не стали городить отдельную ветку почему-то.

The interpreter specified in the shebang line is executed by the kernel itself inside the execve call.

Ненене… Человек говорит почти правильно. Это справедливо для случая, если у Вас, как я Вам сразу и говорил, настроен и используется binfmt_misc. Там ниже, в том же комменте он прямо предлагает посмотреть функцию load_script:

Have a look at the load_script kernel function for more details.

load_script это функция, вот она например, это для загрузки/исполнения скрипта в kernel space -> https://elixir.bootlin.com/linux/latest/source/fs/binfmt_script.c

В «стандартном исполнении», execve() просто заменяет код вызывающего процесса на код вызываемого процесса. Даже файловые дескрипторы может не прихлопывать при замене кода. С ядром это связано, но весьма опосредовано (ну сисколлы-то в ядре должны же исполняться, не Духом же Святым оно там реализуется!), не напрямую как при использовании binfmt_misc.

Собственно, я про необходимость настройки binfmt_misc сразу поэтому и сказал. Можно «по правильному», с полной поддержкой ядра, в kernel space (хотя, если честно, это отчасти чревато), а можно просто как простой процесс, в юзерспейсе. В нашем случае это именно что userspace и ни каких делов.

Тут можно использовать отладочные подходы, типа ptrace. Но тут мне уже реально лень залезать так глубоко, да и для себя лично смысла не вижу.

А хотелось видеть внутренности, как:

Если бы мне хотелось видеть внутренности, то я бы либо извне их получал (через ptrace), либо изнутри анализом аргументов, указанных для данного скрипта (ну там getenv() каким-нибудь, например, примерно так же, как Вы сейчас получаете переменные окружения, которые внешние для Вашего скрипта), либо настроил себе binfmt_misc и смотрел бы что там происходит, либо читал бы строку запуска из вызывающего скрипта и смотрел как будет запущен следующий скрипт или читал бы те же переменные окружения из /proc/PID/environ на лету. Ну так, чисто навскидку что на ум приходит. Чудес-то не бывает, это же просто процесс.

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

Да.

никаких -b

-b это для случая, когда не справился (или даже не пробовали использовать) связку vim, syntastic, splint. Обычно их хватает. Но если генерация была на лету, то -b в наборе опций есть, можно использовать man tcc.

Moisha_Liberman ★★
()
Ответ на: Да. от Moisha_Liberman

А тебе не приходило в голову, что для скриптухи, в которой автоуправление памятью надо из коробки, эти танцы с бубном - перебор?

Но нет, предлагает грабельки расстелить.

А как там насчет двойного освобождения памяти?

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

Да всё как обычно.

Делаем файл dfree.c – здесь splint с syntastic сразу начинают орать. Делаем просто dfree, чтоб не орали.

Файл просто dfree:

#!/usr/bin/tcc -run -b
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv) {
	char* ptr = malloc(sizeof(char));
	*ptr = '0';

	free(ptr);
//	ptr = NULL; 
	free(ptr);
	return(0);
}

Выхлоп:

56440896ea68 : at free: BCHECK: freeing invalid region
./dfree:11: by main

11я строка, да оно и есть. Придётся раскомментировать // ptr = NULL и узбагоиться. =)))

Всё как обычно, всё хорошо.

Но нет, предлагает грабельки расстелить.

Ну, то есть прикопанные грабельки в другой скриптухе, да ещё «заботливо» присыпанные листвой так, что и не докопаешься до них с первого раза, это нормально.

А тебе не приходило в голову, что для скриптухи, в которой автоуправление памятью надо из коробки, эти танцы с бубном - перебор?

Нет. У меня всё нормально. И нет проблем перевести эту скриптуху в просто код на «просто С». А не учить по 10 языков и потом переписывать с языка на язык. Тут всё нужное есть практически сразу.

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

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

Обычно под JIT-компиляцией понимают генерацию исплоняемого кода прямо в памяти, а таким костыльным способом можно даже C компилировать

annulen ★★★★★
()
Ответ на: Да всё как обычно. от Moisha_Liberman

весёлый ты дядя, видимо собираешься вечно жить, раз не жалко тратить время на байтодроч без повода?

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

ОЧЕНЬ медленно, не всегда есть нужные модули в репозиториях (общесистемно ставить через pip не предлагать), ну и с virtualenv возня.

Вот во FreeBSD завезли flua (огрызок Lua 5.4), этот вариант всяко лучше Python, хотя бы тем что он искаропки.

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

ОЧЕНЬ медленно

не всем нужно быстро

общесистемно ставить через pip не предлагать

зачем общесистемно? можно в хомяк или в venv

ну и с virtualenv возня

Так это преимущество а не недостаток.

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

Кстати, недавно довелось чуть чуть кодить на lua. Матерился я на этот язык так что у здешних модеров бы инфаркт случился.

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

зачем общесистемно?

Затем, что обычно скрипты автоматизируют системную рутину. Для юзера есть мышевозный софт… да и не админское это дело — юзеропроблемы решать.

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

Кстати, недавно довелось чуть чуть кодить на lua. Матерился я на этот язык так что у здешних модеров бы инфаркт случился.

А я тут недавно getopt изобретал для flua (огрызок Lua 5.4 из базовой системы FreeBSD), и… мне понравилось.

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