Կեռիկը աշխատում է, երբ այն ձեռքով գործարկում եք որպես root, և վերադարձնում է Operation not permitted այն պահին, երբ ծառայությունը սկսում է այն։ Ֆայլն այդ գործարկումների միջև չի փոխվել. փոխվել է միջավայրը։ systemd-ը գործընթացին տալիս է ավելի փոքր աշխարհ՝ ավելի քիչ հնարավորություններ, այլ /dev, միայն-ընթեռնելի ֆայլային համակարգի ուղիներ և առաջադրանքների սահմանաչափ։ Կարդացեք ձախողումը որպես սահման, որը մերժել է մեկ կոնկրետ գործողություն, ոչ որպես կոտրված սկրիպտ։

Սկսեք այն գործողությունից, որը մերժվել է

Գրանցամատյանի տողը, որն ասում է, թե unit-ը ձախողվել է, գրեթե ոչինչ չի ասում։ Օգտակար տողը նշում է այն կանչը, որը մերժվել է՝ սարքի հանգույց, որը չի բացվել, թղթապանակ, որում չի գրվել, անվանատարածք, որը չի ստեղծվել։ Գտեք այդ կանչը նախքան որևէ հրահանգի դիպչելը, որովհետև յուրաքանչյուրը համապատասխանում է տարբեր սահմանափակման։ Այնուհետև կարդացեք այն unit-ը, որն իրականում աշխատել է, ներառյալ drop-in-ները, փոխանակ փաթեթի ուղարկած ֆայլի։

Ստորև հարցումը տպում է հատվածի ուղին, drop-in թղթապանակները և այն հատկանիշները, որոնք կարևոր են սարքի կամ ֆայլային համակարգի մերժման համար։ Կարդացեք բոլորը նախքան որոշելը, թե որ սահմանն է համապատասխան։

systemctl show "[email protected]" -p FragmentPath -p DropInPaths -p PrivateDevices -p DevicePolicy -p DeviceAllow -p ProtectHome -p ProtectSystem -p TasksMax
journalctl -u "[email protected]" -b --no-pager | grep -iE 'operation not permitted|permission denied|cannot open|failed'

Այդ բլոկում ոչինչ չի գրում։ Եթե մերժված կանչը բացակայում է մատյանում, մեկ գործարկման համար բարձրացրեք հաճախորդի մանրամասնությունը՝ հրահանգներ գուշակելու փոխարեն։ Աշխատող գործընթացը ապացուցում է, որ unit-ը սկսվել է, ոչ թե որ կեռիկն աշխատել է անհրաժեշտ արտոնություններով։

Անվանատարածքը պահանջում է mount իրավունքներ, որոնք TUN սարքը երբեք չի օգտագործում

Մեկ կեռիկի ներսում նման երևացող երկու գործողություններ ունեն տարբեր թույլտվությունների պրոֆիլներ։ /dev/net/tun բացելը և միջերեսը ստեղծելը պահանջում է ցանցային կառավարում և հասանելիություն այդ հանգույցին։ Անվանված ցանցային անվանատարածք ստեղծելը նույնպես պահանջում է mount աշխատանք, որովհետև անվանատարածքի գործիքը mount է անում նոր /sys տեսք և կապում է վիճակի թղթապանակը իր տեղում։ վերին մակարդակի հաճախորդի unit-ը դիտավորյալ թողնում է mount կառավարումը իր սահմանների հավաքածուից դուրս, ուստի անվանատարածքի քայլը մերժվում է, մինչդեռ թունելն ինքը կաշխատեր։

Այդ պատճառով սարքի հանգույցը տալը չի փրկում սկրիպտը։ Սարքի թույլտվությունը պատասխանում է մեկ հարցի՝ կարո՞ղ է այս գործընթացը բացել այս հանգույցը, իսկ անվանատարածքի հարցը այլ է։ Համապատասխանեցրեք ձախողվող կանչը իր հնարավորությանը նախքան որևէ բան լայնացնելը։

Ձեր shell-ում արված փորձարկումը ժառանգում է բոլոր հնարավորությունները, որ ունի անսահմանափակ root-ը, իսկ unit-ը ժառանգում է այն, ինչ պահել է իր սահմանների հավաքածուն։ Այդ երկու գործարկումները տարբեր փորձեր են նույնիսկ երբ երկուականը նույնն է։

Սարքեր, պաշտպանված ուղիներ և առաջադրանքների սահմանաչափեր

Երբ մերժված գործողությունը հայտնի է, հրահանգների երեք խումբ բացատրում են ձախողումների մեծ մասը։ Սարքերի հասանելիությունը կարգավորում է PrivateDevices, որը փոխարինում է /dev -ը նվազագույն կեղծ սարքերի հավաքածուով, և DevicePolicy -ի հետ DeviceAllow, որոնք որոշում են, թե cgroup-ը ինչ է թույլատրում։ /dev/net/tun այդ նվազագույն հավաքածուի մասը չէ, ուստի PrivateDevices=yes ունեցող unit-ը չի կարող բացել այն, ինչ էլ ասի սարքերի քաղաքականությունը։

Ֆայլային համակարգի պաշտպանությունը պատասխանում է երկրորդ հարցին։ ProtectHome=yes դարձնում է /home, /root և /run/user անհասանելի, և ProtectSystem=full դարձնում է /usr, /boot և /etc միայն-ընթեռնելի։ Այդ պատճառով այն կեռիկը, որը գրում է իր իսկ կարգավորումների ֆայլի կողքին, աշխատում է ձեր shell-ում և ձախողվում unit-ի տակ, նույն թույլտվության ձևով, ինչ բացակայող հնարավորությունը։ Տեղափոխեք գրելի մուտքը քաղաքականության թույլատրած ուղի, կամ ավելացրեք նեղ ReadWritePaths= գրառում։

Ռեսուրսների սահմանափակումները երրորդ խումբն են և ամենաքիչ ակնհայտը։ TasksMax= սահմանափակում է, թե քանի առաջադրանք կարող է ստեղծել unit-ը, իսկ ֆայլային նկարագրիչների սահմանաչափը նույն ձևով է վարվում socket-ների և բռնակների համար։ Տեղադրումը, որն անցել է սահմանաչափից, ձախողվում է ռեսուրսի սխալով, ոչ թե թույլտվության սխալով, և այդ պատճառով ճշգրիտ հաղորդագրությունը դեռ կարևոր է։

Հանեք անվանատարածքի քայլը կեռիկից

Նախապատրաստությունը, որը պահանջում է արտոնություն, որը հաճախորդը չպետք է ունենա, պատկանում է իր սեփական unit-ին։ oneshot-ը, որն աշխատում է հաճախորդից առաջ, պահում է իր արդյունքը և դասավորված է կապից առաջ, տալիս է անվանատարածքի քայլին անհրաժեշտը՝ առանց այդ իրավունքները թունելի գործընթացին հանձնելու։ Այնուհետև հաճախորդը հղում է այդ unit-ին՝ սկրիպտը իր up կեռիկից կանչելու փոխարեն։

Ստորև ձևանմուշը մեկնարկային ձև է, ոչ թե մի բան, որ կիրառվում է չկարդացած։ Այն պահում է նախապատրաստությունը այնտեղ, որտեղ ապրում է արտոնությունը, և թողնում է թունելի unit-ը անձեռնմխելի։

# /etc/systemd/system/[email protected]
[Unit]
Description=Namespace preparation for %i
Before=openvpn-client@%i.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/netns-up.sh %i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_SYS_ADMIN
[Install]
WantedBy=multi-user.target

Ավելացրեք հերթականությունը drop-in-ով՝ փաթեթավորված unit-ը խմբագրելու փոխարեն, որպեսզի թարմացումը չկարողանա լուռ գցել ձեր փոփոխությունը։ Թղթապանակը կապված է օրինակի անվան հետ, ուստի երկրորդ պրոֆիլին պետք է իր ֆայլը։

sudo mkdir -p /etc/systemd/system/[email protected]
sudo tee /etc/systemd/system/[email protected]/10-namespace.conf >/dev/null <<'CONF'
[Unit]
[email protected]
[email protected]
CONF
sudo systemctl daemon-reload

Կրկնեք նույն կանչը փոփոխությունից հետո

Վերանորոգումը հաստատվում է միայն այն ժամանակ, երբ նույն կանչը տալիս է այլ արդյունք։ Վերագործարկեք երկու unit-երը, կատարեք այն գործողությունը, որը ձախողվել է, և համեմատեք դրա արդյունքը փոփոխությունից առաջ պահված մատյանի տողի հետ։ unit-ը, որը սկսվում է, մինչ կեռիկն այլևս երբեք չի աշխատում, վերանորոգում չէ։

Ստորև հաջորդականությունը պահում է համեմատությունը ազնիվ, որովհետև ստուգում է մերժված կանչը, ոչ թե unit-ի գույնը։ Պահեք դրա ելքը փոփոխությունից առաջ որսված մատյանի տողի կողքին։

sudo systemctl restart "[email protected]" "[email protected]"
systemctl status "[email protected]" --no-pager
journalctl -u "[email protected]" -b --no-pager | grep -c 'Operation not permitted'
ip -brief addr show tun0

Հաշվեք մերժումները՝ վերջին տողը կարդալու փոխարեն, որովհետև կեռիկը կարող է ձախողվել, նորից փորձել և հաջողել, և միայն հաշիվն է ցույց տալիս, թե արդյոք սահմանը շարժվել է։ Թողեք մեկնաբանություն drop-in-ում՝ նշելով այն հրահանգը, որը թուլացրել եք, և պատճառը, քանի որ հաջորդ թարմացումը համեմատում է ձեր կարգավորումը փաթեթավորված լռելյայնի հետ։ unit-ը, որը սկսվում է միայն այն բանից հետո, երբ անջատված է ամեն պաշտպանություն, ուղղված չէ։

Առնչվող հոդվածներ