GNU/Linux >> LINUX-Kenntnisse >  >> Linux

So umgehen Sie das Linux-Limit zu viele Argumente

Bearbeiten:

Endlich konnte ich <=256 KB als einzelnes Befehlszeilenargument übergeben (siehe Bearbeiten (4) im unteren). Bitte lesen Sie jedoch sorgfältig, wie ich es gemacht habe, und entscheiden Sie selbst, ob dies ein Weg ist, den Sie gehen möchten. Zumindest sollten Sie nach dem, was ich herausgefunden habe, in der Lage sein zu verstehen, warum Sie sonst 'festgefahren' sind.

Mit der Kopplung von ARG_MAX bis ulim -s / 4 kam die Einführung von MAX_ARG_STRLEN als max. Länge eines Arguments:

/*
 *  linux/fs/exec.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

...

#ifdef CONFIG_MMU
/*
 * The nascent bprm->mm is not visible until exec_mmap() but it can
 * use a lot of memory, account these pages in current->mm temporary
 * for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we
 * change the counter back via acct_arg_size(0).
 */

...

static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
 return len <= MAX_ARG_STRLEN;
}

...

#else

...

static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
  return len <= bprm->p;
}

#endif /* CONFIG_MMU */

...

static int copy_strings(int argc, struct user_arg_ptr argv,
      struct linux_binprm *bprm)
{

...

    str = get_user_arg_ptr(argv, argc);

...

    len = strnlen_user(str, MAX_ARG_STRLEN);
    if (!len)
      goto out;

    ret = -E2BIG;
    if (!valid_arg_len(bprm, len))
      goto out;

...

}

...

MAX_ARG_STRLEN ist definiert als das 32-fache der Seitengröße in linux/include/uapi/linux/binfmts.h :

...

/*
 * These are the maximum length and maximum number of strings passed to the
 * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
 * prevent the kernel from being unduly impacted by misaddressed pointers.
 * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
 */
#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
#define MAX_ARG_STRINGS 0x7FFFFFFF

...

Die Standardseitengröße beträgt 4 KB, sodass Sie keine Argumente übergeben können, die länger als 128 KB sind.

Ich kann es jetzt nicht ausprobieren, aber vielleicht löst das Wechseln zum riesigen Seitenmodus (Seitengröße 4 MB) auf Ihrem System dieses Problem, wenn dies möglich ist.

Ausführlichere Informationen und Referenzen finden Sie in dieser Antwort auf eine ähnliche Frage zu Unix &Linux SE.

Änderungen:

(1) Entsprechend dieser Antwort kann man die Seitengröße von x86_64 ändern Linux auf 1 MB, indem Sie CONFIG_TRANSPARENT_HUGEPAGE aktivieren und CONFIG_TRANSPARENT_HUGEPAGE_MADVISE einstellen bis n in der Kernel-Konfiguration.

(2) Nachdem ich meinen Kernel mit der obigen Konfiguration neu kompiliert habe, ändert sich getconf PAGESIZE gibt immer noch 4096 zurück. Gemäß dieser Antwort CONFIG_HUGETLB_PAGE wird auch benötigt, die ich über CONFIG_HUGETLBFS einlesen könnte . Ich kompiliere jetzt neu und werde erneut testen.

(3) Ich habe meinen Kernel mit CONFIG_HUGETLBFS neu kompiliert aktiviert und jetzt /proc/meminfo enthält den entsprechenden HugePages_* Einträge im entsprechenden Abschnitt der Kernel-Dokumentation erwähnt. Die Seitengröße entspricht jedoch getconf PAGESIZE ist noch unverändert. Während ich jetzt in der Lage sein sollte, riesige Seiten über mmap anzufordern Aufrufe, wobei die Standardseitengröße des Kernels MAX_ARG_STRLEN bestimmt ist immer noch auf 4 KB festgelegt.

(4) Ich habe linux/include/uapi/linux/binfmts.h geändert bis #define MAX_ARG_STRLEN (PAGE_SIZE * 64) , habe meinen Kernel neu kompiliert und jetzt erzeugt Ihr Code:

...

117037
123196
123196
129680
129680
136505
143689
151251
159211

...

227982
227982
239981
239981
252611
252611
265906
./testCL: line 11: ./foo: Argument list too long
279901
./testCL: line 11: ./foo: Argument list too long
294632
./testCL: line 11: ./foo: Argument list too long

Das Limit wurde also wie erwartet von 128 KB auf 256 KB verschoben. Ich weiß jedoch nichts über mögliche Nebenwirkungen. Soweit ich das beurteilen kann, scheint mein System einwandfrei zu laufen.


Fügen Sie einfach die Argumente in eine Datei ein und ändern Sie Ihr Programm so, dass es "Argumente" aus einer Datei akzeptiert. Eine gängige Konvention (insbesondere verwendet von GCC und mehreren anderen GNU-Programmen) ist, dass ein Argument wie @/tmp/arglist.txt fordert Ihr Programm auf, Argumente aus der Datei /tmp/arglist.txt zu lesen , oft eine Zeile pro Argument

Sie könnten vielleicht einige Daten durch lange Umgebungsvariablen übergeben, aber sie sind auch begrenzt (und was durch den Kernel begrenzt ist tatsächlich hat es die Größe von main Anfangsstapel von , der sowohl Programmargumente als auch die Umgebung enthält)

Alternativ können Sie Ihr Programm so ändern, dass es durch eine Konfigurationsdatei konfiguriert werden kann, die die Informationen enthält, die Sie durch Argumente weitergeben möchten.

Auf andere Weise gibt es keine Möglichkeit, diese Einschränkung zu umgehen (siehe manpage execve(2) und ihre Grenzen für Argumentgröße und Umgebung). Abschnitt) - sobald Sie Ihr Stack-Limit erhöht haben (unter Verwendung von setrlimit(2) mit RLIMIT_STACK , generell mit ulimit eingebaut in die übergeordnete Shell). Sie müssen sich anderweitig darum kümmern.


Linux
  1. Wie Linux auf den Mainframe kam

  2. Linux – Wie erhalte ich die Uhrzeit eines laufenden Prozesses?

  3. Wie erhalte ich die Anzahl der CPUs in Linux mit C?

  4. Wie erhalte ich die Anzahl der physischen Festplatten in Linux?

  5. Wie erhalte ich die physische Größe einer Datei unter Linux?

So beschränken Sie den Zugriff des Benutzers auf das Linux-System

So begrenzen Sie die Tiefe der rekursiven Dateiauflistung in Linux

So erhalten Sie den Dateinamen aus dem vollständigen Pfad in Linux

So erhalten Sie die Anzahl der Prozessoren / Kerne in Linux

So erhalten Sie Ihre IP-Adresse unter Linux

Holen Sie sich eine IP-Adresse unter Linux:Entdecken Sie die vielen Möglichkeiten