Hi, I think the overriding mechanism should be disabled for suid processes, so substituted *__secure_getenv* for *getenv*.
--- hurdsock.c 2007-07-25 11:24:46.000000000 +0800 +++ hurdsock2.c 2007-07-25 11:01:02.000000000 +0800 @@ -76,14 +76,40 @@ if (domain > max_domain || servers[domain] == MACH_PORT_NULL) { - char name[sizeof (_SERVERS_SOCKET) + 100]; - char *np = &name[sizeof (name)]; - *--np = '\0'; - np = _itoa (domain, np, 10, 0); - *--np = '/'; - np -= sizeof (_SERVERS_SOCKET) - 1; - memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1); - server = __file_name_lookup (np, 0, 0); + char *serverlist; + switch (domain) + { + case PF_LOCAL: + serverlist = __secure_getenv("SERVERS_SOCKET_LOCAL"); + break; + case PF_INET: + serverlist = __secure_getenv("SERVERS_SOCKET_INET"); + break; + default: + serverlist = NULL; + break; + } + if (serverlist && *serverlist) + { + char *tryname; + serverlist = strdupa(serverlist); + tryname = strsep(&serverlist, ":"); + do + server = __file_name_lookup(tryname, 0, 0); + while (server == MACH_PORT_NULL && + (tryname = strsep(&serverlist, ":"))); + } + else + { + char name[sizeof (_SERVERS_SOCKET) + 100]; + char *np = &name[sizeof (name)]; + *--np = '\0'; + np = _itoa (domain, np, 10, 0); + *--np = '/'; + np -= sizeof (_SERVERS_SOCKET) - 1; + memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1); + server = __file_name_lookup (np, 0, 0); + } if (domain <= max_domain) servers[domain] = server; } On 7/23/07, Wei Shen <[EMAIL PROTECTED]> wrote:
Hi all, I made a try to implement a basic way of socket servers (pfinet and pflocal) overriding, as described below. Comments are solicited. 1) Add two new environment variables: SERVERS_SOCKET_LOCAL for the pf_local socket server and SERVERS_SOCKET_INET for the pf_inet server. The value of each variable should be set to a colon-separated list, and each element of the list is a file path that specifies a overriding server. 2) Hack *_hurd_socket_server* in "hurd/hurdsock.c" of Glibc to check for the two environment variables. For example, when looking up the socket server of pf_inet domain, * _hurd_socket_server* first checks SERVERS_SOCKET_INET: (1) if SERVERS_SOCKET_INET is not set or is set to null, then just queries and returns the port of the default pf_inet server as usual; (2) or else, repeatedly tries querying each overriding server in the server list defined by SERVERS_SOCKET_INET, until the first existing overriding server is found (or none is found). Two limitations of the implementation (which I think are not essential) are: (1) Since the library keeps all the server socket ports it has ever looked up, changes of the environmental variables after socket ports initiation will not take effect. (2) *_hurd_socket_server* just try to find the first exsiting overriding server, but can not check whether the server is a correct socket server to skip invalid ones and try others behind (of course, the socket interface can always notify the user if current socket server is invalid). I am also not quite sure on two issues: (1) Should we disable the overriding mechanism for SUID or SGID processes (e.g. substituting *__secure_getenv* for *getenv*). (2) If all overriding servers in the list are not present, need we return another error than EPFNOSUPPORT (I think it is enough to remind the user, though it means "Protocol family not supported". The libc interface will notify the user "Bad file descriptor") used previously when the default server is absent? The modified hurd/hurdsock.c is attached to this mail. I have tested it with Glibc-2.5. Regards, Wei Shen
/* _hurd_socket_server - Find the server for a socket domain. Copyright (C) 1991,92,93,94,95,97,99 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include <hurd.h> #include <sys/socket.h> #include <stdlib.h> #include <string.h> #include <hurd/paths.h> #include <stdio.h> #include "stdio-common/_itoa.h" #include <cthreads.h> /* For `struct mutex'. */ #include "hurdmalloc.h" /* XXX */ static struct mutex lock; static file_t *servers; static int max_domain = -1; /* Return a port to the socket server for DOMAIN. Socket servers translate nodes in the directory _SERVERS_SOCKET (canonically /servers/socket). These naming point nodes are named by the simplest decimal representation of the socket domain number, for example "/servers/socket/3". Socket servers are assumed not to change very often. The library keeps all the server socket ports it has ever looked up, and does not look them up in /servers/socket more than once. */ socket_t _hurd_socket_server (int domain, int dead) { socket_t server; HURD_CRITICAL_BEGIN; __mutex_lock (&lock); if (domain > max_domain) { error_t save = errno; file_t *new = realloc (servers, (domain + 1) * sizeof (file_t)); if (new != NULL) { do new[++max_domain] = MACH_PORT_NULL; while (max_domain < domain); servers = new; } else /* No space to cache the port; we will just fetch it anew below. */ errno = save; } if (dead && domain <= max_domain) { /* The user says the port we returned earlier (now in SERVERS[DOMAIN]) was dead. Clear the cache and fetch a new one below. */ __mach_port_deallocate (__mach_task_self (), servers[domain]); servers[domain] = MACH_PORT_NULL; } if (domain > max_domain || servers[domain] == MACH_PORT_NULL) { char *serverlist; switch (domain) { case PF_LOCAL: serverlist = __secure_getenv("SERVERS_SOCKET_LOCAL"); break; case PF_INET: serverlist = __secure_getenv("SERVERS_SOCKET_INET"); break; default: serverlist = NULL; break; } if (serverlist && *serverlist) { char *tryname; serverlist = strdupa(serverlist); tryname = strsep(&serverlist, ":"); do server = __file_name_lookup(tryname, 0, 0); while (server == MACH_PORT_NULL && (tryname = strsep(&serverlist, ":"))); } else { char name[sizeof (_SERVERS_SOCKET) + 100]; char *np = &name[sizeof (name)]; *--np = '\0'; np = _itoa (domain, np, 10, 0); *--np = '/'; np -= sizeof (_SERVERS_SOCKET) - 1; memcpy (np, _SERVERS_SOCKET, sizeof (_SERVERS_SOCKET) - 1); server = __file_name_lookup (np, 0, 0); } if (domain <= max_domain) servers[domain] = server; } else server = servers[domain]; if (server == MACH_PORT_NULL && errno == ENOENT) /* If the server node is absent, we don't support that protocol. */ errno = EPFNOSUPPORT; __mutex_unlock (&lock); HURD_CRITICAL_END; return server; } static void init (void) { int i; __mutex_init (&lock); for (i = 0; i < max_domain; ++i) servers[i] = MACH_PORT_NULL; (void) &init; /* Avoid "defined but not used" warning. */ } text_set_element (_hurd_preinit_hook, init);
_______________________________________________ Bug-hurd mailing list Bug-hurd@gnu.org http://lists.gnu.org/mailman/listinfo/bug-hurd