Commit Diff


commit - 01b7ba6b7375d24a087d44aa48c0b78d66a6187e
commit + f77a24b0362de269128c9588d65818958a9ec9a9
blob - f6f99ad590182ea6fbbc1c325681cd23eda29ec4
blob + 65ff442b096e36f03c632555fd6def55aea92bc4
--- include/got_error.h
+++ include/got_error.h
@@ -78,6 +78,7 @@
 #define GOT_ERR_UUID_INVALID	62
 #define GOT_ERR_UUID		63
 #define GOT_ERR_LOCKFILE_TIMEOUT 64
+#define GOT_ERR_BAD_REF_NAME	65
 
 static const struct got_error {
 	int code;
@@ -146,6 +147,7 @@ static const struct got_error {
 	{ GOT_ERR_UUID_INVALID, "uuid invalid" },
 	{ GOT_ERR_UUID,		"uuid error" },
 	{ GOT_ERR_LOCKFILE_TIMEOUT,"lockfile timeout" },
+	{ GOT_ERR_BAD_REF_NAME,	"bad reference name" },
 };
 
 /*
blob - adbeed13ac643c78f48533f886ec943ad7de7be0
blob + 9e9655183bf6af53d89c2fcea53352d7d2a47b3e
--- lib/reference.c
+++ lib/reference.c
@@ -17,6 +17,7 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 
+#include <ctype.h>
 #include <dirent.h>
 #include <sha1.h>
 #include <stdio.h>
@@ -36,6 +37,7 @@
 #include "got_lib_delta.h"
 #include "got_lib_inflate.h"
 #include "got_lib_object.h"
+#include "got_lib_lockfile.h"
 
 #ifndef nitems
 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
@@ -157,6 +159,61 @@ get_refs_dir_path(struct got_repository *repo, const c
 		return strdup(got_repo_get_path_git_dir(repo));
 
 	return got_repo_get_path_refs(repo);
+}
+
+static int
+is_valid_ref_name(const char *name)
+{
+	const char *s, *slash, *seg;
+	const char forbidden[] = { ' ', '~', '^', ':', '?', '*', '[' , '\\' };
+	const char *forbidden_seq[] = { "//", "..", "@{" };
+	const char *lfs = GOT_LOCKFILE_SUFFIX;
+	const size_t lfs_len = sizeof(GOT_LOCKFILE_SUFFIX) - 1;
+	int i;
+
+	if (name[0] == '@' && name[1] == '\0')
+		return 0;
+
+	slash = strchr(name, '/');
+	if (slash == NULL)
+		return 0;
+
+	s = name;
+	seg = s;
+	if (seg[0] == '\0' || seg[0] == '.' || seg[0] == '/')
+		return 0;
+	while (*s) {
+		for (i = 0; i < nitems(forbidden); i++) {
+			if (*s == forbidden[i])
+				return 0;
+		}
+		for (i = 0; i < nitems(forbidden_seq); i++) {
+			if (s[0] == forbidden_seq[i][0] &&
+			    s[1] == forbidden_seq[i][1])
+				return 0;
+		}
+		if (iscntrl((unsigned char)s[0]))
+			return 0;
+		if (s[0] == '.' && s[1] == '\0')
+			return 0;
+		if (*s == '/') {
+			const char *nextseg = s + 1;
+			if (nextseg[0] == '\0' || nextseg[0] == '.' ||
+			    nextseg[0] == '/')
+				return 0;
+			if (seg <= s - lfs_len &&
+			    strncmp(s - lfs_len, lfs, lfs_len) == 0)
+				return 0;
+			seg = nextseg;
+		}
+		s++;
+	}
+
+	if (seg <= s - lfs_len &&
+	    strncmp(s - lfs_len, lfs, lfs_len) == 0)
+		return 0;
+
+	return 1;
 }
 
 const struct got_error *
@@ -165,6 +222,9 @@ got_ref_alloc(struct got_reference **ref, const char *
 {
 	const struct got_error *err = NULL;
 
+	if (!is_valid_ref_name(name))
+		return got_error(GOT_ERR_BAD_REF_NAME);
+
 	*ref = calloc(1, sizeof(**ref));
 	if (*ref == NULL)
 		return got_error_from_errno();