Skip to content

rust wasm plugin painc #1280

@jaymie9019

Description

@jaymie9019

If you are reporting any crash or any potential security issue, do not
open an issue in this repo. Please report the issue via ASRC(Alibaba Security Response Center) where the issue will be triaged appropriately.

  • I have searched the issues of this repository and believe that this is not a duplicate.

Ⅰ. Issue Description

自行开发了一个基于 higress rust wasm 的 sdk 的插件在生产环境遇到了 panic,

Ⅱ. Describe what happened

截图中可以可以看到
image

当然这不是一个必现的问题,只有一些特殊的 case 才会遇到,最后我排查到的问题

https://github.com/alibaba/higress/blob/main/plugins/wasm-rust/src/plugin_wrapper.rs 文件中的一行代码

       for (k, v) in self.get_http_request_headers() {
            self.req_headers.insert(k, v);
        }

在这行代码中,底层调用了 hostcalls.rs 中的这个方法

    pub(super) fn deserialize_map(bytes: &[u8]) -> Vec<(String, String)> {
        let mut map = Vec::new();
        if bytes.is_empty() {
            return map;
        }
        let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[0..4]).unwrap()) as usize;
        let mut p = 4 + size * 8;
        for n in 0..size {
            let s = 4 + n * 8;
            let size = u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s..s + 4]).unwrap()) as usize;
            let key = bytes[p..p + size].to_vec();
            p += size + 1;
            let size =
                u32::from_le_bytes(<[u8; 4]>::try_from(&bytes[s + 4..s + 8]).unwrap()) as usize;
            let value = bytes[p..p + size].to_vec();
            p += size + 1;
            map.push((
                String::from_utf8(key).unwrap(),
                String::from_utf8(value).unwrap(),
            ));
        }
        map
    }

这行代码 String::from_utf8(value).unwrap(), 发生了 panic, 原因是有些特殊的 header 头的值无法被转成 utf8 格式的字符串,产生 error,所以 unwrap 就直接 panic。 我排查的思路是找到这个 header,然后打印出 traceId, 然后再去 access-log 中打开某个请求头的日志打印,再用 traceId 查询看下到底长什么样子。 这里给下截图,我把对应的头找到并且打印了出来

image

这里给两个方案

方案1,使用 String::from_utf8_lossy

for (k, v) in self.get_http_request_headers_bytes() {
         let header_value= String::from_utf8_lossy(v.as_slice()).to_string();
          self.req_headers.insert(k, header_value);
        }

方案2

        for (k, v) in self.get_http_request_headers_bytes() {
            if let Ok(header_value) = String::from_utf8(v) {
                self.req_headers.insert(k, header_value);
            }
        }

方案2更安全一些,但是丢弃了部分 header。这里更偏向于方案 1

Metadata

Metadata

Assignees

Labels

help wantedExtra attention is needed

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions