libcareplus支持的补丁类型

Posted rtoax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libcareplus支持的补丁类型相关的知识,希望对你有一定的参考价值。

libcareplus支持的补丁类型

荣涛
2021年10月9日

程序补丁的类型是有限制的,本文主要关于补丁代码类型进行讨论,主要分为如下几个方面:

1. 概述

1.1. 支持的补丁类型

  • 添加函数
  • 添加静态函数
  • 修改函数
  • 添加局部变量
  • 修改局部变量

1.2. 不支持的补丁类型

  • 函数中添加静态变量
  • 函数中修改静态变量
  • 修改静态全局变量
  • 修改全局变量
  • 添加静态全局变量
  • 添加全局变量
  • 宏定义补丁
  • 结构体补丁

2. 支持的补丁类型

2.1. 添加函数

补丁如下:

--- utils/log.c	2021-10-09 15:33:33.194961364 +0800
+++ patches/log.c	2021-10-09 16:05:26.133599487 +0800
@@ -8,8 +8,13 @@ static FILE *__log_fp = NULL;
 
 static pthread_mutex_t __log_fp_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+void print_rongtao(FILE *fp)
+{
+	fprintf(fp, "rongtao");
+}
 
 static int _____print(FILE *fp, char *prefix, char *content) {
+	print_rongtao(fp);
 	return fprintf(fp, "%s%s", prefix?prefix:"", content?content:"empty\\n");
 }

2.2. 添加静态函数

补丁如下:

--- utils/log.c	2021-10-09 15:33:33.194961364 +0800
+++ patches/log.c	2021-10-09 16:07:17.221844935 +0800
@@ -8,8 +8,13 @@ static FILE *__log_fp = NULL;
 
 static pthread_mutex_t __log_fp_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+static void print_rongtao(FILE *fp)
+{
+	fprintf(fp, "rongtao");
+}
 
 static int _____print(FILE *fp, char *prefix, char *content) {
+	print_rongtao(fp);
 	return fprintf(fp, "%s%s", prefix?prefix:"", content?content:"empty\\n");
 }

2.3. 修改函数

补丁如下:

--- utils/log.c	2021-10-09 15:33:33.194961364 +0800
+++ patches/log.c	2021-10-09 16:10:57.359312981 +0800
@@ -10,7 +10,7 @@ static pthread_mutex_t __log_fp_mutex =
 
 
 static int _____print(FILE *fp, char *prefix, char *content) {
-	return fprintf(fp, "%s%s", prefix?prefix:"", content?content:"empty\\n");
+	return fprintf(fp, "rongtao:%s%s", prefix?prefix:"", content?content:"empty\\n");
 }

2.4. 添加局部变量

补丁如下:

--- utils/log.c	2021-10-09 16:14:31.297727449 +0800
+++ patches/log.c	2021-10-09 16:14:03.847415596 +0800
@@ -31,8 +31,10 @@ void set_log_fp(FILE *fp) {
 
 int __vlog(const char *func, int line, char *fmt, ...)
 {
+	char prefix[256] = {0};
 	char buffer[1024] = {0};
 
+	snprintf(prefix, 256, "[%s:%d] ", func, line);
 	va_list va;
 	va_start(va, fmt);
 	vsnprintf(buffer, 1024, fmt, va);
@@ -40,5 +42,5 @@ int __vlog(const char *func, int line, c
 
 	FILE *fp = get_log_fp();
 
-	return _____print(fp, NULL, buffer);
+	return _____print(fp, prefix, buffer);
 }

2.5. 修改局部变量

补丁如下:

--- utils/log.c	2021-10-09 16:14:03.847415596 +0800
+++ patches/log.c	2021-10-09 16:17:00.663424361 +0800
@@ -31,10 +31,10 @@ void set_log_fp(FILE *fp) {
 
 int __vlog(const char *func, int line, char *fmt, ...)
 {
-	char prefix[256] = {0};
+	char prefix[1024] = {0};
 	char buffer[1024] = {0};
 
-	snprintf(prefix, 256, "[%s:%d] ", func, line);
+	snprintf(prefix, 1024, "[VLOG][%s:%d] ", func, line);
 	va_list va;
 	va_start(va, fmt);
 	vsnprintf(buffer, 1024, fmt, va);

3. 不支持的补丁类型

3.1. 函数中添加静态变量

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:38:38.673151762 +0800
@@ -31,6 +31,7 @@ int print_hello(char *s)
 void* task_routine(void *arg)
 {
 	static unsigned long count = 0;
+	static unsigned long _count = 0;
 
 	struct thread *t = (struct thread *)arg;
 	int item = t->i;

3.2. 函数中修改静态变量

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:39:54.874014676 +0800
@@ -30,7 +30,7 @@ int print_hello(char *s)
 
 void* task_routine(void *arg)
 {
-	static unsigned long count = 0;
+	static unsigned long count = 10;
 
 	struct thread *t = (struct thread *)arg;
 	int item = t->i;

3.3. 修改静态全局变量

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:20:49.499024110 +0800
@@ -12,7 +12,7 @@ struct thread {
 };
 
 // global variables
-static int print_interval_sec = 1;
+static int print_interval_sec = 3;

3.4. 修改全局变量

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:20:49.499024110 +0800
@@ -12,7 +12,7 @@ struct thread {
 };
 
 // global variables
-int print_interval_sec = 1;
+int print_interval_sec = 3;

3.5. 添加静态全局变量

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:47:54.953452731 +0800
@@ -13,6 +13,7 @@ struct thread {
 
 // global variables
 int print_interval_sec = 1;
+static print_interval_sec2 = 3;
 
 static char *global_strings[] = {
 "Apple",

需要注意的是,当添加的全局变量没有被使用的时候,在加载热补丁的时候是没问题的,但是当使用了添加的u去安居变量,加载热补丁过程会失败,补丁如下:

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:49:18.657403612 +0800
@@ -13,6 +13,7 @@ struct thread {
 
 // global variables
 int print_interval_sec = 1;
+static print_interval_sec2 = 3;
 
 static char *global_strings[] = {
 "Apple",
@@ -47,6 +48,7 @@ void* task_routine(void *arg)
 				break;
 		}
         sleep(print_interval_sec);
+        sleep(print_interval_sec2);
 		count++;
     }
 	pthread_exit(NULL);

3.6. 添加全局变量

这与添加静态全局变量是相同的错误。

--- main.c	2021-10-09 16:20:39.243907603 +0800
+++ patches/main.c	2021-10-09 16:45:00.535476023 +0800
@@ -13,6 +13,7 @@ struct thread {
 
 // global variables
 int print_interval_sec = 1;
+int print_interval_sec2 = 4;
 
 static char *global_strings[] = {
 "Apple",
@@ -47,6 +48,7 @@ void* task_routine(void *arg)
 				break;
 		}
         sleep(print_interval_sec);
+		sleep(print_interval_sec2);
 		count++;
     }

4. 一个非常有意义的示例

通常,我们在代码中经常会使用字符串拷贝函数strcpy,但strcpy常常成为系统漏洞的源泉,所以,在编程中建议使用strncpy,以防内存越界访问。这两个函数声明如下:

#include <string.h>
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

4.1. 一个strcpy示例

直接看代码:

#include <stdio.h>
#include <string.h>

int main()
{
	int a = 1;
	char s[4] = {0};
	int b = 2;

	strcpy(s, "hello");

	printf("a = %d\\n", a);
	printf("s = %s\\n", s);
	printf("b = %d\\n", b);
}

编译运行:

$ gcc strncpy.c 
$ ./a.out
a = 1
s = hello
b = 111

很明显,变量b被篡改。那么如何解决呢?使用strncpy就解决了。

#include <stdio.h>
#include <string.h>

int main()
{
	int a = 1;
	char s[4] = {0};
	int b = 2;

#ifdef NOTUSE_STRNCPY
	strcpy(s, "hello");
#else
	strncpy(s, "hello", sizeof(s));
#endif

	printf("a = %d\\n", a);
	printf("s = %s\\n", s);
	printf("b = %d\\n", b);
}

编译运行:

$ gcc strncpy.c 
$ ./a.out 
a = 1
s = hell 
b = 2

可见,使用函数strncpy是有益处的。

4.2. 正在运行的程序代码

编写一段程序,这个程序需要使用strcpy函数,不对源字符串进行长度检查,那么在代码中很容易造成目的字符串的地址越界访问问题,如下所示:

int print_hello(char*);
int print_hello1(char *src_s)
{
	char password[6] = {0};
	char s[8] = {0};
	strcpy(s, src_s);
	return print_hello(s);
}

从而可得到两个补丁:

  1. 补丁1
--- ./foo1.c	2021-10-09 17:19:21.540888985 +0800
+++ patches/foo1.c	2021-10-09 17:21:18.647219907 +0800
@@ -9,7 +9,7 @@ int print_hello1(char *src_s)
 {
 	char password[6] = {0};
 	char s[8] = {0};
-	strcpy(s, src_s);
+	strncpy(s, src_s, sizeof(s));
 	return print_hello(s);
 }
  1. 补丁2
--- ./foo2.c	2021-10-09 17:19:47.216180788 +0800
+++ patches/foo2.c	2021-10-09 17:21:29.684345355 +0800
@@ -7,6 +7,6 @@ int print_hello2(char *src_s)
 {
 	char password[6] = {0};
 	char s[4] = {0};
-	strcpy(s, src_s);
+	strncpy(s, src_s, sizeof(s以上是关于libcareplus支持的补丁类型的主要内容,如果未能解决你的问题,请参考以下文章

LibcarePlus用户态程序热补丁

libcareplus一个Qemu-6.1.0热补丁示例

用户态热补丁

libcareplus应用于Qemu-6.1.0

Qemu-6.1.0多热补丁管理

支持动态或静态片段的不同屏幕尺寸?