Skip to content

Commit c0ceb2c

Browse files
committed
Merge branch 'lt/readlink'
* lt/readlink: combine-diff.c: use strbuf_readlink() builtin-blame.c: use strbuf_readlink() make_absolute_path(): check bounds when seeing an overlong symlink Make 'prepare_temp_file()' ignore st_size for symlinks Make 'diff_populate_filespec()' use the new 'strbuf_readlink()' Make 'index_path()' use 'strbuf_readlink()' Make 'ce_compare_link()' use the new 'strbuf_readlink()' Add generic 'strbuf_readlink()' helper function
2 parents 954597b + 912342d commit c0ceb2c

File tree

9 files changed

+62
-50
lines changed

9 files changed

+62
-50
lines changed

abspath.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ const char *make_absolute_path(const char *path)
6464
len = readlink(buf, next_buf, PATH_MAX);
6565
if (len < 0)
6666
die ("Invalid symlink: %s", buf);
67+
if (PATH_MAX <= len)
68+
die("symbolic link too long: %s", buf);
6769
next_buf[len] = '\0';
6870
buf = next_buf;
6971
buf_index = 1 - buf_index;

builtin-apply.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,10 +1559,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
15591559
{
15601560
switch (st->st_mode & S_IFMT) {
15611561
case S_IFLNK:
1562-
strbuf_grow(buf, st->st_size);
1563-
if (readlink(path, buf->buf, st->st_size) != st->st_size)
1564-
return -1;
1565-
strbuf_setlen(buf, st->st_size);
1562+
if (strbuf_readlink(buf, path, st->st_size) < 0)
1563+
return error("unable to read symlink %s", path);
15661564
return 0;
15671565
case S_IFREG:
15681566
if (strbuf_read_file(buf, path, st->st_size) != st->st_size)

builtin-blame.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,6 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
19961996
if (!contents_from || strcmp("-", contents_from)) {
19971997
struct stat st;
19981998
const char *read_from;
1999-
unsigned long fin_size;
20001999

20012000
if (contents_from) {
20022001
if (stat(contents_from, &st) < 0)
@@ -2008,17 +2007,15 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
20082007
die("Cannot lstat %s", path);
20092008
read_from = path;
20102009
}
2011-
fin_size = xsize_t(st.st_size);
20122010
mode = canon_mode(st.st_mode);
20132011
switch (st.st_mode & S_IFMT) {
20142012
case S_IFREG:
20152013
if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
20162014
die("cannot open or read %s", read_from);
20172015
break;
20182016
case S_IFLNK:
2019-
if (readlink(read_from, buf.buf, buf.alloc) != fin_size)
2017+
if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
20202018
die("cannot readlink %s", read_from);
2021-
buf.len = fin_size;
20222019
break;
20232020
default:
20242021
die("unsupported file type %s", read_from);

combine-diff.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -703,15 +703,15 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
703703
goto deleted_file;
704704

705705
if (S_ISLNK(st.st_mode)) {
706-
size_t len = xsize_t(st.st_size);
707-
result_size = len;
708-
result = xmalloc(len + 1);
709-
if (result_size != readlink(elem->path, result, len)) {
706+
struct strbuf buf = STRBUF_INIT;
707+
708+
if (strbuf_readlink(&buf, elem->path, st.st_size) < 0) {
710709
error("readlink(%s): %s", elem->path,
711710
strerror(errno));
712711
return;
713712
}
714-
result[len] = 0;
713+
result_size = buf.len;
714+
result = strbuf_detach(&buf, NULL);
715715
elem->mode = canon_mode(st.st_mode);
716716
}
717717
else if (0 <= (fd = open(elem->path, O_RDONLY)) &&

diff.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,19 +1773,17 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
17731773
s->size = xsize_t(st.st_size);
17741774
if (!s->size)
17751775
goto empty;
1776-
if (size_only)
1777-
return 0;
17781776
if (S_ISLNK(st.st_mode)) {
1779-
int ret;
1780-
s->data = xmalloc(s->size);
1781-
s->should_free = 1;
1782-
ret = readlink(s->path, s->data, s->size);
1783-
if (ret < 0) {
1784-
free(s->data);
1777+
struct strbuf sb = STRBUF_INIT;
1778+
1779+
if (strbuf_readlink(&sb, s->path, s->size))
17851780
goto err_empty;
1786-
}
1781+
s->data = strbuf_detach(&sb, &s->size);
1782+
s->should_free = 1;
17871783
return 0;
17881784
}
1785+
if (size_only)
1786+
return 0;
17891787
fd = open(s->path, O_RDONLY);
17901788
if (fd < 0)
17911789
goto err_empty;
@@ -1883,13 +1881,12 @@ static void prepare_temp_file(const char *name,
18831881
if (S_ISLNK(st.st_mode)) {
18841882
int ret;
18851883
char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
1886-
size_t sz = xsize_t(st.st_size);
1887-
if (sizeof(buf) <= st.st_size)
1888-
die("symlink too long: %s", name);
1889-
ret = readlink(name, buf, sz);
1884+
ret = readlink(name, buf, sizeof(buf));
18901885
if (ret < 0)
18911886
die("readlink(%s)", name);
1892-
prep_temp_blob(temp, buf, sz,
1887+
if (ret == sizeof(buf))
1888+
die("symlink too long: %s", name);
1889+
prep_temp_blob(temp, buf, ret,
18931890
(one->sha1_valid ?
18941891
one->sha1 : null_sha1),
18951892
(one->sha1_valid ?

read-cache.c

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,27 +99,21 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
9999
static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
100100
{
101101
int match = -1;
102-
char *target;
103102
void *buffer;
104103
unsigned long size;
105104
enum object_type type;
106-
int len;
105+
struct strbuf sb = STRBUF_INIT;
107106

108-
target = xmalloc(expected_size);
109-
len = readlink(ce->name, target, expected_size);
110-
if (len != expected_size) {
111-
free(target);
107+
if (strbuf_readlink(&sb, ce->name, expected_size))
112108
return -1;
113-
}
109+
114110
buffer = read_sha1_file(ce->sha1, &type, &size);
115-
if (!buffer) {
116-
free(target);
117-
return -1;
111+
if (buffer) {
112+
if (size == sb.len)
113+
match = memcmp(buffer, sb.buf, size);
114+
free(buffer);
118115
}
119-
if (size == expected_size)
120-
match = memcmp(buffer, target, size);
121-
free(buffer);
122-
free(target);
116+
strbuf_release(&sb);
123117
return match;
124118
}
125119

sha1_file.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,8 +2523,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
25232523
int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object)
25242524
{
25252525
int fd;
2526-
char *target;
2527-
size_t len;
2526+
struct strbuf sb = STRBUF_INIT;
25282527

25292528
switch (st->st_mode & S_IFMT) {
25302529
case S_IFREG:
@@ -2537,20 +2536,17 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
25372536
path);
25382537
break;
25392538
case S_IFLNK:
2540-
len = xsize_t(st->st_size);
2541-
target = xmalloc(len + 1);
2542-
if (readlink(path, target, len + 1) != st->st_size) {
2539+
if (strbuf_readlink(&sb, path, st->st_size)) {
25432540
char *errstr = strerror(errno);
2544-
free(target);
25452541
return error("readlink(\"%s\"): %s", path,
25462542
errstr);
25472543
}
25482544
if (!write_object)
2549-
hash_sha1_file(target, len, blob_type, sha1);
2550-
else if (write_sha1_file(target, len, blob_type, sha1))
2545+
hash_sha1_file(sb.buf, sb.len, blob_type, sha1);
2546+
else if (write_sha1_file(sb.buf, sb.len, blob_type, sha1))
25512547
return error("%s: failed to insert into database",
25522548
path);
2553-
free(target);
2549+
strbuf_release(&sb);
25542550
break;
25552551
case S_IFDIR:
25562552
return resolve_gitlink_ref(path, "HEAD", sha1);

strbuf.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,33 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
288288
return sb->len - oldlen;
289289
}
290290

291+
#define STRBUF_MAXLINK (2*PATH_MAX)
292+
293+
int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
294+
{
295+
if (hint < 32)
296+
hint = 32;
297+
298+
while (hint < STRBUF_MAXLINK) {
299+
int len;
300+
301+
strbuf_grow(sb, hint);
302+
len = readlink(path, sb->buf, hint);
303+
if (len < 0) {
304+
if (errno != ERANGE)
305+
break;
306+
} else if (len < hint) {
307+
strbuf_setlen(sb, len);
308+
return 0;
309+
}
310+
311+
/* .. the buffer was too small - try again */
312+
hint *= 2;
313+
}
314+
strbuf_release(sb);
315+
return -1;
316+
}
317+
291318
int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
292319
{
293320
int ch;

strbuf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124124
/* XXX: if read fails, any partial read is undone */
125125
extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
126126
extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
127+
extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
127128

128129
extern int strbuf_getline(struct strbuf *, FILE *, int);
129130

0 commit comments

Comments
 (0)