2006-09-07 13:12:05 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2006 Franck Bui-Huu
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
|
|
|
#include "builtin.h"
|
|
|
|
#include "archive.h"
|
|
|
|
#include "pkt-line.h"
|
2006-09-10 10:33:34 +00:00
|
|
|
#include "sideband.h"
|
2011-11-19 07:40:04 +00:00
|
|
|
#include "run-command.h"
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
#include "argv-array.h"
|
2006-09-07 13:12:05 +00:00
|
|
|
|
|
|
|
static const char upload_archive_usage[] =
|
2008-07-13 13:36:15 +00:00
|
|
|
"git upload-archive <repo>";
|
2006-09-07 13:12:05 +00:00
|
|
|
|
2006-09-10 10:33:34 +00:00
|
|
|
static const char deadchild[] =
|
2008-07-13 13:36:15 +00:00
|
|
|
"git upload-archive: archiver died with error";
|
2006-09-07 13:12:05 +00:00
|
|
|
|
2008-07-25 10:41:23 +00:00
|
|
|
#define MAX_ARGS (64)
|
2006-09-10 10:33:34 +00:00
|
|
|
|
2011-11-19 07:40:04 +00:00
|
|
|
int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix)
|
2006-09-07 13:12:05 +00:00
|
|
|
{
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
struct argv_array sent_argv = ARGV_ARRAY_INIT;
|
2006-09-07 13:12:05 +00:00
|
|
|
const char *arg_cmd = "argument ";
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
char buf[4096];
|
2006-09-07 13:12:05 +00:00
|
|
|
int len;
|
|
|
|
|
2011-11-15 23:39:33 +00:00
|
|
|
if (argc != 2)
|
|
|
|
usage(upload_archive_usage);
|
|
|
|
|
2013-02-20 20:00:59 +00:00
|
|
|
if (!enter_repo(argv[1], 0))
|
|
|
|
die("'%s' does not appear to be a git repository", argv[1]);
|
2011-11-15 23:39:33 +00:00
|
|
|
|
2006-09-07 13:12:05 +00:00
|
|
|
/* put received options in sent_argv[] */
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
argv_array_push(&sent_argv, "git-upload-archive");
|
|
|
|
for (;;) {
|
2006-09-07 13:12:05 +00:00
|
|
|
/* This will die if not enough free space in buf */
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
len = packet_read_line(0, buf, sizeof(buf));
|
2006-09-07 13:12:05 +00:00
|
|
|
if (len == 0)
|
|
|
|
break; /* got a flush */
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
if (sent_argv.argc > MAX_ARGS)
|
|
|
|
die("Too many options (>%d)", MAX_ARGS - 1);
|
2006-09-07 13:12:05 +00:00
|
|
|
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
if (prefixcmp(buf, arg_cmd))
|
|
|
|
die("'argument' token or flush expected");
|
|
|
|
argv_array_push(&sent_argv, buf + strlen(arg_cmd));
|
2006-09-07 13:12:05 +00:00
|
|
|
}
|
2011-11-15 23:39:33 +00:00
|
|
|
|
|
|
|
/* parse all options sent by the client */
|
upload-archive: use argv_array to store client arguments
The current parsing scheme for upload-archive is to pack
arguments into a fixed-size buffer, separated by NULs, and
put a pointer to each argument in the buffer into a
fixed-size argv array.
This works fine, and the limits are high enough that nobody
reasonable is going to hit them, but it makes the code hard
to follow. Instead, let's just stuff the arguments into an
argv_array, which is much simpler. That lifts the "all
arguments must fit inside 4K together" limit.
We could also trivially lift the MAX_ARGS limitation (in
fact, we have to keep extra code to enforce it). But that
would mean a client could force us to allocate an arbitrary
amount of memory simply by sending us "argument" lines. By
limiting the MAX_ARGS, we limit an attacker to about 4
megabytes (64 times a maximum 64K packet buffer). That may
sound like a lot compared to the 4K limit, but it's not a
big deal compared to what git-archive will actually allocate
while working (e.g., to load blobs into memory). The
important thing is that it is bounded.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 20:01:26 +00:00
|
|
|
return write_archive(sent_argv.argc, sent_argv.argv, prefix, 0, NULL, 1);
|
2006-09-10 10:33:34 +00:00
|
|
|
}
|
|
|
|
|
2009-11-14 21:33:13 +00:00
|
|
|
__attribute__((format (printf, 1, 2)))
|
2006-09-12 07:26:57 +00:00
|
|
|
static void error_clnt(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
va_list params;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
va_start(params, fmt);
|
|
|
|
len = vsprintf(buf, fmt, params);
|
|
|
|
va_end(params);
|
|
|
|
send_sideband(1, 3, buf, len, LARGE_PACKET_MAX);
|
|
|
|
die("sent error to the client: %s", buf);
|
|
|
|
}
|
|
|
|
|
2009-06-17 10:11:10 +00:00
|
|
|
static ssize_t process_input(int child_fd, int band)
|
2006-09-12 07:26:57 +00:00
|
|
|
{
|
|
|
|
char buf[16384];
|
|
|
|
ssize_t sz = read(child_fd, buf, sizeof(buf));
|
|
|
|
if (sz < 0) {
|
2007-01-08 15:58:08 +00:00
|
|
|
if (errno != EAGAIN && errno != EINTR)
|
2006-09-12 07:26:57 +00:00
|
|
|
error_clnt("read error: %s\n", strerror(errno));
|
2009-06-17 10:11:10 +00:00
|
|
|
return sz;
|
2006-09-12 07:26:57 +00:00
|
|
|
}
|
|
|
|
send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
|
2009-06-17 10:11:10 +00:00
|
|
|
return sz;
|
2006-09-12 07:26:57 +00:00
|
|
|
}
|
|
|
|
|
2006-09-10 10:33:34 +00:00
|
|
|
int cmd_upload_archive(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
2011-11-19 07:40:04 +00:00
|
|
|
struct child_process writer = { argv };
|
|
|
|
|
2011-11-15 23:39:33 +00:00
|
|
|
/*
|
|
|
|
* Set up sideband subprocess.
|
|
|
|
*
|
|
|
|
* We (parent) monitor and read from child, sending its fd#1 and fd#2
|
|
|
|
* multiplexed out to our fd#1. If the child dies, we tell the other
|
|
|
|
* end over channel #3.
|
|
|
|
*/
|
2011-11-19 07:40:04 +00:00
|
|
|
argv[0] = "upload-archive--writer";
|
|
|
|
writer.out = writer.err = -1;
|
|
|
|
writer.git_cmd = 1;
|
|
|
|
if (start_command(&writer)) {
|
2006-09-10 10:33:34 +00:00
|
|
|
int err = errno;
|
2011-11-19 07:40:04 +00:00
|
|
|
packet_write(1, "NACK unable to spawn subprocess\n");
|
2006-09-10 10:33:34 +00:00
|
|
|
die("upload-archive: %s", strerror(err));
|
|
|
|
}
|
|
|
|
|
2006-09-07 13:12:05 +00:00
|
|
|
packet_write(1, "ACK\n");
|
|
|
|
packet_flush(1);
|
|
|
|
|
2006-09-10 10:33:34 +00:00
|
|
|
while (1) {
|
|
|
|
struct pollfd pfd[2];
|
|
|
|
|
2011-11-19 07:40:04 +00:00
|
|
|
pfd[0].fd = writer.out;
|
2006-09-10 10:33:34 +00:00
|
|
|
pfd[0].events = POLLIN;
|
2011-11-19 07:40:04 +00:00
|
|
|
pfd[1].fd = writer.err;
|
2006-09-10 10:33:34 +00:00
|
|
|
pfd[1].events = POLLIN;
|
|
|
|
if (poll(pfd, 2, -1) < 0) {
|
|
|
|
if (errno != EINTR) {
|
|
|
|
error("poll failed resuming: %s",
|
|
|
|
strerror(errno));
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2006-09-12 07:26:57 +00:00
|
|
|
if (pfd[1].revents & POLLIN)
|
2006-09-10 10:33:34 +00:00
|
|
|
/* Status stream ready */
|
2009-11-11 22:24:42 +00:00
|
|
|
if (process_input(pfd[1].fd, 2))
|
|
|
|
continue;
|
|
|
|
if (pfd[0].revents & POLLIN)
|
|
|
|
/* Data stream ready */
|
|
|
|
if (process_input(pfd[0].fd, 1))
|
|
|
|
continue;
|
2006-09-12 07:26:57 +00:00
|
|
|
|
2011-11-19 07:40:04 +00:00
|
|
|
if (finish_command(&writer))
|
2006-09-12 07:26:57 +00:00
|
|
|
error_clnt("%s", deadchild);
|
2006-09-10 10:33:34 +00:00
|
|
|
packet_flush(1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|