GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo sortear el límite de demasiados argumentos de Linux

editar:

Finalmente pude pasar <=256 KB como un solo argumento de línea de comando (ver editar (4) en la parte inferior). Sin embargo, lea atentamente cómo lo hice y decida por sí mismo si este es el camino que desea seguir. Al menos deberías ser capaz de entender por qué estás 'atascado' de lo contrario por lo que descubrí.

Con el acoplamiento de ARG_MAX a ulim -s / 4 llegó la introducción de MAX_ARG_STRLEN como máx. longitud de un argumento:

/*
 *  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 se define como 32 veces el tamaño de la página en 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

...

El tamaño de página predeterminado es de 4 KB, por lo que no puede pasar argumentos de más de 128 KB.

No puedo probarlo ahora, pero tal vez cambiar al modo de página grande (tamaño de página de 4 MB) si es posible en su sistema resuelva este problema.

Para obtener información más detallada y referencias, consulte esta respuesta a una pregunta similar sobre Unix y Linux SE.

ediciones:

(1) De acuerdo con esta respuesta, se puede cambiar el tamaño de página de x86_64 Linux a 1 MB habilitando CONFIG_TRANSPARENT_HUGEPAGE y configurando CONFIG_TRANSPARENT_HUGEPAGE_MADVISE a n en la configuración del núcleo.

(2) Después de volver a compilar mi kernel con los cambios de configuración anteriores getconf PAGESIZE todavía devuelve 4096. Según esta respuesta CONFIG_HUGETLB_PAGE también se necesita, que podría obtener a través de CONFIG_HUGETLBFS . Estoy recompilando ahora y volveré a probar.

(3) Recompilé mi kernel con CONFIG_HUGETLBFS habilitado y ahora /proc/meminfo contiene el HugePages_* correspondiente entradas mencionadas en la sección correspondiente de la documentación del kernel. Sin embargo, el tamaño de página según getconf PAGESIZE sigue sin cambios. Entonces, aunque ahora debería poder solicitar páginas grandes a través de mmap llamadas, el tamaño de página predeterminado del kernel determina MAX_ARG_STRLEN todavía está fijo en 4 KB.

(4) Modifiqué linux/include/uapi/linux/binfmts.h a #define MAX_ARG_STRLEN (PAGE_SIZE * 64) , volví a compilar mi núcleo y ahora su código produce:

...

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

Así que ahora el límite se movió de 128 KB a 256 KB como se esperaba. Sin embargo, no conozco los posibles efectos secundarios. Por lo que puedo decir, mi sistema parece funcionar bien.


Simplemente coloque los argumentos en algún archivo y modifique su programa para aceptar "argumentos" de un archivo. Una convención común (especialmente utilizada por GCC y varios otros programas GNU) es que un argumento como @/tmp/arglist.txt le pide a su programa que lea los argumentos del archivo /tmp/arglist.txt , a menudo una línea por argumento

Quizás pueda pasar algunos datos a través de variables de entorno largas, pero también están limitadas (y lo que está limitado por el kernel de hecho es del tamaño de main la pila inicial de, que contiene tanto los argumentos del programa como el entorno)

Alternativamente, modifique su programa para que sea configurable a través de algún archivo de configuración que contenga la información que desea pasar a través de argumentos.

De otras maneras, no hay forma de eludir esa limitación (consulte la página del comando man execve(2) y sus Límites en el tamaño de los argumentos y el entorno sección) - una vez que haya aumentado su límite de pila (usando setrlimit(2) con RLIMIT_STACK , generalmente con ulimit incorporado en el shell principal). Tienes que lidiar con eso de otra manera.


Linux
  1. Cómo llegó Linux al mainframe

  2. Linux:¿cómo obtener de manera confiable el nombre del sistema operativo?

  3. ¿Cómo puedo obtener el estado del teclado en Linux?

  4. ¿Cómo obtener el nombre de usuario en C/C++ en Linux?

  5. ¿Cómo obtener el tamaño físico de un archivo en Linux?

Cómo limitar el acceso del usuario al sistema Linux

Cómo limitar la profundidad de la lista recursiva de archivos en Linux

Cómo obtener el nombre de archivo de la ruta completa en Linux

Cómo obtener la cantidad de procesadores/núcleos en Linux

Cómo obtener su dirección IP en Linux

Obtenga una dirección IP en Linux:descubra las muchas formas