公众号
点击「查看原文」跳转到 GitHub 上对应文件,链接就可以点击了
qq群 点击进入
欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言
本期文章由 HMY lhmouse赞助
标准委员会动态/ide/编译器信息放在这里
最近陆陆续续又有很多c++26 St Louis参会报告出来,这里列一下
另外Ykiko也写了一个 St. Louis WG21 会议回顾
OpenSSH 鉴权超时终止会话时信号竞态条件漏洞,可远程攻击,可拿root shell
2020年10月到24年5月之间的版本全部中招,请及时打补丁
本台记者lhmouse报道
我们在 OpenSSH 的服务器(sshd)中发现了一个漏洞(信号处理器竞赛条件):如果客户端没有在 LoginGraceTime 秒(默认为 120 秒,旧版本为 600 秒)内进行身份验证,那么 sshd 的 SIGALRM 处理器就会被异步调用,但这个信号处理器会调用各种非异步信号安全的函数(例如 syslog())。这种竞赛条件会影响默认配置下的 sshd。
经调查,我们发现该漏洞实际上是 CVE-2006-5051 的回归(”4.4 之前 OpenSSH 中的信号处理器竞赛条件允许远程攻击者导致拒绝服务(崩溃),并可能执行任意代码”),该漏洞由 Mark Dowd 于 2006 年报告。
这一回归是在 2020 年 10 月(OpenSSH 8.5p1)的 752250c 号提交(”修订 OpenSSH 的日志基础架构”)中引入的,该提交意外删除了 sigdie() 中的 “#ifdef DO_LOG_SAFE_IN_SIGHAND”,而 sigdie() 是 sshd 的 SIGALRM 处理程序直接调用的函数。换句话说
如果未针对 CVE-2006-5051 进行回传修补,或未针对 CVE-2008-4109 进行修补(CVE-2008-4109 是针对 CVE-2006-5051 的不正确修补),OpenSSH < 4.4p1 就容易受到此信号处理器竞赛条件的影响; 4.4p1 <= OpenSSH < 8.5p1 不会受到此信号处理器竞赛条件的影响(因为 CVE-2006-5051 补丁在 sigdie() 中添加的 “#ifdef DO_LOG_SAFE_IN_SIGHAND “将此不安全函数转换为安全的 _exit(1) 调用); 8.5p1 <= OpenSSH < 9.8p1 会再次出现这种信号处理竞赛条件(因为 “#ifdef DO_LOG_SAFE_IN_SIGHAND” 被意外地从 sigdie() 中删除了)。
鉴定为和之前xz 被植入木马一样的问题
开源社区并不是免费的,得盯着相关更新了
(安全的同事应该是在关注的。不过这些年降本增效第一个裁的就是安全吧)
const_cast
介绍stop_token,其实就是塞了个状态回调,规范化了一下 直接看代码
#include <chrono>
#include <iostream>
#include <thread>
#include <vector>
using namespace::std::literals;
auto func = [](std::stop_token stoken) { // (1)
int counter{0};
auto thread_id = std::this_thread::get_id();
std::stop_callback callBack(stoken, [&counter, thread_id] { // (2)
std::cout << "Thread id: " << thread_id
<< "; counter: " << counter << '\n';
});
while (counter < 10) {
std::this_thread::sleep_for(0.2s);
++counter;
}
};
int main() {
std::vector<std::jthread> vecThreads(10);
for(auto& thr: vecThreads) thr = std::jthread(func);
std::this_thread::sleep_for(1s); // (3)
for(auto& thr: vecThreads) thr.request_stop(); // (4)
}
直接贴代码吧
template<typename T>
struct sfunc;
template<typename R, typename ...Args>
struct sfunc<R(Args...)> {
struct lambda_handler_result {
void* funcs[3];
};
enum class tag {
free,
copy,
call
};
lambda_handler_result (*lambda_handler)(void*, void**) {nullptr};
void* lambda {nullptr};
template<typename F>
sfunc(F f) { *this = f;}
sfunc() {}
sfunc(const sfunc& f) { *this = f; }
sfunc(sfunc&& f) { *this = f; }
sfunc& operator = (sfunc&& f) {
if(&f == this){
return *this;
}
lambda_handler = f.lambda_handler;
lambda = f.lambda;
f.lambda_handler = nullptr;
f.lambda = nullptr;
return *this;
}
void free_lambda() {
if(lambda_handler) {
auto ff {lambda_handler(lambda, nullptr).funcs[(int)tag::free]};
if(ff){
((void(*)(void*))ff)(lambda);
}
}
lambda = nullptr;
}
sfunc& operator = (const sfunc& f) {
if(&f == this) {
return *this;
}
free_lambda();
lambda_handler = f.lambda_handler;
if(f.lambda) {
auto ff {lambda_handler(lambda, nullptr).funcs[(int)tag::copy]};
if(ff) {
((void(*)(void*, void**))ff)(f.lambda, &lambda);
} else {
lambda = f.lambda;
}
}
return *this;
}
template<typename ...>
struct is_function_pointer;
template<typename T>
struct is_function_pointer<T> {
static constexpr bool value {false};
};
template<typename T, typename ...Ts>
struct is_function_pointer<T(*)(Ts...)> {
static constexpr bool value {true};
};
template<typename F>
auto operator = (F f) {
if constexpr(is_function_pointer<F>::value == true) {
free_lambda();
lambda = (void*)f;
lambda_handler = [](void* l, void**) {
return lambda_handler_result{/* 两个括号jekyll报错*/{nullptr, nullptr, (void*)+[](void* l, Args... args) {
auto& f {*(F)l};
return f(forward<Args>(args)...);
}}};
};
} else {
free_lambda();
lambda = {new F{f}};
lambda_handler = [](void* d, void** v) {
return lambda_handler_result{/* 两个括号jekyll报错*/{(void*)[](void*d){ delete (F*)d;},
(void*)[](void*d, void** v){ *v = new F{*((F*)d)};},
(void*)[](void* l, Args... args)
{
auto& f {*(F*)l};
return f(forward<Args>(args)...);
}}};
};
}
}
inline R operator()(Args... args) {
return ((R(*)(void*, Args...))lambda_handler(nullptr, nullptr).funcs[(int)tag::call])(lambda, forward<Args>(args)...);
}
~sfunc() { free_lambda(); }
};
没SSO
函数没有类型,直接赋值是不可以的
void f(int);
void f(int, int);
// `f` is an overload set with 2 members
auto g = f; // error! cannot deduce the type of `g`
// This is because:
using FF = decltype(f); // error! overload set has not type
std::invocable<int> auto g = f; // error! cannot deduce the type of `g`
// bind invoke也不行,他们要接受对象
而lambda有类型,即使这个类型看不到,那么就可以封装一层
#include <cassert>
#include <utility>
int g(int x) { return x + 1; }
int g(int x, int y) { assert(false); }
class MyClass {
public:
int f(int x) { return x + 1; }
int f(int x, int y) { assert(false); }
};
#define OVERLOAD(...) [&](auto &&... args) -> decltype(auto) { \
return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
}
int main(int argc, char *argv[]) {
assert(OVERLOAD(g)(5) == 6);
MyClass obj;
assert(OVERLOAD(obj.f)(5) == 6);
return 0;
}
没看懂
代码在这 https://github.com/salykova/matmul.c
感觉不是很靠谱,影响因素太多了
自己看吧,我不是业内,不了解
团建了一波,定的酒店露天自助,人均四百,吃出了80的感觉,亏麻
酒店内的餐饮服务还是太坑