Project

General

Profile

Actions

Bug #16151

closed

[PATCH] Fix a class of fstring related use-after-free

Added by alanwu (Alan Wu) over 4 years ago. Updated over 4 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.7.0dev (2019-09-07T18:26:35Z master e9bc8b35c6) [x86_64-linux]
[ruby-core:94831]

Description

Pull request: https://github.com/ruby/ruby/pull/2435

The bug

Run the following against master(e9bc8b3) to observe use-after-free:

-('a' * 30).force_encoding(Encoding::ASCII)
a = ('a' * 30).force_encoding(Encoding::ASCII).taint

t = Thread.new{}
t.name = a
eval('', binding, t.name)
p a
-('a' * 30).force_encoding(Encoding::ASCII)
a = ('a' * 30).force_encoding(Encoding::ASCII).taint

require 'ripper'
ripper = Ripper.new("", a)
eval('', binding, ripper.filename)
p a

There may be other cases in the standard library or in the wild.

Background

When a string has both STR_NOEMBED and STR_SHARED set, it relies on a
different string for its buffer. I will refer to strings that are depended upon
as "shared roots". Shared roots are frozen and have the STR_SHARED unset.
This is a bit unintuitive to me. A name for STR_SHARED that makes more sense
to me would be STR_BUFFER_ELSEWHERE.

What went wrong

It is not safe to free the buffer of a shared root while it has dependants. The
root and its dependants use the same buffer. As such, it is only safe to free
the shared buffer when all users are unreachable on the heap.

The Fix

rb_fstring has a code path that frees and replaces the buffer of its input.
Using this code path on the shared root of dependant strings sets up
use-after-free. This patch removes the problematic code path as no tests
require said buffer replacement functionality. Additionally, there has been
three other issues that steam from this particular code path. See #15926,
#15916 and #16136


I used @mame's commit in #16136 as the starting point for this investigation.
Thank you!

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0