PgSQL · 社区动态 · 说一说PgSQL 9.4.1中的那些安全补丁

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS SQL Server,基础系列 2核4GB
简介: PgSQL 9.4.1在2015年2月5日发布,主打的是安全方面的更新,修补了如下的安全漏洞: CVE-2015-0241 Buffer overruns in “to_char” functions. CVE-2015-0242 Buffer overrun in replacement pr

PgSQL 9.4.1在2015年2月5日发布,主打的是安全方面的更新,修补了如下的安全漏洞:

  • CVE-2015-0241 Buffer overruns in “to_char” functions.
  • CVE-2015-0242 Buffer overrun in replacement printf family of functions.
  • CVE-2015-0243 Memory errors in functions in the pgcrypto extension.
  • CVE-2015-0244 An error in extended protocol message reading.
  • CVE-2014-8161 Constraint violation errors can cause display of values in columns which the user would not normally have rights to see.

也就是说,在9.4 GA版本中,是存在这些安全漏洞的,9.4.1把它们修复了。好消息是,阿里云的RDS PG将直接采用更安全的9.4.1版本。下面我们不妨分析一下这些漏洞的具体情况,看看如果使用9.4 GA,有哪些安全隐患。

CVE-2015-0244

比较起来,CVE-2015-0244这个漏洞较严重些,我们做重点分析。从修复这个问题的代码改动(patch)可以看出,问题主要出在前后端通信过程中。最简单的触发方式,是利用Query Cancellation机制。这里有必要先介绍一下前后端的通信过程和Query Cancellation的实现逻辑。

客户端连接PG时,后端建立一个backend(即后台进程)为其服务,服务逻辑主要在PostgresMain()中。PostgresMain()有一个无条件for循环,不断从客户端读取新的SQL命令,并进行处理。PG每次从客户端读取8K大小的消息;如果一个SQL比较大,大小超过8K,则需要多次读取。

读取一次客户端消息的调用序列如下:


PostgresMain -> ReadCommand -> SocketBackend -> pq_getmessage
                                                        |
                                                        V
             recv <- secure_read  <- pq_recvbuf <- pq_getbytes

其中pq_recvbuf调用secure_read每次读取8K的数据。如果一个SQL很大,比如

INSERT INTO tablename VALUES (1), (2),.....,(10000000)

则需要反复调用secure_read。此时如果用户端发起了一个Query Cancellation,比如在psql控制台按下了Ctl+c,则PG后台进程最终会收到一个SIGINT信号,触发它中断当前的处理,跳转到信号处理函数StatementCancelHandler。其后的函数调用过程如下:


StatementCancelHandler -> ProcessInterrupts -> elog( ERROR,......) 
                                                         |
                                                         V
                     siglongjmp  <-  PG_RE_THROW <- errfinish

可见,最后PG利用siglongjmp,实现了调转。跳转到哪里了呢?我们知道,siglongjmp一般和sigsetjmp成对使用;查看PostgresMain函数,可以发现下面这一行:

if (sigsetjmp(local_sigjmp_buf, 1) != 0)

实际上,siglongjmp就是跳转到这一行,继续执行。接下来执行的逻辑正好是对事务执行回滚和对session(即当前连接)环境做初始化,接着就又开始调用ReadCommand,继续从客户端读取消息了。

仔细分析上述过程,可以发现一个问题:如果PG在读取一个客户端消息的中间,收到了一个Query Cancellation信号,则PG会回滚事务,并将状态改为等待读取新消息,然后再次调用ReadCommand读消息。但是,此时还是从原来的网络连接中,调用recv读取,所以读取到消息,有可能是上一个消息的一部分。就是说,PG可能把上一个消息的一部分,当做一个新的消息的开始来处理!攻击者可以利用这一点,将一个完整的消息,注入到原SQL中,绕过前端的检查,执行原来不被允许的SQL。例如,如果一个网站前端有一个这样的SQL语句:

INSERT INTO table VALUES ( ? )

问号部分,由用户输入并由前端代码填充。正常情况下,如果用户的注入一个'DELETE FROM table',企图删除整个表,是不符合语法的,PG会返回错误。但利用这个漏洞,用户可以在PG接收这个SQL的时候,撤销这次SQL操作,如果用户发起一个Query Cancellation,最终向后台进程发SIGINT信号,则可能会导致后台进程跳转到新消息读取阶段,继续读取消息。此时如果恰好读取到DELETE语句的开头,那么就可以把注入的SQL作为一个新的完整SQL成功执行。

此漏洞直接的修复方法是,在读取一个消息过程中,设置一个状态标识,表明目前正在读取消息的阶段。当发生Query Cancellation中断或者其他会造成中断处理的错误,后台进程跳转到中断处理代码,回滚当前事务后,检测状态标识。如果状态标识被设置,说明是从消息读取阶段被中断的,则直接使用elog( FATAL,…)退出后台进程,并断开连接,

CVE-2015-0241

这个漏洞涉及两个小问题:

一个是to_char代码里面在处理localized month(在具体某个locale下的月份名,例如,”January”在中文locale里面是”一月”)和 localized week day(具体某个locale下得星期的名称,例如,”Monday”在中文里面是”星期一”)时,使用的数组过小,在某些locale下面可能指针越界。

另一个小问题是,to_char在将输入的float类型转换为字符串时,如果指定格式的字符串过长,可能造成存放结果的数组不够大而内存越界。

为修复此漏洞,在下面的文件里面增大了处理数组长度,并加入了对长度的判断。

src/backend/utils/adt/formatting.c

CVE-2015-0242

这个漏洞是PG自带的snprintf函数,在较大的精度要求时可能导致存放结果的数组过小而造成内存越界。这个问题只影响没有snprintf支持的平台。

CVE-2015-0243

只影响插件pgcrypto。主要由于此插件所使用的imath的版本有了变化,造成原来代码里面假设的所调用函数的返回值长度有变化,可能造成数组溢出。

CVE-2014-8161

由于疏忽,BuildIndexValueDescriptionExecBuildSlotValueDescription以及 ri_ReportViolation等函数在打印出错信息时,会把用户无权知道的信息打印出来。例如,在插入数据到一个有非空约束的表中时,用户会看到如下的出错信息:

INSERT INTO t1 (c1) VALUES (5); 
ERROR:  null value in column "c2" violates not-null constraint
DETAIL:  Failing row contains (c1) = (5).

用户实际上没有查看c2这个字段的权限,所以不应该让其感知到c2字段的存在。而这个错误信息暴露了这一点。

再如,假设用户没有查看c1字段值的权限,只有查看c3字段的权限并且c3上有值域约束,则在对c3赋值时,如果使用一个不符合值域约束的值,会提示错误,并且错误信息会把c1的值打印出来:

UPDATE t1 SET c3 = 10; 
ERROR:  new row for relation "t1" violates check constraint "t1_c3_check"
DETAIL:  Failing row contains (c1, c3) = (1, 10).

这样用户很容易通过执行类似update set c3 = "any value" 的语句,把c1的值打出来,造成信息泄露。

目录
相关文章
|
存储 关系型数据库 数据库
|
存储 缓存 关系型数据库
PgSQL · 代码浅析 · PostgreSQL 可靠性分析
背景 PostgreSQL 可靠性与大多数关系数据库一样,都是通过REDO来保障的。 群里有位童鞋问了一个问题,为什么PostgreSQL的REDO块大小默认是8K的,不是512字节。 这位童鞋提问的理由是,大多数的块设备扇区大小是512字节的,512字节可以保证原子写,而如果REDO的块大于512字节,可能会出现partial write。 那么PostgreSQL的redo(wal) 块
2437 0
|
SQL 关系型数据库 测试技术
PgSQL · 特性分析 · PostgreSQL 9.6 如何把你的机器掏空
背景 PostgreSQL 在向和纵向的扩展能力在开源数据库中一直处于非常领先的地位,例如今年推出的9.6,内置了sharding的功能,同时在scale-up的能力也有非常明显的提升,特别是在多核与高并发处理这块。 社区有同学在128核的机器上测试tpc-b的select only模式可以达到几百万的qps,机器的CPU资源被吃光光。 天下大势,分久必合,合久必分。谈了这么多年的shardi
6136 0
|
监控 关系型数据库 MySQL
MySQL · 社区贡献 · AliSQL那些事儿
一直以来我们都在不断对我们的阿里云MySQL分支做极致的性能优化及功能扩展。我们从社区的分支,如上游版本及Percona Server上学习新的改进和功能,并引入到我们的分支中。同时我们也将我们的一些改进思路反馈到上游,让整个社区也能享受到我们的成果。 本文主要介绍下AliSQL贡献给上游MySQL5.7版本的一些跟性能相关的优化。注意这里只摘取了几个比较有意思的优化,在即将开源的AliSQL中
1993 0
|
存储 关系型数据库 MySQL
MySQL · 特性分析 · MyRocks简介
RocksDB是facebook基于LevelDB实现的,目前为facebook内部大量业务提供服务。经过facebook大量工作,将RocksDB作为MySQL的一个存储引擎移植到MySQL,称之为MyRocks。 经过两年的发展,MyRocks已经比较成熟(RC阶段),现已进入了facebook MySQL的主分支了。MyRocks是开源的,参见git 。 下面对MyRocks做一个简单介绍,
2811 0
|
关系型数据库 MySQL 索引
MySQL · 捉虫状态 · bug分析两例
BUG 1 IN查询结果不对 背景 在mysql5.6.16版本下,构建如下测试用例 CREATE TABLE `a` ( `c1` varchar(512) NOT NULL DEFAULT '' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `a` VALUES ('i-28s18atup'),('i-2850jdoa2'),('i-
1380 0
|
关系型数据库 MySQL 索引
MySQL · 社区动态 · MariaDB 10.2 前瞻
继 MariaDB 10.1 之后,对标 MySQL 5.7 的 MariaDB 10.2 版本也即将封板,那么我们就来看看新的版本有哪些新的功能吧。 之前的月报我们写过一篇关于 Window Function 的介绍,除此之外,10.2.2 又即将发布一些新的特性。 Virtual Columns 进一步加强 目前有两种类型的虚拟列:PERSISTENT/STORED 类型,这种类型的虚拟
1826 0
|
关系型数据库 MySQL 数据库