Подстановка строк для обнаружения пустых переменных?

Командаunshare(1)не может этого сделать:

-r, --map-root-user
[...] As a mere convenience feature, it does not support more sophisticated use cases, such as mapping multiple ranges of UIDs and GIDs.

Дополнительные группы, если таковые имеются (video,... )будут потеряны в любом случае (или отображены наnogroup).

Снова изменившись на второе новое пользовательское пространство имен, можно отменить сопоставление. Для этого требуется специальная программа, так как unshare(1)этого не сделает. Вот очень минималистичная программа на C в качестве доказательства концепции (только один пользователь :uid/gid 1000/1000, нулевая проверка на сбой ).Назовем этоrevertuid.c:

#define _GNU_SOURCE
#include 

#include 
#include 
#include 

#include 

int main(int argc, char *argv[]) {
    int fd;

    unshare(CLONE_NEWUSER);
    fd=open("/proc/self/setgroups",O_WRONLY);
    write(fd,"deny",4);
    close(fd);
    fd=open("/proc/self/uid_map",O_WRONLY);
    write(fd,"1000 0 1",8);
    close(fd);
    fd=open("/proc/self/gid_map",O_WRONLY);
    write(fd,"1000 0 1",8);
    close(fd);
    execvp(argv[1],argv+1);
}

Просто выполняется обратное сопоставление сопоставления, сделанного unshare -r -m, что было неизбежно, чтобы иметь возможность быть пользователем root и использовать mount, как видно из:

$ strace unshare -r -m /bin/sleep 1 2>&1 |sed -n '/^unshare/,/^execve/p'
unshare(CLONE_NEWNS|CLONE_NEWUSER)      = 0
open("/proc/self/setgroups", O_WRONLY)  = 3
write(3, "deny", 4)                     = 4
close(3)                                = 0
open("/proc/self/uid_map", O_WRONLY)    = 3
write(3, "0 1000 1", 8)                 = 8
close(3)                                = 0
open("/proc/self/gid_map", O_WRONLY)    = 3
write(3, "0 1000 1", 8)                 = 8
close(3)                                = 0
execve("/bin/sleep", ["/bin/sleep", "1"], [/* 18 vars */]) = 0

Так что получается:

user@stretch-amd64:~$ gcc -o revertuid revertuid.c
user@stretch-amd64:~$ mkdir -p /tmp/src /tmp/dst
user@stretch-amd64:~$ touch /tmp/src/file
user@stretch-amd64:~$ ls /tmp/dst
user@stretch-amd64:~$ id
uid=1000(user) gid=1000(user) groups=1000(user)
user@stretch-amd64:~$ unshare -r -m
root@stretch-amd64:~# mount --bind /tmp/src /tmp/dst
root@stretch-amd64:~# ls /tmp/dst
file
root@stretch-amd64:~# exec./revertuid bash
user@stretch-amd64:~$ ls /tmp/dst
file
user@stretch-amd64:~$ id
uid=1000(user) gid=1000(user) groups=1000(user)

Или короче:

user@stretch-amd64:~$ unshare -r -m sh -c 'mount --bind /tmp/src /tmp/dst; exec./revertuid bash'
user@stretch-amd64:~$ ls /tmp/dst
file

Поведение, вероятно, изменилось после ядра 3.19, как показано вuser_namespaces(7):

The /proc/[pid]/setgroups file was added in Linux 3.19, but was backported to many earlier stable kernel series, because it addresses a security issue. The issue concerned files with permissions such as "rwx---rwx".

1
10.08.2020, 05:50
4 ответа

У вас также могут возникнуть проблемы с файлами /tmp/dir.d/file.

Сzsh:

#! /bin/zsh -
f="/tmp/file.txt" # with.txt extension
timestamp=${(%):-%D{%H%M%S}}

set -o extendedglob
extension=${(M)f%.[^./]#}
print -r -- ${f%$extension}-$timestamp$extension

Со стандартным shсинтаксисом (также будет работать в bash/zsh):

#! /bin/sh -
f="/tmp/file.txt" # with.txt extension
timestamp=$(date +%H%M%S)

case ${f##*/} in
  (*.*) printf '%s\n' "${f%.*}-$timestamp.${f##*.}";;
  (*)   printf '%s\n' "$f-$timestamp";;
esac

С помощью bashвы можете заменить timestamp=$(date +%H%M%S)на printf -v timestamp '%(%H%M%S)T', чтобы избежать запуска этой команды date.

1
18.03.2021, 23:13

Если вам нужен один -вкладыш, вот демонстрация несколько неуклюжего, но работающего решения:

#!/bin/bash

# Test cases
FILE="/tmp/file"
# FILE="/tmp/file."
# FILE="/tmp/file.txt"
# FILE="/tmp/file.txt."

# TIMESTAMP="$(date +%H%M%S)"
printf -v TIMESTAMP '%(%H%M%S)T'

echo "${FILE%%.*}-${TIMESTAMP}.$([[ $FILE =~ \..*$ ]] && { echo "${FILE#*.}"; } || { echo "txt"; })"

Приведенное выше добавляет .txtк имени файла, если отсутствует расширение.

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

echo "${FILE%%.*}-${TIMESTAMP}$([[ $FILE =~ \..*$ ]] && { echo ".${FILE#*.}"; })"
1
18.03.2021, 23:13

для простоты

#!/bin/bash
f="/tmp/file"
timestamp="$(date +%H%M%S)"
out="${f}-${timestamp}";
[ "${f%.*}" != "${f##*.}" ] && out="${f%.*}-${timestamp}.${f##*.}";
echo "$out"

для защиты от .на пути

dir=${f%/*};
file=${f##*/};
name=${file%.*};
suffix=${file##*.};
[ "$dir" != "$file" ] && dir=${dir}/ || unset dir;
[ "$name" != "$suffix" ] && suffix=.${suffix} || unset suffix;
echo "${dir}${name}-${timestamp}${suffix}"

удалите символы новой строки, если вам это нужно в одной строке
примечание :Я рекомендую использовать полную временную метку (дата + время ), чтобы обеспечить ее уникальность

0
18.03.2021, 23:13

Дело не в том, что fне определено, а в том, что ${f#*.}— это значение fс удаленной частью до первой точки. Если точки нет, ничего не удаляется и ${f#*.}совпадает с $f. Кроме того, поскольку он соответствует первой точке , у вас возникают проблемы с путями, такими как ./foo.txt(, он дает-181548./foo.txt).

Вам нужно либо проверить, равно ли ${f#*.}$f, либо использовать что-то вроде ${f#${f%.*}}, которое становится пустым, если нет суффикса, разделенного точкой -. Аналогом для этого будет ${f%.${f##*.}}. Хотя у вас все еще будут проблемы с ./file.

Проблема с ./fileпредлагает сначала отделить часть имени файла от пути, а затем продолжить оттуда.

В качестве альтернативы можно использовать регулярные выражения. Это работает для имен файлов, которые я тестировал :

.
#!/bin/bash
f=$1
timestamp="$(date +%H%M%S)"
re='^((.*/)?[^/.]+)(\.[^/]+)?$'
if [[ $f =~ $re ]]; then
    echo "${BASH_REMATCH[1]}-${timestamp}${BASH_REMATCH[3]}"
fi

Это(.*/)?--необязательный путь, заканчивающийся косой чертой;[^/.]+--начальная часть имени файла;(\.[^/]+)?--дополнительное расширение.

0
18.03.2021, 23:13

Теги

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