如何绕过Linux"Too Many Arguments"限制

swd*_*dev 5 linux shell amazon-sqs

我必须将256Kb的文本作为参数传递给"aws sqs"命令,但是在命令行中运行的限制大约为140Kb.这在许多地方已经讨论过,它已经在Linux内核中从2.6.23内核中解决了.

但无法让它发挥作用.我在用3.14.48-33.39.amzn1.x86_64

这是一个简单的测试示例:

#!/bin/bash

SIZE=1000
while [ $SIZE -lt 300000 ]
do
   echo "$SIZE"
   VAR="`head -c $SIZE < /dev/zero | tr '\0' 'a'`"
   ./foo "$VAR"
   let SIZE="( $SIZE * 20 ) / 19"
done
Run Code Online (Sandbox Code Playgroud)

foo剧本只是:

#!/bin/bash
echo -n "$1" | wc -c
Run Code Online (Sandbox Code Playgroud)

而我的输出是:

117037
123196
123196
129680
129680
136505
./testCL: line 11: ./foo: Argument list too long
143689
./testCL: line 11: ./foo: Argument list too long
151251
./testCL: line 11: ./foo: Argument list too long
159211
Run Code Online (Sandbox Code Playgroud)

那么,如何修改testCL脚本的问题是它可以传递256Kb的数据?顺便说一句,我已经尝试添加ulimit -s 65536到脚本,它没有帮助.

如果这是完全不可能的,我可以解决这个问题,但是你可以从上面的链接中阐明这个引用

"虽然Linux不是Plan 9,但在2.6.23中Linux正在添加变量参数长度.理论上你不应该经常点击"参数列表太长"错误,但是这个补丁也将最大参数长度限制为最大值的25%堆栈限制(ulimit -s)."

msc*_*lli 6


编辑:

我终于能够将 <= 256 KB 作为单个命令行参数传递(请参阅底部的编辑 (4) )。但是,请仔细阅读我是如何做到的,并自行决定这是否是您想要的方式。至少你应该能够从我的发现中理解为什么你会被“卡住”。


ARG_MAX随着to / 4的耦合,ulim -s引入了MAX_ARG_STRLENas max。参数的长度:

/*
 *  linux/fs/exec.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */
Run Code Online (Sandbox Code Playgroud)

...

#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).
 */
Run Code Online (Sandbox Code Playgroud)

...

static bool valid_arg_len(struct linux_binprm *bprm, long len)
{
 return len <= MAX_ARG_STRLEN;
}
Run Code Online (Sandbox Code Playgroud)

...

#else
Run Code Online (Sandbox Code Playgroud)

...

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

#endif /* CONFIG_MMU */
Run Code Online (Sandbox Code Playgroud)

...

static int copy_strings(int argc, struct user_arg_ptr argv,
      struct linux_binprm *bprm)
{
Run Code Online (Sandbox Code Playgroud)

...

    str = get_user_arg_ptr(argv, argc);
Run Code Online (Sandbox Code Playgroud)

...

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

    ret = -E2BIG;
    if (!valid_arg_len(bprm, len))
      goto out;
Run Code Online (Sandbox Code Playgroud)

...

}
Run Code Online (Sandbox Code Playgroud)

...

MAX_ARG_STRLEN被定义为页面大小的 32 倍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
Run Code Online (Sandbox Code Playgroud)

...

默认页面大小为 4 KB,因此您不能传递超过 128 KB 的参数。

我现在无法尝试,但如果可能的话,在您的系统上切换到大页面模式(页面大小 4 MB)也许可以解决此问题。

有关更详细的信息和参考,请参阅Unix & Linux SE 上类似问题答案


编辑:

(1) 根据这个答案,可以通过在内核配置中和设置来的页面大小更改x86_64为 1 MBCONFIG_TRANSPARENT_HUGEPAGECONFIG_TRANSPARENT_HUGEPAGE_MADVISEn

(2) 使用上述配置更改重新编译内核后,getconf PAGESIZE仍然返回 4096。根据这个答案 CONFIG_HUGETLB_PAGE,我也可以通过 拉入CONFIG_HUGETLBFS。我现在正在重新编译并再次测试。

(3) 我重新编译了启用的内核CONFIG_HUGETLBFS,现在包含内核文档相应部分中提到的/proc/meminfo相应。然而,页面大小仍然没有改变。因此,虽然我现在应该能够通过调用请求大页面,但内核的默认页面大小确定仍然固定为 4 KB。HugePages_*getconf PAGESIZEmmapMAX_ARG_STRLEN

(4) 我修改linux/include/uapi/linux/binfmts.h#define MAX_ARG_STRLEN (PAGE_SIZE * 64),重新编译了我的内核,现在你的代码生成:

...

117037
123196
123196
129680
129680
136505
143689
151251
159211
Run Code Online (Sandbox Code Playgroud)

...

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
Run Code Online (Sandbox Code Playgroud)

因此,现在限制如预期从 128 KB 变为 256 KB。但我不知道潜在的副作用。据我所知,我的系统似乎运行得很好。