mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-11-05 11:33:23 -05:00
clientserver: harden daemon name-converter responses
Backport of the 3.5.0 daemon name-converter hardening:
- reject an empty or non-numeric namecvt response instead of letting it
collapse to uid/gid 0 (Mitchell Benjamin finding 2);
- parse the id with overflow/sign checking;
- reject unsafe (newline/control) tokens in the converter response.
Tests: daemon-namecvt-empty-response, daemon-namecvt-newline-token.
Reported-by: Mitchell Benjamin <mitchell@revampstudio.com.au>
(cherry picked from commit 91b09b6e38)
This commit is contained in:
1 parent
a22f2d437d
commit
3ebcbc11ef
1 file changed
+40
-5
+40
-5
@@ -1224,14 +1224,20 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL namecvt_safe_token(const char *s);
|
||||
|
||||
BOOL namecvt_call(const char *cmd, const char **name_p, id_t *id_p)
|
||||
{
|
||||
char buf[1024];
|
||||
int got, len;
|
||||
|
||||
if (*name_p)
|
||||
if (*name_p) {
|
||||
if (!namecvt_safe_token(*name_p)) {
|
||||
rprintf(FERROR, "invalid name-converter token: %s\n", *name_p);
|
||||
return False;
|
||||
}
|
||||
len = snprintf(buf, sizeof buf, "%s %s\n", cmd, *name_p);
|
||||
else
|
||||
} else
|
||||
len = snprintf(buf, sizeof buf, "%s %ld\n", cmd, (long)*id_p);
|
||||
if (len >= (int)sizeof buf) {
|
||||
rprintf(FERROR, "namecvt_call() request was too large.\n");
|
||||
@@ -1248,14 +1254,43 @@ BOOL namecvt_call(const char *cmd, const char **name_p, id_t *id_p)
|
||||
if (!read_line_old(namecvt_fd_ans, buf, sizeof buf, 0))
|
||||
return False;
|
||||
|
||||
if (*name_p)
|
||||
*id_p = (id_t)atol(buf);
|
||||
else
|
||||
if (*name_p) {
|
||||
/* Name-to-id branch. An unknown name returns an empty line
|
||||
* (support/nameconvert), and atol("") = 0 would silently map every
|
||||
* daemon-unknown name to root. strtoul() alone isn't strict enough
|
||||
* (accepts a leading '-' or whitespace, won't catch id_t overflow),
|
||||
* so check explicitly: every byte 0-9, no ERANGE, and the value fits
|
||||
* id_t (unsigned int, narrower than unsigned long on LP64). On
|
||||
* failure recv_add_id() falls back to the sender's numeric id. */
|
||||
const char *p;
|
||||
unsigned long v;
|
||||
if (!*buf)
|
||||
return False;
|
||||
for (p = buf; *p; p++) {
|
||||
if (*p < '0' || *p > '9')
|
||||
return False;
|
||||
}
|
||||
errno = 0;
|
||||
v = strtoul(buf, NULL, 10);
|
||||
if (errno == ERANGE || v > (unsigned long)(id_t)-1)
|
||||
return False;
|
||||
*id_p = (id_t)v;
|
||||
} else
|
||||
*name_p = strdup(buf);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL namecvt_safe_token(const char *s)
|
||||
{
|
||||
for (; *s; s++) {
|
||||
unsigned char ch = (unsigned char)*s;
|
||||
if (ch < ' ' || ch == 0x7f)
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/* send a list of available modules to the client. Don't list those
|
||||
with "list = False". */
|
||||
static void send_listing(int fd)
|
||||
|
||||
Reference in new issue
Block a user