Wie kann überprüft werden, welches Limit überschritten wurde? (Prozess wegen ulimit abgebrochen.)

11

Nehmen wir an, der Prozess läuft in einer begrenzten Umgebung:

(
ulimit  ... -v ... -t ... -x 0 ...
./program
)

Programm wird beendet.

Es kann viele Gründe geben: Speicher- / Zeit- / Dateilimit überschritten; nur einfacher Segfault; oder sogar normale Kündigung mit Rückkehrcode 0.

Wie kann man überprüfen, was der Grund für die Programmbeendigung war, ohne das Programm zu ändern?

PS Ich meine "wenn binär gegeben ist". Vielleicht hilft ein Wrapper (Ptracing usw.)?

Grzegorz Wierzowiecki
quelle

Antworten:

6

Generell glaube ich nicht, dass Sie das leider können. (Einige Betriebssysteme sehen dies möglicherweise vor, aber mir sind nicht diejenigen bekannt, von denen ich weiß, dass sie dies unterstützen.)

Referenzdokument für Ressourcenlimits: getrlimitab POSIX 2008.

Nehmen Sie zum Beispiel das CPU-Limit RLIMIT_CPU.

  • Wenn der Prozess das Soft-Limit überschreitet, wird a gesendet SIGXCPU
  • Wenn der Prozess das harte Limit überschreitet, wird eine Ebene angezeigt SIGKILL

Wenn Sie wait()in Ihrem Programm können, können Sie feststellen, ob es von getötet wurde SIGXCPU. Aber man konnte einen SIGKILLwegen Verletzung der harten Grenze entsandten nicht von einem einfachen alten Mord von außen unterscheiden. Was mehr ist, wenn das Programm das handhabt XCPU, werden Sie das nicht einmal von außen sehen.

Gleiches für RLIMIT_FSIZE. Sie können SIGXFSZden wait()Status sehen, wenn das Programm ihn nicht verarbeitet. Sobald die Dateigrößenbeschränkung überschritten wird, werden nur weitere E / A-Vorgänge, die versuchen, diese Beschränkung erneut zu testen, einfach empfangen EFBIG- dies wird vom Programm intern behandelt (oder leider nicht). Wenn das Programm SIGXFSZwie oben behandelt wird, wissen Sie nichts darüber.

RLIMIT_NOFILE? Du bekommst nicht mal ein Signal. openund Freunde kehren einfach EMFILEzum Programm zurück. Es wird nicht anderweitig gestört, so dass es fehlschlägt (oder nicht), wie auch immer es codiert wurde, um in dieser Situation zu versagen.

RLIMIT_STACK? Gut alt SIGSEGV, kann nicht von der Punktzahl anderer Gründe unterschieden werden, um einen geliefert zu bekommen. (Sie werden jedoch anhand des waitStatus wissen, dass dies den Prozess beendet hat.)

RLIMIT_ASund RLIMIT_DATAwird nur machen malloc()und einige andere beginnen zu scheitern (oder zu empfangen, SIGSEGVwenn das AS-Limit erreicht wird, während versucht wird, den Stack unter Linux zu erweitern). Wenn das Programm nicht sehr gut geschrieben ist, wird es an diesem Punkt wahrscheinlich ziemlich zufällig fehlschlagen.

Kurz gesagt, im Allgemeinen unterscheiden sich die Fehler entweder nicht sichtbar von anderen Gründen für den Prozesssterben, sodass Sie nicht sicher sein können, oder sie können vollständig vom Programm aus behandelt werden. In diesem Fall entscheidet es, ob / wann / wie es weitergeht, nicht Sie von außen.

Soweit ich weiß, können Sie am besten ein bisschen Code schreiben, der Ihr Programm verzweigt, darauf wartet und:

  • Überprüfen Sie den zu erkennenden Exit-Status SIGXCPUund SIGXFSZ(AFAIK, diese Signale werden nur vom Betriebssystem für Probleme mit Ressourcenlimits generiert). Je nach Ihrem genauen Bedarf, können Sie davon ausgehen , dass SIGKILLund SIGSEGVwurden auch an Ressourcengrenzen im Zusammenhang, aber das ist ein bisschen weit hergeholt.
  • Schauen Sie sich an, was Sie aus getrusage(RUSAGE_CHILDREN,...)Ihrer Implementierung herausholen können, um einen Hinweis auf die anderen zu erhalten.

Möglicherweise gibt es hier betriebssystemspezifische Funktionen (möglicherweise ptraceunter Linux oder Solaris dtrace) oder möglicherweise Techniken vom Typ Debugger, die jedoch noch stärker an Ihre spezifische Implementierung gebunden sind.


(Ich hoffe, jemand anderes wird mit einer magischen Sache antworten, von der ich nichts weiß.)

Matte
quelle
In Ordnung. Was ist mit nur diesen drei: (Mem) Überschreiten des Speicherlimits, (Zeit-) Zeitlimit, (Err) anderer Fehler? Ich weiß, wie man Wrapper herstellt, mallocaber leider löst es das Speicherproblem im Allgemeinen nicht, weil es im Allgemeinen um Systemaufrufe geht brk(habe ich recht?).
Grzegorz Wierzowiecki
1
Das Einwickeln von Malloc hilft nicht, wenn Sie das Programm nicht steuern. Wenn Sie sprechen Hacks wie LD_PRELOADing , dass die Grenze für die Einschränkung „nicht den Prozess zu modifizieren“, und es wird ein wenig helfen, aber nicht wirklich - malloc, brk, sbrkund mmapwird mit fehlschlagen ENOMEM, genau so , wie wenn man wirklich in einer Situation für wenig Arbeitsspeicher waren (aber weit unter den Speichergrenzen). Das Zeitlimit ist RLIMIT_CPU, ich kenne kein Zeitlimit für die Wanduhr.
Mat
Vielen Dank, dass Sie mich informiert haben brk. Wie ich sehe, löst die Anforderung 'Programm verarbeitet nicht die Signale X, Y, Z ...' Probleme von SIGXCPU, SIGXFSZ, SIGSEGV dank waitpid (Wenn ich falsch liege, korrigieren Sie mich bitte).
Grzegorz Wierzowiecki
1
SIGSEGV kann in Situationen ausgelöst werden, in denen es sich nicht um Verstöße gegen Ressourcenlimits handelt (Nullzeiger-Dereferenzierung ist die häufigste Ursache). Sie können nicht sicher sein, ob es sich um einen Ulimit-Treffer handelt, der dies verursacht.
Mat
Vielen Dank, dass Sie mich informiert haben brk. Wie ich sehe, löst die Anforderung 'Programm verarbeitet nicht die Signale X, Y, Z ...' Probleme von SIGXCPU, SIGXFSZ, SIGSEGV dank waitpid. Habe ich recht?
Grzegorz Wierzowiecki
3

Ich arbeite derzeit an demselben Thema. Ich konnte eine Teillösung dafür finden. Ich habe Audit Susbsystem verwendet. Sie können die Arbeit unter [1] verfolgen.

[1] https://github.com/PaulDaviesC/Logging-limits.conf

PaulDaviesC
quelle