系统相关
首页 > 系统相关> > 如何绕过Linux“Too Many Arguments”限制

如何绕过Linux“Too Many Arguments”限制

作者:互联网

我必须将256Kb的文本作为参数传递给“aws sqs”命令,但是在命令行中运行的限制大约为140Kb.这已在许多地方讨论过it been solved in the Linux kernel as of 2.6.23 kernel.

但无法让它发挥作用.我使用的是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

而foo脚本只是:

#!/bin/bash
echo -n "$1" | wc -c

而我的输出是:

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

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

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

“While Linux is not Plan 9, in 2.6.23 Linux is adding variable
argument length. Theoretically you shouldn’t hit frequently “argument
list too long” errors again, but this patch also limits the maximum
argument length to 25% of the maximum stack limit (ulimit -s).”

解决方法:

编辑:

我终于能够将< = 256KB作为单个命令行参数传递(参见底部的编辑(4)).但是,请仔细阅读我是如何做到的,并自行决定这是否是您想要的方式.至少你应该能够理解为什么你被我发现的“卡住”了. 随着ARG_MAX与ulim -s / 4的耦合,引入了MAX_ARG_STRLEN作为最大值.参数的长度:

/*
 *  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定义为linux / include / uapi / linux / binfmts.h中页面大小的32倍:

/*
 * 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

默认页面大小为4KB,因此您无法传递超过128KB的参数.

我现在无法尝试,但如果可能在您的系统上切换到巨大的页面模式(页面大小4MB)解决了这个问题.

有关更多详细信息和参考,请参阅this answera similar question on Unix & Linux SE.

编辑:

(1)
根据this answer,可以通过在内核配置中启用CONFIG_TRANSPARENT_HUGEPAGE并将CONFIG_TRANSPARENT_HUGEPAGE_MADVISE设置为n,将x86_64 Linux的页面大小更改为1MB.

(2)
用上面的配置重新编译我的内核后,getconf PAGESIZE仍然返回4096.
根据this answer,还需要CONFIG_HUGETLB_PAGE,我可以通过CONFIG_HUGETLBFS获取.我现在正在重新编译并将再次测试.

(3)
我在启用CONFIG_HUGETLBFS的情况下重新编译了我的内核,现在/ proc / meminfo包含the corresponding section of the kernel documentation中提到的相应HugePages_ *条目.
但是,根据getconf PAGESIZE的页面大小仍然没有变化.因此,虽然我现在应该可以通过mmap调用请求大页面,但内核确定MAX_ARG_STRLEN的默认页面大小仍然固定为4KB.

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

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

所以现在限制从128KB移动到256KB.
我不知道潜在的副作用.
据我所知,我的系统似乎运行得很好.

标签:shell,linux,amazon-sqs
来源: https://codeday.me/bug/20190519/1136548.html