[nas] Improper fixes in the r288
Erik Auerswald
auerswal at unix-ag.uni-kl.de
Sat Sep 14 13:24:20 MDT 2013
Hello Petr,
On 09/12/2013 04:46 PM, Petr Pisar wrote:
> I read some patches for the `Multiple Vulnerabilities in nas 1.9.3' issue and
> I think some changes are not sufficient.
Thanks for your review!
> E.g. here:
>
> --- server/os/access.c (revision 287)
> +++ server/os/access.c (revision 288)
> @@ -478,9 +478,9 @@
> validhosts = host->next;
> FreeHost(host);
> }
> - strcpy(fname, "/etc/X");
> - strcat(fname, display);
> - strcat(fname, ".hosts");
> + strncpy(fname, "/etc/X", sizeof fname); fname[sizeof fname - 1] = '\0';
> + strncat(fname, display, sizeof fname - strlen(fname) - 1);
> + strncat(fname, ".hosts", sizeof fname - strlen(fname) - 1);
> if (fd = fopen(fname, "r")) {
> while (fgets(hostname, sizeof(hostname), fd)) {
> if (ptr = index(hostname, '\n'))
>
> the `sizeof fname - strlen(fname) - 1' will result into -1 if previous command
> fills fname completely. And because the last argument is of type size_t that
> is unsigned, you will pass a very high positive number.
Well, 'sizeof fname' is the length of the buffer, let's call it L. The
last element of the buffer is '\0'[1]. Thus any string inside the buffer
is of length L-1. Thus:
sizeof fname - strlen(fname) - 1 >= L - (L-1) - 1 == 0
[1] fname[sizeof fname - 1] = '\0'
I have written a small example program to show this:
---8<---
~/tmp$ rm a.out
~/tmp$ cat a.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char buf[10];
char *too_long = "this string is too long for the buffer 'buf'";
strncpy(buf, too_long, sizeof buf);
buf[sizeof buf - 1] = '\0';
printf("example string: '%s'\n", too_long);
printf("length of string: %lu\n", strlen(too_long));
printf("size of buf: %lu\n", sizeof buf);
printf("contents of buf: '%s'\n", buf);
printf("length of string in buf: %lu\n", strlen(buf));
printf("'sizeof buf - strlen(buf) - 1': %lu\n",
sizeof buf - strlen(buf) - 1);
exit(EXIT_SUCCESS);
}
~/tmp$ gcc a.c
~/tmp$ ./a.out
example string: 'this string is too long for the buffer
'buf''
length of string: 44
size of buf: 10
contents of buf: 'this stri'
length of string in buf: 9
'sizeof buf - strlen(buf) - 1': 0
---8<---
> Moreover if the copied text gets clamped, you won't notice it and you will
> try to open wrong file in turn.
You are right. The server will try to read a non-existing or malformed
file. But I think that is acceptable, i.e. no security problem. Since
the code in question is used on AMOEBA only and thus not testable for
me, I do not intend to change this.
> In this case, it would be much more elligible to use snprintf() and check the
> return value:
>
> int r = snprinf(fname, sizeof fname, "/etc/X%s.hosts", display);
> if (r < 0 || r >= sizeof fname))
> FatalError();
I changed the code in a way that only the length of the buffers is
checked. That can be done quite mechanically and verified mechanically
as well. Changing the strcpy() + strcat() + strcat() to snprintf() is
less "_obviously_ correct" IMHO.
> Or here:
>
> --- server/os/connection.c (revision 287)
> +++ server/os/connection.c (revision 288)
> @@ -2115,7 +2127,7 @@
> if (AuServerHostName == NULL)
> FatalError
> ("AUDIOHOST not set, or server host name not given\n");
> - sprintf(host, "%s/%s:%s", DEF_AUSVRDIR, AuServerHostName,
> + snprintf(host, sizeof host, "%s/%s:%s", DEF_AUSVRDIR, AuServerHostName,
> 0 /* port */ );
>
> uniqport(&Au.cap_port);
>
> the host will be undefined, if snprintf() cannot fit the string into the its
> size. You should check for sprintf clamp again.
The connection will probably not succeed in that case. Improving
troubleshooting and debug friendliness is out-of-scope for the security
fixes. Again, this affects AMOEBA only.
I do not have an AMOEBA machine to test on, so I want to change as
little as possible of the AMOEBA specific code.
> -- Petr
Thanks again for the review!
Erik
More information about the nas
mailing list