Anonymous | Login | 2024-04-25 12:03 UTC |
Main | My View | View Issues | Change Log | Docs |
Viewing Issue Simple Details [ Jump to Notes ] | [ Issue History ] [ Print ] | ||||||
ID | Category | Severity | Type | Date Submitted | Last Update | ||
0000980 | [1003.1(2008)/Issue 7] Base Definitions and Headers | Editorial | Enhancement Request | 2015-08-29 08:28 | 2016-06-09 15:44 | ||
Reporter | EdSchouten | View Status | public | ||||
Assigned To | ajosey | ||||||
Priority | normal | Resolution | Rejected | ||||
Status | Closed | ||||||
Name | Ed Schouten | ||||||
Organization | Nuxi | ||||||
User Reference | |||||||
Section | n/a | ||||||
Page Number | n/a | ||||||
Line Number | n/a | ||||||
Interp Status | --- | ||||||
Final Accepted Text | |||||||
Summary | 0000980: *at(): could we have bindat() and connectat() as well? | ||||||
Description |
Back in 2008 we introduced the *at() filesystem operations to allow for race-free traversal of the filesystem namespace. What's interesting is that these functions now play an important role in Capsicum (https://www.cl.cam.ac.uk/research/security/capsicum/). [^] Back when Capsicum was implemented, it was observed that we don't provide *at() calls for two rather important operations: binding and connecting to sockets. bindat() and connectat() don't exist. |
||||||
Desired Action |
I would hereby propose that we add two new functions to <sys/socket.h>, having the following prototypes: int bindat(int socket, int directory, const char *filename); int connectat(int socket, int directory, const char *filename); Assuming 'directory' is equal to AT_FDCWD, these functions should behave identically to the following: bind(socket, (struct sockaddr_un){.sun_family = AF_UNIX, .sun_path = filename}, sizeof(struct sockaddr_un)); connect(socket, (struct sockaddr_un){.sun_family = AF_UNIX, .sun_path = filename}, sizeof(struct sockaddr_un)); If 'directory' is not equal to AT_FDCWD, it uses this directory as its working directory instead of the process-wide working directory. As an added bonus, these functions tackle the long-standing issue that struct sockaddr_un::sun_path is of a fixed size, and typically a lot smaller than PATH_MAX. |
||||||
Tags | No tags attached. | ||||||
Attached Files | |||||||
|
Notes | |
(0002797) eblake (manager) 2015-08-30 03:09 |
If these don't already have an existing implementation, then please make sure to add a flags argument: int bindat(int socket, int directory, const char *filename, int flags); int connectat(int socket, int directory, const char *filename, int flags); We've already regretted that some of the *at() functions (like mkdirat) lacked a flags argument. |
(0002798) EdSchouten (updater) 2015-08-31 11:01 |
So right now there are two implementations: FreeBSD: https://svnweb.freebsd.org/base/head/sys/sys/socket.h?view=markup#l608 [^] int bindat(int fd, int s, const struct sockaddr *addr, socklen_t addrlen); int connectat(int fd, int s, const struct sockaddr *name, socklen_t namelen); CloudABI: https://github.com/NuxiNL/cloudlibc/blob/master/src/include/sys/socket.h#L153 [^] int bindat(int s, int fd, const char *path); int connectat(int s, int fd, const char *path); FreeBSD still uses a 'struct sockaddr' instead of a pathname string. CloudABI's variant doesn't have a flags argument. That said, these functions aren't used that often yet. If the Austin Group were to standardize this function, I will see to it that both these platforms have their prototypes synced up to what's agreed upon. Your proposal with the additional 'flags' parameter makes sense. A further question: do we want this function to return -1 and set errno, or have it return the error code directly? My suspicion is that the former makes more sense: that's also how bind(), connect() and the other *at() calls work. |
(0002799) EdSchouten (updater) 2015-08-31 13:55 |
While we're at it, maybe bindat() should also have a mode_t argument to specify the mode of the newly created socket, like openat()/mkdirat()/mkfifoat()/mknodat(). |
(0002800) EdSchouten (updater) 2015-08-31 16:10 |
Oh, wait. We can disregard that. There is no need to set file permissions on sockets atomically, as you'd still need to call listen() before you receive incoming connections. |
(0002802) shware_systems (reporter) 2015-08-31 21:46 edited on: 2015-08-31 22:24 |
I agree these would be a useful addition, but feel as proposed they are underspecified. The FreeBSD implementation comes closer. First off, the examples for "work like" should strcpy(sun_path /* or derived pointer if sun_path not defined */, filename) and correct size for generic usage is better expressed as sizeof(struct sockaddr_un)+strlen(filename), minus, if needed, sizeof(sockaddr_un.sun_path); with a malloc() of this size preceding. <un.h> should define a constant, imo, e.g. SUN_PATH_SIZE, that when set to 0 indicates sockaddr_un does not include a fixed size field named sun_path, leaving it as implied to follow the sun_family field and any implementation-specific header additions. There is no inherent limit less than PATH_MAX on AF_UNIX names. Implementations that define a default "usually adequate" size for sun_path to match historical practice, per the Application Usage section of <un.h>, should still operate properly when address_len is larger as a parameter to these interfaces. As an implementation may map open sockets to be referenced in a directory like /dev/net/eth0/, eth1/, etc., it would be preferable to allow all socket family types, not just AF_UNIX, if filename matches the text version of an IP4 or IP6 address, or a relative path of appropriate format if passed a sockaddr_in or sockaddr_in6 instead of a filepath string. This is implied so stat() may be used by an application to discover which sockets are active without requiring an available per-process file handle for use with fstat(). The prototypes then become: union sock_at_t { struct sockaddr *sockinfo; unsigned char *filepath; }; // This union unifies the two implementation approaches cited int bindat(int socket, const union sock_at_t *address, socklen_t address_len, int directory, int flags); int connectat(int socket, const union sock_at_t *address, socklen_t address_len, int directory, int flags); #define SOCK_AT_ISPATH // flag value to indicate path part of union should be used; #define SOCK_AT_NOFOLLOW // flag to abort if filepath has a filename referencing a symbolic link #define SOCK_AT_NOTRAVERSE // flag to abort if a stat of an address component indicates the target is on another system The directory and flags arguments are last as bind() and connect() could be extended with a ... parameter to account for those fields, with appropriate AF_* constants defined indicating their presence, as an alternative. SOCK_AT_ISPATH would be implied then, rather than needing to be defined. |
(0002803) EdSchouten (updater) 2015-09-01 07:43 |
I think that this is actually a large step in the wrong direction. The question is, why would you want to call the functions that you proposed above without SOCK_AT_ISPATH set? In that case you could just use the existing bind() function, which has been around for decades and available universally. If you would then consider removing SOCK_AT_ISPATH and use that behaviour by default, you could get rid of the union sock_at_t. By doing that, you end up exactly with what eblake and I proposed. Furthermore, I truly dislike the overloading of typing. In this case you could easily avoid it by having two separate functions. Doing this in a single function only increases the risk of calling it incorrectly. Having the directory argument as one of the last arguments is also inconsistent with the rest of all the other *at() functions. They always take the file descriptor and the pathname string it applies to as a consecutive pair of arguments: int linkat(--> int fd1, const char *name1 <--, --> int fd2, const char *name2 <--, int flag); int symlinkat(const char *name1, --> int fd, const char *name2 <--); This is exactly the reason why the bindat() that I propose has the directory descriptor as its second argument. It should not be placed before the socket, nor should it be placed after the pathname string. Keep in mind that even though the examples that I provided use AF_UNIX explicitly, we could always phrase it in such a way that this function can be used for any address family that uses the filesystem namespace to address instances. In the case of the address families defined by POSIX, that would mean just AF_UNIX. |
(0002804) nick (manager) 2015-09-01 16:38 edited on: 2016-06-09 15:15 |
Further details about the BSD implementation can be found at https://www.freebsd.org/cgi/man.cgi?query=bindat&sektion=2&apropos=0&manpath=FreeBSD+10.0-RELEASE [^] and https://www.freebsd.org/cgi/man.cgi?query=connectat&sektion=2&manpath=FreeBSD+10.0-RELEASE [^] |
(0003260) Don Cragun (manager) 2016-06-09 15:42 |
Although we agree that functions like these would be useful, we can't standardize on either interface when there are existing implementations of these function with different function prototypes and suggestions during this discussion that both should be modified to include a flags argument. We are therefore rejecting this bug as currently presented, but strongly encourage the BSD and Nuxi implementors to work together to come up with a unified solution that both groups are willing to implement as a common reference implementation (preferably using the function footprints mentioned in Note: 0002797) and file a new enhancement request with the results of that joint effort. |
Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group |