svn commit: r295247 - user/ngie/bsnmp_cleanup/contrib/bsnmp/lib

NGie Cooper yaneurabeya at gmail.com
Sun Feb 7 05:14:10 UTC 2016


> On Feb 5, 2016, at 15:48, Jilles Tjoelker <jilles at stack.nl> wrote:
> 
> On Thu, Feb 04, 2016 at 09:08:37AM +0000, Garrett Cooper wrote:
>> Author: ngie
>> Date: Thu Feb  4 09:08:36 2016
>> New Revision: 295247
>> URL: https://svnweb.freebsd.org/changeset/base/295247
> 
>> Log:
>>  Use mkstemp(3) instead of mktemp(3) when creating temporary files to fix
>>  the security pragma
> 
>> Modified:
>>  user/ngie/bsnmp_cleanup/contrib/bsnmp/lib/snmpclient.c
> 
>> Modified: user/ngie/bsnmp_cleanup/contrib/bsnmp/lib/snmpclient.c
>> ==============================================================================
>> --- user/ngie/bsnmp_cleanup/contrib/bsnmp/lib/snmpclient.c	Thu Feb  4 09:07:44 2016	(r295246)
>> +++ user/ngie/bsnmp_cleanup/contrib/bsnmp/lib/snmpclient.c	Thu Feb  4 09:08:36 2016	(r295247)
>> @@ -1000,7 +1000,7 @@ open_client_local(const char *path)
>> 	snprintf(snmp_client.local_path, sizeof(snmp_client.local_path),
>> 	    "%s", SNMP_LOCAL_PATH);
>> 
>> -	if (mktemp(snmp_client.local_path) == NULL) {
>> +	if (mkstemp(snmp_client.local_path) == -1) {
>> 		seterr(&snmp_client, "%s", strerror(errno));
>> 		(void)close(snmp_client.fd);
>> 		snmp_client.fd = -1;
> 
> This shuts up the warning, but I think it will also completely break the
> client. Since mkstemp() creates a regular file, the subsequent bind()
> will fail and the client will not start. Also, the file descriptor is
> leaked.
> 
> The security check has guessed correctly that mktemp() is being misused,
> though. If bind() fails because of [EEXIST], it should be retried with a
> new name to guard against a DoS. Fixing the problem this way will not
> make the security check happy, though.
> 
> The problem can be fixed and the security check made happy by creating a
> temporary directory with mode 700 using mkdtemp() and binding to a name
> in there. Deletion will be a two-step process.
> 
> Looking from a higher level, the bind() call may not be needed. It is
> only needed if the server calls getpeername() or passes non-NULL
> pointers to accept(), and uses that information. Using the pathname is
> likely unsafe since it may contain symlinks.

EEXIST isn’t documented as a valid error with bind(2):

     The following errors are specific to binding addresses in the UNIX
     domain.

     [ENOTDIR]    A component of the path prefix is not a directory.

     [ENAMETOOLONG]
                  A component of a pathname exceeded 255 characters, or an
                  entire path name exceeded 1023 characters.

     [ENOENT]     A prefix component of the path name does not exist.

     [ELOOP]      Too many symbolic links were encountered in translating the
                  pathname.

     [EIO]        An I/O error occurred while making the directory entry or
                  allocating the inode.

     [EROFS]      The name would reside on a read-only file system.

     [EISDIR]     An empty pathname was specified.

Testing it out, it fails with EADDRINUSE — yeah, bad choice. I’ll revert the commit and mute the warning.
Thanks!
-Ngie

$ cat ~/test_bind.c 
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <err.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

#define LOCAL_SOCK      "/tmp/my.sock"

int
main(void)
{
        struct sockaddr_un n;
        int s;

        close(open(LOCAL_SOCK, O_CREAT|O_WRONLY));

        s = socket(AF_LOCAL, SOCK_DGRAM, 0);
        if (s == -1)
                err(1, "socket");

        n.sun_family = AF_LOCAL;
        strlcpy(n.sun_path, LOCAL_SOCK, sizeof(n.sun_path));

        if (bind(s, (struct sockaddr*)&n, SUN_LEN(&n)) == -1)
                err(1, "bind");

        unlink(LOCAL_SOCK);

        close(s);

        return (0);
}
$ ~/test_bind 
test_bind: bind: Address already in use


More information about the svn-src-user mailing list