Je suis en cours pdftoppm
d' exécution pour convertir un fichier PDF fourni par l'utilisateur en une image 300DPI. Cela fonctionne très bien, sauf si l'utilisateur fournit un fichier PDF avec un très grand format de page. pdftoppm
allouera suffisamment de mémoire pour contenir en mémoire une image de 300 ppp de cette taille, ce qui, pour une page carrée de 100 pouces correspond à 100 * 300 * 100 * 300 * 4 octets par pixel = 3,5 Go. Un utilisateur malveillant pourrait simplement me donner un fichier PDF de taille stupide et causer toutes sortes de problèmes.
Donc, ce que je voudrais faire, c’est imposer une limite stricte à l’utilisation de la mémoire pour un processus enfant que je suis sur le point d’exécuter - faites en sorte que le processus disparaisse si vous essayez d’allouer plus de 500 Mo de mémoire, par exemple. Est-ce possible?
Je ne pense pas que ulimit puisse être utilisé pour cela, mais existe-t-il un équivalent en un processus?
docker
- être ?Réponses:
Il y a quelques problèmes avec ulimit. Voici une lecture utile sur le sujet: Limiter le temps et la consommation de mémoire d'un programme sous Linux , ce qui conduit à l' outil de délai d'expiration , qui vous permet de mettre en cage un processus (et ses fourchettes) en fonction du temps ou de la consommation de mémoire.
L'outil de délai d'attente requiert Perl 5+ et le
/proc
système de fichiers monté. Après cela, vous copiez l'outil/usr/local/bin
comme par exemple :Après cela, vous pouvez «mettre en cage» votre processus par la consommation de mémoire, comme dans votre question:
Vous pouvez également utiliser
-t <seconds>
et-x <hertz>
pour limiter respectivement le processus en fonction des contraintes de temps ou d'UC.Cet outil fonctionne en vérifiant plusieurs fois par seconde si le processus généré n'a pas dépassé ses limites. Cela signifie qu’il existe en fait une petite fenêtre dans laquelle un processus pourrait être potentiellement sursouscrit avant que les avis de dépassement de délai ne se produisent et que le processus ne soit plus mis à mort.
Une approche plus correcte impliquerait donc probablement des groupes de contrôle, mais elle est beaucoup plus complexe à configurer, même si vous utilisiez Docker ou runC, qui, entre autres choses, offre une abstraction plus conviviale autour des groupes de contrôle.
la source
coreutils
utilitaire standard Linux du même nom! Ainsi, la réponse est potentiellement dangereuse si, quelque part sur votre système, un paquet contient un script qui s’attendtimeout
à être lecoreutils
paquet standard Linux ! Je ne suis pas au courant que cet outil soit empaqueté pour des distributions telles que debian.-t <seconds>
contrainte tue- t-elle le processus après tant de secondes?Une autre façon de limiter cela consiste à utiliser les groupes de contrôle de Linux. Ceci est particulièrement utile si vous souhaitez limiter l'allocation de mémoire physique à un processus (ou à un groupe de processus) distinctement de la mémoire virtuelle. Par exemple:
créera un groupe de contrôle nommé
myGroup
, coiffera l’ensemble des processus exécutés sous myGroup jusqu’à 500 Mo de mémoire physique et jusqu’à 5 000 Mo d’échange. Pour exécuter un processus sous le groupe de contrôle:Notez que sur une distribution Ubuntu moderne, cet exemple nécessite l'installation du
cgroup-bin
package et la modification/etc/default/grub
pour passerGRUB_CMDLINE_LINUX_DEFAULT
à:puis en cours d'exécution
sudo update-grub
et en redémarrant pour démarrer avec les nouveaux paramètres de démarrage du noyau.la source
firejail
programme vous permettra également de démarrer un processus avec des limites de mémoire (en utilisant des groupes de contrôle et des espaces de noms pour limiter davantage que la mémoire). Sur mes systèmes, je n'ai pas eu à changer la ligne de commande du noyau pour que cela fonctionne!GRUB_CMDLINE_LINUX_DEFAULT
modification pour rendre le paramètre persistant? J'ai trouvé un autre moyen de le rendre persistant ici .swapaccount=1
dans GRUB_CMDLINE_LINUX_DEFAULT?Si votre processus ne génère pas plus d'enfants qui utilisent le plus de mémoire, vous pouvez utiliser la
setrlimit
fonction. L’interface utilisateur la plus courante utilise laulimit
commande du shell:Cela ne fera que limiter la mémoire "virtuelle" de votre processus, en prenant en compte et en limitant la mémoire du processus appelé partage avec d'autres processus, ainsi que la mémoire mappée mais non réservée (par exemple, le grand segment de mémoire de Java). Néanmoins, la mémoire virtuelle est l’approximation la plus proche pour les processus qui deviennent vraiment volumineux, rendant lesdites erreurs insignifiantes.
Si votre programme génère des enfants et que ce sont eux qui allouent de la mémoire, il devient plus complexe et vous devez écrire des scripts auxiliaires pour exécuter des processus sous votre contrôle. J'ai écrit dans mon blog, pourquoi et comment .
la source
setrlimit
plus complexe pour plus d'enfants?man setrlimit
«Un processus enfant créé avec fork (2) hérite des limites de ressources de ses parents. Les limites de ressources sont préservées entre execve (2)»ulimit
approche m'a aidé avecfirefox
le bogue 622816 - Le chargement d'une grande image peut "geler" Firefox ou faire planter le système ; qui sur un démarrage USB (à partir de la RAM) a tendance à geler le système d'exploitation, nécessitant un redémarrage forcé; maintenant au moins sefirefox
bloque, laissant le système d'exploitation en vie ... A la vôtre!J'utilise le script ci-dessous, qui fonctionne très bien.
Il utilise cgroups à traversMise à jour: il utilise maintenant les commandes decgmanager
.cgroup-tools
. Nommez ce scriptlimitmem
et mettez-le dans votre $ PATH et vous pourrez l'utiliser commelimitmem 100M bash
. Cela limitera l'utilisation de la mémoire et de l'échange. Pour limiter la mémoire, supprimez la ligne avecmemory.memsw.limit_in_bytes
.edit: Sur les installations Linux par défaut, cela limite uniquement l'utilisation de la mémoire, pas l'utilisation de l'échange. Pour activer la limitation d'utilisation d'échange, vous devez activer la comptabilité d'échange sur votre système Linux. Faites cela en paramétrant / ajoutant
swapaccount=1
de/etc/default/grub
sorte qu'il ressemble à quelque chose commePuis lancez
sudo update-grub
et redémarrez.Disclaimer: Je ne serais pas surpris si
cgroup-tools
également des pauses dans le futur. La solution correcte consisterait à utiliser les API systemd pour la gestion des groupes de contrôle, mais il n'existe aucun outil de ligne de commande pour cet environnement.la source
call to cgmanager_create_sync failed: invalid request
pour chaque processus, j'essaie de courir aveclimitmem 100M processname
. Je suis sur Xubuntu 16.04 LTS et ce paquet est installé.$ limitmem 400M rstudio limiting memory to 400M (cgroup limitmem_24575) for command rstudio Error org.freedesktop.DBus.Error.InvalidArgs: invalid request
une idée?percent
résultats est nul, leexpr
code d'état est 1 et ce script se ferme prématurément. recommande de changer la ligne comme suit :percent=$(( "$peak_mem" / $(( "$bytes_limit" / 100 )) ))
(ref: unix.stackexchange.com/questions/63166/… )Outre les outils de
daemontools
, suggérés par Mark Johnson, vous pouvez également considérerchpst
lesquels se trouvent dansrunit
. Runit lui-même est intégrébusybox
, vous l'avez donc peut-être déjà installé.La page de manuel de
chpst
montre l'option:la source
J'utilise Ubuntu 18.04.2 LTS et le script JanKanis ne fonctionne pas pour moi tout à fait comme il le suggère. Courir,
limitmem 100M script
c’est limiter à 100 Mo de RAM avec un échange illimité .L'exécution
limitmem 100M -s 100M script
échoue silencieusement carcgget -g "memory:$cgname"
aucun paramètre n'est nommémemory.memsw.limit_in_bytes
.J'ai donc désactivé l'échange:
la source
Sur toute distribution basée sur systemd, vous pouvez également utiliser les groupes de contrôle indirectement via systemd-run. Par exemple, dans votre cas de limitation
pdftoppm
à 500 M de RAM, utilisez:Remarque: ceci vous demandera un mot de passe mais l'application sera lancée en tant qu'utilisateur. Ne laissez pas ceci vous induire en erreur en pensant que la commande a besoin
sudo
, car cela entraînerait son exécution sous la racine, ce qui était à peine votre intention.Si vous ne voulez pas entrer le mot de passe (après tout, en tant qu'utilisateur vous possédez votre mémoire, pourquoi auriez-vous besoin d'un mot de passe pour le limiter) , vous pouvez utiliser l'
--user
option, mais pour que cela fonctionne, vous aurez besoin de la prise en charge de cgroupsv2, nécessitesystemd.unified_cgroup_hierarchy
maintenant de démarrer avec le paramètre du noyau .la source