Bug 55130

Summary: Не запускается пользовательская systemd служба
Product: Sisyphus Reporter: Alexey Volkov <qualimock>
Component: kioskAssignee: Олег Соловьев <mcpain>
Status: NEW --- QA Contact: qa-sisyphus
Severity: normal    
Priority: P5 CC: antohami, armatik, jqt4, mcpain, oleg
Version: unstable   
Hardware: x86_64   
OS: Linux   
Attachments:
Description Flags
Лог службы user@1000.service none

Description Alexey Volkov 2025-07-09 21:43:41 MSK
Created attachment 19020 [details]
Лог службы user@1000.service

С активированным режимом Kiosk при логине не стартует служба user@.service (в моем случае user@1000.service).

Происходит это из-за того, что /usr/lib/systemd/systemd --user не может взять переменные окружения XDG_RUNTIME_DIR и DBUS_SESSION_BUS_ADDRESS, что приводит к завершению systemd --user. Она падает с ошибкой, что не может определить путь до RuntimeDirectory. Посмотрев код systemd, увидел, что там используется функция secure_getenv(), которая сравнивает UID с EUID и GID с EGID и только при их равенстве вызывает getenv(), который уже получает нужные переменные окружения (XDG_RUNTIME_DIR и DBUS_SESSION_BUS_ADDRESS).

Я в качестве эксперимента менял secure_getenv() на просто getenv() и служба успешно запускалась с работающим Киоском.

Проверялось на ALT Workstation 11.0 с профилем user-gnome-startup из пакета kiosk-gnome-profiles: https://packages.altlinux.org/en/sisyphus/srpms/kiosk-gnome-profiles/
Если выключить режим Kiosk, вручную запустить службу, обратно включить Kiosk, и потом залогиниться в GDM, то GNOME с этим профилем запустится без проблем.

Ошибка воспроизводится на ALT Workstation K, но так как KDE не так зависит от D-Bus как GNOME, KDE после логина запускается без ошибок, но служба все равно не запускается.
Comment 1 Олег Соловьев 2025-07-22 15:26:19 MSK
(In reply to Alexey Volkov from comment #0)
> Посмотрев код systemd, увидел, что там
> используется функция secure_getenv(), которая сравнивает UID с EUID и GID с
> EGID и только при их равенстве вызывает getenv(), который уже получает
> нужные переменные окружения (XDG_RUNTIME_DIR и DBUS_SESSION_BUS_ADDRESS).

А вот что я нашёл:

В glibc/sysdeps/unix/sysv/linux/dl-parse_auxv.h [1]:
/* Copy the auxiliary vector into AUXV_VALUES and set up GLRO
   variables.  */
static inline
void _dl_parse_auxv (ElfW(auxv_t) *av, dl_parse_auxv_t auxv_values)
{
  ...
  unsigned security_mask = 0;
  ...
  security_mask |= auxv_values[AT_SECURE] != 0;
  security_mask |= ((uid != 0) << 1) | ((gid != 0) << 2);
  __libc_security_mask = security_mask;
  __libc_enable_secure = __libc_security_mask != 0;
  ...
}

В glibc/stdlib/secure-getenv.c [2]:
/* Some programs and especially the libc itself have to be careful
   what values to accept from the environment.  This special version
   checks for SUID or SGID first before doing any work.  */
char *
__libc_secure_getenv (const char *name)
{
  return __libc_enable_secure ? NULL : getenv (name);
}
weak_alias (__libc_secure_getenv, secure_getenv)
libc_hidden_weak (__libc_secure_getenv)

В https://man7.org/linux/man-pages/man3/secure_getenv.3.html:
> The GNU-specific secure_getenv() function is just like getenv()
>   except that it returns NULL in cases where "secure execution" is
>   required.
> ...
> Secure execution may also be required if triggered by some Linux security modules.

А kiosk - LSM и включает secure execution для всех процессов, запущенных пользователем с uid >= 1000.
В kernel-image-6.12/security/kiosk/kiosk_lsm.c [3]:
static int kiosk_bprm_check_security(struct linux_binprm *bprm)
{
         uid_t cur_uid = __kuid_val(bprm->cred->uid);
         struct kiosk_list_struct *node;
 
         if (kiosk_mode == KIOSK_PERMISSIVE)
                 return 0;
 
         if (cur_uid >= 1000) {
                 bprm->secureexec = 1;
         ...
}

[1] https://git.altlinux.org/gears/g/glibc.git?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/dl-parse_auxv.h;h=fb4124050f827dcd8c9567388886dc266212e12e;hb=8c5965291fac4d9814d13c492d45574fccf331c7#l27
[2] https://git.altlinux.org/gears/g/glibc.git?p=glibc.git;a=blob;f=stdlib/secure-getenv.c;h=88bff1b47abdb5a69614d6d7fc62d7f49ba3a83b;hb=8c5965291fac4d9814d13c492d45574fccf331c7#l24
[3] https://git.altlinux.org/gears/k/kernel-image-6.12.git?p=kernel-image-6.12.git;a=blob;f=security/kiosk/kiosk_lsm.c;h=18f810a1ce0f17631b5a18e40a92bad3f9ab8447;hb=5c8a6837cbfaf345ebf52635e02135793aaed3b8#l286

Таким образом, secure_getenv() в недрах systemd возвращает NULL из-за установленного в LSM-модуле флага AT_SECURE.
Если бы флага не было и нет другой необходимости в secureexec, то вызывается уже getenv()