Package: apt
Version: 3.1.16
Severity: normal
X-Debbugs-Cc: [email protected]
Hello mainteiners!
When apt is built with clang-19 and ASAN sanitizer error
dynamic-stack-buffer-overflow arises in apt-pkg/contrib/cmdnline.cc in
CommandLine::SaveInConfig() because length becomes equal to
100 + argc * 50 on the last iteration of the for loop at line 402.
Sanitizer report:
==8539==ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address
0x7fffdce86c7a at pc 0x7d64f755d4e5 bp 0x7fffdce86b50 sp 0x7fffdce86b40
WRITE of size 1 at 0x7fffdce86c7a thread T0
#0 0x7d64f755d4e4 in CommandLine::SaveInConfig(unsigned int const&, char
const* const*) /orig/apt/apt-pkg/contrib/cmndline.cc:428
#1 0x7d64f755ae69 in CommandLine::Parse(int, char const**)
/orig/apt/apt-pkg/contrib/cmndline.cc:192
#2 0x7d64f7bf73b1 in ParseCommandLine(CommandLine&, APT_CMD, Configuration*
const*, pkgSystem**, int, char const**, bool (*)(CommandLine&),
std::vector<aptDispatchWithHelp, std::allocator<aptDispatchWithHelp> > (*)())
/orig/apt/apt-private/private-cmndline.cc:664
#3 0x6418cbeb36a7 in main /orig/apt/cmdline/apt.cc:133
#4 0x7d64f6cce1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId:
8e9fd827446c24067541ac5390e6f527fb5947bb)
#5 0x7d64f6cce28a in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId:
8e9fd827446c24067541ac5390e6f527fb5947bb)
#6 0x6418cbeb2744 in _start (/orig/apt/cmdline/apt+0x6744) (BuildId:
2783315d6ae80f24080be3c68579595c00461472)
Address 0x7fffdce86c7a is located in stack of thread T0
SUMMARY: AddressSanitizer: dynamic-stack-buffer-overflow
/orig/apt/apt-pkg/contrib/cmndline.cc:428 in CommandLine::SaveInConfig(unsigned
int const&, char const* const*)
Shadow bytes around the buggy address:
0x7fffdce86980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86b00: 00 00 00 00 00 00 00 00 00 00 00 00 ca ca ca ca
0x7fffdce86b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7fffdce86c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[02]
0x7fffdce86c80: cb cb cb cb 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fffdce86e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==8539==ABORTING
Reproducing:
To reproduce build the project with ASAN and in cmdline/ do
./apt 0o
"000000000000====================================================================================================================
"
Quotation marks are present to preserve a space in argv[2].
Suggested fixes:
I don't know how exactly to fix it, but there are a couple suggestions:
Option 1) Add an extra length check.
Diff:
--- a/apt-pkg/contrib/cmndline.cc
+++ b/apt-pkg/contrib/cmndline.cc
@@ -417,6 +417,8 @@ void CommandLine::SaveInConfig(unsigned int const
&argc, char const * const * co
closeQuote = true;
}
}
+ if (length >= sizeof(cmdline) - 2)
+ continue;
if (closeQuote == true)
{
cmdline[length++] = '\'';
Option 2) Allocate more memory for the cmdline variable based on
argv length (could be excessive in the suggestion below).
Diff:
--- a/apt-pkg/contrib/cmndline.cc
+++ b/apt-pkg/contrib/cmndline.cc
@@ -394,7 +394,11 @@ bool CommandLine::DispatchArg(Dispatch const *
const Map,bool NoMatch)
than nothing after all. */
void CommandLine::SaveInConfig(unsigned int const &argc, char const *
const * const argv)
{
- char cmdline[100 + argc * 50];
+ unsigned int argvLength = 0;
+ for (int i = 0; i < argc; i++)
+ {
+ argvLength += strlen(argv[i]) + 1;
+ }
+ char cmdline[100 + argvLength * 3];
memset(cmdline, 0, sizeof(cmdline));
unsigned int length = 0;
bool lastWasOption = false;
-- System Information:
Debian Release: trixie/sid
Architecture: amd64 (x86_64)
Kernel: Linux 6.12.11-1-generic (SMP w/12 CPU threads; PREEMPT)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=C, LC_CTYPE=C.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: unable to detect