diff options
| author | Paul Eggert | 2016-02-25 11:57:10 -0800 |
|---|---|---|
| committer | Paul Eggert | 2016-02-25 11:59:13 -0800 |
| commit | c1415cc98c4bba699f870277b5311ed320df22cc (patch) | |
| tree | 6c2f96166404906a96ef93390e8e314781c5a8a3 /src/process.c | |
| parent | e65d4d3a5d7748aa742112a6065e1eeeac0275a6 (diff) | |
| download | emacs-c1415cc98c4bba699f870277b5311ed320df22cc.tar.gz emacs-c1415cc98c4bba699f870277b5311ed320df22cc.zip | |
Integer overflow cleanups for ports and socklen
* src/process.c (struct sockaddr_and_len, conv_sockaddr_to_lisp)
(get_lisp_to_sockaddr_size, Fset_process_datagram_address)
(connect_network_socket):
Use ptrdiff_t, not int, for signed object sizes.
This addresses only a theoretical problem, as in practice these
object sizes are less than 2**31, but we might as well use the
same style here as elsewhere in Emacs.
(string_integer_p): Remove; all uses removed.
(Fmake_network_process): Check that port number is in range.
When converting an integer-string service, rely on strtol
rather than rechecking the string by hand.
* src/process.h, src/w32.c (conv_sockaddr_to_lisp):
Adjust prototypes to match.
Diffstat (limited to 'src/process.c')
| -rw-r--r-- | src/process.c | 73 |
1 files changed, 39 insertions, 34 deletions
diff --git a/src/process.c b/src/process.c index 62a26c381b9..a3212445cde 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -302,7 +302,7 @@ static struct coding_system *proc_encode_coding_system[FD_SETSIZE]; | |||
| 302 | /* Table of `partner address' for datagram sockets. */ | 302 | /* Table of `partner address' for datagram sockets. */ |
| 303 | static struct sockaddr_and_len { | 303 | static struct sockaddr_and_len { |
| 304 | struct sockaddr *sa; | 304 | struct sockaddr *sa; |
| 305 | int len; | 305 | ptrdiff_t len; |
| 306 | } datagram_address[FD_SETSIZE]; | 306 | } datagram_address[FD_SETSIZE]; |
| 307 | #define DATAGRAM_CHAN_P(chan) (datagram_address[chan].sa != 0) | 307 | #define DATAGRAM_CHAN_P(chan) (datagram_address[chan].sa != 0) |
| 308 | #define DATAGRAM_CONN_P(proc) \ | 308 | #define DATAGRAM_CONN_P(proc) \ |
| @@ -2245,12 +2245,12 @@ usage: (make-pipe-process &rest ARGS) */) | |||
| 2245 | The address family of sa is not included in the result. */ | 2245 | The address family of sa is not included in the result. */ |
| 2246 | 2246 | ||
| 2247 | Lisp_Object | 2247 | Lisp_Object |
| 2248 | conv_sockaddr_to_lisp (struct sockaddr *sa, int len) | 2248 | conv_sockaddr_to_lisp (struct sockaddr *sa, ptrdiff_t len) |
| 2249 | { | 2249 | { |
| 2250 | Lisp_Object address; | 2250 | Lisp_Object address; |
| 2251 | int i; | 2251 | ptrdiff_t i; |
| 2252 | unsigned char *cp; | 2252 | unsigned char *cp; |
| 2253 | register struct Lisp_Vector *p; | 2253 | struct Lisp_Vector *p; |
| 2254 | 2254 | ||
| 2255 | /* Workaround for a bug in getsockname on BSD: Names bound to | 2255 | /* Workaround for a bug in getsockname on BSD: Names bound to |
| 2256 | sockets in the UNIX domain are inaccessible; getsockname returns | 2256 | sockets in the UNIX domain are inaccessible; getsockname returns |
| @@ -2325,10 +2325,10 @@ conv_sockaddr_to_lisp (struct sockaddr *sa, int len) | |||
| 2325 | 2325 | ||
| 2326 | /* Get family and required size for sockaddr structure to hold ADDRESS. */ | 2326 | /* Get family and required size for sockaddr structure to hold ADDRESS. */ |
| 2327 | 2327 | ||
| 2328 | static int | 2328 | static ptrdiff_t |
| 2329 | get_lisp_to_sockaddr_size (Lisp_Object address, int *familyp) | 2329 | get_lisp_to_sockaddr_size (Lisp_Object address, int *familyp) |
| 2330 | { | 2330 | { |
| 2331 | register struct Lisp_Vector *p; | 2331 | struct Lisp_Vector *p; |
| 2332 | 2332 | ||
| 2333 | if (VECTORP (address)) | 2333 | if (VECTORP (address)) |
| 2334 | { | 2334 | { |
| @@ -2474,7 +2474,8 @@ set up yet, this function will block until socket setup has completed. */) | |||
| 2474 | (Lisp_Object process, Lisp_Object address) | 2474 | (Lisp_Object process, Lisp_Object address) |
| 2475 | { | 2475 | { |
| 2476 | int channel; | 2476 | int channel; |
| 2477 | int family, len; | 2477 | int family; |
| 2478 | ptrdiff_t len; | ||
| 2478 | 2479 | ||
| 2479 | CHECK_PROCESS (process); | 2480 | CHECK_PROCESS (process); |
| 2480 | 2481 | ||
| @@ -3085,7 +3086,7 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) | |||
| 3085 | int family; | 3086 | int family; |
| 3086 | struct sockaddr *sa = NULL; | 3087 | struct sockaddr *sa = NULL; |
| 3087 | int ret; | 3088 | int ret; |
| 3088 | int addrlen; | 3089 | ptrdiff_t addrlen; |
| 3089 | struct Lisp_Process *p = XPROCESS (proc); | 3090 | struct Lisp_Process *p = XPROCESS (proc); |
| 3090 | Lisp_Object contact = p->childp; | 3091 | Lisp_Object contact = p->childp; |
| 3091 | int optbits = 0; | 3092 | int optbits = 0; |
| @@ -3283,8 +3284,8 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) | |||
| 3283 | memset (datagram_address[s].sa, 0, addrlen); | 3284 | memset (datagram_address[s].sa, 0, addrlen); |
| 3284 | if (remote = Fplist_get (contact, QCremote), !NILP (remote)) | 3285 | if (remote = Fplist_get (contact, QCremote), !NILP (remote)) |
| 3285 | { | 3286 | { |
| 3286 | int rfamily, rlen; | 3287 | int rfamily; |
| 3287 | rlen = get_lisp_to_sockaddr_size (remote, &rfamily); | 3288 | ptrdiff_t rlen = get_lisp_to_sockaddr_size (remote, &rfamily); |
| 3288 | if (rlen != 0 && rfamily == family | 3289 | if (rlen != 0 && rfamily == family |
| 3289 | && rlen == addrlen) | 3290 | && rlen == addrlen) |
| 3290 | conv_lisp_to_sockaddr (rfamily, remote, | 3291 | conv_lisp_to_sockaddr (rfamily, remote, |
| @@ -3428,17 +3429,6 @@ conv_numerical_to_lisp (unsigned char *number, int length, int port) | |||
| 3428 | } | 3429 | } |
| 3429 | #endif | 3430 | #endif |
| 3430 | 3431 | ||
| 3431 | /* Return true if STRING consists only of numerical characters. */ | ||
| 3432 | static bool | ||
| 3433 | string_integer_p (Lisp_Object string) | ||
| 3434 | { | ||
| 3435 | char *s = SSDATA (string), c; | ||
| 3436 | while ((c = *s++)) | ||
| 3437 | if (c < '0' || c > '9') | ||
| 3438 | return false; | ||
| 3439 | return true; | ||
| 3440 | } | ||
| 3441 | |||
| 3442 | /* Create a network stream/datagram client/server process. Treated | 3432 | /* Create a network stream/datagram client/server process. Treated |
| 3443 | exactly like a normal process when reading and writing. Primary | 3433 | exactly like a normal process when reading and writing. Primary |
| 3444 | differences are in status display and process deletion. A network | 3434 | differences are in status display and process deletion. A network |
| @@ -3617,7 +3607,7 @@ usage: (make-network-process &rest ARGS) */) | |||
| 3617 | #ifdef HAVE_LOCAL_SOCKETS | 3607 | #ifdef HAVE_LOCAL_SOCKETS |
| 3618 | struct sockaddr_un address_un; | 3608 | struct sockaddr_un address_un; |
| 3619 | #endif | 3609 | #endif |
| 3620 | int port = 0; | 3610 | EMACS_INT port = 0; |
| 3621 | Lisp_Object tem; | 3611 | Lisp_Object tem; |
| 3622 | Lisp_Object name, buffer, host, service, address; | 3612 | Lisp_Object name, buffer, host, service, address; |
| 3623 | Lisp_Object filter, sentinel; | 3613 | Lisp_Object filter, sentinel; |
| @@ -3807,7 +3797,7 @@ usage: (make-network-process &rest ARGS) */) | |||
| 3807 | error ("%s/%s getaddrinfo_a error %d", SSDATA (host), portstring, ret); | 3797 | error ("%s/%s getaddrinfo_a error %d", SSDATA (host), portstring, ret); |
| 3808 | 3798 | ||
| 3809 | goto open_socket; | 3799 | goto open_socket; |
| 3810 | } | 3800 | } |
| 3811 | #endif /* HAVE_GETADDRINFO_A */ | 3801 | #endif /* HAVE_GETADDRINFO_A */ |
| 3812 | 3802 | ||
| 3813 | #ifdef HAVE_GETADDRINFO | 3803 | #ifdef HAVE_GETADDRINFO |
| @@ -3862,20 +3852,35 @@ usage: (make-network-process &rest ARGS) */) | |||
| 3862 | if (EQ (service, Qt)) | 3852 | if (EQ (service, Qt)) |
| 3863 | port = 0; | 3853 | port = 0; |
| 3864 | else if (INTEGERP (service)) | 3854 | else if (INTEGERP (service)) |
| 3865 | port = (unsigned short) XINT (service); | 3855 | port = XINT (service); |
| 3866 | /* Allow the service to be a string containing the port number, | ||
| 3867 | because that's allowed if you have getaddrbyname. */ | ||
| 3868 | else if (string_integer_p (service)) | ||
| 3869 | port = strtol (SSDATA (service), NULL, 10); | ||
| 3870 | else | 3856 | else |
| 3871 | { | 3857 | { |
| 3872 | struct servent *svc_info; | ||
| 3873 | CHECK_STRING (service); | 3858 | CHECK_STRING (service); |
| 3874 | svc_info = getservbyname (SSDATA (service), | 3859 | |
| 3875 | (socktype == SOCK_DGRAM ? "udp" : "tcp")); | 3860 | port = -1; |
| 3876 | if (svc_info == 0) | 3861 | if (SBYTES (service) != 0) |
| 3877 | error ("Unknown service: %s", SDATA (service)); | 3862 | { |
| 3878 | port = ntohs (svc_info->s_port); | 3863 | /* Allow the service to be a string containing the port number, |
| 3864 | because that's allowed if you have getaddrbyname. */ | ||
| 3865 | char *service_end; | ||
| 3866 | long int lport = strtol (SSDATA (service), &service_end, 10); | ||
| 3867 | if (service_end == SSDATA (service) + SBYTES (service)) | ||
| 3868 | port = lport; | ||
| 3869 | else | ||
| 3870 | { | ||
| 3871 | struct servent *svc_info | ||
| 3872 | = getservbyname (SSDATA (service), | ||
| 3873 | socktype == SOCK_DGRAM ? "udp" : "tcp"); | ||
| 3874 | if (svc_info) | ||
| 3875 | port = ntohs (svc_info->s_port); | ||
| 3876 | } | ||
| 3877 | } | ||
| 3878 | } | ||
| 3879 | |||
| 3880 | if (! (0 <= port && port < 1 << 16)) | ||
| 3881 | { | ||
| 3882 | AUTO_STRING (unknown_service, "Unknown service: %s"); | ||
| 3883 | xsignal1 (Qerror, CALLN (Fformat, unknown_service, service)); | ||
| 3879 | } | 3884 | } |
| 3880 | 3885 | ||
| 3881 | #ifndef HAVE_GETADDRINFO | 3886 | #ifndef HAVE_GETADDRINFO |