garbage in struct sockaddr_un causes bind() error on Minix 3.2.1

124 views
Skip to first unread message

Tanaka Akira

unread,
Mar 8, 2013, 12:25:57 AM3/8/13
to min...@googlegroups.com
Hi.

I found garbage in struct sockaddr_un causes
a problem in bind() on Minix 3.2.1.

It seems Minix 3.2.1 bind() over read a given buffer.

The test program follows specifies the end of the socket address
as the terminating NUL character and the 3rd argument of bind().
But garbage ('?' characters) after that causes
"file name too long" error.
(If I fill '\0' instead of '?', the program works.)

Note that specifying the socket length shorter than
sizeof(struct sockaddr_un) is a traditional way to use
Unix domain socket.
4.3BSD document:
http://www.tuhs.org/Archive/4BSD/Distributions/4.3BSD/usr.tar.gz
doc/ps1/08.ipc/2.t
4.4BSD document: http://docs.freebsd.org/44doc/psd/21.ipc/paper.pdf

Also, the program works well on Minix 3.2.0.

Is the Minix 3.2.1 beahavior intentional?

minix321% uname -srvm
Minix 3.2.1 i686
minix321% ls
tst.c
minix321% cat tst.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
struct sockaddr_un saddr;
int s;
int ret;

memset(&saddr, '?', sizeof(saddr)); /* garbage */
saddr.sun_family = AF_UNIX;
saddr.sun_path[0] = 'f';
saddr.sun_path[1] = 'o';
saddr.sun_path[2] = 'o';
saddr.sun_path[3] = '\0';

s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s == -1) { perror("socket"); exit(EXIT_FAILURE); }

ret = bind(s, (struct sockaddr *)&saddr,
(char *)&saddr.sun_path[4] - (char *)&saddr);
if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); }

return EXIT_SUCCESS;
}
minix321% gcc -Wall tst.c
minix321% ./a.out
bind: file name too long
minix321% ls
a.out tst.c

The program works well on Minix 3.2.0 as follows.

minix320% uname -srvm
Minix 3.2.0 i686
minix320% ls
tst.c
minix320% gcc -Wall tst.c
minix320% ./a.out
minix320% ls
a.out foo tst.c
minix320% ls -l foo
srw-r--r-- 1 akr users 0 Mar 8 14:07 foo
--
Tanaka Akira

Thomas Veerman

unread,
Mar 8, 2013, 9:51:25 AM3/8/13
to min...@googlegroups.com
Hi,

Thanks for your report and test case. This has been fixed in main line
and an adapted version of your test case has been added to our test suite.

--
Thomas

Tanaka Akira

unread,
Mar 9, 2013, 3:40:14 PM3/9/13
to min...@googlegroups.com
2013/3/8 Thomas Veerman <tvee...@gmail.com>:
>
> Thanks for your report and test case. This has been fixed in main line and
> an adapted version of your test case has been added to our test suite.

Thank you.

The sample program works on
Minix 24ac5ce3f967fdfb40c67bbb13681e41ae7a46cc.

However it seems bind() still over-read the buffer.

Following program shows that getsockname() return the garbage
('?' characters).

Minix 3.2.0 doesn't return '?' characters.

minix321% uname -srvm
Minix 3.2.1 i686
minix321% cat tst.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
struct sockaddr_un saddr;
struct sockaddr_un gaddr;
socklen_t len;
int s;
int ret;
int i;

memset(&saddr, '?', sizeof(saddr)); /* garbage */
saddr.sun_family = AF_UNIX;
saddr.sun_path[0] = 'f';
saddr.sun_path[1] = 'o';
saddr.sun_path[2] = 'o';
saddr.sun_path[3] = '\0';

s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s == -1) { perror("socket"); exit(EXIT_FAILURE); }

ret = bind(s, (struct sockaddr *)&saddr,
(char *)&saddr.sun_path[4] - (char *)&saddr);
if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); }

memset(&gaddr, '\0', sizeof(gaddr));
len = sizeof(gaddr);
ret = getsockname(s, (struct sockaddr *)&gaddr, &len);
if (ret == -1) { perror("getsockname"); exit(EXIT_FAILURE); }

printf("len: %d\n", (int)len);
for (i = 0; i < (int)len; i++) {
int c = (unsigned char)((char *)&gaddr)[i];
if ('!' <= c && c <= '~')
printf("%c ", c);
else
printf("%02x ", c);
if (i % 16 == 15)
putchar('\n');
}

return EXIT_SUCCESS;
}
minix321% ls
tst.c
minix321% gcc -Wall tst.c
minix321% ./a.out
len: 128
01 / h o m e / a k r / r e p o r
t 3 / f o o 00 ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

Minix 3.2.0 getsockname() doesn't return '?' characters
as follows:

minix320% uname -srvm
Minix 3.2.0 i686
minix320% ./a.out
len: 128
01 / h o m e / a k r / r e p o r
t 3 / f o o 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Note that I invoked the latest Minix using QEMU as follows:

% cd /.../build/destdir.i386/multiboot
% qemu-system-i386 \
-hda /.../minix321.img \
-m 1024 \
-net nic \
-net user,hostfwd=tcp:127.0.0.1:4022-:22 \
-kernel kernel \
-append 'rootdevname=c0d0p0s0' \
-initrd mod01_ds,mod02_rs,mod03_pm,mod04_sched,mod05_vfs,mod06_memory,mod07_log,mod08_tty,mod09_mfs,mod10_vm,mod11_pfs,mod12_init
\
-curses

So I didn't update user land programs.
--
Tanaka Akira
Reply all
Reply to author
Forward
0 new messages