[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
incorrect lseek() when processing script ending in unterminated line
From: |
Stephane Chazelas |
Subject: |
incorrect lseek() when processing script ending in unterminated line |
Date: |
Wed, 21 Dec 2016 14:35:44 +0000 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
Hello.
That was discovered at
http://unix.stackexchange.com/a/331884
Consider this script that modifies itself (and happens not to
end in a newline character):
$ printf %s 'printf "\necho %s\n" {1..10} >> $0' > script.sh; bash -x
./script.sh
+ printf '\necho %s\n' 1 2 3 4 5 6 7 8 9 10
+ echo 1
1
+ echo 2
2
+ echo 3
3
+ echo 4
4
+ echo 5
5
+ echo 6
6
+ echo 7
7
+ echo 8
8
+ echo 9
9
+ echo 10
10
That's fine so far. Now, if I run an external command instead of
printf (like /usr/bin/printf):
$ printf %s '/usr/bin/printf "\necho %s\n" {1..10} >> $0' > script.sh; bash -x
./script.sh
+ /usr/bin/printf '\necho %s\n' 1 2 3 4 5 6 7 8 9 10
+ ho 6
./script.sh: line 2: ho: command not found
+ echo 7
7
+ echo 8
8
+ echo 9
9
+ echo 10
10
Running bash under strace, we see:
read(255, "/usr/bin/printf \"\\necho %s\\n\" {1"..., 43) = 43
read(255, "", 43) = 0
brk(0x12c5000) = 0x12c5000
write(2, "+ /usr/bin/printf '\\necho %s\\n' "..., 53+ /usr/bin/printf '\necho
%s\n' 1 2 3 4 5 6 7 8 9 10
) = 53
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
lseek(255, 43, SEEK_CUR) = 86
Note that it's a SEEK_CUR, not SEEK_SET above, so we seek 43
bytes past the end of the file.
In gdb breaking on that lseek():
(gdb) bt
#0 lseek64 () at ../sysdeps/unix/syscall-template.S:84
#1 0x00005555555c808f in sync_buffered_stream (bfd=<optimized out>) at
input.c:554
#2 0x00005555555aeff8 in make_child (command=command@entry=0x555555925808
"/usr/bin/printf \"\\necho %s\\n\" {1..10} >> $0", async_p=async_p@entry=0)
at jobs.c:1910
#3 0x0000555555599fcd in execute_disk_command
(words=words@entry=0x555555928d88, redirects=0x555555928b08,
command_line=command_line@entry=0x55555592c5c8 "/usr/bin/printf \"\\necho
%s\\n\" {1..10} >> $0", pipe_in=pipe_in@entry=-1, pipe_out=pipe_out@entry=-1,
async=async@entry=0, fds_to_close=0x555555928aa8, cmdflags=0) at
execute_cmd.c:5232
#4 0x000055555559ac52 in execute_simple_command
(simple_command=0x555555928a48, pipe_in=pipe_in@entry=-1,
pipe_out=pipe_out@entry=-1, async=async@entry=0,
fds_to_close=fds_to_close@entry=0x555555928aa8) at execute_cmd.c:4429
#5 0x000055555559bcea in execute_command_internal
(command=command@entry=0x555555928a08, asynchronous=asynchronous@entry=0,
pipe_in=pipe_in@entry=-1,
pipe_out=pipe_out@entry=-1, fds_to_close=fds_to_close@entry=0x555555928aa8)
at execute_cmd.c:806
#6 0x000055555559dfa2 in execute_command (command=0x555555928a08) at
execute_cmd.c:405
#7 0x0000555555585e30 in reader_loop () at eval.c:180
#8 0x00005555555848fa in main (argc=3, argv=0x7fffffffdb78,
env=0x7fffffffdb98) at shell.c:792
(gdb) frame 1
#1 0x00005555555c808f in sync_buffered_stream (bfd=<optimized out>) at
input.c:554
554 lseek (bp->b_fd, -chars_left, SEEK_CUR);
(gdb) p *bp
$1 = {b_fd = 255, b_buffer = 0x555555927f08 "", b_size = 43, b_used = 0, b_flag
= 1, b_inputp = 43}
Here b_used < b_inputp which as far as I understand is not meant to happen.
That sync_buffered_stream is meant to seek back to where we're
meant to resume reading the script when we've read more than
needed, but here b_inputp > b_used would suggest we've processed
code that is passed what we've read. Or more likely b_used has
incorrectly been set to 0.
I stopped looking at that point.
--
Stephane
- incorrect lseek() when processing script ending in unterminated line,
Stephane Chazelas <=