Отдельная среда с различными / bin / sh

typedef void (make_request_fn) (struct request_queue *q, struct bio *bio);

Это не объявление функции. Это определение типа функции. Позже в том же файле include/linux/blkdev.h, строка 299, такое же имя получает поле в структуре request_queue.

А в файле drivers/md/bcache/request.c, в строке 1140, этому полю присвоена функция flash_dev_make_request, что заставляет вас думать, что вы вызываете функцию make_request_fn(), но на самом деле вы вызываете flash_dev_make_request().

Это действительно базовый способ обеспечения инкапсуляции и полиморфизма и действительно базовая модель ООП в C.

1
12.09.2018, 13:28
5 ответов

Мне удалось добиться почти того, что я изначально хотел, используя пространства имен монтирования . (В моем первоначальном решении также использовался unionfs , но, как оказалось, он вообще не нужен ). Он используется для привязки -mount /bin/bashк /bin/shдля ограниченного набора процессов. Краткая процедура установки новой оболочки, где sh— это bash, описана ниже.

Сначала мы запускаем новую оболочку с изолированным пространством имен монтирования:

sudo unshare -m sudo -u user /bin/bash

А потом в новой оболочке привязываем -крепление /bin/bashк/bin/sh:

sudo mount --bind /bin/bash /bin/sh

Вот именно!

Посмотрим, что у нас в этой оболочке:

user@ubuntu:~$ /bin/sh --version
GNU bash, version...
user@ubuntu:~$ diff -s /bin/sh /bin/bash
Files /bin/sh and /bin/bash are identical

Но при работе в другой оболочке:

user@ubuntu:~$ /bin/sh --version
/bin/sh: 0: Illegal option --
user@ubuntu:~$ diff -s /bin/sh /bin/bash
Binary files /bin/sh and /bin/bash differ
user@ubuntu:~$ diff -s /bin/sh /bin/dash
Files /bin/sh and /bin/dash are identical
1
27.01.2020, 23:11

Скрипты, содержащие не -расширения POSIX, должны иметь соответствующий правильный заголовок #!, в вашем случае:

#!/bin/bash

поэтому я не вижу возможности редактировать все некорректные скрипты.

Кстати, :если вы действительно уверены, вы можете создать временную ссылку на bash и переименовать ее:

cd /bin
ln -s bash nsh
mv nsh sh

Так как mvработает атомарно, это гарантирует, что всегда будет рабочий/bin/sh

В результате сценарии и другие оболочки, работающие в настоящее время, пока вы выполняете переименование, продолжат работать, и после переименования будет вызываться bash вместо dash.

Однако, если ваша система работает таким образом, что позволяет редактировать сценарии, я предпочитаю редактировать только сценарии.

Если вы замените /bin/shссылкой на bash, не забудьте исправить это, чтобы после завершения /bin/shснова стал ссылкой на dash.

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

0
27.01.2020, 23:11

Вы можете легко исправить их, не ломайте свою систему!

find. -name '*.sh' -type f -exec sed -i '1s|^#! */bin/sh|#!/bin/bash|' {} +
4
27.01.2020, 23:11

Я полагаю, что пространства имен монтирования или что-то в этом роде можно использовать, чтобы у разных процессов/пользователей было разное представление о том, что /bin/shтакое.

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

С GNU sedчто-то подобное должно делать, чтобы исправить их:

sed -i -e '1s,^#! */bin/sh,#!/bin/bash,' /all/the/scripts/*
3
27.01.2020, 23:11

Если/bin/sh-> /bin/dashявляется динамически подключаемым исполняемым файлом в вашей системе, как в моей (, вы можете проверить это с помощью файла (1 )), вы можете использовать для этого хак LD_PRELOAD.

Это работает следующим образом :Небольшая динамическая библиотека, загруженная LD_PRELOAD, переопределяет функцию glibc __libc_start_main(, которая вызывает функцию main()исполняемого файла ), и если argv[0] == /bin/sh, то она /bin/bashexec вместо этого с теми же аргументами (, за исключениемargv[0]); в противном случае он обращается к исходному __libc_start_main, как будто ничего не произошло.

$ cat sh_is_bash.c
#define _GNU_SOURCE     /* for RTLD_NEXT */
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int __libc_start_main(
        int (*main)(int,char**,char**), int ac, char **av,
        int (*init)(int,char**,char**), void (*fini)(void),
        void (*rtld_fini)(void), void *stack_end)
{
        typeof(__libc_start_main) *real_lsm;
        if(ac > 0 && !strcmp(av[0], "/bin/sh")){
                av[0] = "/bin/bash";
                execv(av[0], av);
                err(1, "execv %s", av[0]);
        }else if(real_lsm = dlsym(RTLD_NEXT, "__libc_start_main"))
                return real_lsm(main, ac, av, init, fini, rtld_fini, stack_end);
        else
                errx(1, "BUG: dlsym: %s", dlerror());
}
$ cc -fPIC -shared -Wall -W -Wno-parentheses sh_is_bash.c -o sh_is_bash.so -ldl
$ LD_PRELOAD=`pwd`/sh_is_bash.so program...

Любой скрипт с шебангом #! /bin/shбудет выполняться с /bin/bashвместо /bin/sh, если переменная окружения LD_PRELOADсодержит абсолютный путь к sh_is_bash.so.

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

3
27.01.2020, 23:11

Теги

Похожие вопросы