ときどきの雑記帖 RE* (新南口)
Only When I Laugh
JR東日本渋谷駅山手線内回りホーム
移設(拡幅)以来初めて使った。 話には聞いていたけど以前と比べてかなり広くなっていてびっくりした (まあこの後外回りも移設されて島式になるという話だから 今ほど広さを感じなくなるかもしれないけど)。
coalesce
「null合体」で使われていたあの英単語、実は以前からSQLで使われていたのね。
SQL関数coalesceの使い方と読み方 | ⬢ Appirits spirits
こっちは「合体」にはされていないらしい😄
JIT
そう言えばJITコンパイラーをJITと略すことに対して 同様な指摘をしているのは見た記憶がないような気もする
命名にこだわっている #ちょうぜつエンジニアめもりーちゃん pic.twitter.com/D3X3My18D0
— ひさてるさん (@tanakahisateru) March 10, 2022
perlの場合 mapは関数の名前にあるしねえ。 それとPerl 5.0の時点でHashMapという名前を使った例はあったかな?🤔
dirty pipe
話題になってるdirty pipeの脆弱性、修正コードみたらものすごいショボいミスで笑ってる。https://t.co/W8Bn1vY87c
— 小崎 資広 (KOSAKI Motohiro) (@kosaki55tea) March 9, 2022
確かに差分を見ると
kernel/git/torvalds/linux.git - Linux kernel source tree
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index b0e0acdf96c15..6dd5330f7a995 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -414,6 +414,7 @@ static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t by
return 0;
buf->ops = &page_cache_pipe_buf_ops;
+ buf->flags = 0;
get_page(page);
buf->page = page;
buf->offset = offset;
@@ -577,6 +578,7 @@ static size_t push_pipe(struct iov_iter *i, size_t size,
break;
buf->ops = &default_pipe_buf_ops;
+ buf->flags = 0;
buf->page = page;
buf->offset = 0;
buf->len = min_t(ssize_t, left, PAGE_SIZE);
こうなんだけど、周りも含めてコードを見ると
iov_iter.c « lib - kernel/git/torvalds/linux.git - Linux kernel source tree
static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i)
{
struct pipe_inode_info *pipe = i->pipe;
struct pipe_buffer *buf;
unsigned int p_tail = pipe->tail;
unsigned int p_mask = pipe->ring_size - 1;
unsigned int i_head = i->head;
size_t off;
if (unlikely(bytes > i->count))
bytes = i->count;
if (unlikely(!bytes))
return 0;
if (!sanity(i))
return 0;
off = i->iov_offset;
buf = &pipe->bufs[i_head & p_mask];
if (off) {
if (offset == off && buf->page == page) {
/* merge with the last one */
buf->len += bytes;
i->iov_offset += bytes;
goto out;
}
i_head++;
buf = &pipe->bufs[i_head & p_mask];
}
if (pipe_full(i_head, p_tail, pipe->max_usage))
return 0;
buf->ops = &page_cache_pipe_buf_ops;
get_page(page);
buf->page = page;
buf->offset = offset;
buf->len = bytes;
pipe->head = i_head + 1;
i->iov_offset = offset + bytes;
i->head = i_head;
out:
i->count -= bytes;
return bytes;
}
や
static size_t push_pipe(struct iov_iter *i, size_t size,
int *iter_headp, size_t *offp)
{
struct pipe_inode_info *pipe = i->pipe;
unsigned int p_tail = pipe->tail;
unsigned int p_mask = pipe->ring_size - 1;
unsigned int iter_head;
size_t off;
ssize_t left;
if (unlikely(size > i->count))
size = i->count;
if (unlikely(!size))
return 0;
left = size;
data_start(i, &iter_head, &off);
*iter_headp = iter_head;
*offp = off;
if (off) {
left -= PAGE_SIZE - off;
if (left <= 0) {
pipe->bufs[iter_head & p_mask].len += size;
return size;
}
pipe->bufs[iter_head & p_mask].len = PAGE_SIZE;
iter_head++;
}
while (!pipe_full(iter_head, p_tail, pipe->max_usage)) {
struct pipe_buffer *buf = &pipe->bufs[iter_head & p_mask];
struct page *page = alloc_page(GFP_USER);
if (!page)
break;
buf->ops = &default_pipe_buf_ops;
buf->page = page;
buf->offset = 0;
buf->len = min_t(ssize_t, left, PAGE_SIZE);
left -= buf->len;
iter_head++;
pipe->head = iter_head;
if (left == 0)
return size;
}
return size - left;
}
なので(引用したのはパッチが当たってない状態なので注意)、 単純な初期化時のポカミスとも違うような?
とくに
構造体fooを宣言したら直後にmemset(&foo, 0, sizeof foo);するようにしてましたが、処理速度優先だと難しいかな……。 https://t.co/cZJzm6Mkh5
— まアンジー (@ma_angie) March 9, 2022
というのは今回のケースには該当しない気がする。 とは言え問題の構造体がどんなものなのか確かめてみると
struct pipe_buffer {
struct page * page;
unsigned int offset;
unsigned int len;
const struct pipe_buf_operations * ops;
unsigned int flags;
unsigned long private;
};
で、各メンバーの意味はと言えば
Members
struct page * page
the page containing the data for the pipe buffer
unsigned int offset
offset of data inside the page
unsigned int len
length of data inside the page
const struct pipe_buf_operations * ops
operations associated with this buffer. See pipe_buf_operations.
unsigned int flags
pipe buffer flags. See above.
unsigned long private
private data owned by the ops.
なので、private
はまあそういうもの(謎)だとしても
flags
に値を設定してないのはやはりポカミス?
C99
ところで↑のコードの周りも眺めていて気がついたのだけど
iov_iter.c « lib - kernel/git/torvalds/linux.git - Linux kernel source tree
void iov_iter_init(struct iov_iter *i, unsigned int direction,
const struct iovec *iov, unsigned long nr_segs,
size_t count)
{
WARN_ON(direction & ~(READ | WRITE));
*i = (struct iov_iter) {
.iter_type = ITER_IOVEC,
.nofault = false,
.data_source = direction,
.iov = iov,
.nr_segs = nr_segs,
.iov_offset = 0,
.count = count
};
}
C99(以降)の機能ですよね、これ。
D.1.13 指示付きの初期化子 (Sun Studio 12: C ユーザーズガイド)
links
- 20分で分かるDirty Pipe(CVE-2022-0847) - knqyf263’s blog
- [B! Linux] 20分で分かるDirty Pipe(CVE-2022-0847) - knqyf263’s blog
- spliceを使って高速・省メモリでGzipからZIPを作る - knqyf263’s blog
- hiboma/pipeの実装.md at master · hiboma/hiboma · GitHub
- kernel exploit 有用的结构体——spray&victim — bsauce
- splice and pipes — The Linux Kernel documentation
- linuxカーネルパイプpipe実装詳細 - JPDEBUG.COM
- pipeバッファ - Linuxの備忘録とか・・・(目次へ)
- struct pipe_buffer
- Toward a better list iterator for the Linux kernel | Hacker News
- Toward a better list iterator for the kernel [LWN.net]