<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>dwt&#039;s life - 内核开发</title>
<link>https://www.dwt.life/tag/%E5%86%85%E6%A0%B8%E5%BC%80%E5%8F%91/</link>
<atom:link href="https://www.dwt.life/feed/tag/%E5%86%85%E6%A0%B8%E5%BC%80%E5%8F%91/" rel="self" type="application/rss+xml" />
<language>zh-CN</language>
<description></description>
<lastBuildDate>Wed, 07 Jul 2021 11:47:23 +0800</lastBuildDate>
<pubDate>Wed, 07 Jul 2021 11:47:23 +0800</pubDate>
<item>
<title>WAF 内核级防篡改模块实现思路</title>
<link>https://www.dwt.life/archives/30/</link>
<guid>https://www.dwt.life/archives/30/</guid>
<pubDate>Wed, 07 Jul 2021 11:47:23 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[graph TDA(内核加载) --&gt; J[&quot;获取HOOK表、关闭写保护&quot;];J --&gt; B[hook sys method];B --&gt; C[Write]...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<div class="mermaid">
graph TD

A(内核加载) --&gt; J[&quot;获取HOOK表、关闭写保护&quot;];
J --&gt; B[hook sys method];
B --&gt; C[Write];
B --&gt; D[Read];
B --&gt; E[&quot;Unlink(Unlinkat)&quot;];
B --&gt; F[&quot;Mkdir(Mkdirat)&quot;];
B --&gt; G[&quot;Creat&quot;];
B --&gt; H[&quot;Rmdir&quot;];
B --&gt; I[&quot;Move&quot;];
C --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
D --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
E --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
F --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
G --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
H --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
I --&gt; K[&quot;开启写保护、保存原hook函数&quot;];
K --&gt; O[&quot;等待触发相关操作&quot;];
O --&gt; P{&quot;根据传递的参数FD、Path和process确定权限&quot;};
P --&gt; |权限允许| Q[调用并返回原hook函数]
P -- 权限不允许 --&gt; R[&quot;记录日志并返回-EACCESS&quot;]</div>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://www.dwt.life/archives/30/#comments</comments>
<wfw:commentRss>https://www.dwt.life/feed/tag/%E5%86%85%E6%A0%B8%E5%BC%80%E5%8F%91/</wfw:commentRss>
</item>
<item>
<title>openat与open的区别及用法示例（dfd）</title>
<link>https://www.dwt.life/archives/29/</link>
<guid>https://www.dwt.life/archives/29/</guid>
<pubDate>Tue, 06 Jul 2021 09:12:52 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[从2.6.16版本开始，GNU/Linux引入opeant系统调用：#define _XOPEN_SOURCE 700 /* Or define _POSIX_C_SOURCE &gt;= 20...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>从2.6.16版本开始，GNU/Linux引入opeant系统调用：</p><pre><code>#define _XOPEN_SOURCE 700 /* Or define _POSIX_C_SOURCE &gt;= 200809 */
#include &lt;fcntl.h&gt;
int openat(int  dirfd , const char * pathname , int  flags , ... /* mode_t  mode */);</code></pre><p>Returns file descriptor on success, or –1 on error<br>同open相比，多了一个dirfd参数。关于它的用法，参考以下解释：</p><blockquote><p>If pathname specifies a relative pathname, then it is interpreted<br>relative to the directory referred to by the open file descriptor<br>dirfd, rather than relative to the process’s current working<br>directory.</p><p>If pathname specifies a relative pathname, and dirfd contains the<br>special value AT_FDCWD , then pathname is interpreted relative to the<br>process’s current working directory (i.e., the same behavior as<br>open(2)).</p><p>If pathname specifies an absolute pathname, then dirfd is ignored.</p></blockquote><p>总结起来，如果pathname是绝对路径，则dirfd参数没用。如果pathname是相对路径，并且dirfd的值不是AT_FDCWD，则pathname的参照物是相对于dirfd指向的目录，而不是进程的当前工作目录；反之，如果dirfd的值是AT_FDCWD，pathname则是相对于进程当前工作目录的相对路径，此时等同于open。参考kernel代码则一目了然：</p><p>引入openat（及其它at结尾的函数）有以下两个原因：</p><blockquote><p>First, openat() allows an application to avoid race conditions that<br>could occur when using open(2) to open files in directories other than<br>the current working directory. These race conditions result from the<br>fact that some component of the directory prefix given to open(2)<br>could be changed in parallel with the call to open(2). Such races can<br>be avoided by opening a file descriptor for the target directory, and<br>then specifying that file descriptor as the dirfd argument of<br>openat().</p><p>Second, openat() allows the implementation of a per-thread “current<br>working directory”, via file descriptor(s) maintained by the<br>application. (This functionality can also be obtained by tricks based<br>on the use of /proc/self/fd/dirfd, but less efficiently.)</p></blockquote><p>引入openat是方便一个进程内的各线程可拥有不同的当前目录，传统的chdir会影响整个进程，而使用openat只需要每个线程在初始化时打开一个目录(调用open)，然后就可以以openat在“当前目录”操作文件了，如：</p><pre><code>int dirfd = open(&quot;/tmp&quot;); // 相当于chdir到“/tmp”
int filefd = openat(dirfd, &quot;myfile&quot;); // 在/tmp目录下打开“myfile”文件 </code></pre><p>用法示例：</p><pre><code>#include &lt;stdio.h&gt;  
#include &lt;sys/stat.h&gt;  
#include &lt;fcntl.h&gt;  
#include &lt;stdlib.h&gt;  
#include &lt;unistd.h&gt;  
  
void creat_at(char *dir_path, char *relative_path)  
{  
    int dir_fd;  
    int fd;  
    int flags;  
    mode_t mode;  
  
    dir_fd = open(dir_path, O_RDONLY);  //fd参数是通过打开相对路径名所在的目录来获取。
    if (dir_fd &lt; 0)   
    {  
        perror(&quot;open&quot;);  
        exit(EXIT_FAILURE);  
    }  
  
    flags = O_CREAT | O_TRUNC | O_RDWR;  
    mode = 0640;  //-rw-r-----
    fd = openat(dir_fd, relative_path, flags, mode);  
    if (fd &lt; 0)   
    {  
        perror(&quot;openat&quot;);  
        exit(EXIT_FAILURE);  
    }  
  
    write(fd, &quot;HELLO&quot;, 5);  
  
    close(fd);  
    close(dir_fd);  
}  
  
int main()  
{  
    creat_at(&quot;../03.文件IO&quot;, &quot;log.txt&quot;);  
    return 0;  
}</code></pre><p>借用dirfd，将DIR*转换成int类型的文件描述符</p><pre><code>#include &lt;sys/types.h&gt;  
#include &lt;sys/stat.h&gt;  
#include &lt;fcntl.h&gt;  
#include &lt;dirent.h&gt;  
#include &lt;stdio.h&gt;  
#include &lt;unistd.h&gt;  
  
int main()  
{  
    DIR *dir;  
    int dirfd2;  
    int fd;  
    int n;  
  
    dir = opendir(&quot;../03.文件IO&quot;);  
    if(NULL == dir)  
    {  
        perror(&quot;open dir error&quot;);  
        return -1;  
    }  
    dirfd2 = dirfd(dir);  
    if(-1 == dirfd2)  
    {  
        perror(&quot;dirfd error&quot;);  
        return -1;  
    }  
  
    fd = openat(dirfd2,&quot;output.log&quot;,O_CREAT|O_RDWR|O_TRUNC, \
　　　　　　　　　　　　　　　　　　　　　　S_IRWXU|S_IRWXG|S_IRWXO);  
    if(-1 == fd)  
    {  
        perror(&quot;opeat error&quot;);  
        return -1;  
    }  
    n = write(fd,&quot;Hello world!\n&quot;,15);  
      
    close(fd);  
    closedir(dir);  
  
    return 0;  
  
}</code></pre>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://www.dwt.life/archives/29/#comments</comments>
<wfw:commentRss>https://www.dwt.life/feed/tag/%E5%86%85%E6%A0%B8%E5%BC%80%E5%8F%91/</wfw:commentRss>
</item>
<item>
<title>郵件回復歸檔：關於Linux Kernel不同版本存在的模塊開發問題</title>
<link>https://www.dwt.life/archives/28/</link>
<guid>https://www.dwt.life/archives/28/</guid>
<pubDate>Mon, 05 Jul 2021 14:14:02 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[來自https://szlin.me/的博主的郵件解答，其中第一點有不小的作用。Hi Rick,一般而言, 遇到這種改版造成行為改變的議題, 我常用以下兩種方法.找出並定位改變的 kernel ...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>來自<a href="https://szlin.me/">https://szlin.me/</a>的博主的郵件解答，其中第一點有不小的作用。</p><blockquote><p>Hi Rick,</p><p>一般而言, 遇到這種改版造成行為改變的議題, 我常用以下兩種方法.</p><ol><li>找出並定位改變的 kernel 版本 - 使用 git blame + bisect 來找出 function argument or content 的差異, 並詳細閱讀 commit log, 大概就會有手感.</li></ol><p>如果找到並閱讀完 commit log 還是沒有頭緒, 可試試</p><ol start="2"><li>透過 grep 關鍵字, 找出其他也有使用該 function 的檔案, 了解它們在新版的使用方法. 並可搭配 git blame 來看如何這些檔案如何從舊版移植到新版</li></ol><p>以上行為也可以搭配 kernel documentation 來閱讀, 雖然有時候文件會跟不上 code 進版速度.</p><p>最後, 若公司允許, 建議把 driver 進行 upstream, 推入 Linux kernel mainline 中.<br>這樣一來就不會有因為 kernel 進版而導致錯誤, 因為 Linux kernel 本身進板時, maintainer 就會處理了.</p><p>以上, 希望對你有所幫助.</p><p>SZ</p></blockquote>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://www.dwt.life/archives/28/#comments</comments>
<wfw:commentRss>https://www.dwt.life/feed/tag/%E5%86%85%E6%A0%B8%E5%BC%80%E5%8F%91/</wfw:commentRss>
</item>
<item>
<title>linux 内核函数 filp_open、filp_read、IS_ERR、ERR_PTR、PTR_ERR 简介</title>
<link>https://www.dwt.life/archives/22/</link>
<guid>https://www.dwt.life/archives/22/</guid>
<pubDate>Fri, 02 Jul 2021 11:41:00 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[内核态文件操作在用户态，我们操作文件可以用C库函数：open()、read()、write()等，但是在内核态没有库函数可用，这时就需要用内核的一些函数：filp_open、filp_close...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>内核态文件操作<br>在用户态，我们操作文件可以用C库函数：open()、read()、write()等，但是在内核态没有库函数可用，这时就需要用内核的一些函数：<code>filp_open</code>、<code>filp_close</code>、<code>vfs_read</code>、<code>vfs_write</code>、<code>set_fs</code>、<code>get_fs</code>等函数，</p><p>在下列文件中声明：</p><pre><code class="lang-c">/usr/lib/modules/3.10.0-514.el7.x86_64/build/include/linux/fs.h

/usr/lib/modules/3.10.0-514.el7.x86_64/build/include/asm-generic/uaccess.h

/usr/src/kernels/3.10.0-514.el7.x86_64/include/linux/err.h</code></pre><h2>filp_open</h2><p><code>extern struct file *filp_open(const char *, int, umode_t);</code></p><p>参数说明：</p><p>第一个参数表明要打开或创建文件的名称(包括路径部分)。</p><p>第二个参数文件的打开方式，其取值与标准库中的open相应参数类似，可以取O_CREAT,O_RDWR,O_RDONLY等。</p><p>第三个参数创建文件时使用，设置创建文件的读写权限，其它情况可以设为0</p><p>该函数返回strcut file*结构指针，供后继函数操作使用，该返回值用IS_ERR()来检验其有效性。</p><h2>filp_close</h2><p><code>extern int filp_close(struct file *, fl_owner_t id);</code></p><p>参数说明：</p><p>第一个参数是filp_open返回的file结构体指针</p><p>第二个参数基本上都是NULL</p><h2>vfs_read/write</h2><p><code>extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);</code><br><code>extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);</code></p><p>参数说明：</p><p>第一个参数是filp_open返回的file结构体指针</p><p>第二个参数是buf，注意，这个参数有用__user修饰，表明buf指向用户空间的地址，如果传入内核空间的地址，就会报错，并返回-EFAULT，</p><p>但在kernel中，要使这两个读写函数使用kernel空间的buf指针也能正确工作，需要使用set_fs()</p><h2>set_fs</h2><p><code>static inline void set_fs(mm_segment_t fs)</code></p><p>该函数的作用是改变kernel对内存地址检查的处理方式，</p><p>其实该函数的参数fs只有两个取值：USER_DS，KERNEL_DS，分别代表用户空间和内核空间，</p><p>默认情况下，kernel取值为USER_DS，即对用户空间地址检查并做变换。</p><p>那么要在这种对内存地址做检查变换的函数中使用内核空间地址，就需要使用set_fs(KERNEL_DS)进行设置，</p><p>它的作用是取得当前的设置，这两个函数的一般用法为：</p><pre><code class="lang-c">filp_open()
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
...... //与内存有关的操作
set_fs(old_fs);
filp_close</code></pre><p>第三个参数表明文件要读写的起始位置。</p><p>几点说明：（从网上查找的资料）</p><p>Linux Kernel组成员不赞成在kernel中独立的读写文件(这样做可能会影响到策略和安全问题)，对内核需要操作的文件内容，最好由应用层配合完成。</p><p>这些函数的正确运行需要依赖于进程环境，因此,有些函数不能在中断的handle或Kernel中不属于任何进程的代码中执行，否则可能出现崩溃，要避免这种情况发生，可以在kernel中创建内核线程，将这些函数放在线程环境下执行。</p><pre><code class="lang-c">
#ifndef _LINUX_ERR_H
#define _LINUX_ERR_H
#include &lt;linux/compiler.h&gt;
#include &lt;asm/errno.h&gt;
/*
 * Kernel pointers have redundant information, so we can use a
 * scheme where we can return either an error code or a dentry
 * pointer with the same return value.
 *
 * This should be a per-architecture thing, to allow different
 * error and pointer decisions.
 */
#define MAX_ERRNO       4095
 
#ifndef __ASSEMBLY__
 
#define IS_ERR_VALUE(x) unlikely((x) &gt;= (unsigned long)-MAX_ERRNO)
 
static inline void * __must_check ERR_PTR(long error)
{
        return (void *) error;
}

static inline long __must_check PTR_ERR(const void *ptr)
{
        return (long) ptr;
}
 
static inline long __must_check IS_ERR(const void *ptr)
{
        return IS_ERR_VALUE((unsigned long)ptr);
}
 
static inline long __must_check IS_ERR_OR_NULL(const void *ptr)
{
        return !ptr || IS_ERR_VALUE((unsigned long)ptr);
}</code></pre><p>内核中的函数常常返回指针，问题是如果出错，也希望能够通过返回的指针体现出来。</p><p>总体来说，如果内核返回一个指针，那么有三种情况：合法指针，NULL指针和非法指针。</p><p>在linux中有很多错误，内核错误可以参考include/asm-generic/errno-base.h。</p><p>MAX_ERRNO定义了最大的错误号4095，刚好是4k-1，所以内核地址保留了0xfffffffffffff000~0xffffffffffffffff（64位系统）用来记录错误号，也就是说这段地址和Linux的错误号是一一对应的，可以用上面的内联函数相互转化。</p><p>比如说我们上面的filp_open函数返回值，用IS_ERR函数去检查，如果地址落在0xfffffffffffff000~0xffffffffffffffff范围，</p><p>表示filp_open函数失败，IS_ERR为1，同时filp_open返回的错误地址对应一个linux的错误号，</p><p>如果想知道是哪个错误号，就用PTR_ERR函数来转化。</p><p>错误的返回地址和错误号是可以使用 ERR_PTR、PTR_ERR 相互转化的。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://www.dwt.life/archives/22/#comments</comments>
<wfw:commentRss>https://www.dwt.life/feed/tag/%E5%86%85%E6%A0%B8%E5%BC%80%E5%8F%91/</wfw:commentRss>
</item>
</channel>
</rss>