GNU/Linux >> Znalost Linux >  >> Linux

Jak obejít limit Linux Too Many Arguments

upravit:

Konečně se mi podařilo předat <=256 kB jako jediný argument příkazového řádku (viz úprava (4) ve spodní části). Přečtěte si prosím pozorně, jak jsem to udělal, a sami se rozhodněte, zda je to cesta, kterou se chcete vydat. Přinejmenším byste měli být schopni pochopit, proč jste „zaseknutý“ jinak z toho, co jsem zjistil.

Se spojením ARG_MAX do ulim -s / 4 přišlo zavedení MAX_ARG_STRLEN jako max. délka argumentu:

/*
 *  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 je definována jako 32násobek velikosti stránky v 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

...

Výchozí velikost stránky je 4 KB, takže nemůžete předávat argumenty delší než 128 KB.

Teď to nemohu vyzkoušet, ale možná tento problém vyřeší přepnutí do režimu velké stránky (velikost stránky 4 MB), pokud je to možné ve vašem systému.

Podrobnější informace a odkazy naleznete v této odpovědi na podobnou otázku na Unix &Linux SE.

úpravy:

(1) Podle této odpovědi lze změnit velikost stránky x86_64 Linux na 1 MB povolením CONFIG_TRANSPARENT_HUGEPAGE a nastavení CONFIG_TRANSPARENT_HUGEPAGE_MADVISE na n v konfiguraci jádra.

(2) Po rekompilaci mého jádra s výše uvedenými změnami konfigurace getconf PAGESIZE stále vrací 4096. Podle této odpovědi CONFIG_HUGETLB_PAGE je také potřeba, kterou bych mohl stáhnout přes CONFIG_HUGETLBFS . Nyní provádím rekompilaci a znovu otestuji.

(3) Překompiloval jsem své jádro s CONFIG_HUGETLBFS povoleno a nyní /proc/meminfo obsahuje odpovídající HugePages_* položky uvedené v odpovídající části dokumentace jádra. Nicméně velikost stránky podle getconf PAGESIZE je stále beze změny. Takže i když bych nyní měl být schopen požadovat velké stránky prostřednictvím mmap volání, výchozí velikost stránky jádra určuje MAX_ARG_STRLEN je stále fixní na 4 kB.

(4) Upravil jsem linux/include/uapi/linux/binfmts.h na #define MAX_ARG_STRLEN (PAGE_SIZE * 64) , překompiloval mé jádro a váš kód nyní vytváří:

...

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

Nyní se tedy limit posunul ze 128 kB na 256 kB, jak se očekávalo. Nevím však o potenciálních vedlejších účincích. Pokud mohu soudit, zdá se, že můj systém běží v pořádku.


Jednoduše vložte argumenty do nějakého souboru a upravte svůj program tak, aby akceptoval "argumenty" ze souboru. Běžnou konvencí (používá se zejména GCC a několika dalšími programy GNU) je, že argument jako @/tmp/arglist.txt požádá váš program, aby přečetl argumenty ze souboru /tmp/arglist.txt , často jeden řádek na argument

Možná můžete předávat některá data přes dlouhé proměnné prostředí, ale ty jsou také omezené (a co je omezeno jádrem ve skutečnosti je velikost main počáteční zásobník 's, obsahující argumenty programu i prostředí)

Případně upravte svůj program tak, aby byl konfigurovatelný pomocí nějakého konfiguračního souboru, který by obsahoval informace, které chcete předat argumenty.

Jinými způsoby neexistuje způsob, jak toto omezení obejít (viz manuálová stránka execve(2) a její Omezení velikosti argumentů a prostředí sekce) - jakmile zvýšíte limit zásobníku (pomocí setrlimit(2) s RLIMIT_STACK , obvykle s ulimit vestavěný v nadřazeném shellu). Musíte se s tím vypořádat jinak.


Linux
  1. Linux:Jak získat všechny přihlašovací protokoly ze systému?

  2. Jak získat počet CPU v Linuxu pomocí C?

  3. Jak získat uživatelské jméno v C/C++ v Linuxu?

  1. Jak se Linux dostal k sálovému počítači

  2. Linux – jak spolehlivě získat název operačního systému?

  3. Jak získat fyzickou velikost souboru v Linuxu?

  1. Linux – jak získat čas nástěnných hodin běžícího procesu?

  2. Jak změnit časový limit MySQL v Linuxu?

  3. Jak mohu získat stav klávesnice v Linuxu?